mirror of
				https://github.com/fabianonline/telegram_backup.git
				synced 2025-10-30 23:29:22 +00:00 
			
		
		
		
	Removed libraries.
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,297 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| import com.droidkit.actors.mailbox.Mailbox; | ||||
| import com.droidkit.actors.messages.DeadLetter; | ||||
| import com.droidkit.actors.messages.NamedMessage; | ||||
| import com.droidkit.actors.tasks.*; | ||||
| import com.droidkit.actors.tasks.messages.TaskError; | ||||
| import com.droidkit.actors.tasks.messages.TaskResult; | ||||
| import com.droidkit.actors.tasks.messages.TaskTimeout; | ||||
|  | ||||
| import java.lang.reflect.Array; | ||||
| import java.util.UUID; | ||||
|  | ||||
| /** | ||||
|  * Actor object | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class Actor { | ||||
|  | ||||
|     private UUID uuid; | ||||
|     private String path; | ||||
|  | ||||
|     private ActorContext context; | ||||
|     private Mailbox mailbox; | ||||
|  | ||||
|     private ActorAskImpl askPattern; | ||||
|  | ||||
|     public Actor() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * <p>INTERNAL API</p> | ||||
|      * Initialization of actor | ||||
|      * | ||||
|      * @param uuid    uuid of actor | ||||
|      * @param path    path of actor | ||||
|      * @param context context of actor | ||||
|      * @param mailbox mailbox of actor | ||||
|      */ | ||||
|     public final void initActor(UUID uuid, String path, ActorContext context, Mailbox mailbox) { | ||||
|         this.uuid = uuid; | ||||
|         this.path = path; | ||||
|         this.context = context; | ||||
|         this.mailbox = mailbox; | ||||
|         this.askPattern = new ActorAskImpl(self()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor System | ||||
|      * | ||||
|      * @return Actor System | ||||
|      */ | ||||
|     public final ActorSystem system() { | ||||
|         return context.getSystem(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Self actor reference | ||||
|      * | ||||
|      * @return self reference | ||||
|      */ | ||||
|     public final ActorRef self() { | ||||
|         return context.getSelf(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor context | ||||
|      * | ||||
|      * @return context | ||||
|      */ | ||||
|     protected final ActorContext context() { | ||||
|         return context; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sender of last received message | ||||
|      * | ||||
|      * @return sender's ActorRef | ||||
|      */ | ||||
|     public final ActorRef sender() { | ||||
|         return context.sender(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor UUID | ||||
|      * | ||||
|      * @return uuid | ||||
|      */ | ||||
|     protected final UUID getUuid() { | ||||
|         return uuid; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor path | ||||
|      * | ||||
|      * @return path | ||||
|      */ | ||||
|     protected final String getPath() { | ||||
|         return path; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor mailbox | ||||
|      * | ||||
|      * @return mailbox | ||||
|      */ | ||||
|     public final Mailbox getMailbox() { | ||||
|         return mailbox; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called before first message receiving | ||||
|      */ | ||||
|     public void preStart() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public final void onReceiveGlobal(Object message) { | ||||
|         if (message instanceof DeadLetter) { | ||||
|             if (askPattern.onDeadLetter((DeadLetter) message)) { | ||||
|                 return; | ||||
|             } | ||||
|         } else if (message instanceof TaskResult) { | ||||
|             if (askPattern.onTaskResult((TaskResult) message)) { | ||||
|                 return; | ||||
|             } | ||||
|         } else if (message instanceof TaskTimeout) { | ||||
|             if (askPattern.onTaskTimeout((TaskTimeout) message)) { | ||||
|                 return; | ||||
|             } | ||||
|         } else if (message instanceof TaskError) { | ||||
|             if (askPattern.onTaskError((TaskError) message)) { | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         onReceive(message); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Receiving of message | ||||
|      * | ||||
|      * @param message message | ||||
|      */ | ||||
|     public void onReceive(Object message) { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called after actor shutdown | ||||
|      */ | ||||
|     public void postStop() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Reply message to sender of last message | ||||
|      * | ||||
|      * @param message reply message | ||||
|      */ | ||||
|     public void reply(Object message) { | ||||
|         if (context.sender() != null) { | ||||
|             context.sender().send(message, self()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public AskFuture combine(AskFuture... futures) { | ||||
|         return askPattern.combine(futures); | ||||
|     } | ||||
|  | ||||
|     public AskFuture combine(AskCallback<Object[]> callback, AskFuture... futures) { | ||||
|         AskFuture future = combine(futures); | ||||
|         future.addListener(callback); | ||||
|         return future; | ||||
|     } | ||||
|  | ||||
|     public <T> AskFuture combine(final String name, final Class<T> clazz, AskFuture... futures) { | ||||
|         return combine(new AskCallback<Object[]>() { | ||||
|             @Override | ||||
|             public void onResult(Object[] result) { | ||||
|                 T[] res = (T[]) Array.newInstance(clazz, result.length); | ||||
|                 for (int i = 0; i < result.length; i++) { | ||||
|                     res[i] = (T) result[i]; | ||||
|                 } | ||||
|                 self().send(new NamedMessage(name, res)); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onError(Throwable throwable) { | ||||
|                 self().send(new NamedMessage(name, throwable)); | ||||
|             } | ||||
|         }, futures); | ||||
|     } | ||||
|  | ||||
|     public <T> AskFuture combine(final String name, AskFuture... futures) { | ||||
|         return combine(new AskCallback<Object[]>() { | ||||
|             @Override | ||||
|             public void onResult(Object[] result) { | ||||
|                 self().send(new NamedMessage(name, result)); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onError(Throwable throwable) { | ||||
|                 self().send(new NamedMessage(name, throwable)); | ||||
|             } | ||||
|         }, futures); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param selection ActorSelection of task | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorSelection selection) { | ||||
|         return askPattern.ask(system().actorOf(selection), 0, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param selection ActorSelection of task | ||||
|      * @param timeout   timeout of task | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorSelection selection, long timeout) { | ||||
|         return askPattern.ask(system().actorOf(selection), timeout, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param selection ActorSelection of task | ||||
|      * @param callback  callback for ask | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorSelection selection, AskCallback callback) { | ||||
|         return askPattern.ask(system().actorOf(selection), 0, callback); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param selection ActorSelection of task | ||||
|      * @param timeout   timeout of task | ||||
|      * @param callback  callback for ask | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorSelection selection, long timeout, AskCallback callback) { | ||||
|         return askPattern.ask(system().actorOf(selection), timeout, callback); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param ref ActorRef of task | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorRef ref) { | ||||
|         return askPattern.ask(ref, 0, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param ref     ActorRef of task | ||||
|      * @param timeout timeout of task | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorRef ref, long timeout) { | ||||
|         return askPattern.ask(ref, timeout, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param ref      ActorRef of task | ||||
|      * @param callback callback for ask | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorRef ref, AskCallback callback) { | ||||
|         return askPattern.ask(ref, 0, callback); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Ask TaskActor for result | ||||
|      * | ||||
|      * @param ref      ActorRef of task | ||||
|      * @param timeout  timeout of task | ||||
|      * @param callback callback for ask | ||||
|      * @return Future | ||||
|      */ | ||||
|     public AskFuture ask(ActorRef ref, long timeout, AskCallback callback) { | ||||
|         return askPattern.ask(ref, timeout, callback); | ||||
|     } | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| /** | ||||
|  * Context of actor | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorContext { | ||||
|     private final ActorScope actorScope; | ||||
|  | ||||
|     /** | ||||
|      * <p>INTERNAL API</p> | ||||
|      * Creating of actor context | ||||
|      * | ||||
|      * @param scope actor scope | ||||
|      */ | ||||
|     public ActorContext(ActorScope scope) { | ||||
|         this.actorScope = scope; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor Reference | ||||
|      * | ||||
|      * @return reference | ||||
|      */ | ||||
|     public ActorRef getSelf() { | ||||
|         return actorScope.getActorRef(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actor system | ||||
|      * | ||||
|      * @return Actor system | ||||
|      */ | ||||
|     public ActorSystem getSystem() { | ||||
|         return actorScope.getActorSystem(); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Sender of last received message | ||||
|      * | ||||
|      * @return sender's ActorRef | ||||
|      */ | ||||
|     public ActorRef sender() { | ||||
|         return actorScope.getSender(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Stopping actor | ||||
|      */ | ||||
|     public void stopSelf() { | ||||
|         try { | ||||
|             actorScope.shutdownActor(); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| /** | ||||
|  * Object for manual actors creating | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public interface ActorCreator<T extends Actor> { | ||||
|     /** | ||||
|      * Create actor | ||||
|      * | ||||
|      * @return Actor | ||||
|      */ | ||||
|     public T create(); | ||||
| } | ||||
| @@ -1,121 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| import com.droidkit.actors.mailbox.AbsActorDispatcher; | ||||
|  | ||||
| import java.util.UUID; | ||||
|  | ||||
| /** | ||||
|  * Reference to Actor that allows to send messages to real Actor | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorRef { | ||||
|     private ActorSystem system; | ||||
|     private AbsActorDispatcher dispatcher; | ||||
|     private UUID uuid; | ||||
|     private String path; | ||||
|  | ||||
|     public UUID getUuid() { | ||||
|         return uuid; | ||||
|     } | ||||
|  | ||||
|     public String getPath() { | ||||
|         return path; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * <p>INTERNAL API</p> | ||||
|      * Creating actor reference | ||||
|      * | ||||
|      * @param system     actor system | ||||
|      * @param dispatcher dispatcher of actor | ||||
|      * @param path       path of actor | ||||
|      * @param uuid       uuid of actor | ||||
|      */ | ||||
|     public ActorRef(ActorSystem system, AbsActorDispatcher dispatcher, UUID uuid, String path) { | ||||
|         this.system = system; | ||||
|         this.dispatcher = dispatcher; | ||||
|         this.uuid = uuid; | ||||
|         this.path = path; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message with empty sender | ||||
|      * | ||||
|      * @param message message | ||||
|      */ | ||||
|     public void send(Object message) { | ||||
|         send(message, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message with specified sender | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param sender  sender | ||||
|      */ | ||||
|     public void send(Object message, ActorRef sender) { | ||||
|         send(message, 0, sender); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message with empty sender and delay | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param delay   delay | ||||
|      */ | ||||
|     public void send(Object message, long delay) { | ||||
|         send(message, delay, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param delay   delay | ||||
|      * @param sender  sender | ||||
|      */ | ||||
|     public void send(Object message, long delay, ActorRef sender) { | ||||
|         dispatcher.sendMessage(path, message, ActorTime.currentTime() + delay, sender); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message once | ||||
|      * | ||||
|      * @param message message | ||||
|      */ | ||||
|     public void sendOnce(Object message) { | ||||
|         send(message, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message once | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param sender  sender | ||||
|      */ | ||||
|     public void sendOnce(Object message, ActorRef sender) { | ||||
|         sendOnce(message, 0, sender); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message once | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param delay   delay | ||||
|      */ | ||||
|     public void sendOnce(Object message, long delay) { | ||||
|         sendOnce(message, delay, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send message once | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param delay   delay | ||||
|      * @param sender  sender | ||||
|      */ | ||||
|     public void sendOnce(Object message, long delay, ActorRef sender) { | ||||
|         dispatcher.sendMessageOnce(path, message, ActorTime.currentTime() + delay, sender); | ||||
|     } | ||||
| } | ||||
| @@ -1,128 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| import com.droidkit.actors.mailbox.AbsActorDispatcher; | ||||
| import com.droidkit.actors.mailbox.Mailbox; | ||||
|  | ||||
| import java.util.UUID; | ||||
|  | ||||
| /** | ||||
|  * <p>INTERNAL API</p> | ||||
|  * Actor Scope contains states of actor, UUID, Path, Props and Actor (if created). | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorScope { | ||||
|  | ||||
|     public static final int STATE_STARTING = 0; | ||||
|     public static final int STATE_RUNNING = 1; | ||||
|     public static final int STATE_SHUTDOWN = 2; | ||||
|  | ||||
|     private final UUID uuid; | ||||
|     private final String path; | ||||
|     private final Props props; | ||||
|  | ||||
|     private final ActorRef actorRef; | ||||
|     private final Mailbox mailbox; | ||||
|  | ||||
|     private final AbsActorDispatcher dispatcher; | ||||
|  | ||||
|     private final ActorSystem actorSystem; | ||||
|  | ||||
|     private int state; | ||||
|  | ||||
|     private Actor actor; | ||||
|  | ||||
|     private ActorRef sender; | ||||
|  | ||||
|     public ActorScope(ActorSystem actorSystem, Mailbox mailbox, ActorRef actorRef, AbsActorDispatcher dispatcher, UUID uuid, String path, Props props) { | ||||
|         this.actorSystem = actorSystem; | ||||
|         this.mailbox = mailbox; | ||||
|         this.actorRef = actorRef; | ||||
|         this.dispatcher = dispatcher; | ||||
|         this.uuid = uuid; | ||||
|         this.path = path; | ||||
|         this.props = props; | ||||
|         this.state = STATE_STARTING; | ||||
|     } | ||||
|  | ||||
|     public AbsActorDispatcher getDispatcher() { | ||||
|         return dispatcher; | ||||
|     } | ||||
|  | ||||
|     public int getState() { | ||||
|         return state; | ||||
|     } | ||||
|  | ||||
|     public UUID getUuid() { | ||||
|         return uuid; | ||||
|     } | ||||
|  | ||||
|     public String getPath() { | ||||
|         return path; | ||||
|     } | ||||
|  | ||||
|     public Props getProps() { | ||||
|         return props; | ||||
|     } | ||||
|  | ||||
|     public ActorRef getActorRef() { | ||||
|         return actorRef; | ||||
|     } | ||||
|  | ||||
|     public Mailbox getMailbox() { | ||||
|         return mailbox; | ||||
|     } | ||||
|  | ||||
|     public Actor getActor() { | ||||
|         return actor; | ||||
|     } | ||||
|  | ||||
|     public ActorSystem getActorSystem() { | ||||
|         return actorSystem; | ||||
|     } | ||||
|  | ||||
|     public ActorRef getSender() { | ||||
|         return sender; | ||||
|     } | ||||
|  | ||||
|     public void setSender(ActorRef sender) { | ||||
|         this.sender = sender; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create actor | ||||
|      * | ||||
|      * @throws Exception | ||||
|      */ | ||||
|     public void createActor() throws Exception { | ||||
|         if (state == STATE_STARTING) { | ||||
|             actor = props.create(); | ||||
|             CurrentActor.setCurrentActor(actor); | ||||
|             actor.initActor(getUuid(), getPath(), new ActorContext(this), getMailbox()); | ||||
|             actor.preStart(); | ||||
|         } else if (state == STATE_RUNNING) { | ||||
|             throw new RuntimeException("Actor already created"); | ||||
|         } else if (state == STATE_SHUTDOWN) { | ||||
|             throw new RuntimeException("Actor shutdown"); | ||||
|         } else { | ||||
|             throw new RuntimeException("Unknown ActorScope state"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shutdown actor | ||||
|      * | ||||
|      * @throws Exception | ||||
|      */ | ||||
|     public void shutdownActor() throws Exception { | ||||
|         if (state == STATE_STARTING || state == STATE_RUNNING || | ||||
|                 state == STATE_SHUTDOWN) { | ||||
|             actorSystem.removeActor(this); | ||||
|             dispatcher.disconnectScope(this); | ||||
|             actor.postStop(); | ||||
|             actor = null; | ||||
|         } else { | ||||
|             throw new RuntimeException("Unknown ActorScope state"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| /** | ||||
|  * Actor selection: group and path of actor | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorSelection { | ||||
|     private final Props props; | ||||
|     private final String path; | ||||
|  | ||||
|     public ActorSelection(Props props, String path) { | ||||
|         this.props = props; | ||||
|         this.path = path; | ||||
|     } | ||||
|  | ||||
|     public Props getProps() { | ||||
|         return props; | ||||
|     } | ||||
|  | ||||
|     public String getPath() { | ||||
|         return path; | ||||
|     } | ||||
| } | ||||
| @@ -1,129 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| import com.droidkit.actors.mailbox.AbsActorDispatcher; | ||||
| import com.droidkit.actors.mailbox.ActorDispatcher; | ||||
|  | ||||
| import java.util.HashMap; | ||||
|  | ||||
| /** | ||||
|  * Entry point for Actor Model, creates all actors and dispatchers | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorSystem { | ||||
|  | ||||
|     private static final ActorSystem mainSystem = new ActorSystem(); | ||||
|  | ||||
|     /** | ||||
|      * Main actor system | ||||
|      * | ||||
|      * @return ActorSystem | ||||
|      */ | ||||
|     public static ActorSystem system() { | ||||
|         return mainSystem; | ||||
|     } | ||||
|  | ||||
|     private static final String DEFAULT_DISPATCHER = "default"; | ||||
|  | ||||
|     private final HashMap<String, AbsActorDispatcher> dispatchers = new HashMap<String, AbsActorDispatcher>(); | ||||
|     private final HashMap<String, ActorScope> actors = new HashMap<String, ActorScope>(); | ||||
|  | ||||
|     /** | ||||
|      * Creating new actor system | ||||
|      */ | ||||
|     public ActorSystem() { | ||||
|         addDispatcher(DEFAULT_DISPATCHER); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Adding dispatcher with threads count = {@code Runtime.getRuntime().availableProcessors()} | ||||
|      * | ||||
|      * @param dispatcherId dispatcher id | ||||
|      */ | ||||
|     public void addDispatcher(String dispatcherId) { | ||||
|         addDispatcher(dispatcherId, new ActorDispatcher(this, Runtime.getRuntime().availableProcessors())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Registering custom dispatcher | ||||
|      * | ||||
|      * @param dispatcherId dispatcher id | ||||
|      * @param dispatcher   dispatcher object | ||||
|      */ | ||||
|     public void addDispatcher(String dispatcherId, AbsActorDispatcher dispatcher) { | ||||
|         synchronized (dispatchers) { | ||||
|             if (dispatchers.containsKey(dispatcherId)) { | ||||
|                 return; | ||||
|             } | ||||
|             dispatchers.put(dispatcherId, dispatcher); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public <T extends Actor> ActorRef actorOf(ActorSelection selection) { | ||||
|         return actorOf(selection.getProps(), selection.getPath()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creating or getting existing actor from actor class | ||||
|      * | ||||
|      * @param actor Actor Class | ||||
|      * @param path  Actor Path | ||||
|      * @param <T>   Actor Class | ||||
|      * @return ActorRef | ||||
|      */ | ||||
|     public <T extends Actor> ActorRef actorOf(Class<T> actor, String path) { | ||||
|         return actorOf(Props.create(actor), path); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creating or getting existing actor from actor props | ||||
|      * | ||||
|      * @param props Actor Props | ||||
|      * @param path  Actor Path | ||||
|      * @return ActorRef | ||||
|      */ | ||||
|     public ActorRef actorOf(Props props, String path) { | ||||
|         // TODO: Remove lock | ||||
|         synchronized (actors) { | ||||
|             // Searching for already created actor | ||||
|             ActorScope scope = actors.get(path); | ||||
|  | ||||
|             // If already created - return ActorRef | ||||
|             if (scope != null) { | ||||
|                 return scope.getActorRef(); | ||||
|             } | ||||
|  | ||||
|             // Finding dispatcher for actor | ||||
|             String dispatcherId = props.getDispatcher() == null ? DEFAULT_DISPATCHER : props.getDispatcher(); | ||||
|  | ||||
|             AbsActorDispatcher mailboxesDispatcher; | ||||
|             synchronized (dispatchers) { | ||||
|                 if (!dispatchers.containsKey(dispatcherId)) { | ||||
|                     throw new RuntimeException("Unknown dispatcherId '" + dispatcherId + "'"); | ||||
|                 } | ||||
|                 mailboxesDispatcher = dispatchers.get(dispatcherId); | ||||
|             } | ||||
|  | ||||
|             // Creating actor scope | ||||
|             scope = mailboxesDispatcher.createScope(path, props); | ||||
|  | ||||
|             // Saving actor in collection | ||||
|             actors.put(path, scope); | ||||
|  | ||||
|             return scope.getActorRef(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * WARRING! Call only during processing message in actor! | ||||
|      * | ||||
|      * @param scope Actor Scope | ||||
|      */ | ||||
|     void removeActor(ActorScope scope) { | ||||
|         synchronized (actors) { | ||||
|             if (actors.get(scope.getPath()) == scope) { | ||||
|                 actors.remove(scope.getPath()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,27 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| /** | ||||
|  * Time used by actor system, uses System.nanoTime() inside | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorTime { | ||||
|  | ||||
|     private static long lastTime = 0; | ||||
|     private static final Object timeLock = new Object(); | ||||
|  | ||||
|     /** | ||||
|      * Getting current actor system time | ||||
|      * | ||||
|      * @return actor system time | ||||
|      */ | ||||
|     public static long currentTime() { | ||||
|         long res = System.nanoTime() / 1000000; | ||||
|         synchronized (timeLock) { | ||||
|             if (lastTime < res) { | ||||
|                 lastTime = res; | ||||
|             } | ||||
|             return lastTime; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| /** | ||||
|  * <p>INTERNAL API!</p> | ||||
|  * Keeps current actor for thread. Will be used for better implementations of patterns. | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class CurrentActor { | ||||
|     private static ThreadLocal<Actor> currentActor = new ThreadLocal<Actor>(); | ||||
|  | ||||
|     public static void setCurrentActor(Actor actor) { | ||||
|         currentActor.set(actor); | ||||
|     } | ||||
|  | ||||
|     public static Actor getCurrentActor() { | ||||
|         return currentActor.get(); | ||||
|     } | ||||
| } | ||||
| @@ -1,88 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| /** | ||||
|  * <p>Props is a configuration class to specify options for the creation of actors, think of it as an immutable and | ||||
|  * thus freely shareable recipe for creating an actor including associated dispatcher information.</p> | ||||
|  * For more information you may read about <a href="http://doc.akka.io/docs/akka/2.3.5/java/untyped-actors.html">Akka Props</a>. | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public final class Props<T extends Actor> { | ||||
|     private static final int TYPE_DEFAULT = 1; | ||||
|     private static final int TYPE_CREATOR = 2; | ||||
|  | ||||
|     private final Class<T> aClass; | ||||
|     private final Object[] args; | ||||
|     private final int type; | ||||
|     private final ActorCreator<T> creator; | ||||
|  | ||||
|     private final String dispatcher; | ||||
|  | ||||
|     private Props(Class<T> aClass, Object[] args, int type, String dispatcher, ActorCreator<T> creator) { | ||||
|         this.aClass = aClass; | ||||
|         this.args = args; | ||||
|         this.type = type; | ||||
|         this.creator = creator; | ||||
|         this.dispatcher = dispatcher; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creating actor from Props | ||||
|      * | ||||
|      * @return Actor | ||||
|      * @throws Exception | ||||
|      */ | ||||
|     public T create() throws Exception { | ||||
|         if (type == TYPE_DEFAULT) { | ||||
|             if (args == null || args.length == 0) { | ||||
|                 return aClass.newInstance(); | ||||
|             } | ||||
|         } else if (type == TYPE_CREATOR) { | ||||
|             return creator.create(); | ||||
|         } | ||||
|  | ||||
|         throw new RuntimeException("Unsupported create method"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Getting dispatcher id if available | ||||
|      * | ||||
|      * @return | ||||
|      */ | ||||
|     public String getDispatcher() { | ||||
|         return dispatcher; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Changing dispatcher | ||||
|      * | ||||
|      * @param dispatcher dispatcher id | ||||
|      * @return this | ||||
|      */ | ||||
|     public Props<T> changeDispatcher(String dispatcher) { | ||||
|         return new Props<T>(aClass, args, type, dispatcher, creator); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create props from class | ||||
|      * | ||||
|      * @param tClass Actor class | ||||
|      * @param <T>    Actor class | ||||
|      * @return Props object | ||||
|      */ | ||||
|     public static <T extends Actor> Props<T> create(Class<T> tClass) { | ||||
|         return new Props(tClass, null, TYPE_DEFAULT, null, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create props from Actor creator | ||||
|      * | ||||
|      * @param clazz   Actor class | ||||
|      * @param creator Actor creator class | ||||
|      * @param <T>     Actor class | ||||
|      * @return Props object | ||||
|      */ | ||||
|     public static <T extends Actor> Props<T> create(Class<T> clazz, ActorCreator<T> creator) { | ||||
|         return new Props<T>(clazz, null, TYPE_CREATOR, null, creator); | ||||
|     } | ||||
| } | ||||
| @@ -1,137 +0,0 @@ | ||||
| package com.droidkit.actors; | ||||
|  | ||||
| import com.droidkit.actors.messages.NamedMessage; | ||||
|  | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashSet; | ||||
|  | ||||
| /** | ||||
|  * ReflectedActor is Actor that uses java reflection for processing of messages | ||||
|  * For each message developer must create method named "onReceive" with one argument | ||||
|  * with type of message | ||||
|  * For special message {@link com.droidkit.actors.messages.NamedMessage} you can create method | ||||
|  * named like {@code onDownloadReceive}. First letter in {@code Download} will be lowed and ReflectedActor | ||||
|  * will use this as {@code download} for name of message. | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ReflectedActor extends Actor { | ||||
|  | ||||
|     private ArrayList<Event> events = new ArrayList<Event>(); | ||||
|     private ArrayList<NamedEvent> namedEvents = new ArrayList<NamedEvent>(); | ||||
|  | ||||
|     @Override | ||||
|     public final void preStart() { | ||||
|         Method[] methods = getClass().getDeclaredMethods(); | ||||
|         for (Method m : methods) { | ||||
|             if (m.getName().startsWith("onReceive") && m.getParameterTypes().length == 1) { | ||||
|                 if (m.getName().equals("onReceive") && m.getParameterTypes()[0] == Object.class) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 events.add(new Event(m.getParameterTypes()[0], m)); | ||||
|                 continue; | ||||
|             } | ||||
|             if (m.getName().startsWith("on") && m.getName().endsWith("Receive")) { | ||||
|                 String methodName = m.getName(); | ||||
|                 String name = methodName.substring("on".length(), methodName.length() - "Receive".length()); | ||||
|                 if (name.length() > 0) { | ||||
|                     name = name.substring(0, 1).toLowerCase() + name.substring(1); | ||||
|                     namedEvents.add(new NamedEvent(name, m.getParameterTypes()[0], m)); | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         preStartImpl(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Replacement for preStart | ||||
|      */ | ||||
|     public void preStartImpl() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Object message) { | ||||
|         if (message instanceof NamedMessage) { | ||||
|             NamedMessage named = (NamedMessage) message; | ||||
|             for (NamedEvent event : namedEvents) { | ||||
|                 if (event.name.equals(named.getName())) { | ||||
|                     if (event.check(named.getMessage())) { | ||||
|                         try { | ||||
|                             event.method.invoke(this, named.getMessage()); | ||||
|                         } catch (IllegalAccessException e) { | ||||
|                             e.printStackTrace(); | ||||
|                         } catch (InvocationTargetException e) { | ||||
|                             e.printStackTrace(); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (Event event : events) { | ||||
|             if (event.check(message)) { | ||||
|                 try { | ||||
|                     event.method.invoke(this, message); | ||||
|                 } catch (IllegalAccessException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } catch (InvocationTargetException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     class NamedEvent { | ||||
|         private String name; | ||||
|         private Class arg; | ||||
|         private Method method; | ||||
|  | ||||
|         NamedEvent(String name, Class arg, Method method) { | ||||
|             this.name = name; | ||||
|             this.arg = arg; | ||||
|             this.method = method; | ||||
|         } | ||||
|  | ||||
|         public String getName() { | ||||
|             return name; | ||||
|         } | ||||
|  | ||||
|         public Class getArg() { | ||||
|             return arg; | ||||
|         } | ||||
|  | ||||
|         public Method getMethod() { | ||||
|             return method; | ||||
|         } | ||||
|  | ||||
|         public boolean check(Object obj) { | ||||
|             if (arg.isAssignableFrom(obj.getClass())) { | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     class Event { | ||||
|         private Class arg; | ||||
|         private Method method; | ||||
|  | ||||
|         Event(Class arg, Method method) { | ||||
|             this.arg = arg; | ||||
|             this.method = method; | ||||
|         } | ||||
|  | ||||
|         public boolean check(Object obj) { | ||||
|             if (arg.isAssignableFrom(obj.getClass())) { | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,84 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| /** | ||||
|  * Queue for dispatching messages for {@link ThreadPoolDispatcher}. | ||||
|  * Implementation MUST BE thread-safe. | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public abstract class AbstractDispatchQueue<T> { | ||||
|  | ||||
|     /** | ||||
|      * Value used for result of waitDelay when dispatcher need to wait forever | ||||
|      */ | ||||
|     protected static final long FOREVER = Long.MAX_VALUE; | ||||
|  | ||||
|     private QueueListener listener; | ||||
|  | ||||
|     /** | ||||
|      * Fetch message for dispatching and removing it from dispatch queue | ||||
|      * | ||||
|      * @param time current time from ActorTime | ||||
|      * @return message or null if there is no message for processing | ||||
|      */ | ||||
|     public abstract T dispatch(long time); | ||||
|  | ||||
|     /** | ||||
|      * Expected delay for nearest message. | ||||
|      * You might provide most accurate value as you can, | ||||
|      * this will minimize unnecessary thread work. | ||||
|      * For example, if you will return zero here then thread will | ||||
|      * loop continuously and consume processor time. | ||||
|      * | ||||
|      * @param time current time from ActorTime | ||||
|      * @return delay in ms | ||||
|      */ | ||||
|     public abstract long waitDelay(long time); | ||||
|  | ||||
|     /** | ||||
|      * Implementation of adding message to queue | ||||
|      * | ||||
|      * @param message | ||||
|      * @param atTime | ||||
|      */ | ||||
|     protected abstract void putToQueueImpl(T message, long atTime); | ||||
|  | ||||
|     /** | ||||
|      * Adding message to queue | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param atTime  time (use {@link com.droidkit.actors.ActorTime#currentTime()} for currentTime) | ||||
|      */ | ||||
|     public final void putToQueue(T message, long atTime) { | ||||
|         putToQueueImpl(message, atTime); | ||||
|         notifyQueueChanged(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Notification about queue change. | ||||
|      */ | ||||
|     protected void notifyQueueChanged() { | ||||
|         QueueListener lListener = listener; | ||||
|         if (lListener != null) { | ||||
|             lListener.onQueueChanged(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Getting of current queue listener | ||||
|      * | ||||
|      * @return queue listener | ||||
|      */ | ||||
|     public QueueListener getListener() { | ||||
|         return listener; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Setting queue listener | ||||
|      * | ||||
|      * @param listener queue listener | ||||
|      */ | ||||
|     public void setListener(QueueListener listener) { | ||||
|         this.listener = listener; | ||||
|     } | ||||
| } | ||||
| @@ -1,47 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| /** | ||||
|  * Abstract thread dispatcher for messages | ||||
|  */ | ||||
| public abstract class AbstractDispatcher<T, Q extends AbstractDispatchQueue<T>> { | ||||
|     final private Q queue; | ||||
|     final Dispatch<T> dispatch; | ||||
|  | ||||
|     protected AbstractDispatcher(Q queue, Dispatch<T> dispatch) { | ||||
|         this.queue = queue; | ||||
|         this.dispatch = dispatch; | ||||
|         this.queue.setListener(new QueueListener() { | ||||
|             @Override | ||||
|             public void onQueueChanged() { | ||||
|                 notifyDispatcher(); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Queue used for dispatching | ||||
|      * | ||||
|      * @return queue | ||||
|      */ | ||||
|     public Q getQueue() { | ||||
|         return queue; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Actual execution of action | ||||
|      * | ||||
|      * @param message action | ||||
|      */ | ||||
|     protected void dispatchMessage(T message) { | ||||
|         if (dispatch != null) { | ||||
|             dispatch.dispatchMessage(message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Notification about queue change | ||||
|      */ | ||||
|     protected void notifyDispatcher() { | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| /** | ||||
|  * Used as callback for message processing | ||||
|  */ | ||||
| public interface Dispatch<T> { | ||||
|     void dispatchMessage(T message); | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| /** | ||||
|  * Listener for monitoring queue changes in dispatchers | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public interface QueueListener { | ||||
|     public void onQueueChanged(); | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| import static com.droidkit.actors.ActorTime.currentTime; | ||||
|  | ||||
| /** | ||||
|  * RunnableDispatcher is used for executing various Runnable in background | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class RunnableDispatcher extends ThreadPoolDispatcher<Runnable, SimpleDispatchQueue<Runnable>> { | ||||
|  | ||||
|     /** | ||||
|      * Creating of dispatcher with one thread | ||||
|      */ | ||||
|     public RunnableDispatcher() { | ||||
|         this(1); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creating of dispatcher with {@code threadsCount} threads | ||||
|      * | ||||
|      * @param threadsCount number of threads | ||||
|      */ | ||||
|     public RunnableDispatcher(int threadsCount) { | ||||
|         super(threadsCount, new SimpleDispatchQueue<Runnable>()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Creating of dispatcher with {@code threadsCount} threads and {@code priority} | ||||
|      * | ||||
|      * @param threadsCount number of threads | ||||
|      * @param priority     priority of threads | ||||
|      */ | ||||
|     public RunnableDispatcher(int threadsCount, int priority) { | ||||
|         super(threadsCount, priority, new SimpleDispatchQueue<Runnable>()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void dispatchMessage(Runnable object) { | ||||
|         object.run(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Post action to queue | ||||
|      * | ||||
|      * @param action action | ||||
|      */ | ||||
|     public void postAction(Runnable action) { | ||||
|         postAction(action, 0); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Post action to queue with delay | ||||
|      * | ||||
|      * @param action action | ||||
|      * @param delay  delay | ||||
|      */ | ||||
|     public void postAction(Runnable action, long delay) { | ||||
|         getQueue().putToQueue(action, currentTime() + delay); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removing action from queue | ||||
|      * | ||||
|      * @param action action | ||||
|      */ | ||||
|     public void removeAction(Runnable action) { | ||||
|         getQueue().removeFromQueue(action); | ||||
|     } | ||||
| } | ||||
| @@ -1,116 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.Map; | ||||
| import java.util.TreeMap; | ||||
|  | ||||
| /** | ||||
|  * Simple queue implementation for dispatchers | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class SimpleDispatchQueue<T> extends AbstractDispatchQueue<T> { | ||||
|  | ||||
|     protected final TreeMap<Long, Message> messages = new TreeMap<Long, Message>(); | ||||
|  | ||||
|     protected final ArrayList<Message> freeMessages = new ArrayList<Message>(); | ||||
|  | ||||
|     /** | ||||
|      * Removing message from queue | ||||
|      * | ||||
|      * @param t message | ||||
|      */ | ||||
|     public void removeFromQueue(T t) { | ||||
|         synchronized (messages) { | ||||
|             for (Map.Entry<Long, Message> messageEntry : messages.entrySet()) { | ||||
|                 if (messageEntry.getValue().equals(t)) { | ||||
|                     Message message = messages.remove(messageEntry.getKey()); | ||||
|                     recycle(message); | ||||
|                     notifyQueueChanged(); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public T dispatch(long time) { | ||||
|         synchronized (messages) { | ||||
|             if (messages.size() > 0) { | ||||
|                 long firstKey = messages.firstKey(); | ||||
|                 if (firstKey < time) { | ||||
|                     Message message = messages.remove(firstKey); | ||||
|                     T res = message.action; | ||||
|                     recycle(message); | ||||
|                     return res; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long waitDelay(long time) { | ||||
|         synchronized (messages) { | ||||
|             if (messages.size() > 0) { | ||||
|                 long firstKey = messages.firstKey(); | ||||
|                 if (firstKey < time) { | ||||
|                     return 0; | ||||
|                 } else { | ||||
|                     return time - firstKey; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return FOREVER; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void putToQueueImpl(T action, long atTime) { | ||||
|         Message message = obtainMessage(); | ||||
|         message.setMessage(action, atTime); | ||||
|         synchronized (messages) { | ||||
|             while (messages.containsKey(atTime)) { | ||||
|                 atTime++; | ||||
|             } | ||||
|             messages.put(atTime, message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Getting new message object for writing to queue | ||||
|      * | ||||
|      * @return Message object | ||||
|      */ | ||||
|     protected Message obtainMessage() { | ||||
|         synchronized (freeMessages) { | ||||
|             if (freeMessages.size() > 0) { | ||||
|                 return freeMessages.remove(0); | ||||
|             } | ||||
|         } | ||||
|         return new Message(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Saving message object to free cache | ||||
|      * | ||||
|      * @param message Message object | ||||
|      */ | ||||
|     protected void recycle(Message message) { | ||||
|         synchronized (freeMessages) { | ||||
|             freeMessages.add(message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Holder for messages | ||||
|      */ | ||||
|     protected class Message { | ||||
|         public long destTime; | ||||
|         public T action; | ||||
|  | ||||
|         public void setMessage(T action, long destTime) { | ||||
|             this.action = action; | ||||
|             this.destTime = destTime; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,129 +0,0 @@ | ||||
| package com.droidkit.actors.dispatch; | ||||
|  | ||||
| import static com.droidkit.actors.ActorTime.currentTime; | ||||
|  | ||||
| /** | ||||
|  * ThreadPoolDispatcher is used for dispatching messages on it's own threads. | ||||
|  * Class is completely thread-safe. | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ThreadPoolDispatcher<T, Q extends AbstractDispatchQueue<T>> extends AbstractDispatcher<T, Q> { | ||||
|  | ||||
|     private final Thread[] threads; | ||||
|  | ||||
|     private boolean isClosed = false; | ||||
|  | ||||
|     /** | ||||
|      * Dispatcher constructor. Create threads with NORM_PRIORITY. | ||||
|      * | ||||
|      * @param count    thread count | ||||
|      * @param queue    queue for messages | ||||
|      *                 (see {@link com.droidkit.actors.dispatch.AbstractDispatchQueue} for more information) | ||||
|      * @param dispatch Dispatch for message processing | ||||
|      */ | ||||
|     public ThreadPoolDispatcher(int count, Q queue, Dispatch<T> dispatch) { | ||||
|         this(count, Thread.NORM_PRIORITY, queue, dispatch); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Dispatcher constructor. Create threads with NORM_PRIORITY. | ||||
|      * Should override dispatchMessage for message processing. | ||||
|      * | ||||
|      * @param count thread count | ||||
|      * @param queue queue for messages | ||||
|      *              (see {@link com.droidkit.actors.dispatch.AbstractDispatchQueue} for more information) | ||||
|      */ | ||||
|     public ThreadPoolDispatcher(int count, Q queue) { | ||||
|         this(count, Thread.NORM_PRIORITY, queue, null); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Dispatcher constructor. Create threads with NORM_PRIORITY. | ||||
|      * Should override dispatchMessage for message processing. | ||||
|      * | ||||
|      * @param count    thread count | ||||
|      * @param priority thread priority | ||||
|      * @param queue    queue for messages | ||||
|      *                 (see {@link com.droidkit.actors.dispatch.AbstractDispatchQueue} for more information) | ||||
|      */ | ||||
|     public ThreadPoolDispatcher(int count, int priority, Q queue) { | ||||
|         this(count, priority, queue, null); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Dispatcher constructor | ||||
|      * | ||||
|      * @param count    thread count | ||||
|      * @param priority thread priority | ||||
|      * @param queue    queue for messages | ||||
|      *                 (see {@link com.droidkit.actors.dispatch.AbstractDispatchQueue} for more information) | ||||
|      * @param dispatch Dispatch for message processing | ||||
|      */ | ||||
|     public ThreadPoolDispatcher(int count, int priority, final Q queue, Dispatch<T> dispatch) { | ||||
|         super(queue, dispatch); | ||||
|  | ||||
|         this.threads = new Thread[count]; | ||||
|         for (int i = 0; i < count; i++) { | ||||
|             this.threads[i] = new DispatcherThread(); | ||||
|             this.threads[i].setPriority(priority); | ||||
|             this.threads[i].start(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Closing of dispatcher no one actions will be executed after calling this method. | ||||
|      */ | ||||
|     public void close() { | ||||
|         isClosed = true; | ||||
|         notifyDispatcher(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Notification about queue change | ||||
|      */ | ||||
|     @Override | ||||
|     protected void notifyDispatcher() { | ||||
|         if (threads != null) { | ||||
|             synchronized (threads) { | ||||
|                 threads.notifyAll(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Thread class for dispatching | ||||
|      */ | ||||
|     private class DispatcherThread extends Thread { | ||||
|         @Override | ||||
|         public void run() { | ||||
|             while (!isClosed) { | ||||
|                 T action = getQueue().dispatch(currentTime()); | ||||
|                 if (action == null) { | ||||
|                     synchronized (threads) { | ||||
|                         try { | ||||
|                             long delay = getQueue().waitDelay(currentTime()); | ||||
|                             if (delay > 0) { | ||||
|                                 threads.wait(delay); | ||||
|                             } | ||||
|                             continue; | ||||
|                         } catch (InterruptedException e) { | ||||
|                             e.printStackTrace(); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 try { | ||||
|                     dispatchMessage(action); | ||||
|                 } catch (Throwable t) { | ||||
|                     // Possibly danger situation, but i hope this will not corrupt JVM | ||||
|                     // For example: on Android we could always continue execution after OutOfMemoryError | ||||
|                     // Anyway, better to catch all errors manually in dispatchMessage | ||||
|                     t.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,131 +0,0 @@ | ||||
| package com.droidkit.actors.mailbox; | ||||
|  | ||||
| import com.droidkit.actors.*; | ||||
| import com.droidkit.actors.dispatch.AbstractDispatcher; | ||||
| import com.droidkit.actors.messages.DeadLetter; | ||||
| import com.droidkit.actors.messages.PoisonPill; | ||||
| import com.droidkit.actors.messages.StartActor; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.UUID; | ||||
|  | ||||
| /** | ||||
|  * Abstract Actor Dispatcher, used for dispatching messages for actors | ||||
|  */ | ||||
| public abstract class AbsActorDispatcher { | ||||
|  | ||||
|     private final HashMap<Mailbox, ActorScope> mailboxes = new HashMap<Mailbox, ActorScope>(); | ||||
|     private final HashMap<String, ActorScope> scopes = new HashMap<String, ActorScope>(); | ||||
|     private final HashMap<String, Props> actorProps = new HashMap<String, Props>(); | ||||
|  | ||||
|     private final ActorSystem actorSystem; | ||||
|     private AbstractDispatcher<Envelope, MailboxesQueue> dispatcher; | ||||
|  | ||||
|     public AbsActorDispatcher(ActorSystem actorSystem) { | ||||
|         this.actorSystem = actorSystem; | ||||
|     } | ||||
|  | ||||
|     protected void initDispatcher(AbstractDispatcher<Envelope, MailboxesQueue> dispatcher) { | ||||
|         if (this.dispatcher != null) { | ||||
|             throw new RuntimeException("Double dispatcher init"); | ||||
|         } | ||||
|         this.dispatcher = dispatcher; | ||||
|     } | ||||
|  | ||||
|     public final ActorScope createScope(String path, Props props) { | ||||
|         // TODO: add path check | ||||
|  | ||||
|         Mailbox mailbox = new Mailbox(dispatcher.getQueue()); | ||||
|         UUID uuid = UUID.randomUUID(); | ||||
|         ActorRef ref = new ActorRef(actorSystem, this, uuid, path); | ||||
|         ActorScope scope = new ActorScope(actorSystem, mailbox, ref, this, UUID.randomUUID(), path, props); | ||||
|  | ||||
|         synchronized (mailboxes) { | ||||
|             mailboxes.put(mailbox, scope); | ||||
|             scopes.put(scope.getPath(), scope); | ||||
|             actorProps.put(path, props); | ||||
|         } | ||||
|  | ||||
|         // Sending init message | ||||
|         scope.getActorRef().send(StartActor.INSTANCE); | ||||
|         return scope; | ||||
|     } | ||||
|  | ||||
|     public final void disconnectScope(ActorScope scope) { | ||||
|         synchronized (mailboxes) { | ||||
|             mailboxes.remove(scope.getMailbox()); | ||||
|             scopes.remove(scope.getPath()); | ||||
|         } | ||||
|         for (Envelope envelope : scope.getMailbox().allEnvelopes()) { | ||||
|             if (envelope.getSender() != null) { | ||||
|                 envelope.getSender().send(new DeadLetter(envelope.getMessage())); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public final void sendMessage(String path, Object message, long time, ActorRef sender) { | ||||
|         synchronized (mailboxes) { | ||||
|             if (!scopes.containsKey(path)) { | ||||
|                 if (sender != null) { | ||||
|                     sender.send(new DeadLetter(message)); | ||||
|                 } | ||||
|             } else { | ||||
|                 Mailbox mailbox = scopes.get(path).getMailbox(); | ||||
|                 mailbox.schedule(new Envelope(message, mailbox, sender), time); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public final void sendMessageOnce(String path, Object message, long time, ActorRef sender) { | ||||
|         synchronized (mailboxes) { | ||||
|             if (!scopes.containsKey(path)) { | ||||
|                 if (sender != null) { | ||||
|                     sender.send(new DeadLetter(message)); | ||||
|                 } | ||||
|             } else { | ||||
|                 Mailbox mailbox = scopes.get(path).getMailbox(); | ||||
|                 mailbox.scheduleOnce(new Envelope(message, mailbox, sender), time); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Processing of envelope | ||||
|      * | ||||
|      * @param envelope envelope | ||||
|      */ | ||||
|     protected void processEnvelope(Envelope envelope) { | ||||
|         ActorScope actor = null; | ||||
|         synchronized (mailboxes) { | ||||
|             actor = mailboxes.get(envelope.getMailbox()); | ||||
|         } | ||||
|         if (actor == null) { | ||||
|             //TODO: add logging | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         try { | ||||
|             if (envelope.getMessage() == StartActor.INSTANCE) { | ||||
|                 try { | ||||
|                     actor.createActor(); | ||||
|                 } catch (Exception e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } else if (envelope.getMessage() == PoisonPill.INSTANCE) { | ||||
|                 try { | ||||
|                     actor.shutdownActor(); | ||||
|                 } catch (Exception e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } else { | ||||
|                 CurrentActor.setCurrentActor(actor.getActor()); | ||||
|                 actor.setSender(envelope.getSender()); | ||||
|                 actor.getActor().onReceiveGlobal(envelope.getMessage()); | ||||
|             } | ||||
|         } finally { | ||||
|             dispatcher.getQueue().unlockMailbox(envelope.getMailbox()); | ||||
|             CurrentActor.setCurrentActor(null); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| package com.droidkit.actors.mailbox; | ||||
|  | ||||
| import com.droidkit.actors.ActorSystem; | ||||
| import com.droidkit.actors.dispatch.Dispatch; | ||||
| import com.droidkit.actors.dispatch.ThreadPoolDispatcher; | ||||
|  | ||||
| /** | ||||
|  * Basic ActorDispatcher backed by ThreadPoolDispatcher | ||||
|  */ | ||||
| public class ActorDispatcher extends AbsActorDispatcher { | ||||
|     public ActorDispatcher(ActorSystem actorSystem, int threadsCount) { | ||||
|         this(actorSystem, threadsCount, Thread.MIN_PRIORITY); | ||||
|     } | ||||
|  | ||||
|     public ActorDispatcher(ActorSystem actorSystem, int threadsCount, int priority) { | ||||
|         super(actorSystem); | ||||
|         initDispatcher(new ThreadPoolDispatcher<Envelope, MailboxesQueue>(threadsCount, priority, new MailboxesQueue(), | ||||
|                 new Dispatch<Envelope>() { | ||||
|                     @Override | ||||
|                     public void dispatchMessage(Envelope message) { | ||||
|                         processEnvelope(message); | ||||
|                     } | ||||
|                 })); | ||||
|     } | ||||
| } | ||||
| @@ -1,54 +0,0 @@ | ||||
| package com.droidkit.actors.mailbox; | ||||
|  | ||||
| import com.droidkit.actors.ActorRef; | ||||
|  | ||||
| /** | ||||
|  * Actor system envelope | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class Envelope { | ||||
|     private final Object message; | ||||
|     private final ActorRef sender; | ||||
|     private final Mailbox mailbox; | ||||
|  | ||||
|     /** | ||||
|      * Creating of envelope | ||||
|      * | ||||
|      * @param message message | ||||
|      * @param mailbox mailbox | ||||
|      * @param sender  sender reference | ||||
|      */ | ||||
|     public Envelope(Object message, Mailbox mailbox, ActorRef sender) { | ||||
|         this.message = message; | ||||
|         this.sender = sender; | ||||
|         this.mailbox = mailbox; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Message in envelope | ||||
|      * | ||||
|      * @return message | ||||
|      */ | ||||
|     public Object getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Mailbox for envelope | ||||
|      * | ||||
|      * @return mailbox | ||||
|      */ | ||||
|     public Mailbox getMailbox() { | ||||
|         return mailbox; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sender of message | ||||
|      * | ||||
|      * @return sender reference | ||||
|      */ | ||||
|     public ActorRef getSender() { | ||||
|         return sender; | ||||
|     } | ||||
| } | ||||
| @@ -1,88 +0,0 @@ | ||||
| package com.droidkit.actors.mailbox; | ||||
|  | ||||
| import java.util.Iterator; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
|  | ||||
| /** | ||||
|  * Actor mailbox, queue of envelopes. | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class Mailbox { | ||||
|     private final ConcurrentHashMap<Long, Envelope> envelopes = new ConcurrentHashMap<Long, Envelope>(); | ||||
|  | ||||
|     private MailboxesQueue queue; | ||||
|  | ||||
|     /** | ||||
|      * Creating mailbox | ||||
|      * | ||||
|      * @param queue MailboxesQueue | ||||
|      */ | ||||
|     public Mailbox(MailboxesQueue queue) { | ||||
|         this.queue = queue; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send envelope at time | ||||
|      * | ||||
|      * @param envelope envelope | ||||
|      * @param time     time | ||||
|      */ | ||||
|     public void schedule(Envelope envelope, long time) { | ||||
|         if (envelope.getMailbox() != this) { | ||||
|             throw new RuntimeException("envelope.mailbox != this mailbox"); | ||||
|         } | ||||
|  | ||||
|         long id = queue.sendEnvelope(envelope, time); | ||||
|  | ||||
|         envelopes.put(id, envelope); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Send envelope once at time | ||||
|      * | ||||
|      * @param envelope envelope | ||||
|      * @param time     time | ||||
|      */ | ||||
|     public void scheduleOnce(Envelope envelope, long time) { | ||||
|         if (envelope.getMailbox() != this) { | ||||
|             throw new RuntimeException("envelope.mailbox != this mailbox"); | ||||
|         } | ||||
|  | ||||
|         Iterator<Map.Entry<Long, Envelope>> iterator = envelopes.entrySet().iterator(); | ||||
|         while (iterator.hasNext()) { | ||||
|             Map.Entry<Long, Envelope> entry = iterator.next(); | ||||
|             if (isEqualEnvelope(entry.getValue(), envelope)) { | ||||
|                 queue.removeEnvelope(entry.getKey()); | ||||
|                 iterator.remove(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         schedule(envelope, time); | ||||
|     } | ||||
|  | ||||
|     void removeEnvelope(long key) { | ||||
|         envelopes.remove(key); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Override this if you need to change filtering for scheduleOnce behaviour. | ||||
|      * By default it check equality only of class names. | ||||
|      * | ||||
|      * @param a | ||||
|      * @param b | ||||
|      * @return is equal | ||||
|      */ | ||||
|     protected boolean isEqualEnvelope(Envelope a, Envelope b) { | ||||
|         return a.getMessage().getClass() == b.getMessage().getClass(); | ||||
|     } | ||||
|  | ||||
|     public synchronized Envelope[] allEnvelopes() { | ||||
|         return envelopes.values().toArray(new Envelope[0]); | ||||
|     } | ||||
|  | ||||
|     public synchronized int getMailboxSize() { | ||||
|         return envelopes.size(); | ||||
|     } | ||||
| } | ||||
| @@ -1,145 +0,0 @@ | ||||
| package com.droidkit.actors.mailbox; | ||||
|  | ||||
| import com.droidkit.actors.dispatch.AbstractDispatchQueue; | ||||
|  | ||||
| import java.util.HashSet; | ||||
| import java.util.Map; | ||||
| import java.util.TreeMap; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
| import java.util.concurrent.atomic.AtomicLong; | ||||
|  | ||||
| /** | ||||
|  * Queue of multiple mailboxes for MailboxesDispatcher | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class MailboxesQueue extends AbstractDispatchQueue<Envelope> { | ||||
|  | ||||
|     private static final long MULTIPLE = 10000L; | ||||
|  | ||||
|     private final TreeMap<Long, Long> timeShift = new TreeMap<Long, Long>(); | ||||
|     private final TreeMap<Long, Envelope> envelopes = new TreeMap<Long, Envelope>(); | ||||
|     private final HashSet<Mailbox> blocked = new HashSet<Mailbox>(); | ||||
|  | ||||
|     /** | ||||
|      * Locking mailbox from processing messages from it | ||||
|      * | ||||
|      * @param mailbox mailbox for locking | ||||
|      */ | ||||
|     public void lockMailbox(Mailbox mailbox) { | ||||
|         synchronized (blocked) { | ||||
|             blocked.add(mailbox); | ||||
|         } | ||||
|         notifyQueueChanged(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Unlocking mailbox | ||||
|      * | ||||
|      * @param mailbox mailbox for unlocking | ||||
|      */ | ||||
|     public void unlockMailbox(Mailbox mailbox) { | ||||
|         synchronized (blocked) { | ||||
|             blocked.remove(mailbox); | ||||
|         } | ||||
|         notifyQueueChanged(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sending envelope | ||||
|      * | ||||
|      * @param envelope envelope | ||||
|      * @param time     time (see {@link com.droidkit.actors.ActorTime#currentTime()}}) | ||||
|      * @return envelope real time | ||||
|      */ | ||||
|     public long sendEnvelope(Envelope envelope, long time) { | ||||
|         long shift = 0; | ||||
|         synchronized (envelopes) { | ||||
|             if (timeShift.containsKey(time)) { | ||||
|                 shift = timeShift.get(time); | ||||
|             } | ||||
|             while (envelopes.containsKey(time * MULTIPLE + shift)) { | ||||
|                 shift++; | ||||
|             } | ||||
|  | ||||
|             if (shift != 0) { | ||||
|                 timeShift.put(time, shift); | ||||
|             } | ||||
|             envelopes.put(time * MULTIPLE + shift, envelope); | ||||
|         } | ||||
|         notifyQueueChanged(); | ||||
|         return time * MULTIPLE + shift; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Removing envelope from queue | ||||
|      * | ||||
|      * @param id envelope id | ||||
|      */ | ||||
|     public void removeEnvelope(long id) { | ||||
|         synchronized (envelopes) { | ||||
|             envelopes.remove(id); | ||||
|         } | ||||
|         notifyQueueChanged(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * getting first available envelope | ||||
|      * MUST BE wrapped with envelopes and blocked sync | ||||
|      * | ||||
|      * @return envelope entry | ||||
|      */ | ||||
|     private Map.Entry<Long, Envelope> firstEnvelope() { | ||||
|         for (Map.Entry<Long, Envelope> entry : envelopes.entrySet()) { | ||||
|             if (!blocked.contains(entry.getValue().getMailbox())) { | ||||
|                 return entry; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Envelope dispatch(long time) { | ||||
|         time = time * MULTIPLE; | ||||
|         synchronized (envelopes) { | ||||
|             synchronized (blocked) { | ||||
|                 Map.Entry<Long, Envelope> envelope = firstEnvelope(); | ||||
|                 if (envelope != null) { | ||||
|                     if (envelope.getKey() < time) { | ||||
|                         envelopes.remove(envelope.getKey()); | ||||
|                         envelope.getValue().getMailbox().removeEnvelope(envelope.getKey()); | ||||
|                         //TODO: Better design | ||||
|                         // Locking of mailbox before dispatch return | ||||
|                         blocked.add(envelope.getValue().getMailbox()); | ||||
|                         return envelope.getValue(); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long waitDelay(long time) { | ||||
|         time = time * MULTIPLE; | ||||
|         synchronized (envelopes) { | ||||
|             synchronized (blocked) { | ||||
|                 Map.Entry<Long, Envelope> envelope = firstEnvelope(); | ||||
|  | ||||
|                 if (envelope != null) { | ||||
|                     if (envelope.getKey() <= time) { | ||||
|                         return 0; | ||||
|                     } else { | ||||
|                         return (time - envelope.getKey()) / MULTIPLE; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return FOREVER; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void putToQueueImpl(Envelope message, long atTime) { | ||||
|         sendEnvelope(message, atTime); | ||||
|     } | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| package com.droidkit.actors.messages; | ||||
|  | ||||
| /** | ||||
|  * DeadLetter sent whet message was not processed by target actor | ||||
|  */ | ||||
| public class DeadLetter { | ||||
|     private Object message; | ||||
|  | ||||
|     public DeadLetter(Object message) { | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public Object getMessage() { | ||||
|         return message; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "DeadLetter(" + message + ")"; | ||||
|     } | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| package com.droidkit.actors.messages; | ||||
|  | ||||
| /** | ||||
|  * Simple named message | ||||
|  */ | ||||
| public class NamedMessage { | ||||
|     private String name; | ||||
|     private Object message; | ||||
|  | ||||
|     public NamedMessage(String name, Object message) { | ||||
|         this.name = name; | ||||
|         this.message = message; | ||||
|     } | ||||
|  | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
|  | ||||
|     public Object getMessage() { | ||||
|         return message; | ||||
|     } | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| package com.droidkit.actors.messages; | ||||
|  | ||||
| /** | ||||
|  * PoisonPill message for killing actors | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public final class PoisonPill { | ||||
|     public static final PoisonPill INSTANCE = new PoisonPill(); | ||||
|  | ||||
|     private PoisonPill() { | ||||
|     } | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| package com.droidkit.actors.messages; | ||||
|  | ||||
| /** | ||||
|  * Message for starting actors | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public final class StartActor { | ||||
|     public static final StartActor INSTANCE = new StartActor(); | ||||
|  | ||||
|     private StartActor() { | ||||
|     } | ||||
| } | ||||
| @@ -1,165 +0,0 @@ | ||||
| package com.droidkit.actors.tasks; | ||||
|  | ||||
| import com.droidkit.actors.ActorRef; | ||||
| import com.droidkit.actors.messages.DeadLetter; | ||||
| import com.droidkit.actors.tasks.messages.*; | ||||
|  | ||||
| import java.util.HashMap; | ||||
|  | ||||
| /** | ||||
|  * Implementation of Ask pattern | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class ActorAskImpl { | ||||
|  | ||||
|     private HashMap<Integer, AskContainer> asks = new HashMap<Integer, AskContainer>(); | ||||
|     private int nextReqId = 1; | ||||
|     private ActorRef self; | ||||
|  | ||||
|     public ActorAskImpl(ActorRef self) { | ||||
|         this.self = self; | ||||
|     } | ||||
|  | ||||
|     public <T> AskFuture<T[]> combine(AskFuture... futures) { | ||||
|         final AskFuture resultFuture = new AskFuture(this, 0); | ||||
|         final CombineContainer container = new CombineContainer(futures.length); | ||||
|         for (int i = 0; i < futures.length; i++) { | ||||
|             final int index = i; | ||||
|             container.futures[index] = futures[index]; | ||||
|             container.callbacks[index] = new AskCallback() { | ||||
|                 @Override | ||||
|                 public void onResult(Object result) { | ||||
|                     container.completed[index] = true; | ||||
|                     container.results[index] = result; | ||||
|                     boolean isCompleted = true; | ||||
|                     for (boolean c : container.completed) { | ||||
|                         if (!c) { | ||||
|                             isCompleted = false; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     if (isCompleted && !container.isCompleted) { | ||||
|                         container.isCompleted = true; | ||||
|                         for (int i = 0; i < container.futures.length; i++) { | ||||
|                             container.futures[i].removeListener(container.callbacks[i]); | ||||
|                         } | ||||
|                         resultFuture.onResult(container.results); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onError(Throwable throwable) { | ||||
|                     if (!container.isCompleted) { | ||||
|                         container.isCompleted = true; | ||||
|                         for (int i = 0; i < container.futures.length; i++) { | ||||
|                             container.futures[i].removeListener(container.callbacks[i]); | ||||
|                             container.futures[i].cancel(); | ||||
|                         } | ||||
|                         resultFuture.onError(throwable); | ||||
|                     } | ||||
|  | ||||
|                 } | ||||
|             }; | ||||
|             container.futures[index].addListener(container.callbacks[index]); | ||||
|         } | ||||
|         return resultFuture; | ||||
|     } | ||||
|  | ||||
|     public <T> AskFuture<T> ask(ActorRef ref, long timeout, AskCallback<T> callback) { | ||||
|         int reqId = nextReqId++; | ||||
|         AskFuture<T> future = new AskFuture<T>(this, reqId); | ||||
|         if (callback != null) { | ||||
|             future.addListener(callback); | ||||
|         } | ||||
|         AskContainer container = new AskContainer(future, ref, reqId); | ||||
|         asks.put(reqId, container); | ||||
|         ref.send(new TaskRequest(reqId), self); | ||||
|         if (timeout > 0) { | ||||
|             self.send(new TaskTimeout(reqId), timeout); | ||||
|         } | ||||
|         return future; | ||||
|     } | ||||
|  | ||||
|     public boolean onTaskResult(TaskResult result) { | ||||
|         AskContainer container = asks.remove(result.getRequestId()); | ||||
|         if (container != null) { | ||||
|             container.future.onResult(result.getRes()); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public boolean onTaskError(TaskError error) { | ||||
|         AskContainer container = asks.remove(error.getRequestId()); | ||||
|         if (container != null) { | ||||
|             container.future.onError(error.getThrowable()); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public boolean onTaskTimeout(TaskTimeout taskTimeout) { | ||||
|         AskContainer container = asks.remove(taskTimeout.getRequestId()); | ||||
|         if (container != null) { | ||||
|             container.future.onTimeout(); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public boolean onTaskCancelled(int reqId) { | ||||
|         AskContainer container = asks.remove(reqId); | ||||
|         if (container != null) { | ||||
|             container.ref.send(new TaskCancel(reqId), self); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public boolean onDeadLetter(DeadLetter letter) { | ||||
|         if (letter.getMessage() instanceof TaskRequest) { | ||||
|             TaskRequest request = (TaskRequest) letter.getMessage(); | ||||
|             AskContainer container = asks.remove(request.getRequestId()); | ||||
|             if (container != null) { | ||||
|                 // Mimic dead letter with timeout exception | ||||
|                 container.future.onError(new AskTimeoutException()); | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     private class AskContainer { | ||||
|         public final AskFuture future; | ||||
|         public final ActorRef ref; | ||||
|         public final int requestId; | ||||
|  | ||||
|         private AskContainer(AskFuture future, ActorRef ref, int requestId) { | ||||
|             this.future = future; | ||||
|             this.ref = ref; | ||||
|             this.requestId = requestId; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class CombineContainer { | ||||
|         public boolean isCompleted = false; | ||||
|         public Object[] results; | ||||
|         public boolean[] completed; | ||||
|         public AskFuture[] futures; | ||||
|         public AskCallback[] callbacks; | ||||
|  | ||||
|         public CombineContainer(int count) { | ||||
|             results = new Object[count]; | ||||
|             completed = new boolean[count]; | ||||
|             callbacks = new AskCallback[count]; | ||||
|             futures = new AskFuture[count]; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| package com.droidkit.actors.tasks; | ||||
|  | ||||
| /** | ||||
|  * Callback for Ask pattern | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public interface AskCallback<T> { | ||||
|     public void onResult(T result); | ||||
|  | ||||
|     public void onError(Throwable throwable); | ||||
| } | ||||
| @@ -1,10 +0,0 @@ | ||||
| package com.droidkit.actors.tasks; | ||||
|  | ||||
| /** | ||||
|  * Exception about cancelling task | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class AskCancelledException extends Exception { | ||||
|  | ||||
| } | ||||
| @@ -1,105 +0,0 @@ | ||||
| package com.droidkit.actors.tasks; | ||||
|  | ||||
| import java.util.LinkedList; | ||||
|  | ||||
| /** | ||||
|  * Modified future for ask pattern of Actors | ||||
|  * Created to work only in actor threads | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class AskFuture<T> { | ||||
|  | ||||
|     private LinkedList<AskCallback> callbacks = new LinkedList<AskCallback>(); | ||||
|  | ||||
|     private ActorAskImpl askImpl; | ||||
|     private int reqId; | ||||
|  | ||||
|     private boolean isCompleted = false; | ||||
|     private boolean isCanceled = false; | ||||
|     private boolean isError = false; | ||||
|     private T result = null; | ||||
|     private Throwable error = null; | ||||
|  | ||||
|     AskFuture(ActorAskImpl askImpl, int reqId) { | ||||
|         this.askImpl = askImpl; | ||||
|         this.reqId = reqId; | ||||
|     } | ||||
|  | ||||
|     public void addListener(AskCallback callback) { | ||||
|         callbacks.add(callback); | ||||
|     } | ||||
|  | ||||
|     public void removeListener(AskCallback callback) { | ||||
|         callbacks.remove(callback); | ||||
|     } | ||||
|  | ||||
|     public boolean isCompleted() { | ||||
|         return isCompleted; | ||||
|     } | ||||
|  | ||||
|     public boolean isError() { | ||||
|         return isError; | ||||
|     } | ||||
|  | ||||
|     public boolean isCanceled() { | ||||
|         return isCanceled; | ||||
|     } | ||||
|  | ||||
|     public Throwable error() { | ||||
|         return error; | ||||
|     } | ||||
|  | ||||
|     public T result() { | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     public void cancel() { | ||||
|         if (isCompleted) { | ||||
|             return; | ||||
|         } | ||||
|         isCompleted = true; | ||||
|         isError = false; | ||||
|         isCanceled = true; | ||||
|  | ||||
|         for (AskCallback callback : callbacks) { | ||||
|             callback.onError(new AskCancelledException()); | ||||
|         } | ||||
|  | ||||
|         askImpl.onTaskCancelled(reqId); | ||||
|     } | ||||
|  | ||||
|     void onError(Throwable throwable) { | ||||
|         if (isCompleted) { | ||||
|             return; | ||||
|         } | ||||
|         isCompleted = true; | ||||
|         isCanceled = false; | ||||
|         isError = true; | ||||
|         error = throwable; | ||||
|         result = null; | ||||
|  | ||||
|         for (AskCallback callback : callbacks) { | ||||
|             callback.onError(throwable); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void onResult(T res) { | ||||
|         if (isCompleted) { | ||||
|             return; | ||||
|         } | ||||
|         isCompleted = true; | ||||
|         isCanceled = false; | ||||
|         isError = false; | ||||
|         error = null; | ||||
|         result = res; | ||||
|  | ||||
|         for (AskCallback callback : callbacks) { | ||||
|             callback.onResult(res); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void onTimeout() { | ||||
|         onError(new AskTimeoutException()); | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +0,0 @@ | ||||
| package com.droidkit.actors.tasks; | ||||
|  | ||||
| /** | ||||
|  * Exception for Ask timeout | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class AskTimeoutException extends Exception { | ||||
| } | ||||
| @@ -1,177 +0,0 @@ | ||||
| package com.droidkit.actors.tasks; | ||||
|  | ||||
| import com.droidkit.actors.Actor; | ||||
| import com.droidkit.actors.ActorRef; | ||||
| import com.droidkit.actors.messages.PoisonPill; | ||||
| import com.droidkit.actors.tasks.messages.TaskCancel; | ||||
| import com.droidkit.actors.tasks.messages.TaskError; | ||||
| import com.droidkit.actors.tasks.messages.TaskRequest; | ||||
| import com.droidkit.actors.tasks.messages.TaskResult; | ||||
|  | ||||
| import java.util.HashSet; | ||||
|  | ||||
| /** | ||||
|  * Actor for performing various async tasks | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public abstract class TaskActor<T> extends Actor { | ||||
|     private final HashSet<TaskListener> requests = new HashSet<TaskListener>(); | ||||
|  | ||||
|     private T result; | ||||
|     private boolean isCompleted; | ||||
|     private boolean isCompletedSuccess; | ||||
|     private long dieTimeout = 300; | ||||
|  | ||||
|     /** | ||||
|      * Timeout for dying after task complete | ||||
|      * | ||||
|      * @param timeOut timeout in ms | ||||
|      */ | ||||
|     public void setTimeOut(long timeOut) { | ||||
|         dieTimeout = timeOut; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void preStart() { | ||||
|         startTask(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Object message) { | ||||
|         if (message instanceof TaskRequest) { | ||||
|             TaskRequest request = (TaskRequest) message; | ||||
|             if (isCompleted) { | ||||
|                 if (isCompletedSuccess) { | ||||
|                     reply(result); | ||||
|                 } | ||||
|             } else { | ||||
|                 TaskListener listener = new TaskListener(request.getRequestId(), sender()); | ||||
|                 requests.add(listener); | ||||
|             } | ||||
|         } else if (message instanceof TaskCancel) { | ||||
|             if (isCompleted) { | ||||
|                 return; | ||||
|             } | ||||
|             TaskCancel cancel = (TaskCancel) message; | ||||
|             TaskListener listener = new TaskListener(cancel.getRequestId(), sender()); | ||||
|             requests.remove(listener); | ||||
|             if (requests.size() == 0) { | ||||
|                 onTaskObsolete(); | ||||
|                 context().stopSelf(); | ||||
|             } | ||||
|         } else if (message instanceof Result) { | ||||
|             if (!isCompleted) { | ||||
|                 Result res = (Result) message; | ||||
|                 isCompleted = true; | ||||
|                 isCompletedSuccess = true; | ||||
|                 result = (T) res.getRes(); | ||||
|                 for (TaskListener request : requests) { | ||||
|                     request.getSender().send(new TaskResult<T>(request.getRequestId(), result)); | ||||
|                 } | ||||
|                 self().send(PoisonPill.INSTANCE, dieTimeout); | ||||
|             } | ||||
|         } else if (message instanceof Error) { | ||||
|             if (!isCompleted) { | ||||
|                 isCompleted = true; | ||||
|                 Error error = (Error) message; | ||||
|                 for (TaskListener request : requests) { | ||||
|                     request.getSender().send(new TaskError(request.getRequestId(), error.getError())); | ||||
|                 } | ||||
|                 context().stopSelf(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Starting of task execution | ||||
|      */ | ||||
|     public abstract void startTask(); | ||||
|  | ||||
|     /** | ||||
|      * Called before killing actor after clearing TaskListeners | ||||
|      */ | ||||
|     public void onTaskObsolete() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call this method in any thread after task complete | ||||
|      * | ||||
|      * @param res result of task | ||||
|      */ | ||||
|     public void complete(T res) { | ||||
|         self().send(new Result(res)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call this method in any thread after task exception | ||||
|      * | ||||
|      * @param t exception | ||||
|      */ | ||||
|     public void error(Throwable t) { | ||||
|         self().send(new Error(t)); | ||||
|     } | ||||
|  | ||||
|     private static class Error { | ||||
|         private Throwable error; | ||||
|  | ||||
|         private Error(Throwable error) { | ||||
|             this.error = error; | ||||
|         } | ||||
|  | ||||
|         public Throwable getError() { | ||||
|             return error; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class Result { | ||||
|         private Object res; | ||||
|  | ||||
|         private Result(Object res) { | ||||
|             this.res = res; | ||||
|         } | ||||
|  | ||||
|         public Object getRes() { | ||||
|             return res; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class TaskListener { | ||||
|         private int requestId; | ||||
|         private ActorRef sender; | ||||
|  | ||||
|         private TaskListener(int requestId, ActorRef sender) { | ||||
|             this.requestId = requestId; | ||||
|             this.sender = sender; | ||||
|         } | ||||
|  | ||||
|         public int getRequestId() { | ||||
|             return requestId; | ||||
|         } | ||||
|  | ||||
|         public ActorRef getSender() { | ||||
|             return sender; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public boolean equals(Object o) { | ||||
|             if (this == o) return true; | ||||
|             if (o == null || getClass() != o.getClass()) return false; | ||||
|  | ||||
|             TaskListener that = (TaskListener) o; | ||||
|  | ||||
|             if (requestId != that.requestId) return false; | ||||
|             if (!sender.equals(that.sender)) return false; | ||||
|  | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public int hashCode() { | ||||
|             int result = requestId; | ||||
|             result = 31 * result + sender.hashCode(); | ||||
|             return result; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package com.droidkit.actors.tasks.messages; | ||||
|  | ||||
| /** | ||||
|  * Message about task cancelling | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class TaskCancel { | ||||
|     private int requestId; | ||||
|  | ||||
|     public TaskCancel(int requestId) { | ||||
|         this.requestId = requestId; | ||||
|     } | ||||
|  | ||||
|     public int getRequestId() { | ||||
|         return requestId; | ||||
|     } | ||||
| } | ||||
| @@ -1,24 +0,0 @@ | ||||
| package com.droidkit.actors.tasks.messages; | ||||
|  | ||||
| /** | ||||
|  * Message about task error | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class TaskError { | ||||
|     private final int requestId; | ||||
|     private final Throwable throwable; | ||||
|  | ||||
|     public TaskError(int requestId, Throwable throwable) { | ||||
|         this.requestId = requestId; | ||||
|         this.throwable = throwable; | ||||
|     } | ||||
|  | ||||
|     public int getRequestId() { | ||||
|         return requestId; | ||||
|     } | ||||
|  | ||||
|     public Throwable getThrowable() { | ||||
|         return throwable; | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package com.droidkit.actors.tasks.messages; | ||||
|  | ||||
| /** | ||||
|  * Message about requesting task | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class TaskRequest { | ||||
|     private final int requestId; | ||||
|  | ||||
|     public TaskRequest(int requestId) { | ||||
|         this.requestId = requestId; | ||||
|     } | ||||
|  | ||||
|     public int getRequestId() { | ||||
|         return requestId; | ||||
|     } | ||||
| } | ||||
| @@ -1,25 +0,0 @@ | ||||
| package com.droidkit.actors.tasks.messages; | ||||
|  | ||||
| /** | ||||
|  * Message with task result | ||||
|  * | ||||
|  * @param <T> type of task result | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class TaskResult<T> { | ||||
|     private final int requestId; | ||||
|     private final T res; | ||||
|  | ||||
|     public TaskResult(int requestId, T res) { | ||||
|         this.requestId = requestId; | ||||
|         this.res = res; | ||||
|     } | ||||
|  | ||||
|     public T getRes() { | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public int getRequestId() { | ||||
|         return requestId; | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package com.droidkit.actors.tasks.messages; | ||||
|  | ||||
| /** | ||||
|  * Message about Task timeout | ||||
|  * | ||||
|  * @author Stepan Ex3NDR Korshakov (me@ex3ndr.com) | ||||
|  */ | ||||
| public class TaskTimeout { | ||||
|     private final int requestId; | ||||
|  | ||||
|     public TaskTimeout(int requestId) { | ||||
|         this.requestId = requestId; | ||||
|     } | ||||
|  | ||||
|     public int getRequestId() { | ||||
|         return requestId; | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| import org.telegram.api.TLAbsUpdates; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 11.11.13 | ||||
|  * Time: 7:42 | ||||
|  */ | ||||
| public interface ApiCallback { | ||||
|     public void onAuthCancelled(TelegramApi api); | ||||
|  | ||||
|     public void onUpdatesInvalidated(TelegramApi api); | ||||
|  | ||||
|     public void onUpdate(TLAbsUpdates updates); | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 10.11.13 | ||||
|  * Time: 2:31 | ||||
|  */ | ||||
| public class AppInfo { | ||||
|     protected int apiId; | ||||
|     protected String deviceModel; | ||||
|     protected String systemVersion; | ||||
|     protected String appVersion; | ||||
|     protected String langCode; | ||||
|  | ||||
|     public AppInfo(int apiId, String deviceModel, String systemVersion, String appVersion, String langCode) { | ||||
|         this.apiId = apiId; | ||||
|         this.deviceModel = deviceModel; | ||||
|         this.systemVersion = systemVersion; | ||||
|         this.appVersion = appVersion; | ||||
|         this.langCode = langCode; | ||||
|     } | ||||
|  | ||||
|     public int getApiId() { | ||||
|         return apiId; | ||||
|     } | ||||
|  | ||||
|     public String getDeviceModel() { | ||||
|         return deviceModel; | ||||
|     } | ||||
|  | ||||
|     public String getSystemVersion() { | ||||
|         return systemVersion; | ||||
|     } | ||||
|  | ||||
|     public String getAppVersion() { | ||||
|         return appVersion; | ||||
|     } | ||||
|  | ||||
|     public String getLangCode() { | ||||
|         return langCode; | ||||
|     } | ||||
| } | ||||
| @@ -1,60 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLGzipObject; | ||||
| import org.telegram.tl.TLMethod; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.util.zip.GZIPOutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
| import static org.telegram.tl.StreamingUtils.writeByteArray; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 07.12.13. | ||||
|  */ | ||||
| public class GzipRequest<T extends TLObject> extends TLMethod<T> { | ||||
|  | ||||
|     private static final int CLASS_ID = TLGzipObject.CLASS_ID; | ||||
|  | ||||
|     private TLMethod<T> method; | ||||
|  | ||||
|     public GzipRequest(TLMethod<T> method) { | ||||
|         this.method = method; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public T deserializeResponse(InputStream stream, TLContext context) throws IOException { | ||||
|         return method.deserializeResponse(stream, context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         ByteArrayOutputStream resOutput = new ByteArrayOutputStream(); | ||||
|         GZIPOutputStream gzipOutputStream = new GZIPOutputStream(resOutput); | ||||
|         method.serialize(gzipOutputStream); | ||||
|         gzipOutputStream.flush(); | ||||
|         gzipOutputStream.close(); | ||||
|         byte[] body = resOutput.toByteArray(); | ||||
|         writeTLBytes(body, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         throw new IOException("Unsupported operation"); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "gzip<" + method + ">"; | ||||
|     } | ||||
| } | ||||
| @@ -1,39 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 11.11.13 | ||||
|  * Time: 4:48 | ||||
|  */ | ||||
| public class Logger { | ||||
|     private static LoggerInterface logInterface; | ||||
|  | ||||
|     public static void registerInterface(LoggerInterface logInterface) { | ||||
|         Logger.logInterface = logInterface; | ||||
|     } | ||||
|  | ||||
|     public static void w(String tag, String message) { | ||||
|         if (logInterface != null) { | ||||
|             logInterface.w(tag, message); | ||||
|         } else { | ||||
|             System.out.println(tag + ":" + message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void d(String tag, String message) { | ||||
|         if (logInterface != null) { | ||||
|             logInterface.d(tag, message); | ||||
|         } else { | ||||
|             System.out.println(tag + ":" + message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void e(String tag, Throwable t) { | ||||
|         if (logInterface != null) { | ||||
|             logInterface.e(tag, t); | ||||
|         } else { | ||||
|             t.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 11.11.13 | ||||
|  * Time: 4:48 | ||||
|  */ | ||||
| public interface LoggerInterface { | ||||
|     void w(String tag, String message); | ||||
|  | ||||
|     void d(String tag, String message); | ||||
|  | ||||
|     void e(String tag, Throwable t); | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 05.11.13 | ||||
|  * Time: 14:10 | ||||
|  */ | ||||
| public interface RpcCallback<T extends TLObject> { | ||||
|     public void onResult(T result); | ||||
|  | ||||
|     public void onError(int errorCode, String message); | ||||
| } | ||||
| @@ -1,13 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 09.11.13 | ||||
|  * Time: 18:06 | ||||
|  */ | ||||
| public interface RpcCallbackEx<T extends TLObject> extends RpcCallback<T> { | ||||
|     public void onConfirmed(); | ||||
| } | ||||
| @@ -1,56 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 05.11.13 | ||||
|  * Time: 13:59 | ||||
|  */ | ||||
| public class RpcException extends IOException { | ||||
|     private static final Pattern REGEXP_PATTERN = Pattern.compile("[A-Z_0-9]+"); | ||||
|  | ||||
|     private static String getErrorTag(String srcMessage) { | ||||
|         if (srcMessage == null) { | ||||
|             return "UNKNOWN"; | ||||
|         } | ||||
|         Matcher matcher = REGEXP_PATTERN.matcher(srcMessage); | ||||
|         if (matcher.find()) { | ||||
|             return matcher.group(); | ||||
|         } | ||||
|         return "UNKNOWN"; | ||||
|     } | ||||
|  | ||||
|     private static String getErrorMessage(String srcMessage) { | ||||
|         if (srcMessage == null) { | ||||
|             return "Unknown error"; | ||||
|         } | ||||
|         int index = srcMessage.indexOf(":"); | ||||
|         if (index > 0) { | ||||
|             return srcMessage.substring(index); | ||||
|         } else { | ||||
|             return srcMessage; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private int errorCode; | ||||
|  | ||||
|     private String errorTag; | ||||
|  | ||||
|     public RpcException(int errorCode, String message) { | ||||
|         super(getErrorMessage(message)); | ||||
|         this.errorCode = errorCode; | ||||
|         this.errorTag = getErrorTag(message); | ||||
|     } | ||||
|  | ||||
|     public int getErrorCode() { | ||||
|         return errorCode; | ||||
|     } | ||||
|  | ||||
|     public String getErrorTag() { | ||||
|         return errorTag; | ||||
|     } | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,26 +0,0 @@ | ||||
| package org.telegram.api.engine; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 06.11.13 | ||||
|  * Time: 1:27 | ||||
|  */ | ||||
| public class TimeoutException extends IOException { | ||||
|     public TimeoutException() { | ||||
|     } | ||||
|  | ||||
|     public TimeoutException(String s) { | ||||
|         super(s); | ||||
|     } | ||||
|  | ||||
|     public TimeoutException(String s, Throwable throwable) { | ||||
|         super(s, throwable); | ||||
|     } | ||||
|  | ||||
|     public TimeoutException(Throwable throwable) { | ||||
|         super(throwable); | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +0,0 @@ | ||||
| package org.telegram.api.engine.file; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 18.11.13. | ||||
|  */ | ||||
| public interface DownloadListener { | ||||
|     public void onPartDownloaded(int percent, int downloadedSize); | ||||
|  | ||||
|     public void onDownloaded(); | ||||
|  | ||||
|     public void onFailed(); | ||||
| } | ||||
| @@ -1,368 +0,0 @@ | ||||
| package org.telegram.api.engine.file; | ||||
|  | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.io.RandomAccessFile; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Random; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| import org.telegram.api.TLAbsInputFileLocation; | ||||
| import org.telegram.api.engine.Logger; | ||||
| import org.telegram.api.engine.TelegramApi; | ||||
| import org.telegram.api.upload.TLFile; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 18.11.13. | ||||
|  */ | ||||
| public class Downloader { | ||||
|     public static final int FILE_QUEUED = 0; | ||||
|     public static final int FILE_DOWNLOADING = 1; | ||||
|     public static final int FILE_COMPLETED = 2; | ||||
|     public static final int FILE_CANCELED = 3; | ||||
|     public static final int FILE_FAILURE = 4; | ||||
|  | ||||
|     private final AtomicInteger fileIds = new AtomicInteger(1); | ||||
|  | ||||
|     private final String TAG; | ||||
|  | ||||
|     private TelegramApi api; | ||||
|  | ||||
|     private static final long DOWNLOAD_TIMEOUT = 30 * 1000; | ||||
|  | ||||
|     private static final long DEFAULT_DELAY = 15 * 1000; | ||||
|  | ||||
|     private static final int BLOCK_SIZE = 16 * 1024; | ||||
|  | ||||
|     private static final int PARALLEL_DOWNLOAD_COUNT = 2; | ||||
|  | ||||
|     private static final int PARALLEL_PARTS_COUNT = 4; | ||||
|  | ||||
|     private static final int BLOCK_QUEUED = 0; | ||||
|     private static final int BLOCK_DOWNLOADING = 1; | ||||
|     private static final int BLOCK_COMPLETED = 2; | ||||
|  | ||||
|     private ArrayList<DownloadTask> tasks = new ArrayList<DownloadTask>(); | ||||
|  | ||||
|     private ArrayList<DownloadFileThread> threads = new ArrayList<DownloadFileThread>(); | ||||
|  | ||||
|     private final Object threadLocker = new Object(); | ||||
|  | ||||
|     private Random rnd = new Random(); | ||||
|  | ||||
|     public Downloader(TelegramApi api) { | ||||
|         this.TAG = api.toString() + "#Downloader"; | ||||
|         this.api = api; | ||||
|  | ||||
|         for (int i = 0; i < PARALLEL_PARTS_COUNT; i++) { | ||||
|             DownloadFileThread thread = new DownloadFileThread(); | ||||
|             thread.start(); | ||||
|             threads.add(thread); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public TelegramApi getApi() { | ||||
|         return api; | ||||
|     } | ||||
|  | ||||
|     private synchronized DownloadTask getTask(int taskId) { | ||||
|         for (DownloadTask task : tasks) { | ||||
|             if (task.taskId == taskId) { | ||||
|                 return task; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public synchronized void cancelTask(int taskId) { | ||||
|         DownloadTask task = getTask(taskId); | ||||
|         if (task != null && task.state != FILE_COMPLETED) { | ||||
|             task.state = FILE_CANCELED; | ||||
|             Logger.d(TAG, "File #" + task.taskId + "| Canceled"); | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     public synchronized int getTaskState(int taskId) { | ||||
|         DownloadTask task = getTask(taskId); | ||||
|         if (task != null) { | ||||
|             return task.state; | ||||
|         } | ||||
|  | ||||
|         return FILE_CANCELED; | ||||
|     } | ||||
|  | ||||
|     public void waitForTask(int taskId) { | ||||
|         while (true) { | ||||
|             int state = getTaskState(taskId); | ||||
|             if ((state == FILE_COMPLETED) || (state == FILE_FAILURE) || (state == FILE_CANCELED)) { | ||||
|                 return; | ||||
|             } | ||||
|             synchronized (threadLocker) { | ||||
|                 try { | ||||
|                     threadLocker.wait(DEFAULT_DELAY); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     Logger.e(TAG, e); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public synchronized int requestTask(int dcId, TLAbsInputFileLocation location, int size, String destFile, DownloadListener listener) { | ||||
|         int blockSize = BLOCK_SIZE; | ||||
|         int totalBlockCount = (int) Math.ceil(((double) size) / blockSize); | ||||
|  | ||||
|         DownloadTask task = new DownloadTask(); | ||||
|         task.listener = listener; | ||||
|         task.blockSize = blockSize; | ||||
|         task.destFile = destFile; | ||||
|         try { | ||||
|             task.file = new RandomAccessFile(destFile, "rw"); | ||||
|             task.file.setLength(size); | ||||
|         } catch (FileNotFoundException e) { | ||||
|             Logger.e(TAG, e); | ||||
|         } catch (IOException e) { | ||||
|             Logger.e(TAG, e); | ||||
|         } | ||||
|         task.taskId = fileIds.getAndIncrement(); | ||||
|         task.dcId = dcId; | ||||
|         task.location = location; | ||||
|         task.size = size; | ||||
|         task.blocks = new DownloadBlock[totalBlockCount]; | ||||
|         for (int i = 0; i < totalBlockCount; i++) { | ||||
|             task.blocks[i] = new DownloadBlock(); | ||||
|             task.blocks[i].task = task; | ||||
|             task.blocks[i].index = i; | ||||
|             task.blocks[i].state = BLOCK_QUEUED; | ||||
|         } | ||||
|         task.state = FILE_QUEUED; | ||||
|         task.queueTime = System.nanoTime(); | ||||
|         tasks.add(task); | ||||
|  | ||||
|         Logger.d(TAG, "File #" + task.taskId + "| Requested"); | ||||
|  | ||||
|         updateFileQueueStates(); | ||||
|  | ||||
|         return task.taskId; | ||||
|     } | ||||
|  | ||||
|     private synchronized DownloadTask[] getActiveTasks() { | ||||
|         ArrayList<DownloadTask> res = new ArrayList<DownloadTask>(); | ||||
|         for (DownloadTask task : tasks) { | ||||
|             if (task.state == FILE_DOWNLOADING) { | ||||
|                 res.add(task); | ||||
|             } | ||||
|         } | ||||
|         return res.toArray(new DownloadTask[res.size()]); | ||||
|     } | ||||
|  | ||||
|     private synchronized void updateFileQueueStates() { | ||||
|         DownloadTask[] activeTasks = getActiveTasks(); | ||||
|         outer: | ||||
|         for (DownloadTask task : activeTasks) { | ||||
|             for (DownloadBlock block : task.blocks) { | ||||
|                 if (block.state != BLOCK_COMPLETED) { | ||||
|                     continue outer; | ||||
|                 } | ||||
|             } | ||||
|             onTaskCompleted(task); | ||||
|         } | ||||
|         activeTasks = getActiveTasks(); | ||||
|  | ||||
|         int count = activeTasks.length; | ||||
|         while (count < PARALLEL_DOWNLOAD_COUNT) { | ||||
|             long mintime = Long.MAX_VALUE; | ||||
|             DownloadTask minTask = null; | ||||
|             for (DownloadTask task : tasks) { | ||||
|                 if (task.state == FILE_QUEUED && task.queueTime < mintime) { | ||||
|                     minTask = task; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (minTask == null) { | ||||
|                 break; | ||||
|             } | ||||
|             minTask.state = FILE_DOWNLOADING; | ||||
|             Logger.d(TAG, "File #" + minTask.taskId + "| Downloading"); | ||||
|         } | ||||
|  | ||||
|         synchronized (threadLocker) { | ||||
|             threadLocker.notifyAll(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private synchronized void onTaskCompleted(DownloadTask task) { | ||||
|         if (task.state != FILE_COMPLETED) { | ||||
|             Logger.d(TAG, "File #" + task.taskId + "| Completed in " + (System.nanoTime() - task.queueTime) / (1000 * 1000L) + " ms"); | ||||
|             task.state = FILE_COMPLETED; | ||||
|             try { | ||||
|                 if (task.file != null) { | ||||
|                     task.file.close(); | ||||
|                     task.file = null; | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 Logger.e(TAG, e); | ||||
|             } | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     private synchronized void onTaskFailure(DownloadTask task) { | ||||
|         if (task.state != FILE_FAILURE) { | ||||
|             Logger.d(TAG, "File #" + task.taskId + "| Failure in " + (System.nanoTime() - task.queueTime) / (1000 * 1000L) + " ms"); | ||||
|             task.state = FILE_FAILURE; | ||||
|             try { | ||||
|                 if (task.file != null) { | ||||
|                     task.file.close(); | ||||
|                     task.file = null; | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 Logger.e(TAG, e); | ||||
|             } | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     private synchronized DownloadTask fetchTask() { | ||||
|         DownloadTask[] activeTasks = getActiveTasks(); | ||||
|         if (activeTasks.length == 0) { | ||||
|             return null; | ||||
|         } else if (activeTasks.length == 1) { | ||||
|             return activeTasks[0]; | ||||
|         } else { | ||||
|             return activeTasks[rnd.nextInt(activeTasks.length)]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private synchronized DownloadBlock fetchBlock() { | ||||
|         DownloadTask task = fetchTask(); | ||||
|         if (task == null) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < task.blocks.length; i++) { | ||||
|             if (task.blocks[i].state == BLOCK_QUEUED) { | ||||
|                 task.blocks[i].state = BLOCK_DOWNLOADING; | ||||
|                 if (task.lastSuccessBlock == 0) { | ||||
|                     task.lastSuccessBlock = System.nanoTime(); | ||||
|                 } | ||||
|                 return task.blocks[i]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| 	private synchronized void onBlockDownloaded(DownloadBlock block, byte[] data) { | ||||
|         try { | ||||
|             if (block.task.file != null) { | ||||
|                 block.task.file.seek(block.index * block.task.blockSize); | ||||
| 				block.task.file.write(data); | ||||
|             } else { | ||||
|                 return; | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             Logger.e(TAG, e); | ||||
|         } | ||||
|         block.task.lastSuccessBlock = System.nanoTime(); | ||||
|         block.state = BLOCK_COMPLETED; | ||||
|         if (block.task.listener != null) { | ||||
|             int downloadedCount = 0; | ||||
|             for (DownloadBlock b : block.task.blocks) { | ||||
|                 if (b.state == BLOCK_COMPLETED) { | ||||
|                     downloadedCount++; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             int percent = downloadedCount * 100 / block.task.blocks.length; | ||||
|             block.task.listener.onPartDownloaded(percent, downloadedCount); | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     private synchronized void onBlockFailure(DownloadBlock block) { | ||||
|         block.state = BLOCK_QUEUED; | ||||
|         if (block.task.lastSuccessBlock != 0 && (System.nanoTime() - block.task.lastSuccessBlock > DOWNLOAD_TIMEOUT * 1000L * 1000L)) { | ||||
|             onTaskFailure(block.task); | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     private class DownloadTask { | ||||
|  | ||||
|         public DownloadListener listener; | ||||
|         public long lastNotifyTime; | ||||
|  | ||||
|         public int taskId; | ||||
|  | ||||
|         public int blockSize; | ||||
|  | ||||
|         public int dcId; | ||||
|         public TLAbsInputFileLocation location; | ||||
|         public int size; | ||||
|  | ||||
|         public long queueTime; | ||||
|  | ||||
|         public int state; | ||||
|  | ||||
|         public DownloadBlock[] blocks; | ||||
|  | ||||
|         public String destFile; | ||||
|  | ||||
|         public RandomAccessFile file; | ||||
|  | ||||
|         public long lastSuccessBlock; | ||||
|     } | ||||
|  | ||||
|     private class DownloadBlock { | ||||
|         public DownloadTask task; | ||||
|         public int state; | ||||
|         public int index; | ||||
|     } | ||||
|  | ||||
|     private class DownloadFileThread extends Thread { | ||||
|  | ||||
|         public DownloadFileThread() { | ||||
|             setName("DownloadFileThread#" + hashCode()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             setPriority(Thread.MIN_PRIORITY); | ||||
|             while (true) { | ||||
|                 Logger.d(TAG, "DownloadFileThread iteration"); | ||||
|                 try { | ||||
|                     Thread.sleep(50); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     e.printStackTrace(); | ||||
|                     return; | ||||
|                 } | ||||
|                 DownloadBlock block = fetchBlock(); | ||||
|                 if (block == null) { | ||||
|                     synchronized (threadLocker) { | ||||
|                         try { | ||||
|                             threadLocker.wait(); | ||||
|                             continue; | ||||
|                         } catch (InterruptedException e) { | ||||
|                             Logger.e(TAG, e); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 long start = System.nanoTime(); | ||||
|                 Logger.d(TAG, "Block #" + block.index + " of #" + block.task.taskId + "| Starting"); | ||||
|                 try { | ||||
|                     TLFile file = api.doGetFile(block.task.dcId, block.task.location, block.index * block.task.blockSize, block.task.blockSize); | ||||
|                     Logger.d(TAG, "Block #" + block.index + " of #" + block.task.taskId + "| Downloaded in " + (System.nanoTime() - start) / (1000 * 1000L) + " ms"); | ||||
|                     onBlockDownloaded(block, file.getBytes()); | ||||
|                 } catch (IOException e) { | ||||
|                     Logger.d(TAG, "Block #" + block.index + " of #" + block.task.taskId + "| Failure"); | ||||
|                     Logger.e(TAG, e); | ||||
|                     onBlockFailure(block); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| package org.telegram.api.engine.file; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 19.11.13. | ||||
|  */ | ||||
| public interface UploadListener { | ||||
|     public void onPartUploaded(int percent, int downloadedSize); | ||||
| } | ||||
| @@ -1,413 +0,0 @@ | ||||
| package org.telegram.api.engine.file; | ||||
|  | ||||
| import org.telegram.api.engine.Logger; | ||||
| import org.telegram.api.engine.TelegramApi; | ||||
| import org.telegram.mtproto.secure.CryptoUtils; | ||||
| import org.telegram.mtproto.secure.Entropy; | ||||
|  | ||||
| import java.io.FileNotFoundException; | ||||
| import java.io.IOException; | ||||
| import java.io.RandomAccessFile; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Random; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 19.11.13. | ||||
|  */ | ||||
| public class Uploader { | ||||
|  | ||||
|     private static final int KB = 1024; | ||||
|     private static final int MB = 1024 * KB; | ||||
|  | ||||
|     private final AtomicInteger fileIds = new AtomicInteger(1); | ||||
|  | ||||
|     public static final int FILE_QUEUED = 0; | ||||
|     public static final int FILE_IN_PROGRESS = 1; | ||||
|     public static final int FILE_COMPLETED = 2; | ||||
|     public static final int FILE_CANCELED = 3; | ||||
|  | ||||
|     private static final int BLOCK_QUEUED = 0; | ||||
|     private static final int BLOCK_DOWNLOADING = 1; | ||||
|     private static final int BLOCK_COMPLETED = 2; | ||||
|  | ||||
|     private static final int PARALLEL_DOWNLOAD_COUNT = 2; | ||||
|  | ||||
|     private static final int PARALLEL_PARTS_COUNT = 4; | ||||
|  | ||||
|     private static final int[] BLOCK_SIZES = new int[]{8 * KB, 16 * KB, 32 * KB, 64 * KB, 128 * KB, 256 * KB, 512 * KB}; | ||||
|  | ||||
|     private static final long DEFAULT_DELAY = 15 * 1000; | ||||
|  | ||||
|     private static final int BIG_FILE_MIN = 10 * 1024 * 1024; | ||||
|  | ||||
|     private static final int MAX_BLOCK_COUNT = 3000; | ||||
|  | ||||
|     private final String TAG; | ||||
|  | ||||
|     private TelegramApi api; | ||||
|  | ||||
|     private ArrayList<UploadTask> tasks = new ArrayList<UploadTask>(); | ||||
|  | ||||
|     private ArrayList<UploadFileThread> threads = new ArrayList<UploadFileThread>(); | ||||
|  | ||||
|     private final Object threadLocker = new Object(); | ||||
|  | ||||
|     private Random rnd = new Random(); | ||||
|  | ||||
|     public Uploader(TelegramApi api) { | ||||
|         this.TAG = api.toString() + "#Uploader"; | ||||
|         this.api = api; | ||||
|  | ||||
|         for (int i = 0; i < PARALLEL_PARTS_COUNT; i++) { | ||||
|             UploadFileThread thread = new UploadFileThread(); | ||||
|             thread.start(); | ||||
|             threads.add(thread); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public TelegramApi getApi() { | ||||
|         return api; | ||||
|     } | ||||
|  | ||||
|     private synchronized UploadTask getTask(int taskId) { | ||||
|         for (UploadTask task : tasks) { | ||||
|             if (task.taskId == taskId) { | ||||
|                 return task; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public synchronized void cancelTask(int taskId) { | ||||
|         UploadTask task = getTask(taskId); | ||||
|         if (task != null && task.state != FILE_COMPLETED) { | ||||
|             task.state = FILE_CANCELED; | ||||
|             Logger.d(TAG, "File #" + task.taskId + "| Canceled"); | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     public synchronized int getTaskState(int taskId) { | ||||
|         UploadTask task = getTask(taskId); | ||||
|         if (task != null) { | ||||
|             return task.state; | ||||
|         } | ||||
|  | ||||
|         return FILE_CANCELED; | ||||
|     } | ||||
|  | ||||
|     public void waitForTask(int taskId) { | ||||
|         while (true) { | ||||
|             int state = getTaskState(taskId); | ||||
|             if ((state == FILE_COMPLETED) || (state == FILE_CANCELED)) { | ||||
|                 return; | ||||
|             } | ||||
|             synchronized (threadLocker) { | ||||
|                 try { | ||||
|                     threadLocker.wait(DEFAULT_DELAY); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     Logger.e(TAG, e); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public UploadResult getUploadResult(int taskId) { | ||||
|         UploadTask task = getTask(taskId); | ||||
|         if (task == null) { | ||||
|             return null; | ||||
|         } | ||||
|         if (task.state != FILE_COMPLETED) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         return new UploadResult(task.uniqId, task.blocks.length, task.hash, task.usedBigFile); | ||||
|     } | ||||
|  | ||||
|     public synchronized int requestTask(String srcFile, UploadListener listener) { | ||||
|         UploadTask task = new UploadTask(); | ||||
|         task.taskId = fileIds.getAndIncrement(); | ||||
|         task.uniqId = Entropy.generateRandomId(); | ||||
|         task.listener = listener; | ||||
|         task.srcFile = srcFile; | ||||
|         try { | ||||
|             task.file = new RandomAccessFile(srcFile, "r"); | ||||
|             task.size = (int) task.file.length(); | ||||
|             if (task.size >= BIG_FILE_MIN) { | ||||
|                 task.usedBigFile = true; | ||||
|                 Logger.d(TAG, "File #" + task.uniqId + "| Using big file method"); | ||||
|             } else { | ||||
|                 task.usedBigFile = false; | ||||
|             } | ||||
|             long start = System.currentTimeMillis(); | ||||
|             Logger.d(TAG, "File #" + task.uniqId + "| Calculating hash"); | ||||
|             task.hash = CryptoUtils.MD5(task.file); | ||||
|             Logger.d(TAG, "File #" + task.uniqId + "| Hash " + task.hash + " in " + (System.currentTimeMillis() - start) + " ms"); | ||||
|         } catch (FileNotFoundException e) { | ||||
|             Logger.e(TAG, e); | ||||
|         } catch (IOException e) { | ||||
|             Logger.e(TAG, e); | ||||
|         } | ||||
|  | ||||
|         task.blockSize = BLOCK_SIZES[BLOCK_SIZES.length - 1]; | ||||
|         for (int size : BLOCK_SIZES) { | ||||
|             int totalBlockCount = (int) Math.ceil(((double) task.size) / size); | ||||
|             if (totalBlockCount < MAX_BLOCK_COUNT) { | ||||
|                 task.blockSize = size; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Logger.d(TAG, "File #" + task.uniqId + "| Using block size: " + task.blockSize); | ||||
|  | ||||
|         int totalBlockCount = (int) Math.ceil(((double) task.size) / task.blockSize); | ||||
|         task.blocks = new UploadBlock[totalBlockCount]; | ||||
|         for (int i = 0; i < totalBlockCount; i++) { | ||||
|             task.blocks[i] = new UploadBlock(); | ||||
|             task.blocks[i].task = task; | ||||
|             task.blocks[i].index = i; | ||||
|             task.blocks[i].state = BLOCK_QUEUED; | ||||
|         } | ||||
|         task.state = FILE_QUEUED; | ||||
|         task.queueTime = System.nanoTime(); | ||||
|         tasks.add(task); | ||||
|  | ||||
|         Logger.d(TAG, "File #" + task.uniqId + "| Requested"); | ||||
|  | ||||
|         updateFileQueueStates(); | ||||
|  | ||||
|         return task.taskId; | ||||
|     } | ||||
|  | ||||
|     private synchronized UploadTask[] getActiveTasks() { | ||||
|         ArrayList<UploadTask> res = new ArrayList<UploadTask>(); | ||||
|         for (UploadTask task : tasks) { | ||||
|             if (task.state == FILE_IN_PROGRESS) { | ||||
|                 res.add(task); | ||||
|             } | ||||
|         } | ||||
|         return res.toArray(new UploadTask[res.size()]); | ||||
|     } | ||||
|  | ||||
|     private synchronized void updateFileQueueStates() { | ||||
|         UploadTask[] activeTasks = getActiveTasks(); | ||||
|         outer: | ||||
|         for (UploadTask task : activeTasks) { | ||||
|             for (UploadBlock block : task.blocks) { | ||||
|                 if (block.state != BLOCK_COMPLETED) { | ||||
|                     continue outer; | ||||
|                 } | ||||
|             } | ||||
|             onTaskCompleted(task); | ||||
|         } | ||||
|         activeTasks = getActiveTasks(); | ||||
|  | ||||
|         int count = activeTasks.length; | ||||
|         while (count < PARALLEL_DOWNLOAD_COUNT) { | ||||
|             long mintime = Long.MAX_VALUE; | ||||
|             UploadTask minTask = null; | ||||
|             for (UploadTask task : tasks) { | ||||
|                 if (task.state == FILE_QUEUED && task.queueTime < mintime) { | ||||
|                     minTask = task; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (minTask == null) { | ||||
|                 break; | ||||
|             } | ||||
|             minTask.state = FILE_IN_PROGRESS; | ||||
|             Logger.d(TAG, "File #" + minTask.uniqId + "| Uploading"); | ||||
|         } | ||||
|  | ||||
|         synchronized (threadLocker) { | ||||
|             threadLocker.notifyAll(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private synchronized void onTaskCompleted(UploadTask task) { | ||||
|         if (task.state != FILE_COMPLETED) { | ||||
|             Logger.d(TAG, "File #" + task.uniqId + "| Completed in " + (System.nanoTime() - task.queueTime) / (1000 * 1000L) + " ms"); | ||||
|             task.state = FILE_COMPLETED; | ||||
|             try { | ||||
|                 if (task.file != null) { | ||||
|                     task.file.close(); | ||||
|                     task.file = null; | ||||
|                 } | ||||
|             } catch (IOException e) { | ||||
|                 Logger.e(TAG, e); | ||||
|             } | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     private synchronized UploadTask fetchTask() { | ||||
|         UploadTask[] activeTasks = getActiveTasks(); | ||||
|         if (activeTasks.length == 0) { | ||||
|             return null; | ||||
|         } else if (activeTasks.length == 1) { | ||||
|             return activeTasks[0]; | ||||
|         } else { | ||||
|             return activeTasks[rnd.nextInt(activeTasks.length)]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private synchronized UploadBlock fetchBlock() { | ||||
|         UploadTask task = fetchTask(); | ||||
|         if (task == null) { | ||||
|             return null; | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < task.blocks.length; i++) { | ||||
|             if (task.blocks[i].state == BLOCK_QUEUED) { | ||||
|                 task.blocks[i].state = BLOCK_DOWNLOADING; | ||||
|                 byte[] block = new byte[Math.min(task.size - task.blockSize * i, task.blockSize)]; | ||||
|                 try { | ||||
|                     task.file.seek(task.blockSize * i); | ||||
|                     task.file.readFully(block); | ||||
|                 } catch (IOException e) { | ||||
|                     Logger.e(TAG, e); | ||||
|                 } | ||||
|                 task.blocks[i].workData = block; | ||||
|                 return task.blocks[i]; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     private synchronized void onBlockUploaded(UploadBlock block) { | ||||
|         block.state = BLOCK_COMPLETED; | ||||
|         if (block.task.listener != null) { | ||||
|             int downloadedCount = 0; | ||||
|             for (UploadBlock b : block.task.blocks) { | ||||
|                 if (b.state == BLOCK_COMPLETED) { | ||||
|                     downloadedCount++; | ||||
|                 } | ||||
|             } | ||||
|             int percent = downloadedCount * 100 / block.task.blocks.length; | ||||
|             block.task.listener.onPartUploaded(percent, downloadedCount); | ||||
|         } | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     private synchronized void onBlockFailure(UploadBlock block) { | ||||
|         block.state = BLOCK_QUEUED; | ||||
|         updateFileQueueStates(); | ||||
|     } | ||||
|  | ||||
|     public static class UploadResult { | ||||
|         private long fileId; | ||||
|         private boolean usedBigFile; | ||||
|         private int partsCount; | ||||
|         private String hash; | ||||
|  | ||||
|         public UploadResult(long fileId, int partsCount, String hash, boolean usedBigFile) { | ||||
|             this.fileId = fileId; | ||||
|             this.partsCount = partsCount; | ||||
|             this.hash = hash; | ||||
|             this.usedBigFile = usedBigFile; | ||||
|         } | ||||
|  | ||||
|         public long getFileId() { | ||||
|             return fileId; | ||||
|         } | ||||
|  | ||||
|         public boolean isUsedBigFile() { | ||||
|             return usedBigFile; | ||||
|         } | ||||
|  | ||||
|         public int getPartsCount() { | ||||
|             return partsCount; | ||||
|         } | ||||
|  | ||||
|         public String getHash() { | ||||
|             return hash; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private class UploadTask { | ||||
|  | ||||
|         public UploadListener listener; | ||||
|  | ||||
|         public boolean usedBigFile; | ||||
|  | ||||
|         public long uniqId; | ||||
|  | ||||
|         public int taskId; | ||||
|  | ||||
|         public int blockSize; | ||||
|  | ||||
|         public long queueTime; | ||||
|  | ||||
|         public int state; | ||||
|  | ||||
|         public int size; | ||||
|  | ||||
|         public UploadBlock[] blocks; | ||||
|  | ||||
|         public String srcFile; | ||||
|  | ||||
|         public RandomAccessFile file; | ||||
|  | ||||
|         public String hash; | ||||
|     } | ||||
|  | ||||
|     private class UploadBlock { | ||||
|         public UploadTask task; | ||||
|         public int state; | ||||
|         public int index; | ||||
|         public byte[] workData; | ||||
|     } | ||||
|  | ||||
|     private class UploadFileThread extends Thread { | ||||
|  | ||||
|         public UploadFileThread() { | ||||
|             setName("UploadFileThread#" + hashCode()); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void run() { | ||||
|             setPriority(Thread.MIN_PRIORITY); | ||||
|             while (true) { | ||||
|                 Logger.d(TAG, "UploadFileThread iteration"); | ||||
|                 try { | ||||
|                     Thread.sleep(50); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     e.printStackTrace(); | ||||
|                     return; | ||||
|                 } | ||||
|                 UploadBlock block = fetchBlock(); | ||||
|                 if (block == null) { | ||||
|                     synchronized (threadLocker) { | ||||
|                         try { | ||||
|                             threadLocker.wait(); | ||||
|                             continue; | ||||
|                         } catch (InterruptedException e) { | ||||
|                             Logger.e(TAG, e); | ||||
|                             return; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 long start = System.nanoTime(); | ||||
|                 Logger.d(TAG, "Block #" + block.index + " of #" + block.task.uniqId + "| Starting"); | ||||
|                 try { | ||||
|                     if (block.task.usedBigFile) { | ||||
|                         api.doSaveBigFilePart(block.task.uniqId, block.index, block.task.blocks.length, block.workData); | ||||
|                     } else { | ||||
|                         api.doSaveFilePart(block.task.uniqId, block.index, block.workData); | ||||
|                     } | ||||
|                     block.workData = null; | ||||
|                     Logger.d(TAG, "Block #" + block.index + " of #" + block.task.uniqId + "| Uploaded in " + (System.nanoTime() - start) / (1000 * 1000L) + " ms"); | ||||
|                     onBlockUploaded(block); | ||||
|                 } catch (IOException e) { | ||||
|                     Logger.d(TAG, "Block #" + block.index + " of #" + block.task.uniqId + "| Failure"); | ||||
|                     Logger.e(TAG, e); | ||||
|                     onBlockFailure(block); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,41 +0,0 @@ | ||||
| package org.telegram.api.engine.storage; | ||||
|  | ||||
| import org.telegram.api.TLConfig; | ||||
| import org.telegram.mtproto.state.AbsMTProtoState; | ||||
| import org.telegram.mtproto.state.ConnectionInfo; | ||||
| import org.telegram.mtproto.state.KnownSalt; | ||||
|  | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 10:19 | ||||
|  */ | ||||
| public interface AbsApiState { | ||||
|  | ||||
|     int getPrimaryDc(); | ||||
|  | ||||
|     public void setPrimaryDc(int dc); | ||||
|  | ||||
|     boolean isAuthenticated(int dcId); | ||||
|  | ||||
|     void setAuthenticated(int dcId, boolean auth); | ||||
|  | ||||
|     void updateSettings(TLConfig config); | ||||
|  | ||||
|  | ||||
|     byte[] getAuthKey(int dcId); | ||||
|  | ||||
|     void putAuthKey(int dcId, byte[] key); | ||||
|  | ||||
|     ConnectionInfo[] getAvailableConnections(int dcId); | ||||
|  | ||||
|     AbsMTProtoState getMtProtoState(int dcId); | ||||
|  | ||||
|     void resetAuth(); | ||||
|  | ||||
|     void reset(); | ||||
| } | ||||
| @@ -1,14 +0,0 @@ | ||||
| package org.telegram.mtproto; | ||||
|  | ||||
| import org.telegram.tl.TLMethod; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 3:56 | ||||
|  */ | ||||
| public interface CallWrapper { | ||||
|     public TLObject wrapObject(TLMethod srcRequest); | ||||
| } | ||||
| @@ -1,561 +0,0 @@ | ||||
| package org.telegram.mtproto; | ||||
|  | ||||
| import com.droidkit.actors.*; | ||||
| import org.telegram.mtproto.log.Logger; | ||||
| import org.telegram.mtproto.schedule.Scheduller; | ||||
| import org.telegram.mtproto.secure.Entropy; | ||||
| import org.telegram.mtproto.state.AbsMTProtoState; | ||||
| import org.telegram.mtproto.state.KnownSalt; | ||||
| import org.telegram.mtproto.time.TimeOverlord; | ||||
| import org.telegram.mtproto.tl.*; | ||||
| import org.telegram.mtproto.transport.*; | ||||
| import org.telegram.mtproto.util.BytesCache; | ||||
| import org.telegram.tl.DeserializeException; | ||||
| import org.telegram.tl.TLMethod; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.IOException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| import static org.telegram.mtproto.secure.CryptoUtils.*; | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:14 | ||||
|  */ | ||||
| public class MTProto { | ||||
|  | ||||
|     public static final int MODE_GENERAL = 0; | ||||
|     public static final int MODE_GENERAL_LOW_MODE = 1; | ||||
|     public static final int MODE_FILE = 2; | ||||
|     public static final int MODE_PUSH = 3; | ||||
|  | ||||
|     private static final AtomicInteger instanceIndex = new AtomicInteger(1000); | ||||
|  | ||||
|     private static final int MESSAGES_CACHE = 100; | ||||
|     private static final int MESSAGES_CACHE_MIN = 10; | ||||
|  | ||||
|     private static final int MAX_INTERNAL_FLOOD_WAIT = 10;//10 sec | ||||
|  | ||||
|     private static final int PING_INTERVAL_REQUEST = 60000;// 1 min | ||||
|     private static final int PING_INTERVAL = 75;//75 secs | ||||
|  | ||||
|     private static final int PING_PUSH_REQUEST = 9 * 60 * 1000; // 5 Min | ||||
|  | ||||
|     private static final int ERROR_MSG_ID_TOO_SMALL = 16; | ||||
|     private static final int ERROR_MSG_ID_TOO_BIG = 17; | ||||
|     private static final int ERROR_MSG_ID_BITS = 18; | ||||
|     private static final int ERROR_CONTAINER_MSG_ID_INCORRECT = 19; | ||||
|     private static final int ERROR_TOO_OLD = 20; | ||||
|     private static final int ERROR_SEQ_NO_TOO_SMALL = 32; | ||||
|     private static final int ERROR_SEQ_NO_TOO_BIG = 33; | ||||
|     private static final int ERROR_SEQ_EXPECTED_EVEN = 34; | ||||
|     private static final int ERROR_SEQ_EXPECTED_ODD = 35; | ||||
|     private static final int ERROR_BAD_SERVER_SALT = 48; | ||||
|     private static final int ERROR_BAD_CONTAINER = 64; | ||||
|  | ||||
|     private static final int PING_TIMEOUT = 60 * 1000; | ||||
|     private static final int RESEND_TIMEOUT = 60 * 1000; | ||||
|  | ||||
|     private static final int FUTURE_REQUEST_COUNT = 64; | ||||
|     private static final int FUTURE_MINIMAL = 5; | ||||
|     private static final long FUTURE_TIMEOUT = 5 * 60 * 60 * 1000;//5 min | ||||
|     private static final long FUTURE_NO_TIME_TIMEOUT = 15 * 60 * 1000;//15 sec | ||||
|  | ||||
|     private final String TAG; | ||||
|     private final int INSTANCE_INDEX; | ||||
|  | ||||
|     private MTProtoContext protoContext; | ||||
|     private ActorSystem actorSystem; | ||||
|  | ||||
|     private byte[] authKey; | ||||
|     private byte[] authKeyId; | ||||
|     private byte[] session; | ||||
|     private AbsMTProtoState state; | ||||
|  | ||||
|     private int desiredConnectionCount; | ||||
|     private TransportPool transportPool; | ||||
|  | ||||
|     private int mode = MODE_GENERAL; | ||||
|     private final Scheduller scheduller; | ||||
|     private final ArrayList<Long> receivedMessages = new ArrayList<Long>(); | ||||
|     private final ActorRef responseActor; | ||||
|     private final ActorRef actionsActor; | ||||
|     private MTProtoCallback callback; | ||||
|  | ||||
|     private boolean isClosed; | ||||
|  | ||||
|     public MTProto(AbsMTProtoState state, | ||||
|                    MTProtoCallback callback, | ||||
|                    CallWrapper callWrapper, | ||||
|                    int connectionsCount, | ||||
|                    int mode) { | ||||
|         this.INSTANCE_INDEX = instanceIndex.incrementAndGet(); | ||||
|         this.TAG = "MTProto#" + INSTANCE_INDEX; | ||||
|         this.mode = mode; | ||||
|         this.actorSystem = new ActorSystem(); | ||||
|         this.actorSystem.addDispatcher("connector"); | ||||
|         this.responseActor = actorSystem.actorOf(processor()); | ||||
|         this.actionsActor = actorSystem.actorOf(internal()); | ||||
|  | ||||
|         this.state = state; | ||||
|         this.callback = callback; | ||||
|         this.authKey = state.getAuthKey(); | ||||
|         this.authKeyId = substring(SHA1(authKey), 12, 8); | ||||
|         this.protoContext = MTProtoContext.getInstance(); | ||||
|         this.desiredConnectionCount = connectionsCount; | ||||
|         this.session = Entropy.generateSeed(8); | ||||
|         this.scheduller = new Scheduller(this, callWrapper); | ||||
|         this.scheduller.postMessage(new MTPing(Entropy.generateRandomId()), false, Long.MAX_VALUE); | ||||
|  | ||||
|         this.transportPool = new TransportTcpPool(this, new TransportPoolCallback() { | ||||
|             @Override | ||||
|             public void onMTMessage(MTMessage message) { | ||||
|                 responseActor.send(message); | ||||
|             } | ||||
|  | ||||
|             @Override | ||||
|             public void onFastConfirm(int hash) { | ||||
|                 // We might not send this to response actor for providing faster confirmation | ||||
|                 int[] ids = scheduller.mapFastConfirm(hash); | ||||
|                 for (int id : ids) { | ||||
|                     MTProto.this.callback.onConfirmed(id); | ||||
|                 } | ||||
|             } | ||||
|         }, desiredConnectionCount); | ||||
|         switch (mode) { | ||||
|             case MODE_GENERAL: | ||||
|             case MODE_PUSH: | ||||
|                 transportPool.switchMode(TransportPool.MODE_DEFAULT); | ||||
|                 break; | ||||
|             case MODE_GENERAL_LOW_MODE: | ||||
|             case MODE_FILE: | ||||
|                 transportPool.switchMode(TransportPool.MODE_LOWMODE); | ||||
|                 break; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         this.actionsActor.sendOnce(new RequestPingDelay()); | ||||
|         this.actionsActor.sendOnce(new RequestSalt()); | ||||
|     } | ||||
|  | ||||
|     public AbsMTProtoState getState() { | ||||
|         return state; | ||||
|     } | ||||
|  | ||||
|     public void resetNetworkBackoff() { | ||||
|         this.transportPool.resetConnectionBackoff(); | ||||
|         this.actionsActor.sendOnce(new RequestPingDelay()); | ||||
|     } | ||||
|  | ||||
|     public void reloadConnectionInformation() { | ||||
|         this.transportPool.reloadConnectionInformation(); | ||||
|         this.actionsActor.sendOnce(new RequestPingDelay()); | ||||
|     } | ||||
|  | ||||
|     public int getInstanceIndex() { | ||||
|         return INSTANCE_INDEX; | ||||
|     } | ||||
|  | ||||
|     public Scheduller getScheduller() { | ||||
|         return scheduller; | ||||
|     } | ||||
|  | ||||
|     public byte[] getSession() { | ||||
|         return session; | ||||
|     } | ||||
|  | ||||
|     public byte[] getAuthKeyId() { | ||||
|         return authKeyId; | ||||
|     } | ||||
|  | ||||
|     public byte[] getAuthKey() { | ||||
|         return authKey; | ||||
|     } | ||||
|  | ||||
|     public ActorSystem getActorSystem() { | ||||
|         return actorSystem; | ||||
|     } | ||||
|  | ||||
|     public boolean isClosed() { | ||||
|         return isClosed; | ||||
|     } | ||||
|  | ||||
|     public int sendRpcMessage(TLMethod request, long timeout, boolean highPriority) { | ||||
|         int id = scheduller.postMessage(request, true, timeout, highPriority); | ||||
|         Logger.d(TAG, "sendMessage #" + id + " " + request.toString() + " with timeout " + timeout + " ms"); | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     public void forgetMessage(int id) { | ||||
|         scheduller.forgetMessage(id); | ||||
|     } | ||||
|  | ||||
|     public void switchMode(int mode) { | ||||
|         if (this.mode != mode) { | ||||
|             this.mode = mode; | ||||
|  | ||||
|             switch (mode) { | ||||
|                 case MODE_GENERAL: | ||||
|                 case MODE_PUSH: | ||||
|                     transportPool.switchMode(TransportPool.MODE_DEFAULT); | ||||
|                     break; | ||||
|                 case MODE_GENERAL_LOW_MODE: | ||||
|                 case MODE_FILE: | ||||
|                     transportPool.switchMode(TransportPool.MODE_LOWMODE); | ||||
|                     break; | ||||
|  | ||||
|             } | ||||
|  | ||||
|             this.actionsActor.sendOnce(new RequestPingDelay()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void close() { | ||||
|         if (!isClosed) { | ||||
|             this.isClosed = true; | ||||
|             // TODO: implement | ||||
|             // this.actorSystem.close(); | ||||
|             this.transportPool.close(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Finding message type | ||||
|     private void onMTMessage(MTMessage mtMessage) { | ||||
|         if (mtMessage.getSeqNo() % 2 == 1) { | ||||
|             scheduller.confirmMessage(mtMessage.getMessageId()); | ||||
|         } | ||||
|         if (!needProcessing(mtMessage.getMessageId())) { | ||||
|             if (Logger.LOG_IGNORED) { | ||||
|                 Logger.d(TAG, "Ignoring messages #" + mtMessage.getMessageId()); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|         try { | ||||
|             TLObject intMessage = protoContext.deserializeMessage(new ByteArrayInputStream(mtMessage.getContent())); | ||||
|             onMTProtoMessage(mtMessage.getMessageId(), intMessage); | ||||
|         } catch (DeserializeException e) { | ||||
|             callback.onApiMessage(mtMessage.getContent(), this); | ||||
|         } catch (IOException e) { | ||||
|             Logger.e(TAG, e); | ||||
|             // ??? | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void onMTProtoMessage(long msgId, TLObject object) { | ||||
|         Logger.d(TAG, "MTProtoMessage: " + object.toString()); | ||||
|  | ||||
|         if (object instanceof MTBadMessage) { | ||||
|             MTBadMessage badMessage = (MTBadMessage) object; | ||||
|             Logger.d(TAG, "BadMessage: " + badMessage.getErrorCode() + " #" + badMessage.getBadMsgId()); | ||||
|             scheduller.onMessageConfirmed(badMessage.getBadMsgId()); | ||||
|             long time = scheduller.getMessageIdGenerationTime(badMessage.getBadMsgId()); | ||||
|             if (time != 0) { | ||||
|                 if (badMessage.getErrorCode() == ERROR_MSG_ID_TOO_BIG | ||||
|                         || badMessage.getErrorCode() == ERROR_MSG_ID_TOO_SMALL) { | ||||
|                     long delta = System.nanoTime() / 1000000 - time; | ||||
|                     TimeOverlord.getInstance().onForcedServerTimeArrived((msgId >> 32) * 1000, delta); | ||||
|                     if (badMessage.getErrorCode() == ERROR_MSG_ID_TOO_BIG) { | ||||
|                         scheduller.resetMessageId(); | ||||
|                     } | ||||
|                     scheduller.resendAsNewMessage(badMessage.getBadMsgId()); | ||||
|                 } else if (badMessage.getErrorCode() == ERROR_SEQ_NO_TOO_BIG || badMessage.getErrorCode() == ERROR_SEQ_NO_TOO_SMALL) { | ||||
|                     if (scheduller.isMessageFromCurrentGeneration(badMessage.getBadMsgId())) { | ||||
|                         Logger.d(TAG, "Resetting session"); | ||||
|                         session = Entropy.generateSeed(8); | ||||
|                         transportPool.onSessionChanged(session); | ||||
|                         scheduller.resetSession(); | ||||
|                     } | ||||
|                     scheduller.resendAsNewMessage(badMessage.getBadMsgId()); | ||||
|                 } else if (badMessage.getErrorCode() == ERROR_BAD_SERVER_SALT) { | ||||
|                     long salt = ((MTBadServerSalt) badMessage).getNewSalt(); | ||||
|                     // Sync time | ||||
|                     long delta = System.nanoTime() / 1000000 - time; | ||||
|                     TimeOverlord.getInstance().onMethodExecuted(badMessage.getBadMsgId(), msgId, delta); | ||||
|                     state.badServerSalt(salt); | ||||
|                     Logger.d(TAG, "Reschedule messages because bad_server_salt #" + badMessage.getBadMsgId()); | ||||
|                     scheduller.resendAsNewMessage(badMessage.getBadMsgId()); | ||||
|                     this.actionsActor.sendOnce(new RequestSalt()); | ||||
|                 } else if (badMessage.getErrorCode() == ERROR_BAD_CONTAINER || | ||||
|                         badMessage.getErrorCode() == ERROR_CONTAINER_MSG_ID_INCORRECT) { | ||||
|                     scheduller.resendMessage(badMessage.getBadMsgId()); | ||||
|                 } else if (badMessage.getErrorCode() == ERROR_TOO_OLD) { | ||||
|                     scheduller.resendAsNewMessage(badMessage.getBadMsgId()); | ||||
|                 } else { | ||||
|                     if (Logger.LOG_IGNORED) { | ||||
|                         Logger.d(TAG, "Ignored BadMsg #" + badMessage.getErrorCode() + " (" + badMessage.getBadMsgId() + ", " + badMessage.getBadMsqSeqno() + ")"); | ||||
|                     } | ||||
|                     scheduller.forgetMessageByMsgId(badMessage.getBadMsgId()); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (Logger.LOG_IGNORED) { | ||||
|                     Logger.d(TAG, "Unknown package #" + badMessage.getBadMsgId()); | ||||
|                 } | ||||
|             } | ||||
|         } else if (object instanceof MTMsgsAck) { | ||||
|             MTMsgsAck ack = (MTMsgsAck) object; | ||||
|             String log = ""; | ||||
|             for (Long ackMsgId : ack.getMessages()) { | ||||
|                 scheduller.onMessageConfirmed(ackMsgId); | ||||
|                 if (log.length() > 0) { | ||||
|                     log += ", "; | ||||
|                 } | ||||
|                 log += ackMsgId; | ||||
|                 int id = scheduller.mapSchedullerId(ackMsgId); | ||||
|                 if (id > 0) { | ||||
|                     callback.onConfirmed(id); | ||||
|                 } | ||||
|             } | ||||
|             Logger.d(TAG, "msgs_ack: " + log); | ||||
|         } else if (object instanceof MTRpcResult) { | ||||
|             MTRpcResult result = (MTRpcResult) object; | ||||
|  | ||||
|             Logger.d(TAG, "rpc_result: " + result.getMessageId()); | ||||
|  | ||||
|             int id = scheduller.mapSchedullerId(result.getMessageId()); | ||||
|             if (id > 0) { | ||||
|                 int responseConstructor = readInt(result.getContent()); | ||||
|                 if (responseConstructor == MTRpcError.CLASS_ID) { | ||||
|                     try { | ||||
|                         MTRpcError error = (MTRpcError) protoContext.deserializeMessage(result.getContent()); | ||||
|                         BytesCache.getInstance().put(result.getContent()); | ||||
|  | ||||
|                         if (error.getErrorCode() == 420) { | ||||
|                             if (error.getErrorTag().startsWith("FLOOD_WAIT_")) { | ||||
|                                 // Secs | ||||
|                                 int delay = Integer.parseInt(error.getErrorTag().substring("FLOOD_WAIT_".length())); | ||||
|                                 if (delay <= MAX_INTERNAL_FLOOD_WAIT) { | ||||
|                                     scheduller.resendAsNewMessageDelayed(result.getMessageId(), delay * 1000); | ||||
|                                     return; | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                         if (error.getErrorCode() == 401) { | ||||
|                             if (error.getErrorTag().equals("AUTH_KEY_UNREGISTERED") || | ||||
|                                     error.getErrorTag().equals("AUTH_KEY_INVALID") || | ||||
|                                     error.getErrorTag().equals("USER_DEACTIVATED") || | ||||
|                                     error.getErrorTag().equals("SESSION_REVOKED") || | ||||
|                                     error.getErrorTag().equals("SESSION_EXPIRED")) { | ||||
|                                 Logger.w(TAG, "Auth key invalidated: " + error.getErrorTag()); | ||||
|                                 callback.onAuthInvalidated(this); | ||||
|                                 close(); | ||||
|                                 return; | ||||
|                             } | ||||
|                         } | ||||
|  | ||||
|                         callback.onRpcError(id, error.getErrorCode(), error.getMessage(), this); | ||||
|                         scheduller.forgetMessage(id); | ||||
|                     } catch (IOException e) { | ||||
|                         Logger.e(TAG, e); | ||||
|                         return; | ||||
|                     } | ||||
|                 } else { | ||||
|                     Logger.d(TAG, "rpc_result: " + result.getMessageId() + " #" + Integer.toHexString(responseConstructor)); | ||||
|                     callback.onRpcResult(id, result.getContent(), this); | ||||
|                     BytesCache.getInstance().put(result.getContent()); | ||||
|                     scheduller.forgetMessage(id); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (Logger.LOG_IGNORED) { | ||||
|                     Logger.d(TAG, "ignored rpc_result: " + result.getMessageId()); | ||||
|                 } | ||||
|                 BytesCache.getInstance().put(result.getContent()); | ||||
|             } | ||||
|             scheduller.onMessageConfirmed(result.getMessageId()); | ||||
|             long time = scheduller.getMessageIdGenerationTime(result.getMessageId()); | ||||
|             if (time != 0) { | ||||
|                 long delta = System.nanoTime() / 1000000 - time; | ||||
|                 TimeOverlord.getInstance().onMethodExecuted(result.getMessageId(), msgId, delta); | ||||
|             } | ||||
|         } else if (object instanceof MTPong) { | ||||
|             MTPong pong = (MTPong) object; | ||||
|             if (Logger.LOG_PING) { | ||||
|                 Logger.d(TAG, "pong: " + pong.getPingId()); | ||||
|             } | ||||
|             scheduller.onMessageConfirmed(pong.getMessageId()); | ||||
|             scheduller.forgetMessageByMsgId(pong.getMessageId()); | ||||
|             long time = scheduller.getMessageIdGenerationTime(pong.getMessageId()); | ||||
|             if (time != 0) { | ||||
|                 long delta = System.nanoTime() / 1000000 - time; | ||||
|                 TimeOverlord.getInstance().onMethodExecuted(pong.getMessageId(), msgId, delta); | ||||
|             } | ||||
|         } else if (object instanceof MTFutureSalts) { | ||||
|             MTFutureSalts salts = (MTFutureSalts) object; | ||||
|             scheduller.onMessageConfirmed(salts.getRequestId()); | ||||
|             scheduller.forgetMessageByMsgId(salts.getRequestId()); | ||||
|  | ||||
|             long time = scheduller.getMessageIdGenerationTime(salts.getRequestId()); | ||||
|  | ||||
|             if (time > 0) { | ||||
|                 KnownSalt[] knownSalts = new KnownSalt[salts.getSalts().size()]; | ||||
|                 for (int i = 0; i < knownSalts.length; i++) { | ||||
|                     MTFutureSalt salt = salts.getSalts().get(i); | ||||
|                     knownSalts[i] = new KnownSalt(salt.getValidSince(), salt.getValidUntil(), salt.getSalt()); | ||||
|                 } | ||||
|  | ||||
|                 long delta = System.nanoTime() / 1000000 - time; | ||||
|                 TimeOverlord.getInstance().onForcedServerTimeArrived(salts.getNow(), delta); | ||||
|                 state.mergeKnownSalts(salts.getNow(), knownSalts); | ||||
|             } | ||||
|         } else if (object instanceof MTMessageDetailedInfo) { | ||||
|             MTMessageDetailedInfo detailedInfo = (MTMessageDetailedInfo) object; | ||||
|             Logger.d(TAG, "msg_detailed_info: " + detailedInfo.getMsgId() + ", answer: " + detailedInfo.getAnswerMsgId()); | ||||
|             if (receivedMessages.contains(detailedInfo.getAnswerMsgId())) { | ||||
|                 scheduller.confirmMessage(detailedInfo.getAnswerMsgId()); | ||||
|             } else { | ||||
|                 int id = scheduller.mapSchedullerId(detailedInfo.getMsgId()); | ||||
|                 if (id > 0) { | ||||
|                     scheduller.postMessage(new MTNeedResendMessage(new long[]{detailedInfo.getAnswerMsgId()}), false, RESEND_TIMEOUT); | ||||
|                 } else { | ||||
|                     scheduller.confirmMessage(detailedInfo.getAnswerMsgId()); | ||||
|                     scheduller.forgetMessageByMsgId(detailedInfo.getMsgId()); | ||||
|                 } | ||||
|             } | ||||
|         } else if (object instanceof MTNewMessageDetailedInfo) { | ||||
|             MTNewMessageDetailedInfo detailedInfo = (MTNewMessageDetailedInfo) object; | ||||
|             Logger.d(TAG, "msg_new_detailed_info: " + detailedInfo.getAnswerMsgId()); | ||||
|             if (receivedMessages.contains(detailedInfo.getAnswerMsgId())) { | ||||
|                 scheduller.confirmMessage(detailedInfo.getAnswerMsgId()); | ||||
|             } else { | ||||
|                 scheduller.postMessage(new MTNeedResendMessage(new long[]{detailedInfo.getAnswerMsgId()}), false, RESEND_TIMEOUT); | ||||
|             } | ||||
|         } else if (object instanceof MTNewSessionCreated) { | ||||
|             callback.onSessionCreated(this); | ||||
|         } else { | ||||
|             if (Logger.LOG_IGNORED) { | ||||
|                 Logger.d(TAG, "Ignored MTProto message " + object.toString()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private boolean needProcessing(long messageId) { | ||||
|         synchronized (receivedMessages) { | ||||
|             if (receivedMessages.contains(messageId)) { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             if (receivedMessages.size() > MESSAGES_CACHE_MIN) { | ||||
|                 boolean isSmallest = true; | ||||
|                 for (Long l : receivedMessages) { | ||||
|                     if (messageId > l) { | ||||
|                         isSmallest = false; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 if (isSmallest) { | ||||
|                     return false; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             while (receivedMessages.size() >= MESSAGES_CACHE - 1) { | ||||
|                 receivedMessages.remove(0); | ||||
|             } | ||||
|             receivedMessages.add(messageId); | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     private ActorSelection internal() { | ||||
|         return new ActorSelection(Props.create(InternalActionsActor.class, new ActorCreator<InternalActionsActor>() { | ||||
|             @Override | ||||
|             public InternalActionsActor create() { | ||||
|                 return new InternalActionsActor(MTProto.this); | ||||
|             } | ||||
|         }), "internal_" + INSTANCE_INDEX); | ||||
|     } | ||||
|  | ||||
|     private ActorSelection processor() { | ||||
|         return new ActorSelection(Props.create(ResponseActor.class, new ActorCreator<ResponseActor>() { | ||||
|             @Override | ||||
|             public ResponseActor create() { | ||||
|                 return new ResponseActor(MTProto.this); | ||||
|             } | ||||
|         }), "response_" + INSTANCE_INDEX); | ||||
|     } | ||||
|  | ||||
|     private static class RequestSalt { | ||||
|     } | ||||
|  | ||||
|     private static class RequestPingDelay { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private static class InternalActionsActor extends Actor { | ||||
|  | ||||
|         private int lastPingMessage = -1; | ||||
|         private final MTProto proto; | ||||
|  | ||||
|         public InternalActionsActor(MTProto proto) { | ||||
|             this.proto = proto; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onReceive(Object message) { | ||||
|             if (message instanceof RequestSalt) { | ||||
|                 onRequestSaltsMessage(); | ||||
|             } else if (message instanceof RequestPingDelay) { | ||||
|                 onPingDelayMessage(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public void onRequestSaltsMessage() { | ||||
|             // Logger.d(TAG, "Salt check timeout"); | ||||
|             if (TimeOverlord.getInstance().getTimeAccuracy() > 1000) { | ||||
|                 // Logger.d(TAG, "Time is not accurate: " + TimeOverlord.getInstance().getTimeAccuracy()); | ||||
|                 self().send(new RequestSalt(), FUTURE_NO_TIME_TIMEOUT); | ||||
|                 return; | ||||
|             } | ||||
|             int count = proto.state.maximumCachedSalts((int) (TimeOverlord.getInstance().getServerTime() / 1000)); | ||||
|             if (count < FUTURE_MINIMAL) { | ||||
|                 // Logger.d(TAG, "Too few actual salts: " + count + ", requesting news"); | ||||
|                 proto.scheduller.postMessage(new MTGetFutureSalts(FUTURE_REQUEST_COUNT), false, FUTURE_TIMEOUT); | ||||
|             } | ||||
|             self().send(new RequestSalt(), FUTURE_TIMEOUT); | ||||
|         } | ||||
|  | ||||
|         public void onPingDelayMessage() { | ||||
|             if (lastPingMessage >= 0) { | ||||
|                 proto.forgetMessage(lastPingMessage); | ||||
|                 lastPingMessage = -1; | ||||
|             } | ||||
|             if (proto.mode == MODE_GENERAL) { | ||||
|                 // Logger.d(TAG, "Ping delay disconnect for " + PING_INTERVAL + " sec"); | ||||
|                 lastPingMessage = proto.scheduller.postMessage(new MTPingDelayDisconnect(Entropy.generateRandomId(), PING_INTERVAL), | ||||
|                         false, PING_INTERVAL_REQUEST); | ||||
|                 self().send(new RequestPingDelay(), PING_INTERVAL_REQUEST); | ||||
|             } else if (proto.mode == MODE_PUSH) { | ||||
|                 lastPingMessage = proto.scheduller.postMessage(new MTPing(Entropy.generateRandomId()), false, PING_INTERVAL_REQUEST); | ||||
|                 self().send(new RequestPingDelay(), PING_PUSH_REQUEST); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class ResponseActor extends Actor { | ||||
|         private final MTProto proto; | ||||
|  | ||||
|         private ResponseActor(MTProto proto) { | ||||
|             this.proto = proto; | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onReceive(Object message) { | ||||
|             if (message instanceof MTMessage) { | ||||
|                 MTMessage mtMessage = (MTMessage) message; | ||||
|                 proto.onMTMessage(mtMessage); | ||||
|                 BytesCache.getInstance().put(mtMessage.getContent()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "mtproto#" + INSTANCE_INDEX; | ||||
|     } | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| package org.telegram.mtproto; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 04.11.13 | ||||
|  * Time: 22:11 | ||||
|  */ | ||||
| public interface MTProtoCallback { | ||||
|     public void onSessionCreated(MTProto proto); | ||||
|  | ||||
|     public void onAuthInvalidated(MTProto proto); | ||||
|  | ||||
|     public void onApiMessage(byte[] message, MTProto proto); | ||||
|  | ||||
|     public void onRpcResult(int callId, byte[] response, MTProto proto); | ||||
|  | ||||
|     public void onRpcError(int callId, int errorCode, String message, MTProto proto); | ||||
|  | ||||
|     public void onConfirmed(int callId); | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| package org.telegram.mtproto; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 6:47 | ||||
|  */ | ||||
| public class ServerException extends IOException { | ||||
|     public ServerException() { | ||||
|     } | ||||
|  | ||||
|     public ServerException(String s) { | ||||
|         super(s); | ||||
|     } | ||||
|  | ||||
|     public ServerException(String s, Throwable throwable) { | ||||
|         super(s, throwable); | ||||
|     } | ||||
|  | ||||
|     public ServerException(Throwable throwable) { | ||||
|         super(throwable); | ||||
|     } | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| package org.telegram.mtproto; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 6:44 | ||||
|  */ | ||||
| public class TransportSecurityException extends IOException { | ||||
|     public TransportSecurityException() { | ||||
|     } | ||||
|  | ||||
|     public TransportSecurityException(String s) { | ||||
|         super(s); | ||||
|     } | ||||
|  | ||||
|     public TransportSecurityException(String s, Throwable throwable) { | ||||
|         super(s, throwable); | ||||
|     } | ||||
|  | ||||
|     public TransportSecurityException(Throwable throwable) { | ||||
|         super(throwable); | ||||
|     } | ||||
| } | ||||
| @@ -1,64 +0,0 @@ | ||||
| package org.telegram.mtproto.backoff; | ||||
|  | ||||
| import org.telegram.mtproto.log.Logger; | ||||
|  | ||||
| import java.util.Random; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 27.12.13. | ||||
|  */ | ||||
| public class ExponentalBackoff { | ||||
|  | ||||
|     private static final int MIN_DELAY = 100; | ||||
|     private static final int MAX_DELAY = 15000; | ||||
|     private static final int MAX_FAILURE_COUNT = 50; | ||||
|  | ||||
|     private Random rnd = new Random(); | ||||
|  | ||||
|     private AtomicInteger currentFailureCount = new AtomicInteger(); | ||||
|  | ||||
|     private final String TAG; | ||||
|  | ||||
|     public ExponentalBackoff(String logTag) { | ||||
|         this.TAG = logTag; | ||||
|     } | ||||
|  | ||||
|     public void onFailure() throws InterruptedException { | ||||
|         int val = currentFailureCount.incrementAndGet(); | ||||
|         if (val > 50) { | ||||
|             currentFailureCount.compareAndSet(val, MAX_FAILURE_COUNT); | ||||
|             val = MAX_FAILURE_COUNT; | ||||
|         } | ||||
|  | ||||
|         int delay = MIN_DELAY + ((MAX_DELAY - MIN_DELAY) / MAX_FAILURE_COUNT) * val; | ||||
|  | ||||
|         synchronized (this) { | ||||
|             Logger.d(TAG, "onFailure: wait " + delay + " ms"); | ||||
|             wait(delay); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onFailureNoWait() { | ||||
|         Logger.d(TAG, "onFailureNoWait"); | ||||
|         int val = currentFailureCount.incrementAndGet(); | ||||
|         if (val > 50) { | ||||
|             currentFailureCount.compareAndSet(val, MAX_FAILURE_COUNT); | ||||
|             val = MAX_FAILURE_COUNT; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onSuccess() { | ||||
|         Logger.d(TAG, "onSuccess"); | ||||
|         reset(); | ||||
|     } | ||||
|  | ||||
|     public void reset() { | ||||
|         Logger.d(TAG, "reset"); | ||||
|         currentFailureCount.set(0); | ||||
|  | ||||
|         synchronized (this) { | ||||
|             notifyAll(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
| package org.telegram.mtproto.log; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 10.11.13 | ||||
|  * Time: 2:11 | ||||
|  */ | ||||
| public interface LogInterface { | ||||
|     void w(String tag, String message); | ||||
|  | ||||
|     void d(String tag, String message); | ||||
|  | ||||
|     void e(String tag, Throwable t); | ||||
| } | ||||
| @@ -1,44 +0,0 @@ | ||||
| package org.telegram.mtproto.log; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 3:54 | ||||
|  */ | ||||
| public class Logger { | ||||
|  | ||||
|     public static final boolean LOG_THREADS = true; | ||||
|     public static final boolean LOG_IGNORED = true; | ||||
|     public static final boolean LOG_PING = true; | ||||
|  | ||||
|     private static LogInterface logInterface; | ||||
|  | ||||
|     public static void registerInterface(LogInterface logInterface) { | ||||
|         Logger.logInterface = logInterface; | ||||
|     } | ||||
|  | ||||
|     public static void w(String tag, String message) { | ||||
|         if (logInterface != null) { | ||||
|             logInterface.w(tag, message); | ||||
|         } else { | ||||
|             System.out.println(tag + ":" + message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void d(String tag, String message) { | ||||
|         if (logInterface != null) { | ||||
|             logInterface.d(tag, message); | ||||
|         } else { | ||||
|             System.out.println(tag + ":" + message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void e(String tag, Throwable t) { | ||||
|         if (logInterface != null) { | ||||
|             logInterface.e(tag, t); | ||||
|         } else { | ||||
|             t.printStackTrace(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,225 +0,0 @@ | ||||
| package org.telegram.mtproto.pq; | ||||
|  | ||||
| import org.telegram.mtproto.ServerException; | ||||
| import org.telegram.mtproto.TransportSecurityException; | ||||
| import org.telegram.mtproto.log.Logger; | ||||
| import org.telegram.mtproto.secure.CryptoUtils; | ||||
| import org.telegram.mtproto.secure.Entropy; | ||||
| import org.telegram.mtproto.secure.Keys; | ||||
| import org.telegram.mtproto.secure.pq.PQSolver; | ||||
| import org.telegram.mtproto.state.ConnectionInfo; | ||||
| import org.telegram.mtproto.time.TimeOverlord; | ||||
| import org.telegram.mtproto.tl.pq.*; | ||||
| import org.telegram.mtproto.transport.ConnectionType; | ||||
| import org.telegram.mtproto.transport.PlainTcpConnection; | ||||
| import org.telegram.mtproto.transport.TransportRate; | ||||
| import org.telegram.tl.TLMethod; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.math.BigInteger; | ||||
|  | ||||
| import static org.telegram.mtproto.secure.CryptoUtils.*; | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 4:11 | ||||
|  */ | ||||
| public class Authorizer { | ||||
|     private static final String TAG = "Authorizer"; | ||||
|     private static final int AUTH_ATTEMPT_COUNT = 5; | ||||
|     private static final int AUTH_RETRY_COUNT = 5; | ||||
|  | ||||
|     private PlainTcpConnection context; | ||||
|     private TLInitContext initContext; | ||||
|  | ||||
|     public Authorizer() { | ||||
|         initContext = new TLInitContext(); | ||||
|     } | ||||
|  | ||||
|     private <T extends TLObject> T executeMethod(TLMethod<T> object) throws IOException { | ||||
|         long requestMessageId = TimeOverlord.getInstance().createWeakMessageId(); | ||||
|         long start = System.nanoTime(); | ||||
|         byte[] data = object.serialize(); | ||||
|         ByteArrayOutputStream out = new ByteArrayOutputStream(); | ||||
|         writeLong(0, out); // Empty AUTH_ID | ||||
|         writeLong(requestMessageId, out); // MessageID | ||||
|         writeInt(data.length, out); | ||||
|         writeByteArray(data, out); | ||||
|         byte[] response = context.executeMethod(out.toByteArray()); | ||||
|         ByteArrayInputStream in = new ByteArrayInputStream(response); | ||||
|         long authId = readLong(in); | ||||
|         if (authId != 0) { | ||||
|             throw new IOException("Auth id might be equal to zero"); | ||||
|         } | ||||
|         long messageId = readLong(in); | ||||
|         // TimeOverlord.getInstance().onMethodExecuted(requestMessageId, messageId, (System.nanoTime() - start) / 1000000); | ||||
|         int length = readInt(in); | ||||
|         byte[] messageResponse = readBytes(length, in); | ||||
|         return object.deserializeResponse(messageResponse, initContext); | ||||
|     } | ||||
|  | ||||
|     private PqAuth authAttempt() throws IOException { | ||||
|         // PQ-Auth start | ||||
|         byte[] nonce = Entropy.generateSeed(16); | ||||
|         ResPQ resPQ = executeMethod(new ReqPQ(nonce)); | ||||
|         byte[] serverNonce = resPQ.getServerNonce(); | ||||
|  | ||||
|         long fingerprint = 0; | ||||
|         Keys.Key publicKey = null; | ||||
|         outer: | ||||
|         for (Long srcFingerprint : resPQ.getFingerprints()) { | ||||
|             for (Keys.Key key : Keys.AVAILABLE_KEYS) { | ||||
|                 if (srcFingerprint.equals(key.getFingerprint())) { | ||||
|                     fingerprint = srcFingerprint; | ||||
|                     publicKey = key; | ||||
|                     break outer; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (fingerprint == 0) { | ||||
|             throw new IOException("Unknown public keys"); | ||||
|         } | ||||
|  | ||||
|         BigInteger pq = loadBigInt(resPQ.getPq()); | ||||
|         BigInteger p = null; | ||||
|         try { | ||||
|             long start = System.currentTimeMillis(); | ||||
|             p = PQSolver.solvePq(pq); | ||||
|             Logger.d(TAG, "Solved PQ in " + (System.currentTimeMillis() - start) + " ms"); | ||||
|         } catch (Exception e) { | ||||
|             throw new IOException(); | ||||
|         } | ||||
|         BigInteger q = pq.divide(p); | ||||
|  | ||||
|         byte[] newNonce = Entropy.generateSeed(32); | ||||
|  | ||||
|         PQInner inner = new PQInner(resPQ.getPq(), fromBigInt(p), fromBigInt(q), nonce, | ||||
|                 serverNonce, newNonce); | ||||
|  | ||||
|         byte[] pqInner = inner.serialize(); | ||||
|  | ||||
|         // PQ INNER | ||||
|         byte[] hash = CryptoUtils.SHA1(pqInner); | ||||
|         byte[] seed = Entropy.generateSeed(255 - hash.length - pqInner.length); | ||||
|         byte[] dataWithHash = concat(hash, pqInner, seed); | ||||
|  | ||||
|         byte[] encrypted = CryptoUtils.RSA(dataWithHash, publicKey.getPublicKey(), publicKey.getExponent()); | ||||
|  | ||||
|         long start = System.nanoTime(); | ||||
|         ServerDhParams dhParams = executeMethod(new ReqDhParams(nonce, serverNonce, fromBigInt(p), fromBigInt(q), | ||||
|                 fingerprint, encrypted)); | ||||
|         long dhParamsDuration = (System.nanoTime() - start) / (1000 * 1000); | ||||
|  | ||||
|         if (dhParams instanceof ServerDhFailure) { | ||||
|             ServerDhFailure hdFailure = (ServerDhFailure) dhParams; | ||||
|             if (arrayEq(hdFailure.getNewNonceHash(), SHA1(newNonce))) { | ||||
|                 throw new ServerException("Received server_DH_params_fail#79cb045d"); | ||||
|             } else { | ||||
|                 throw new TransportSecurityException("Received server_DH_params_fail#79cb045d with incorrect hash"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // PQ-Auth end | ||||
|         // DH-Auth start | ||||
|         ServerDhOk serverDhParams = (ServerDhOk) dhParams; | ||||
|  | ||||
|         byte[] encryptedAnswer = serverDhParams.getEncryptedAnswer(); | ||||
|  | ||||
|         byte[] tmpAesKey = concat(SHA1(newNonce, serverNonce), substring(SHA1(serverNonce, newNonce), 0, 12)); | ||||
|         byte[] tmpAesIv = concat(concat(substring(SHA1(serverNonce, newNonce), 12, 8), SHA1(newNonce, newNonce)), | ||||
|                 substring(newNonce, 0, 4)); | ||||
|  | ||||
|         byte[] answer = AES256IGEDecrypt(encryptedAnswer, tmpAesIv, tmpAesKey); | ||||
|         ByteArrayInputStream stream = new ByteArrayInputStream(answer); | ||||
|         byte[] answerHash = readBytes(20, stream); // Hash | ||||
|         ServerDhInner dhInner = (ServerDhInner) initContext.deserializeMessage(stream); | ||||
|         if (!arrayEq(answerHash, SHA1(dhInner.serialize()))) { | ||||
|             throw new TransportSecurityException(); | ||||
|         } | ||||
|  | ||||
|         TimeOverlord.getInstance().onServerTimeArrived(dhInner.getServerTime() * 1000L, dhParamsDuration); | ||||
|  | ||||
|         for (int i = 0; i < AUTH_RETRY_COUNT; i++) { | ||||
|             BigInteger b = loadBigInt(Entropy.generateSeed(256)); | ||||
|             BigInteger g = new BigInteger(dhInner.getG() + ""); | ||||
|             BigInteger dhPrime = loadBigInt(dhInner.getDhPrime()); | ||||
|             BigInteger gb = g.modPow(b, dhPrime); | ||||
|  | ||||
|             BigInteger authKeyVal = loadBigInt(dhInner.getG_a()).modPow(b, dhPrime); | ||||
|             byte[] authKey = alignKeyZero(fromBigInt(authKeyVal), 256); | ||||
|             byte[] authAuxHash = substring(SHA1(authKey), 0, 8); | ||||
|  | ||||
|             ClientDhInner clientDHInner = new ClientDhInner(nonce, serverNonce, i, fromBigInt(gb)); | ||||
|             byte[] innerData = clientDHInner.serialize(); | ||||
|             byte[] innerDataWithHash = align(concat(SHA1(innerData), innerData), 16); | ||||
|             byte[] dataWithHashEnc = AES256IGEEncrypt(innerDataWithHash, tmpAesIv, tmpAesKey); | ||||
|  | ||||
|             DhGenResult result = executeMethod(new ReqSetDhClientParams(nonce, serverNonce, dataWithHashEnc)); | ||||
|  | ||||
|             if (result instanceof DhGenOk) { | ||||
|                 byte[] newNonceHash = substring(SHA1(newNonce, new byte[]{1}, authAuxHash), 4, 16); | ||||
|  | ||||
|                 if (!arrayEq(result.getNewNonceHash(), newNonceHash)) | ||||
|                     throw new TransportSecurityException(); | ||||
|  | ||||
|                 long serverSalt = readLong(xor(substring(newNonce, 0, 8), substring(serverNonce, 0, 8)), 0); | ||||
|  | ||||
|                 return new PqAuth(authKey, serverSalt, context.getSocket()); | ||||
|             } else if (result instanceof DhGenRetry) { | ||||
|                 byte[] newNonceHash = substring(SHA1(newNonce, new byte[]{2}, authAuxHash), 4, 16); | ||||
|  | ||||
|                 if (!arrayEq(result.getNewNonceHash(), newNonceHash)) | ||||
|                     throw new TransportSecurityException(); | ||||
|  | ||||
|             } else if (result instanceof DhGenFailure) { | ||||
|                 byte[] newNonceHash = substring(SHA1(newNonce, new byte[]{3}, authAuxHash), 4, 16); | ||||
|  | ||||
|                 if (!arrayEq(result.getNewNonceHash(), newNonceHash)) | ||||
|                     throw new TransportSecurityException(); | ||||
|  | ||||
|                 throw new ServerException(); | ||||
|             } | ||||
|         } | ||||
|         throw new ServerException(); | ||||
|     } | ||||
|  | ||||
|     public PqAuth doAuth(ConnectionInfo[] infos) { | ||||
|         TransportRate rate = new TransportRate(infos); | ||||
|         for (int i = 0; i < AUTH_ATTEMPT_COUNT; i++) { | ||||
|             ConnectionType connectionType = rate.tryConnection(); | ||||
|             try { | ||||
|                 context = new PlainTcpConnection(connectionType.getHost(), connectionType.getPort()); | ||||
|                 rate.onConnectionSuccess(connectionType.getId()); | ||||
|             } catch (IOException e) { | ||||
|                 Logger.e(TAG, e); | ||||
|                 rate.onConnectionFailure(connectionType.getId()); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             try { | ||||
|                 return authAttempt(); | ||||
|             } catch (IOException e) { | ||||
|                 Logger.e(TAG, e); | ||||
|             } finally { | ||||
|                 if (context != null) { | ||||
|                     context.destroy(); | ||||
|                     context = null; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             try { | ||||
|                 Thread.sleep(300); | ||||
|             } catch (InterruptedException e) { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -1,33 +0,0 @@ | ||||
| package org.telegram.mtproto.pq; | ||||
|  | ||||
| import java.net.Socket; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:14 | ||||
|  */ | ||||
| public class PqAuth { | ||||
|     private byte[] authKey; | ||||
|     private long serverSalt; | ||||
|     private Socket socket; | ||||
|  | ||||
|     public PqAuth(byte[] authKey, long serverSalt, Socket socket) { | ||||
|         this.authKey = authKey; | ||||
|         this.serverSalt = serverSalt; | ||||
|         this.socket = socket; | ||||
|     } | ||||
|  | ||||
|     public byte[] getAuthKey() { | ||||
|         return authKey; | ||||
|     } | ||||
|  | ||||
|     public long getServerSalt() { | ||||
|         return serverSalt; | ||||
|     } | ||||
|  | ||||
|     public Socket getSocket() { | ||||
|         return socket; | ||||
|     } | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| package org.telegram.mtproto.schedule; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 29.12.13. | ||||
|  */ | ||||
| public class PrepareSchedule { | ||||
|     private long delay; | ||||
|     private int[] allowedContexts; | ||||
|     private boolean doWait; | ||||
|  | ||||
|     public boolean isDoWait() { | ||||
|         return doWait; | ||||
|     } | ||||
|  | ||||
|     public void setDoWait(boolean doWait) { | ||||
|         this.doWait = doWait; | ||||
|     } | ||||
|  | ||||
|     public long getDelay() { | ||||
|         return delay; | ||||
|     } | ||||
|  | ||||
|     public void setDelay(long delay) { | ||||
|         this.delay = delay; | ||||
|     } | ||||
|  | ||||
|     public int[] getAllowedContexts() { | ||||
|         return allowedContexts; | ||||
|     } | ||||
|  | ||||
|     public void setAllowedContexts(int[] allowedContexts) { | ||||
|         this.allowedContexts = allowedContexts; | ||||
|     } | ||||
| } | ||||
| @@ -1,37 +0,0 @@ | ||||
| package org.telegram.mtproto.schedule; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 19:59 | ||||
|  */ | ||||
| public class PreparedPackage { | ||||
|     private boolean isHighPriority; | ||||
|     private int seqNo; | ||||
|     private long messageId; | ||||
|     private byte[] content; | ||||
|  | ||||
|     public PreparedPackage(int seqNo, long messageId, byte[] content, boolean isHighPriority) { | ||||
|         this.seqNo = seqNo; | ||||
|         this.messageId = messageId; | ||||
|         this.content = content; | ||||
|         this.isHighPriority = isHighPriority; | ||||
|     } | ||||
|  | ||||
|     public boolean isHighPriority() { | ||||
|         return isHighPriority; | ||||
|     } | ||||
|  | ||||
|     public int getSeqNo() { | ||||
|         return seqNo; | ||||
|     } | ||||
|  | ||||
|     public long getMessageId() { | ||||
|         return messageId; | ||||
|     } | ||||
|  | ||||
|     public byte[] getContent() { | ||||
|         return content; | ||||
|     } | ||||
| } | ||||
| @@ -1,627 +0,0 @@ | ||||
| package org.telegram.mtproto.schedule; | ||||
|  | ||||
| import org.telegram.mtproto.CallWrapper; | ||||
| import org.telegram.mtproto.MTProto; | ||||
| import org.telegram.mtproto.log.Logger; | ||||
| import org.telegram.mtproto.time.TimeOverlord; | ||||
| import org.telegram.mtproto.tl.*; | ||||
| import org.telegram.tl.TLMethod; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.CopyOnWriteArrayList; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:51 | ||||
|  */ | ||||
| public class Scheduller { | ||||
|  | ||||
|     private final String TAG;//  = "MTProtoScheduller"; | ||||
|  | ||||
|     // Share identity values across all connections to avoid collisions | ||||
|     private static final AtomicInteger messagesIds = new AtomicInteger(1); | ||||
|     private static final ConcurrentHashMap<Long, Long> idGenerationTime = new ConcurrentHashMap<Long, Long>(); | ||||
|  | ||||
|     // private static final int SCHEDULLER_TIMEOUT = 15 * 1000;//15 sec | ||||
|     private static final int SCHEDULLER_TIMEOUT = 24 * 60 * 60 * 1000;//24 hours | ||||
|  | ||||
|     private static final long CONFIRM_TIMEOUT = 60 * 1000;//60 sec | ||||
|  | ||||
|     private static final int MAX_WORKLOAD_SIZE = 1024; | ||||
|     private static final int BIG_MESSAGE_SIZE = 1024; | ||||
|     private static final long RETRY_TIMEOUT = 15 * 1000; | ||||
|  | ||||
|     private static final int MAX_ACK_COUNT = 16; | ||||
|  | ||||
|     private SortedMap<Integer, SchedullerPackage> messages = Collections.synchronizedSortedMap(new TreeMap<Integer, SchedullerPackage>()); | ||||
|     private HashSet<Long> currentMessageGeneration = new HashSet<Long>(); | ||||
|     private HashSet<Long> confirmedMessages = new HashSet<Long>(); | ||||
|     private CopyOnWriteArrayList<SchedullerListener> schedullerListeners = new CopyOnWriteArrayList<SchedullerListener>(); | ||||
|  | ||||
|     private long firstConfirmTime = 0; | ||||
|  | ||||
|     private long lastMessageId = 0; | ||||
|     private long lastDependId = 0; | ||||
|     private int seqNo = 0; | ||||
|  | ||||
|     private CallWrapper wrapper; | ||||
|  | ||||
|     public Scheduller(MTProto mtProto, CallWrapper wrapper) { | ||||
|         TAG = "MTProto#" + mtProto.getInstanceIndex() + "#Scheduller"; | ||||
|         this.wrapper = wrapper; | ||||
|     } | ||||
|  | ||||
|     public void addListener(SchedullerListener listener) { | ||||
|         schedullerListeners.remove(listener); | ||||
|         schedullerListeners.add(listener); | ||||
|     } | ||||
|  | ||||
|     public void removeListener(SchedullerListener listener) { | ||||
|         schedullerListeners.remove(listener); | ||||
|     } | ||||
|  | ||||
|     private void notifyChanged() { | ||||
|         for (SchedullerListener listener : schedullerListeners) { | ||||
|             listener.onSchedullerUpdated(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private synchronized long generateMessageId() { | ||||
|         long messageId = TimeOverlord.getInstance().createWeakMessageId(); | ||||
|         if (messageId <= lastMessageId) { | ||||
|             messageId = lastMessageId = lastMessageId + 4; | ||||
|         } | ||||
|         while (idGenerationTime.containsKey(messageId)) { | ||||
|             messageId += 4; | ||||
|         } | ||||
|         lastMessageId = messageId; | ||||
|         idGenerationTime.put(messageId, getCurrentTime()); | ||||
|         currentMessageGeneration.add(messageId); | ||||
|         return messageId; | ||||
|     } | ||||
|  | ||||
|     private synchronized int generateSeqNoWeak() { | ||||
|         return seqNo * 2; | ||||
|     } | ||||
|  | ||||
|     private synchronized int generateSeqNo() { | ||||
|         int res = seqNo * 2 + 1; | ||||
|         seqNo++; | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     private synchronized void generateParams(SchedullerPackage schedullerPackage) { | ||||
|         schedullerPackage.messageId = generateMessageId(); | ||||
|         schedullerPackage.seqNo = generateSeqNo(); | ||||
|         schedullerPackage.idGenerationTime = getCurrentTime(); | ||||
|         schedullerPackage.relatedMessageIds.add(schedullerPackage.messageId); | ||||
|         schedullerPackage.generatedMessageIds.add(schedullerPackage.messageId); | ||||
|     } | ||||
|  | ||||
|     private long getCurrentTime() { | ||||
|         return System.nanoTime() / 1000000; | ||||
|     } | ||||
|  | ||||
|     public long getMessageIdGenerationTime(long msgId) { | ||||
|         if (idGenerationTime.containsKey(msgId)) { | ||||
|             return idGenerationTime.get(msgId); | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public int postMessageDelayed(TLObject object, boolean isRpc, long timeout, int delay, int contextId, boolean highPrioroty) { | ||||
|         int id = messagesIds.incrementAndGet(); | ||||
|         SchedullerPackage schedullerPackage = new SchedullerPackage(id); | ||||
|         schedullerPackage.object = object; | ||||
|         schedullerPackage.addTime = getCurrentTime(); | ||||
|         schedullerPackage.scheduleTime = schedullerPackage.addTime + delay; | ||||
|         schedullerPackage.expiresTime = schedullerPackage.scheduleTime + timeout; | ||||
|         schedullerPackage.ttlTime = schedullerPackage.scheduleTime + timeout * 2; | ||||
|         schedullerPackage.isRpc = isRpc; | ||||
|         schedullerPackage.queuedToChannel = contextId; | ||||
|         schedullerPackage.priority = highPrioroty ? PRIORITY_HIGH : PRIORITY_NORMAL; | ||||
|         schedullerPackage.isDepend = highPrioroty; | ||||
|         schedullerPackage.supportTag = object.toString(); | ||||
|         schedullerPackage.serverErrorCount = 0; | ||||
|         messages.put(id, schedullerPackage); | ||||
|         notifyChanged(); | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     public int postMessage(TLObject object, boolean isApi, long timeout) { | ||||
|         return postMessageDelayed(object, isApi, timeout, 0, -1, false); | ||||
|     } | ||||
|  | ||||
|     public int postMessage(TLObject object, boolean isApi, long timeout, boolean highPrioroty) { | ||||
|         return postMessageDelayed(object, isApi, timeout, 0, -1, highPrioroty); | ||||
|     } | ||||
|  | ||||
|     public synchronized void prepareScheduller(PrepareSchedule prepareSchedule, int[] connectionIds) { | ||||
|         long time = getCurrentTime(); | ||||
|  | ||||
|         // Clear packages for unknown channels | ||||
|         outer: | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.queuedToChannel != -1) { | ||||
|                 for (int id : connectionIds) { | ||||
|                     if (schedullerPackage.queuedToChannel == id) { | ||||
|                         continue outer; | ||||
|                     } | ||||
|                 } | ||||
|                 forgetMessage(schedullerPackage.id); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // If there are no connections provide default delay | ||||
|         if (connectionIds.length == 0) { | ||||
|             prepareSchedule.setDelay(SCHEDULLER_TIMEOUT); | ||||
|             prepareSchedule.setAllowedContexts(connectionIds); | ||||
|             prepareSchedule.setDoWait(true); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         long minDelay = SCHEDULLER_TIMEOUT; | ||||
|         boolean allConnections = false; | ||||
|         boolean doWait = true; | ||||
|         HashSet<Integer> supportedConnections = new HashSet<Integer>(); | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             boolean isPendingPackage = false; | ||||
|             long packageTime = 0; | ||||
|  | ||||
|             if (schedullerPackage.state == STATE_QUEUED) { | ||||
|                 isPendingPackage = true; | ||||
|                 if (schedullerPackage.scheduleTime <= time) { | ||||
|                     packageTime = 0; | ||||
|                 } else { | ||||
|                     packageTime = Math.max(schedullerPackage.scheduleTime - time, 0); | ||||
|                 } | ||||
|             } else if (schedullerPackage.state == STATE_SENT) { | ||||
|                 if (getCurrentTime() <= schedullerPackage.expiresTime) { | ||||
|                     if (time - schedullerPackage.lastAttemptTime >= RETRY_TIMEOUT) { | ||||
|                         isPendingPackage = true; | ||||
|                         packageTime = 0; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (isPendingPackage) { | ||||
|                 if (schedullerPackage.queuedToChannel == -1) { | ||||
|                     allConnections = true; | ||||
|                 } else { | ||||
|                     supportedConnections.add(schedullerPackage.queuedToChannel); | ||||
|                 } | ||||
|  | ||||
|                 if (packageTime == 0) { | ||||
|                     minDelay = 0; | ||||
|                     doWait = false; | ||||
|                 } else { | ||||
|                     minDelay = Math.min(packageTime, minDelay); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         prepareSchedule.setDoWait(doWait); | ||||
|         prepareSchedule.setDelay(minDelay); | ||||
|  | ||||
|         if (allConnections) { | ||||
|             prepareSchedule.setAllowedContexts(connectionIds); | ||||
|         } else { | ||||
|             Integer[] allowedBoxed = supportedConnections.toArray(new Integer[0]); | ||||
|             int[] allowed = new int[allowedBoxed.length]; | ||||
|             for (int i = 0; i < allowed.length; i++) { | ||||
|                 allowed[i] = allowedBoxed[i]; | ||||
|             } | ||||
|             prepareSchedule.setAllowedContexts(allowed); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public synchronized void registerFastConfirm(long msgId, int fastConfirm) { | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             boolean contains = false; | ||||
|             for (Long relatedMsgId : schedullerPackage.relatedMessageIds) { | ||||
|                 if (relatedMsgId == msgId) { | ||||
|                     contains = true; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             if (contains) { | ||||
|                 schedullerPackage.relatedFastConfirm.add(fastConfirm); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public int mapSchedullerId(long msgId) { | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.generatedMessageIds.contains(msgId)) { | ||||
|                 return schedullerPackage.id; | ||||
|             } | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public void resetMessageId() { | ||||
|         lastMessageId = 0; | ||||
|         lastDependId = 0; | ||||
|     } | ||||
|  | ||||
|     public void resetSession() { | ||||
|         lastMessageId = 0; | ||||
|         lastDependId = 0; | ||||
|         seqNo = 0; | ||||
|         currentMessageGeneration.clear(); | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             schedullerPackage.idGenerationTime = 0; | ||||
|             schedullerPackage.dependMessageId = 0; | ||||
|             schedullerPackage.messageId = 0; | ||||
|             schedullerPackage.seqNo = 0; | ||||
|         } | ||||
|         notifyChanged(); | ||||
|     } | ||||
|  | ||||
|     public boolean isMessageFromCurrentGeneration(long msgId) { | ||||
|         return currentMessageGeneration.contains(msgId); | ||||
|     } | ||||
|  | ||||
|     public void resendAsNewMessage(long msgId) { | ||||
|         resendAsNewMessageDelayed(msgId, 0); | ||||
|     } | ||||
|  | ||||
|     public void resendAsNewMessageDelayed(long msgId, int delay) { | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.relatedMessageIds.contains(msgId)) { | ||||
|                 schedullerPackage.idGenerationTime = 0; | ||||
|                 schedullerPackage.dependMessageId = 0; | ||||
|                 schedullerPackage.messageId = 0; | ||||
|                 schedullerPackage.seqNo = 0; | ||||
|                 schedullerPackage.state = STATE_QUEUED; | ||||
|                 schedullerPackage.scheduleTime = getCurrentTime() + delay; | ||||
|                 Logger.d(TAG, "Resending as new #" + schedullerPackage.id); | ||||
|             } | ||||
|         } | ||||
|         notifyChanged(); | ||||
|     } | ||||
|  | ||||
|     public void resendMessage(long msgId) { | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.relatedMessageIds.contains(msgId)) { | ||||
|                 // schedullerPackage.relatedMessageIds.clear(); | ||||
|                 schedullerPackage.state = STATE_QUEUED; | ||||
|                 schedullerPackage.lastAttemptTime = 0; | ||||
|             } | ||||
|         } | ||||
|         notifyChanged(); | ||||
|     } | ||||
|  | ||||
|     public int[] mapFastConfirm(int fastConfirm) { | ||||
|         ArrayList<Integer> res = new ArrayList<Integer>(); | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.state == STATE_SENT) { | ||||
|                 if (schedullerPackage.relatedFastConfirm.contains(fastConfirm)) { | ||||
|                     res.add(schedullerPackage.id); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         int[] res2 = new int[res.size()]; | ||||
|         for (int i = 0; i < res2.length; i++) { | ||||
|             res2[i] = res.get(i); | ||||
|         } | ||||
|         return res2; | ||||
|     } | ||||
|  | ||||
|     public void onMessageConfirmed(long msgId) { | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.state == STATE_SENT) { | ||||
|                 if (schedullerPackage.relatedMessageIds.contains(msgId)) { | ||||
|                     schedullerPackage.state = STATE_CONFIRMED; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void confirmMessage(long msgId) { | ||||
|         synchronized (confirmedMessages) { | ||||
|             confirmedMessages.add(msgId); | ||||
|             if (firstConfirmTime == 0) { | ||||
|                 firstConfirmTime = getCurrentTime(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public synchronized void forgetMessageByMsgId(long msgId) { | ||||
|         int scId = mapSchedullerId(msgId); | ||||
|         if (scId > 0) { | ||||
|             forgetMessage(scId); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public synchronized void forgetMessage(int id) { | ||||
|         Logger.d(TAG, "Forgetting message: #" + id); | ||||
|         messages.remove(id); | ||||
|     } | ||||
|  | ||||
|     private synchronized ArrayList<SchedullerPackage> actualPackages(int contextId) { | ||||
|         ArrayList<SchedullerPackage> foundedPackages = new ArrayList<SchedullerPackage>(); | ||||
|         long time = getCurrentTime(); | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.queuedToChannel != -1 && contextId != schedullerPackage.queuedToChannel) { | ||||
|                 continue; | ||||
|             } | ||||
|             boolean isPendingPackage = false; | ||||
|  | ||||
|             if (schedullerPackage.ttlTime <= getCurrentTime()) { | ||||
|                 forgetMessage(schedullerPackage.id); | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (schedullerPackage.state == STATE_QUEUED) { | ||||
|                 if (schedullerPackage.scheduleTime <= time) { | ||||
|                     isPendingPackage = true; | ||||
|                 } | ||||
|             } else if (schedullerPackage.state == STATE_SENT) { | ||||
|                 if (getCurrentTime() <= schedullerPackage.expiresTime) { | ||||
|                     if (getCurrentTime() - schedullerPackage.lastAttemptTime >= RETRY_TIMEOUT) { | ||||
|                         isPendingPackage = true; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (isPendingPackage) { | ||||
|                 if (schedullerPackage.serialized == null) { | ||||
|                     try { | ||||
|                         if (schedullerPackage.isRpc) { | ||||
|                             schedullerPackage.serialized = wrapper.wrapObject((TLMethod) schedullerPackage.object).serialize(); | ||||
|                         } else { | ||||
|                             schedullerPackage.serialized = schedullerPackage.object.serialize(); | ||||
|                         } | ||||
|                     } catch (IOException e) { | ||||
|                         Logger.e(TAG, e); | ||||
|                         forgetMessage(schedullerPackage.id); | ||||
|                         continue; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 foundedPackages.add(schedullerPackage); | ||||
|             } | ||||
|         } | ||||
|         return foundedPackages; | ||||
|     } | ||||
|  | ||||
|     public synchronized boolean hasRequests() { | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.isRpc) | ||||
|                 return true; | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public synchronized PreparedPackage doSchedule(int contextId, boolean isInited) { | ||||
|         ArrayList<SchedullerPackage> foundedPackages = actualPackages(contextId); | ||||
|  | ||||
|         synchronized (confirmedMessages) { | ||||
|             if (foundedPackages.size() == 0 && | ||||
|                     (confirmedMessages.size() <= MAX_ACK_COUNT || (System.nanoTime() - firstConfirmTime) < CONFIRM_TIMEOUT)) { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         boolean useHighPriority = false; | ||||
|  | ||||
|         for (SchedullerPackage p : foundedPackages) { | ||||
|             if (p.priority == PRIORITY_HIGH) { | ||||
|                 useHighPriority = true; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         ArrayList<SchedullerPackage> packages = new ArrayList<SchedullerPackage>(); | ||||
|  | ||||
|         if (useHighPriority) { | ||||
|             Logger.d("Scheduller", "Using high priority scheduling"); | ||||
|             int totalSize = 0; | ||||
|             for (SchedullerPackage p : foundedPackages) { | ||||
|                 if (p.priority == PRIORITY_HIGH) { | ||||
|                     packages.add(p); | ||||
|                     totalSize += p.serialized.length; | ||||
|                     if (totalSize > MAX_WORKLOAD_SIZE) { | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } else { | ||||
|             int totalSize = 0; | ||||
|             for (SchedullerPackage p : foundedPackages) { | ||||
|                 packages.add(p); | ||||
|                 Logger.d("Scheduller", "Prepare package: " + p.supportTag + " of size " + p.serialized.length); | ||||
|                 totalSize += p.serialized.length; | ||||
|                 Logger.d("Scheduller", "Total size: " + totalSize); | ||||
|                 if (totalSize > MAX_WORKLOAD_SIZE) { | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         Logger.d(TAG, "Iteration: count: " + packages.size() + ", confirm:" + confirmedMessages.size()); | ||||
|         Logger.d(TAG, "Building package"); | ||||
|         if (foundedPackages.size() == 0 && confirmedMessages.size() != 0) { | ||||
|             Long[] msgIds; | ||||
|             synchronized (confirmedMessages) { | ||||
|                 msgIds = confirmedMessages.toArray(new Long[confirmedMessages.size()]); | ||||
|                 confirmedMessages.clear(); | ||||
|             } | ||||
|             MTMsgsAck ack = new MTMsgsAck(msgIds); | ||||
|             Logger.d(TAG, "Single msg_ack"); | ||||
|             try { | ||||
|                 return new PreparedPackage(generateSeqNoWeak(), generateMessageId(), ack.serialize(), useHighPriority); | ||||
|             } catch (IOException e) { | ||||
|                 Logger.e(TAG, e); | ||||
|                 return null; | ||||
|             } | ||||
|         } else if (foundedPackages.size() == 1 && confirmedMessages.size() == 0) { | ||||
|             SchedullerPackage schedullerPackage = foundedPackages.get(0); | ||||
|             schedullerPackage.state = STATE_SENT; | ||||
|             if (schedullerPackage.idGenerationTime == 0) { | ||||
|                 generateParams(schedullerPackage); | ||||
|             } | ||||
|             Logger.d(TAG, "Single package: #" + schedullerPackage.id + " " + schedullerPackage.supportTag + " (" + schedullerPackage.messageId + ", " + schedullerPackage.seqNo + ")"); | ||||
|             schedullerPackage.writtenToChannel = contextId; | ||||
|             schedullerPackage.lastAttemptTime = getCurrentTime(); | ||||
|             return new PreparedPackage(schedullerPackage.seqNo, schedullerPackage.messageId, schedullerPackage.serialized, useHighPriority); | ||||
|         } else { | ||||
|             MTMessagesContainer container = new MTMessagesContainer(); | ||||
|             if ((confirmedMessages.size() > 0 && !useHighPriority) || (!isInited)) { | ||||
|                 try { | ||||
|                     Long[] msgIds; | ||||
|                     synchronized (confirmedMessages) { | ||||
|                         msgIds = confirmedMessages.toArray(new Long[0]); | ||||
|                         confirmedMessages.clear(); | ||||
|                     } | ||||
|                     MTMsgsAck ack = new MTMsgsAck(msgIds); | ||||
|                     Logger.d(TAG, "Adding msg_ack: " + msgIds.length); | ||||
|                     container.getMessages().add(new MTMessage(generateMessageId(), generateSeqNoWeak(), ack.serialize())); | ||||
|                 } catch (IOException e) { | ||||
|                     Logger.e(TAG, e); | ||||
|                 } | ||||
|             } | ||||
|             for (SchedullerPackage schedullerPackage : packages) { | ||||
|                 schedullerPackage.state = STATE_SENT; | ||||
|                 if (schedullerPackage.idGenerationTime == 0) { | ||||
|                     generateParams(schedullerPackage); | ||||
|                 } | ||||
|  | ||||
|                 if (schedullerPackage.isDepend) { | ||||
|                     if (schedullerPackage.dependMessageId == 0) { | ||||
|                         if (lastDependId > 0) { | ||||
|                             schedullerPackage.dependMessageId = lastDependId; | ||||
|                         } else { | ||||
|                             schedullerPackage.dependMessageId = -1; | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     lastDependId = schedullerPackage.messageId; | ||||
|                 } | ||||
|                 schedullerPackage.writtenToChannel = contextId; | ||||
|                 schedullerPackage.lastAttemptTime = getCurrentTime(); | ||||
|                 if (schedullerPackage.isDepend && schedullerPackage.dependMessageId > 0) { | ||||
|  | ||||
|                     Logger.d(TAG, "Adding package: #" + schedullerPackage.id + " " + schedullerPackage.supportTag + " (" + schedullerPackage.messageId + " on " + schedullerPackage.dependMessageId + ", " + schedullerPackage.seqNo + ")"); | ||||
|  | ||||
|                     MTInvokeAfter invokeAfter = new MTInvokeAfter(schedullerPackage.dependMessageId, schedullerPackage.serialized); | ||||
|                     try { | ||||
|                         container.getMessages().add(new MTMessage(schedullerPackage.messageId, schedullerPackage.seqNo, invokeAfter.serialize())); | ||||
|                     } catch (IOException e) { | ||||
|                         Logger.e(TAG, e); | ||||
|                         // Never happens | ||||
|                     } | ||||
|                 } else { | ||||
|                     Logger.d(TAG, "Adding package: #" + schedullerPackage.id + " " + schedullerPackage.supportTag + " (" + schedullerPackage.messageId + ", " + schedullerPackage.seqNo + ")"); | ||||
|                     container.getMessages().add(new MTMessage(schedullerPackage.messageId, schedullerPackage.seqNo, schedullerPackage.serialized)); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             long containerMessageId = generateMessageId(); | ||||
|             int containerSeq = generateSeqNoWeak(); | ||||
|  | ||||
|             for (SchedullerPackage schedullerPackage : packages) { | ||||
|                 schedullerPackage.relatedMessageIds.add(containerMessageId); | ||||
|             } | ||||
|  | ||||
|             Logger.d(TAG, "Sending Package (" + containerMessageId + ", " + containerSeq + ")"); | ||||
|  | ||||
|             try { | ||||
|                 return new PreparedPackage(containerSeq, containerMessageId, container.serialize(), useHighPriority); | ||||
|             } catch (IOException e) { | ||||
|                 // Might not happens | ||||
|                 Logger.e(TAG, e); | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public synchronized void onConnectionDies(int connectionId) { | ||||
|         Logger.d(TAG, "Connection dies " + connectionId); | ||||
|         for (SchedullerPackage schedullerPackage : messages.values().toArray(new SchedullerPackage[0])) { | ||||
|             if (schedullerPackage.writtenToChannel != connectionId) { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             if (schedullerPackage.queuedToChannel != -1) { | ||||
|                 Logger.d(TAG, "Removing: #" + schedullerPackage.id + " " + schedullerPackage.supportTag); | ||||
|                 forgetMessage(schedullerPackage.id); | ||||
|             } else { | ||||
|                 if (schedullerPackage.isRpc) { | ||||
|                     if (schedullerPackage.state == STATE_CONFIRMED || schedullerPackage.state == STATE_QUEUED) { | ||||
|                         Logger.d(TAG, "Re-schedule: #" + schedullerPackage.id + " " + schedullerPackage.supportTag); | ||||
|                         schedullerPackage.state = STATE_QUEUED; | ||||
|                         schedullerPackage.lastAttemptTime = 0; | ||||
|                     } | ||||
|                 } else { | ||||
|                     if (schedullerPackage.state == STATE_SENT) { | ||||
|                         Logger.d(TAG, "Re-schedule: #" + schedullerPackage.id + " " + schedullerPackage.supportTag); | ||||
|                         schedullerPackage.state = STATE_QUEUED; | ||||
|                         schedullerPackage.lastAttemptTime = 0; | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|             } | ||||
|         } | ||||
|         notifyChanged(); | ||||
|     } | ||||
|  | ||||
|     private static final int PRIORITY_HIGH = 1; | ||||
|     private static final int PRIORITY_NORMAL = 0; | ||||
|  | ||||
|     private static final int STATE_QUEUED = 0; | ||||
|     private static final int STATE_SENT = 1; | ||||
|     private static final int STATE_CONFIRMED = 2; | ||||
|  | ||||
|     private class SchedullerPackage { | ||||
|  | ||||
|         public SchedullerPackage(int id) { | ||||
|             this.id = id; | ||||
|         } | ||||
|  | ||||
|         public String supportTag; | ||||
|  | ||||
|         public int id; | ||||
|  | ||||
|         public TLObject object; | ||||
|         public byte[] serialized; | ||||
|  | ||||
|         public long addTime; | ||||
|         public long scheduleTime; | ||||
|         public long expiresTime; | ||||
|         public long ttlTime; | ||||
|         public long lastAttemptTime; | ||||
|  | ||||
|         public int writtenToChannel = -1; | ||||
|  | ||||
|         public int queuedToChannel = -1; | ||||
|  | ||||
|         public int state = STATE_QUEUED; | ||||
|  | ||||
|         public int priority = PRIORITY_NORMAL; | ||||
|  | ||||
|         public boolean isDepend; | ||||
|  | ||||
|         public boolean isSent; | ||||
|  | ||||
|         public long idGenerationTime; | ||||
|         public long dependMessageId; | ||||
|         public long messageId; | ||||
|         public int seqNo; | ||||
|         public HashSet<Integer> relatedFastConfirm = new HashSet<Integer>(); | ||||
|         public HashSet<Long> relatedMessageIds = new HashSet<Long>(); | ||||
|         public HashSet<Long> generatedMessageIds = new HashSet<Long>(); | ||||
|  | ||||
|         public int serverErrorCount; | ||||
|  | ||||
|         public boolean isRpc; | ||||
|     } | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| package org.telegram.mtproto.schedule; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 03.04.14. | ||||
|  */ | ||||
| public interface SchedullerListener { | ||||
|     public void onSchedullerUpdated(Scheduller scheduller); | ||||
| } | ||||
| @@ -1,277 +0,0 @@ | ||||
| package org.telegram.mtproto.secure; | ||||
|  | ||||
| import org.telegram.mtproto.secure.aes.AESImplementation; | ||||
| import org.telegram.mtproto.secure.aes.DefaultAESImplementation; | ||||
|  | ||||
| import javax.crypto.BadPaddingException; | ||||
| import javax.crypto.Cipher; | ||||
| import javax.crypto.IllegalBlockSizeException; | ||||
| import javax.crypto.NoSuchPaddingException; | ||||
| import java.io.*; | ||||
| import java.math.BigInteger; | ||||
| import java.security.*; | ||||
| import java.security.spec.InvalidKeySpecException; | ||||
| import java.security.spec.RSAPublicKeySpec; | ||||
|  | ||||
| /** | ||||
|  * Author: Korshakov Stepan | ||||
|  * Created: 18.07.13 3:54 | ||||
|  */ | ||||
| public class CryptoUtils { | ||||
|  | ||||
|     private static final ThreadLocal<MessageDigest> md5 = new ThreadLocal<MessageDigest>() { | ||||
|         @Override | ||||
|         protected MessageDigest initialValue() { | ||||
|             MessageDigest crypt = null; | ||||
|             try { | ||||
|                 crypt = MessageDigest.getInstance("MD5"); | ||||
|             } catch (NoSuchAlgorithmException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|             return crypt; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     private static final ThreadLocal<MessageDigest> sha1 = new ThreadLocal<MessageDigest>() { | ||||
|         @Override | ||||
|         protected MessageDigest initialValue() { | ||||
|             MessageDigest crypt = null; | ||||
|             try { | ||||
|                 crypt = MessageDigest.getInstance("SHA-1"); | ||||
|             } catch (NoSuchAlgorithmException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|             return crypt; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     private static AESImplementation currentImplementation = new DefaultAESImplementation(); | ||||
|  | ||||
|     public static void setAESImplementation(AESImplementation implementation) { | ||||
|         currentImplementation = implementation; | ||||
|     } | ||||
|  | ||||
|     public static byte[] RSA(byte[] src, BigInteger key, BigInteger exponent) { | ||||
|         try { | ||||
|             KeyFactory keyFactory = KeyFactory.getInstance("RSA"); | ||||
|             PublicKey publicKey = keyFactory.generatePublic(new RSAPublicKeySpec(key, exponent)); | ||||
|             Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding"); | ||||
|             cipher.init(Cipher.ENCRYPT_MODE, publicKey); | ||||
|             return cipher.doFinal(src); | ||||
|         } catch (NoSuchAlgorithmException e) { | ||||
|             e.printStackTrace(); | ||||
|         } catch (NoSuchPaddingException e) { | ||||
|             e.printStackTrace(); | ||||
|         } catch (BadPaddingException e) { | ||||
|             e.printStackTrace(); | ||||
|         } catch (IllegalBlockSizeException e) { | ||||
|             e.printStackTrace(); | ||||
|         } catch (InvalidKeyException e) { | ||||
|             e.printStackTrace(); | ||||
|         } catch (InvalidKeySpecException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static void AES256IGEDecryptBig(byte[] src, byte[] dest, int len, byte[] iv, byte[] key) { | ||||
|         currentImplementation.AES256IGEDecrypt(src, dest, len, iv, key); | ||||
|     } | ||||
|  | ||||
|     public static byte[] AES256IGEDecrypt(byte[] src, byte[] iv, byte[] key) { | ||||
|         byte[] res = new byte[src.length]; | ||||
|         currentImplementation.AES256IGEDecrypt(src, res, src.length, iv, key); | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public static void AES256IGEDecrypt(File src, File dest, byte[] iv, byte[] key) throws IOException { | ||||
|         currentImplementation.AES256IGEDecrypt(src.getAbsolutePath(), dest.getAbsolutePath(), iv, key); | ||||
|     } | ||||
|  | ||||
|     public static void AES256IGEEncrypt(File src, File dest, byte[] iv, byte[] key) throws IOException { | ||||
|         currentImplementation.AES256IGEEncrypt(src.getAbsolutePath(), dest.getAbsolutePath(), iv, key); | ||||
|     } | ||||
|  | ||||
|     public static byte[] AES256IGEEncrypt(byte[] src, byte[] iv, byte[] key) { | ||||
|         byte[] res = new byte[src.length]; | ||||
|         currentImplementation.AES256IGEEncrypt(src, res, src.length, iv, key); | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public static String MD5(byte[] src) { | ||||
|         try { | ||||
|             MessageDigest crypt = MessageDigest.getInstance("MD5"); | ||||
|             crypt.reset(); | ||||
|             crypt.update(src); | ||||
|             return ToHex(crypt.digest()); | ||||
|         } catch (NoSuchAlgorithmException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static String MD5(RandomAccessFile randomAccessFile) { | ||||
|         try { | ||||
|             MessageDigest crypt = md5.get(); | ||||
|             crypt.reset(); | ||||
|             byte[] block = new byte[8 * 1024]; | ||||
|             for (int i = 0; i < randomAccessFile.length(); i += 8 * 1024) { | ||||
|                 int len = (int) Math.min(block.length, randomAccessFile.length() - i); | ||||
|                 randomAccessFile.readFully(block, 0, len); | ||||
|                 crypt.update(block, 0, len); | ||||
|             } | ||||
|             return ToHex(crypt.digest()); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static byte[] MD5Raw(byte[] src) { | ||||
|         MessageDigest crypt = md5.get(); | ||||
|         crypt.reset(); | ||||
|         crypt.update(src); | ||||
|         return crypt.digest(); | ||||
|     } | ||||
|  | ||||
|     public static String ToHex(byte[] src) { | ||||
|         String res = ""; | ||||
|         for (int i = 0; i < src.length; i++) { | ||||
|             res += String.format("%02X", src[i] & 0xFF); | ||||
|         } | ||||
|         return res.toLowerCase(); | ||||
|     } | ||||
|  | ||||
|     public static byte[] SHA1(InputStream in) throws IOException { | ||||
|         MessageDigest crypt = sha1.get(); | ||||
|         crypt.reset(); | ||||
|         // Transfer bytes from in to out | ||||
|         byte[] buf = new byte[4 * 1024]; | ||||
|         int len; | ||||
|         while ((len = in.read(buf)) > 0) { | ||||
|             Thread.yield(); | ||||
|             // out.write(buf, 0, len); | ||||
|             crypt.update(buf, 0, len); | ||||
|         } | ||||
|         in.close(); | ||||
|         return crypt.digest(); | ||||
|     } | ||||
|  | ||||
|     public static byte[] SHA1(String fileName) throws IOException { | ||||
|         MessageDigest crypt = sha1.get(); | ||||
|         crypt.reset(); | ||||
|         FileInputStream in = new FileInputStream(fileName); | ||||
|         // Transfer bytes from in to out | ||||
|         byte[] buf = new byte[4 * 1024]; | ||||
|         int len; | ||||
|         while ((len = in.read(buf)) > 0) { | ||||
|             Thread.yield(); | ||||
|             // out.write(buf, 0, len); | ||||
|             crypt.update(buf, 0, len); | ||||
|         } | ||||
|         in.close(); | ||||
|         return crypt.digest(); | ||||
|     } | ||||
|  | ||||
|     public static byte[] SHA1(byte[] src) { | ||||
|         MessageDigest crypt = sha1.get(); | ||||
|         crypt.reset(); | ||||
|         crypt.update(src); | ||||
|         return crypt.digest(); | ||||
|     } | ||||
|  | ||||
|     public static byte[] SHA1(byte[]... src1) { | ||||
|         MessageDigest crypt = sha1.get(); | ||||
|         crypt.reset(); | ||||
|         for (int i = 0; i < src1.length; i++) { | ||||
|             crypt.update(src1[i]); | ||||
|         } | ||||
|         return crypt.digest(); | ||||
|     } | ||||
|  | ||||
|     public static boolean arrayEq(byte[] a, byte[] b) { | ||||
|         if (a.length != b.length) { | ||||
|             return false; | ||||
|         } | ||||
|         for (int i = 0; i < a.length; i++) { | ||||
|             if (a[i] != b[i]) | ||||
|                 return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public static byte[] concat(byte[]... v) { | ||||
|         int len = 0; | ||||
|         for (int i = 0; i < v.length; i++) { | ||||
|             len += v[i].length; | ||||
|         } | ||||
|         byte[] res = new byte[len]; | ||||
|         int offset = 0; | ||||
|         for (int i = 0; i < v.length; i++) { | ||||
|             System.arraycopy(v[i], 0, res, offset, v[i].length); | ||||
|             offset += v[i].length; | ||||
|         } | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public static byte[] substring(byte[] src, int start, int len) { | ||||
|         byte[] res = new byte[len]; | ||||
|         System.arraycopy(src, start, res, 0, len); | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public static byte[] align(byte[] src, int factor) { | ||||
|         if (src.length % factor == 0) { | ||||
|             return src; | ||||
|         } | ||||
|         int padding = factor - src.length % factor; | ||||
|  | ||||
|         return concat(src, Entropy.generateSeed(padding)); | ||||
|     } | ||||
|  | ||||
|     public static byte[] alignKeyZero(byte[] src, int size) { | ||||
|         if (src.length == size) { | ||||
|             return src; | ||||
|         } | ||||
|  | ||||
|         if (src.length > size) { | ||||
|             return substring(src, src.length - size, size); | ||||
|         } else { | ||||
|             return concat(new byte[size - src.length], src); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static byte[] xor(byte[] a, byte[] b) { | ||||
|         byte[] res = new byte[a.length]; | ||||
|         for (int i = 0; i < a.length; i++) { | ||||
|             res[i] = (byte) (a[i] ^ b[i]); | ||||
|         } | ||||
|         return res; | ||||
|     } | ||||
|  | ||||
|     public static BigInteger loadBigInt(byte[] data) { | ||||
|         return new BigInteger(1, data); | ||||
|     } | ||||
|  | ||||
|     public static byte[] fromBigInt(BigInteger val) { | ||||
|         byte[] res = val.toByteArray(); | ||||
|         if (res[0] == 0) { | ||||
|             byte[] res2 = new byte[res.length - 1]; | ||||
|             System.arraycopy(res, 1, res2, 0, res2.length); | ||||
|             return res2; | ||||
|         } else { | ||||
|             return res; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static boolean isZero(byte[] src) { | ||||
|         for (int i = 0; i < src.length; i++) { | ||||
|             if (src[i] != 0) { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
| @@ -1,45 +0,0 @@ | ||||
| package org.telegram.mtproto.secure; | ||||
|  | ||||
| import java.security.SecureRandom; | ||||
|  | ||||
| import static org.telegram.mtproto.secure.CryptoUtils.xor; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 4:05 | ||||
|  */ | ||||
| public final class Entropy { | ||||
|     private static SecureRandom random = new SecureRandom(); | ||||
|  | ||||
|     public static byte[] generateSeed(int size) { | ||||
|         synchronized (random) { | ||||
|             return random.generateSeed(size); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static byte[] generateSeed(byte[] sourceSeed) { | ||||
|         synchronized (random) { | ||||
|             return xor(random.generateSeed(sourceSeed.length), sourceSeed); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static long generateRandomId() { | ||||
|         synchronized (random) { | ||||
|             return random.nextLong(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static int randomInt() { | ||||
|         synchronized (random) { | ||||
|             return random.nextInt(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static void feedEntropy(byte[] data) { | ||||
|         synchronized (random) { | ||||
|             random.setSeed(data); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| package org.telegram.mtproto.secure; | ||||
|  | ||||
| public class KeyParameter { | ||||
|     private byte[] key; | ||||
|  | ||||
|     public KeyParameter(byte[] key) { | ||||
|         this(key, 0, key.length); | ||||
|     } | ||||
|  | ||||
|     public KeyParameter(byte[] key, int keyOff, int keyLen) { | ||||
|         this.key = new byte[keyLen]; | ||||
|  | ||||
|         System.arraycopy(key, keyOff, this.key, 0, keyLen); | ||||
|     } | ||||
|  | ||||
|     public byte[] getKey() { | ||||
|         return key; | ||||
|     } | ||||
| } | ||||
| @@ -1,46 +0,0 @@ | ||||
| package org.telegram.mtproto.secure; | ||||
|  | ||||
| import java.math.BigInteger; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 6:04 | ||||
|  */ | ||||
| public class Keys { | ||||
|     public static class Key { | ||||
|         private BigInteger publicKey; | ||||
|         private BigInteger exponent; | ||||
|         private long fingerprint; | ||||
|  | ||||
|         public Key(String publicKey, String exponent, long fingerprint) { | ||||
|             this.publicKey = new BigInteger(publicKey, 16); | ||||
|             this.exponent = new BigInteger(exponent, 16); | ||||
|             this.fingerprint = fingerprint; | ||||
|         } | ||||
|  | ||||
|         public BigInteger getPublicKey() { | ||||
|             return publicKey; | ||||
|         } | ||||
|  | ||||
|         public BigInteger getExponent() { | ||||
|             return exponent; | ||||
|         } | ||||
|  | ||||
|         public long getFingerprint() { | ||||
|             return fingerprint; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static final Key[] AVAILABLE_KEYS = new Key[]{ | ||||
|             new Key("0c6aeda78b02a251db4b6441031f467fa871faed32526c436524b1fb3b5dca28efb8c089dd1b46d92c895993d87108254951c5f001a0f055f3063dcd14d431a300eb9e29517e359a1c9537e5e87ab1b116faecf5d17546ebc21db234d9d336a693efcb2b6fbcca1e7d1a0be414dca408a11609b9c4269a920b09fed1f9a1597be02761430f09e4bc48fcafbe289054c99dba51b6b5eb7d9c3a2ab4e490545b4676bd620e93804bcac93bf94f73f92c729ca899477ff17625ef14a934d51dc11d5f8650a3364586b3a52fcff2fedec8a8406cac4e751705a472e55707e3c8cd5594342b119c6c3293532d85dbe9271ed54a2fd18b4dc79c04a30951107d5639397", | ||||
|                     "010001", 0x9a996a1db11c729bL), | ||||
|             new Key("0b1066749655935f0a5936f517034c943bea7f3365a8931ae52c8bcb14856f004b83d26cf2839be0f22607470d67481771c1ce5ec31de16b20bbaa4ecd2f7d2ecf6b6356f27501c226984263edc046b89fb6d3981546b01d7bd34fedcfcc1058e2d494bda732ff813e50e1c6ae249890b225f82b22b1e55fcb063dc3c0e18e91c28d0c4aa627dec8353eee6038a95a4fd1ca984eb09f94aeb7a2220635a8ceb450ea7e61d915cdb4eecedaa083aa3801daf071855ec1fb38516cb6c2996d2d60c0ecbcfa57e4cf1fb0ed39b2f37e94ab4202ecf595e167b3ca62669a6da520859fb6d6c6203dfdfc79c75ec3ee97da8774b2da903e3435f2cd294670a75a526c1", | ||||
|                     "010001", 0xb05b2a6f70cdea78L), | ||||
|             new Key("0c150023e2f70db7985ded064759cfecf0af328e69a41daf4d6f01b538135a6f91f8f8b2a0ec9ba9720ce352efcf6c5680ffc424bd634864902de0b4bd6d49f4e580230e3ae97d95c8b19442b3c0a10d8f5633fecedd6926a7f6dab0ddb7d457f9ea81b8465fcd6fffeed114011df91c059caedaf97625f6c96ecc74725556934ef781d866b34f011fce4d835a090196e9a5f0e4449af7eb697ddb9076494ca5f81104a305b6dd27665722c46b60e5df680fb16b210607ef217652e60236c255f6a28315f4083a96791d7214bf64c1df4fd0db1944fb26a2a57031b32eee64ad15a8ba68885cde74a5bfc920f6abf59ba5c75506373e7130f9042da922179251f", | ||||
|                     "010001", 0xc3b42b026ce86b21L), | ||||
|             new Key("0c2a8c55b4a62e2b78a19b91cf692bcdc4ba7c23fe4d06f194e2a0c30f6d9996f7d1a2bcc89bc1ac4333d44359a6c433252d1a8402d9970378b5912b75bc8cc3fa76710a025bcb9032df0b87d7607cc53b928712a174ea2a80a8176623588119d42ffce40205c6d72160860d8d80b22a8b8651907cf388effbef29cd7cf2b4eb8a872052da1351cfe7fec214ce48304ea472bd66329d60115b3420d08f6894b0410b6ab9450249967617670c932f7cbdb5d6fbcce1e492c595f483109999b2661fcdeec31b196429b7834c7211a93c6789d9ee601c18c39e521fda9d7264e61e518add6f0712d2d5228204b851e13c4f322e5c5431c3b7f31089668486aadc59f", | ||||
|                     "010001", 0x71e025b6c76033e3L) | ||||
|     }; | ||||
| } | ||||
| @@ -1,833 +0,0 @@ | ||||
| package org.telegram.mtproto.secure.aes; | ||||
|  | ||||
| import org.telegram.mtproto.secure.KeyParameter; | ||||
|  | ||||
| /** | ||||
|  * an implementation of the AES (Rijndael), from FIPS-197. | ||||
|  * <p/> | ||||
|  * For further details see: <a href="http://csrc.nist.gov/encryption/aes/">http://csrc.nist.gov/encryption/aes/</a>. | ||||
|  * <p/> | ||||
|  * This implementation is based on optimizations from Dr. Brian Gladman's paper and C code at | ||||
|  * <a href="http://fp.gladman.plus.com/cryptography_technology/rijndael/">http://fp.gladman.plus.com/cryptography_technology/rijndael/</a> | ||||
|  * <p/> | ||||
|  * There are three levels of tradeoff of speed vs memory | ||||
|  * Because java has no preprocessor, they are written as three separate classes from which to choose | ||||
|  * <p/> | ||||
|  * The fastest uses 8Kbytes of static tables to precompute round calculations, 4 256 word tables for encryption | ||||
|  * and 4 for decryption. | ||||
|  * <p/> | ||||
|  * The middle performance version uses only one 256 word table for each, for a total of 2Kbytes, | ||||
|  * adding 12 rotate operations per round to compute the values contained in the other tables from | ||||
|  * the contents of the first | ||||
|  * <p/> | ||||
|  * The slowest version uses no static tables at all and computes the values in each round | ||||
|  * <p/> | ||||
|  * This file contains the fast version with 8Kbytes of static tables for round precomputation | ||||
|  */ | ||||
| public class AESFastEngine { | ||||
|     // The S box | ||||
|     private static final byte[] S = { | ||||
|             (byte) 99, (byte) 124, (byte) 119, (byte) 123, (byte) 242, (byte) 107, (byte) 111, (byte) 197, | ||||
|             (byte) 48, (byte) 1, (byte) 103, (byte) 43, (byte) 254, (byte) 215, (byte) 171, (byte) 118, | ||||
|             (byte) 202, (byte) 130, (byte) 201, (byte) 125, (byte) 250, (byte) 89, (byte) 71, (byte) 240, | ||||
|             (byte) 173, (byte) 212, (byte) 162, (byte) 175, (byte) 156, (byte) 164, (byte) 114, (byte) 192, | ||||
|             (byte) 183, (byte) 253, (byte) 147, (byte) 38, (byte) 54, (byte) 63, (byte) 247, (byte) 204, | ||||
|             (byte) 52, (byte) 165, (byte) 229, (byte) 241, (byte) 113, (byte) 216, (byte) 49, (byte) 21, | ||||
|             (byte) 4, (byte) 199, (byte) 35, (byte) 195, (byte) 24, (byte) 150, (byte) 5, (byte) 154, | ||||
|             (byte) 7, (byte) 18, (byte) 128, (byte) 226, (byte) 235, (byte) 39, (byte) 178, (byte) 117, | ||||
|             (byte) 9, (byte) 131, (byte) 44, (byte) 26, (byte) 27, (byte) 110, (byte) 90, (byte) 160, | ||||
|             (byte) 82, (byte) 59, (byte) 214, (byte) 179, (byte) 41, (byte) 227, (byte) 47, (byte) 132, | ||||
|             (byte) 83, (byte) 209, (byte) 0, (byte) 237, (byte) 32, (byte) 252, (byte) 177, (byte) 91, | ||||
|             (byte) 106, (byte) 203, (byte) 190, (byte) 57, (byte) 74, (byte) 76, (byte) 88, (byte) 207, | ||||
|             (byte) 208, (byte) 239, (byte) 170, (byte) 251, (byte) 67, (byte) 77, (byte) 51, (byte) 133, | ||||
|             (byte) 69, (byte) 249, (byte) 2, (byte) 127, (byte) 80, (byte) 60, (byte) 159, (byte) 168, | ||||
|             (byte) 81, (byte) 163, (byte) 64, (byte) 143, (byte) 146, (byte) 157, (byte) 56, (byte) 245, | ||||
|             (byte) 188, (byte) 182, (byte) 218, (byte) 33, (byte) 16, (byte) 255, (byte) 243, (byte) 210, | ||||
|             (byte) 205, (byte) 12, (byte) 19, (byte) 236, (byte) 95, (byte) 151, (byte) 68, (byte) 23, | ||||
|             (byte) 196, (byte) 167, (byte) 126, (byte) 61, (byte) 100, (byte) 93, (byte) 25, (byte) 115, | ||||
|             (byte) 96, (byte) 129, (byte) 79, (byte) 220, (byte) 34, (byte) 42, (byte) 144, (byte) 136, | ||||
|             (byte) 70, (byte) 238, (byte) 184, (byte) 20, (byte) 222, (byte) 94, (byte) 11, (byte) 219, | ||||
|             (byte) 224, (byte) 50, (byte) 58, (byte) 10, (byte) 73, (byte) 6, (byte) 36, (byte) 92, | ||||
|             (byte) 194, (byte) 211, (byte) 172, (byte) 98, (byte) 145, (byte) 149, (byte) 228, (byte) 121, | ||||
|             (byte) 231, (byte) 200, (byte) 55, (byte) 109, (byte) 141, (byte) 213, (byte) 78, (byte) 169, | ||||
|             (byte) 108, (byte) 86, (byte) 244, (byte) 234, (byte) 101, (byte) 122, (byte) 174, (byte) 8, | ||||
|             (byte) 186, (byte) 120, (byte) 37, (byte) 46, (byte) 28, (byte) 166, (byte) 180, (byte) 198, | ||||
|             (byte) 232, (byte) 221, (byte) 116, (byte) 31, (byte) 75, (byte) 189, (byte) 139, (byte) 138, | ||||
|             (byte) 112, (byte) 62, (byte) 181, (byte) 102, (byte) 72, (byte) 3, (byte) 246, (byte) 14, | ||||
|             (byte) 97, (byte) 53, (byte) 87, (byte) 185, (byte) 134, (byte) 193, (byte) 29, (byte) 158, | ||||
|             (byte) 225, (byte) 248, (byte) 152, (byte) 17, (byte) 105, (byte) 217, (byte) 142, (byte) 148, | ||||
|             (byte) 155, (byte) 30, (byte) 135, (byte) 233, (byte) 206, (byte) 85, (byte) 40, (byte) 223, | ||||
|             (byte) 140, (byte) 161, (byte) 137, (byte) 13, (byte) 191, (byte) 230, (byte) 66, (byte) 104, | ||||
|             (byte) 65, (byte) 153, (byte) 45, (byte) 15, (byte) 176, (byte) 84, (byte) 187, (byte) 22, | ||||
|     }; | ||||
|  | ||||
|     // The inverse S-box | ||||
|     private static final byte[] Si = { | ||||
|             (byte) 82, (byte) 9, (byte) 106, (byte) 213, (byte) 48, (byte) 54, (byte) 165, (byte) 56, | ||||
|             (byte) 191, (byte) 64, (byte) 163, (byte) 158, (byte) 129, (byte) 243, (byte) 215, (byte) 251, | ||||
|             (byte) 124, (byte) 227, (byte) 57, (byte) 130, (byte) 155, (byte) 47, (byte) 255, (byte) 135, | ||||
|             (byte) 52, (byte) 142, (byte) 67, (byte) 68, (byte) 196, (byte) 222, (byte) 233, (byte) 203, | ||||
|             (byte) 84, (byte) 123, (byte) 148, (byte) 50, (byte) 166, (byte) 194, (byte) 35, (byte) 61, | ||||
|             (byte) 238, (byte) 76, (byte) 149, (byte) 11, (byte) 66, (byte) 250, (byte) 195, (byte) 78, | ||||
|             (byte) 8, (byte) 46, (byte) 161, (byte) 102, (byte) 40, (byte) 217, (byte) 36, (byte) 178, | ||||
|             (byte) 118, (byte) 91, (byte) 162, (byte) 73, (byte) 109, (byte) 139, (byte) 209, (byte) 37, | ||||
|             (byte) 114, (byte) 248, (byte) 246, (byte) 100, (byte) 134, (byte) 104, (byte) 152, (byte) 22, | ||||
|             (byte) 212, (byte) 164, (byte) 92, (byte) 204, (byte) 93, (byte) 101, (byte) 182, (byte) 146, | ||||
|             (byte) 108, (byte) 112, (byte) 72, (byte) 80, (byte) 253, (byte) 237, (byte) 185, (byte) 218, | ||||
|             (byte) 94, (byte) 21, (byte) 70, (byte) 87, (byte) 167, (byte) 141, (byte) 157, (byte) 132, | ||||
|             (byte) 144, (byte) 216, (byte) 171, (byte) 0, (byte) 140, (byte) 188, (byte) 211, (byte) 10, | ||||
|             (byte) 247, (byte) 228, (byte) 88, (byte) 5, (byte) 184, (byte) 179, (byte) 69, (byte) 6, | ||||
|             (byte) 208, (byte) 44, (byte) 30, (byte) 143, (byte) 202, (byte) 63, (byte) 15, (byte) 2, | ||||
|             (byte) 193, (byte) 175, (byte) 189, (byte) 3, (byte) 1, (byte) 19, (byte) 138, (byte) 107, | ||||
|             (byte) 58, (byte) 145, (byte) 17, (byte) 65, (byte) 79, (byte) 103, (byte) 220, (byte) 234, | ||||
|             (byte) 151, (byte) 242, (byte) 207, (byte) 206, (byte) 240, (byte) 180, (byte) 230, (byte) 115, | ||||
|             (byte) 150, (byte) 172, (byte) 116, (byte) 34, (byte) 231, (byte) 173, (byte) 53, (byte) 133, | ||||
|             (byte) 226, (byte) 249, (byte) 55, (byte) 232, (byte) 28, (byte) 117, (byte) 223, (byte) 110, | ||||
|             (byte) 71, (byte) 241, (byte) 26, (byte) 113, (byte) 29, (byte) 41, (byte) 197, (byte) 137, | ||||
|             (byte) 111, (byte) 183, (byte) 98, (byte) 14, (byte) 170, (byte) 24, (byte) 190, (byte) 27, | ||||
|             (byte) 252, (byte) 86, (byte) 62, (byte) 75, (byte) 198, (byte) 210, (byte) 121, (byte) 32, | ||||
|             (byte) 154, (byte) 219, (byte) 192, (byte) 254, (byte) 120, (byte) 205, (byte) 90, (byte) 244, | ||||
|             (byte) 31, (byte) 221, (byte) 168, (byte) 51, (byte) 136, (byte) 7, (byte) 199, (byte) 49, | ||||
|             (byte) 177, (byte) 18, (byte) 16, (byte) 89, (byte) 39, (byte) 128, (byte) 236, (byte) 95, | ||||
|             (byte) 96, (byte) 81, (byte) 127, (byte) 169, (byte) 25, (byte) 181, (byte) 74, (byte) 13, | ||||
|             (byte) 45, (byte) 229, (byte) 122, (byte) 159, (byte) 147, (byte) 201, (byte) 156, (byte) 239, | ||||
|             (byte) 160, (byte) 224, (byte) 59, (byte) 77, (byte) 174, (byte) 42, (byte) 245, (byte) 176, | ||||
|             (byte) 200, (byte) 235, (byte) 187, (byte) 60, (byte) 131, (byte) 83, (byte) 153, (byte) 97, | ||||
|             (byte) 23, (byte) 43, (byte) 4, (byte) 126, (byte) 186, (byte) 119, (byte) 214, (byte) 38, | ||||
|             (byte) 225, (byte) 105, (byte) 20, (byte) 99, (byte) 85, (byte) 33, (byte) 12, (byte) 125, | ||||
|     }; | ||||
|  | ||||
|     // vector used in calculating key schedule (powers of x in GF(256)) | ||||
|     private static final int[] rcon = { | ||||
|             0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, | ||||
|             0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91}; | ||||
|  | ||||
|     // precomputation tables of calculations for rounds | ||||
|     private static final int[] T0 = | ||||
|             { | ||||
|                     0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, | ||||
|                     0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, | ||||
|                     0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, | ||||
|                     0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, | ||||
|                     0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, | ||||
|                     0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, | ||||
|                     0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, | ||||
|                     0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, | ||||
|                     0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, | ||||
|                     0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, | ||||
|                     0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, | ||||
|                     0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, | ||||
|                     0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, | ||||
|                     0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, | ||||
|                     0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, | ||||
|                     0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, | ||||
|                     0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, | ||||
|                     0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, | ||||
|                     0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, | ||||
|                     0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, | ||||
|                     0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, | ||||
|                     0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, | ||||
|                     0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, | ||||
|                     0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, | ||||
|                     0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, | ||||
|                     0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, | ||||
|                     0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, | ||||
|                     0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, | ||||
|                     0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, | ||||
|                     0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, | ||||
|                     0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, | ||||
|                     0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, | ||||
|                     0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, | ||||
|                     0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, | ||||
|                     0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, | ||||
|                     0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, | ||||
|                     0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, | ||||
|                     0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, | ||||
|                     0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, | ||||
|                     0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, | ||||
|                     0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, | ||||
|                     0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, | ||||
|                     0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, | ||||
|                     0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, | ||||
|                     0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, | ||||
|                     0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, | ||||
|                     0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, | ||||
|                     0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, | ||||
|                     0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, | ||||
|                     0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, | ||||
|                     0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, | ||||
|                     0x3a16162c}; | ||||
|  | ||||
|     private static final int[] T1 = | ||||
|             { | ||||
|                     0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, | ||||
|                     0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, | ||||
|                     0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, | ||||
|                     0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, | ||||
|                     0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, | ||||
|                     0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, | ||||
|                     0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, | ||||
|                     0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, | ||||
|                     0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, | ||||
|                     0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, | ||||
|                     0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, | ||||
|                     0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, | ||||
|                     0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, | ||||
|                     0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, | ||||
|                     0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, | ||||
|                     0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, | ||||
|                     0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, | ||||
|                     0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, | ||||
|                     0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, | ||||
|                     0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, | ||||
|                     0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, | ||||
|                     0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, | ||||
|                     0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, | ||||
|                     0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, | ||||
|                     0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, | ||||
|                     0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, | ||||
|                     0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, | ||||
|                     0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, | ||||
|                     0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, | ||||
|                     0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, | ||||
|                     0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, | ||||
|                     0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, | ||||
|                     0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, | ||||
|                     0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, | ||||
|                     0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, | ||||
|                     0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, | ||||
|                     0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, | ||||
|                     0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, | ||||
|                     0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, | ||||
|                     0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, | ||||
|                     0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, | ||||
|                     0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, | ||||
|                     0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, | ||||
|                     0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, | ||||
|                     0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, | ||||
|                     0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, | ||||
|                     0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, | ||||
|                     0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, | ||||
|                     0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, | ||||
|                     0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, | ||||
|                     0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, | ||||
|                     0x16162c3a}; | ||||
|  | ||||
|     private static final int[] T2 = | ||||
|             { | ||||
|                     0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, | ||||
|                     0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, | ||||
|                     0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, | ||||
|                     0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, | ||||
|                     0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, | ||||
|                     0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, | ||||
|                     0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, | ||||
|                     0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, | ||||
|                     0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, | ||||
|                     0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, | ||||
|                     0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, | ||||
|                     0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, | ||||
|                     0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, | ||||
|                     0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, | ||||
|                     0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, | ||||
|                     0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, | ||||
|                     0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, | ||||
|                     0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, | ||||
|                     0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, | ||||
|                     0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, | ||||
|                     0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, | ||||
|                     0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, | ||||
|                     0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, | ||||
|                     0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, | ||||
|                     0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, | ||||
|                     0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, | ||||
|                     0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, | ||||
|                     0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, | ||||
|                     0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, | ||||
|                     0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, | ||||
|                     0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, | ||||
|                     0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, | ||||
|                     0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, | ||||
|                     0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, | ||||
|                     0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, | ||||
|                     0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, | ||||
|                     0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, | ||||
|                     0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, | ||||
|                     0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, | ||||
|                     0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, | ||||
|                     0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, | ||||
|                     0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, | ||||
|                     0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, | ||||
|                     0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, | ||||
|                     0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, | ||||
|                     0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, | ||||
|                     0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, | ||||
|                     0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, | ||||
|                     0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, | ||||
|                     0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, | ||||
|                     0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, | ||||
|                     0x162c3a16}; | ||||
|  | ||||
|     private static final int[] T3 = | ||||
|             { | ||||
|                     0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, | ||||
|                     0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, | ||||
|                     0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, | ||||
|                     0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, | ||||
|                     0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, | ||||
|                     0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, | ||||
|                     0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, | ||||
|                     0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, | ||||
|                     0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, | ||||
|                     0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, | ||||
|                     0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, | ||||
|                     0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, | ||||
|                     0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, | ||||
|                     0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, | ||||
|                     0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, | ||||
|                     0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, | ||||
|                     0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, | ||||
|                     0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, | ||||
|                     0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, | ||||
|                     0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, | ||||
|                     0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, | ||||
|                     0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, | ||||
|                     0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, | ||||
|                     0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, | ||||
|                     0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, | ||||
|                     0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, | ||||
|                     0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, | ||||
|                     0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, | ||||
|                     0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, | ||||
|                     0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, | ||||
|                     0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, | ||||
|                     0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, | ||||
|                     0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, | ||||
|                     0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, | ||||
|                     0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, | ||||
|                     0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, | ||||
|                     0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, | ||||
|                     0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, | ||||
|                     0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, | ||||
|                     0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, | ||||
|                     0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, | ||||
|                     0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, | ||||
|                     0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, | ||||
|                     0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, | ||||
|                     0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, | ||||
|                     0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, | ||||
|                     0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, | ||||
|                     0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, | ||||
|                     0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, | ||||
|                     0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, | ||||
|                     0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, | ||||
|                     0x2c3a1616}; | ||||
|  | ||||
|     private static final int[] Tinv0 = | ||||
|             { | ||||
|                     0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, | ||||
|                     0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, | ||||
|                     0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, | ||||
|                     0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, | ||||
|                     0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, | ||||
|                     0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, | ||||
|                     0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, | ||||
|                     0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, | ||||
|                     0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, | ||||
|                     0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, | ||||
|                     0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, | ||||
|                     0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, | ||||
|                     0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, | ||||
|                     0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, | ||||
|                     0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, | ||||
|                     0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, | ||||
|                     0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, | ||||
|                     0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, | ||||
|                     0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, | ||||
|                     0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, | ||||
|                     0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, | ||||
|                     0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, | ||||
|                     0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, | ||||
|                     0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, | ||||
|                     0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, | ||||
|                     0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, | ||||
|                     0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, | ||||
|                     0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, | ||||
|                     0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, | ||||
|                     0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, | ||||
|                     0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, | ||||
|                     0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, | ||||
|                     0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, | ||||
|                     0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, | ||||
|                     0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, | ||||
|                     0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, | ||||
|                     0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, | ||||
|                     0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, | ||||
|                     0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, | ||||
|                     0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, | ||||
|                     0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, | ||||
|                     0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, | ||||
|                     0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, | ||||
|                     0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, | ||||
|                     0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, | ||||
|                     0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, | ||||
|                     0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, | ||||
|                     0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, | ||||
|                     0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, | ||||
|                     0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, | ||||
|                     0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, | ||||
|                     0x4257b8d0}; | ||||
|  | ||||
|     private static final int[] Tinv1 = | ||||
|             { | ||||
|                     0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, | ||||
|                     0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, | ||||
|                     0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, | ||||
|                     0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, | ||||
|                     0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, | ||||
|                     0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, | ||||
|                     0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, | ||||
|                     0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, | ||||
|                     0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, | ||||
|                     0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, | ||||
|                     0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, | ||||
|                     0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, | ||||
|                     0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, | ||||
|                     0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, | ||||
|                     0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, | ||||
|                     0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, | ||||
|                     0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, | ||||
|                     0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, | ||||
|                     0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, | ||||
|                     0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, | ||||
|                     0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, | ||||
|                     0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, | ||||
|                     0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, | ||||
|                     0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, | ||||
|                     0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, | ||||
|                     0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, | ||||
|                     0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, | ||||
|                     0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, | ||||
|                     0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, | ||||
|                     0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, | ||||
|                     0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, | ||||
|                     0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, | ||||
|                     0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, | ||||
|                     0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, | ||||
|                     0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, | ||||
|                     0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, | ||||
|                     0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, | ||||
|                     0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, | ||||
|                     0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4, | ||||
|                     0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, | ||||
|                     0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, | ||||
|                     0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, | ||||
|                     0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, | ||||
|                     0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, | ||||
|                     0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, | ||||
|                     0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, | ||||
|                     0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, | ||||
|                     0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, | ||||
|                     0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, | ||||
|                     0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, | ||||
|                     0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, | ||||
|                     0x57b8d042}; | ||||
|  | ||||
|     private static final int[] Tinv2 = | ||||
|             { | ||||
|                     0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, | ||||
|                     0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, | ||||
|                     0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, | ||||
|                     0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, | ||||
|                     0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, | ||||
|                     0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, | ||||
|                     0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, | ||||
|                     0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, | ||||
|                     0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, | ||||
|                     0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, | ||||
|                     0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, | ||||
|                     0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, | ||||
|                     0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, | ||||
|                     0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, | ||||
|                     0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, | ||||
|                     0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, | ||||
|                     0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, | ||||
|                     0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, | ||||
|                     0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, | ||||
|                     0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, | ||||
|                     0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff, | ||||
|                     0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, | ||||
|                     0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296, | ||||
|                     0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, | ||||
|                     0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, | ||||
|                     0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, | ||||
|                     0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, | ||||
|                     0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, | ||||
|                     0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, | ||||
|                     0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, | ||||
|                     0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, | ||||
|                     0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, | ||||
|                     0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, | ||||
|                     0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, | ||||
|                     0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, | ||||
|                     0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, | ||||
|                     0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, | ||||
|                     0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, | ||||
|                     0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, | ||||
|                     0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, | ||||
|                     0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, | ||||
|                     0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, | ||||
|                     0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, | ||||
|                     0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, | ||||
|                     0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, | ||||
|                     0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, | ||||
|                     0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, | ||||
|                     0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, | ||||
|                     0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, | ||||
|                     0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, | ||||
|                     0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, | ||||
|                     0xb8d04257}; | ||||
|  | ||||
|     private static final int[] Tinv3 = | ||||
|             { | ||||
|                     0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, | ||||
|                     0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, | ||||
|                     0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, | ||||
|                     0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, | ||||
|                     0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f, | ||||
|                     0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, | ||||
|                     0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, | ||||
|                     0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, | ||||
|                     0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, | ||||
|                     0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, | ||||
|                     0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, | ||||
|                     0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, | ||||
|                     0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, | ||||
|                     0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, | ||||
|                     0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, | ||||
|                     0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, | ||||
|                     0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, | ||||
|                     0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, | ||||
|                     0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, | ||||
|                     0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, | ||||
|                     0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, | ||||
|                     0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, | ||||
|                     0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee, | ||||
|                     0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, | ||||
|                     0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, | ||||
|                     0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, | ||||
|                     0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, | ||||
|                     0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, | ||||
|                     0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, | ||||
|                     0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, | ||||
|                     0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, | ||||
|                     0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, | ||||
|                     0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, | ||||
|                     0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, | ||||
|                     0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, | ||||
|                     0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, | ||||
|                     0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, | ||||
|                     0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, | ||||
|                     0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, | ||||
|                     0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, | ||||
|                     0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, | ||||
|                     0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, | ||||
|                     0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, | ||||
|                     0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, | ||||
|                     0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, | ||||
|                     0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, | ||||
|                     0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, | ||||
|                     0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, | ||||
|                     0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, | ||||
|                     0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c, | ||||
|                     0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, | ||||
|                     0xd04257b8}; | ||||
|  | ||||
|     private int shift( | ||||
|             int r, | ||||
|             int shift) { | ||||
|         return (r >>> shift) | (r << -shift); | ||||
|     } | ||||
|  | ||||
|     /* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ | ||||
|  | ||||
|     private static final int m1 = 0x80808080; | ||||
|     private static final int m2 = 0x7f7f7f7f; | ||||
|     private static final int m3 = 0x0000001b; | ||||
|  | ||||
|     private int FFmulX(int x) { | ||||
|         return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3)); | ||||
|     } | ||||
|  | ||||
|     /*  | ||||
|        The following defines provide alternative definitions of FFmulX that might | ||||
|        give improved performance if a fast 32-bit multiply is not available. | ||||
|         | ||||
|        private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }  | ||||
|        private static final int  m4 = 0x1b1b1b1b; | ||||
|        private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }  | ||||
|  | ||||
|     */ | ||||
|  | ||||
|     private int inv_mcol(int x) { | ||||
|         int f2 = FFmulX(x); | ||||
|         int f4 = FFmulX(f2); | ||||
|         int f8 = FFmulX(f4); | ||||
|         int f9 = x ^ f8; | ||||
|  | ||||
|         return f2 ^ f4 ^ f8 ^ shift(f2 ^ f9, 8) ^ shift(f4 ^ f9, 16) ^ shift(f9, 24); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     private int subWord(int x) { | ||||
|         return (S[x & 255] & 255 | ((S[(x >> 8) & 255] & 255) << 8) | ((S[(x >> 16) & 255] & 255) << 16) | S[(x >> 24) & 255] << 24); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Calculate the necessary round keys | ||||
|      * The number of calculations depends on key size and block size | ||||
|      * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits | ||||
|      * This code is written assuming those are the only possible values | ||||
|      */ | ||||
|     private int[][] generateWorkingKey( | ||||
|             byte[] key, | ||||
|             boolean forEncryption) { | ||||
|         int KC = key.length / 4;  // key length in words | ||||
|         int t; | ||||
|  | ||||
|         if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.length)) { | ||||
|             throw new IllegalArgumentException("Key length not 128/192/256 bits."); | ||||
|         } | ||||
|  | ||||
|         ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes | ||||
|         int[][] W = new int[ROUNDS + 1][4];   // 4 words in a block | ||||
|  | ||||
|         // | ||||
|         // copy the key into the round key array | ||||
|         // | ||||
|  | ||||
|         t = 0; | ||||
|         int i = 0; | ||||
|         while (i < key.length) { | ||||
|             W[t >> 2][t & 3] = (key[i] & 0xff) | ((key[i + 1] & 0xff) << 8) | ((key[i + 2] & 0xff) << 16) | (key[i + 3] << 24); | ||||
|             i += 4; | ||||
|             t++; | ||||
|         } | ||||
|  | ||||
|         // | ||||
|         // while not enough round key material calculated | ||||
|         // calculate new values | ||||
|         // | ||||
|         int k = (ROUNDS + 1) << 2; | ||||
|         for (i = KC; (i < k); i++) { | ||||
|             int temp = W[(i - 1) >> 2][(i - 1) & 3]; | ||||
|             if ((i % KC) == 0) { | ||||
|                 temp = subWord(shift(temp, 8)) ^ rcon[(i / KC) - 1]; | ||||
|             } else if ((KC > 6) && ((i % KC) == 4)) { | ||||
|                 temp = subWord(temp); | ||||
|             } | ||||
|  | ||||
|             W[i >> 2][i & 3] = W[(i - KC) >> 2][(i - KC) & 3] ^ temp; | ||||
|         } | ||||
|  | ||||
|         if (!forEncryption) { | ||||
|             for (int j = 1; j < ROUNDS; j++) { | ||||
|                 for (i = 0; i < 4; i++) { | ||||
|                     W[j][i] = inv_mcol(W[j][i]); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return W; | ||||
|     } | ||||
|  | ||||
|     private int ROUNDS; | ||||
|     private int[][] WorkingKey = null; | ||||
|     private int C0, C1, C2, C3; | ||||
|     private boolean forEncryption; | ||||
|  | ||||
|     private static final int BLOCK_SIZE = 16; | ||||
|  | ||||
|     /** | ||||
|      * default constructor - 128 bit block size. | ||||
|      */ | ||||
|     public AESFastEngine() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * initialise an AES cipher. | ||||
|      * | ||||
|      * @param forEncryption whether or not we are for encryption. | ||||
|      * @param params        the parameters required to set up the cipher. | ||||
|      * @throws IllegalArgumentException if the params argument is | ||||
|      *                                  inappropriate. | ||||
|      */ | ||||
|     public void init( | ||||
|             boolean forEncryption, | ||||
|             KeyParameter params) { | ||||
|  | ||||
|         WorkingKey = generateWorkingKey(params.getKey(), forEncryption); | ||||
|         this.forEncryption = forEncryption; | ||||
|     } | ||||
|  | ||||
|     public String getAlgorithmName() { | ||||
|         return "AES"; | ||||
|     } | ||||
|  | ||||
|     public int getBlockSize() { | ||||
|         return BLOCK_SIZE; | ||||
|     } | ||||
|  | ||||
|     public int processBlock( | ||||
|             byte[] in, | ||||
|             int inOff, | ||||
|             byte[] out, | ||||
|             int outOff) { | ||||
|         if (WorkingKey == null) { | ||||
|             throw new IllegalStateException("AES engine not initialised"); | ||||
|         } | ||||
|  | ||||
|         if ((inOff + (32 / 2)) > in.length) { | ||||
|             throw new RuntimeException("input buffer too short"); | ||||
|         } | ||||
|  | ||||
|         if ((outOff + (32 / 2)) > out.length) { | ||||
|             throw new RuntimeException("output buffer too short"); | ||||
|         } | ||||
|  | ||||
|         if (forEncryption) { | ||||
|             unpackBlock(in, inOff); | ||||
|             encryptBlock(WorkingKey); | ||||
|             packBlock(out, outOff); | ||||
|         } else { | ||||
|             unpackBlock(in, inOff); | ||||
|             decryptBlock(WorkingKey); | ||||
|             packBlock(out, outOff); | ||||
|         } | ||||
|  | ||||
|         return BLOCK_SIZE; | ||||
|     } | ||||
|  | ||||
|     public void reset() { | ||||
|     } | ||||
|  | ||||
|     private void unpackBlock( | ||||
|             byte[] bytes, | ||||
|             int off) { | ||||
|         int index = off; | ||||
|  | ||||
|         C0 = (bytes[index++] & 0xff); | ||||
|         C0 |= (bytes[index++] & 0xff) << 8; | ||||
|         C0 |= (bytes[index++] & 0xff) << 16; | ||||
|         C0 |= bytes[index++] << 24; | ||||
|  | ||||
|         C1 = (bytes[index++] & 0xff); | ||||
|         C1 |= (bytes[index++] & 0xff) << 8; | ||||
|         C1 |= (bytes[index++] & 0xff) << 16; | ||||
|         C1 |= bytes[index++] << 24; | ||||
|  | ||||
|         C2 = (bytes[index++] & 0xff); | ||||
|         C2 |= (bytes[index++] & 0xff) << 8; | ||||
|         C2 |= (bytes[index++] & 0xff) << 16; | ||||
|         C2 |= bytes[index++] << 24; | ||||
|  | ||||
|         C3 = (bytes[index++] & 0xff); | ||||
|         C3 |= (bytes[index++] & 0xff) << 8; | ||||
|         C3 |= (bytes[index++] & 0xff) << 16; | ||||
|         C3 |= bytes[index++] << 24; | ||||
|     } | ||||
|  | ||||
|     private void packBlock( | ||||
|             byte[] bytes, | ||||
|             int off) { | ||||
|         int index = off; | ||||
|  | ||||
|         bytes[index++] = (byte) C0; | ||||
|         bytes[index++] = (byte) (C0 >> 8); | ||||
|         bytes[index++] = (byte) (C0 >> 16); | ||||
|         bytes[index++] = (byte) (C0 >> 24); | ||||
|  | ||||
|         bytes[index++] = (byte) C1; | ||||
|         bytes[index++] = (byte) (C1 >> 8); | ||||
|         bytes[index++] = (byte) (C1 >> 16); | ||||
|         bytes[index++] = (byte) (C1 >> 24); | ||||
|  | ||||
|         bytes[index++] = (byte) C2; | ||||
|         bytes[index++] = (byte) (C2 >> 8); | ||||
|         bytes[index++] = (byte) (C2 >> 16); | ||||
|         bytes[index++] = (byte) (C2 >> 24); | ||||
|  | ||||
|         bytes[index++] = (byte) C3; | ||||
|         bytes[index++] = (byte) (C3 >> 8); | ||||
|         bytes[index++] = (byte) (C3 >> 16); | ||||
|         bytes[index++] = (byte) (C3 >> 24); | ||||
|     } | ||||
|  | ||||
|     private void encryptBlock(int[][] KW) { | ||||
|         int r, r0, r1, r2, r3; | ||||
|  | ||||
|         C0 ^= KW[0][0]; | ||||
|         C1 ^= KW[0][1]; | ||||
|         C2 ^= KW[0][2]; | ||||
|         C3 ^= KW[0][3]; | ||||
|  | ||||
|         r = 1; | ||||
|         while (r < ROUNDS - 1) { | ||||
|             r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[(C3 >> 24) & 255] ^ KW[r][0]; | ||||
|             r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[(C0 >> 24) & 255] ^ KW[r][1]; | ||||
|             r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[(C1 >> 24) & 255] ^ KW[r][2]; | ||||
|             r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[(C2 >> 24) & 255] ^ KW[r++][3]; | ||||
|             C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[(r3 >> 24) & 255] ^ KW[r][0]; | ||||
|             C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[(r0 >> 24) & 255] ^ KW[r][1]; | ||||
|             C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[(r1 >> 24) & 255] ^ KW[r][2]; | ||||
|             C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[(r2 >> 24) & 255] ^ KW[r++][3]; | ||||
|         } | ||||
|  | ||||
|         r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[(C3 >> 24) & 255] ^ KW[r][0]; | ||||
|         r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[(C0 >> 24) & 255] ^ KW[r][1]; | ||||
|         r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[(C1 >> 24) & 255] ^ KW[r][2]; | ||||
|         r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[(C2 >> 24) & 255] ^ KW[r++][3]; | ||||
|  | ||||
|         // the final round's table is a simple function of S so we don't use a whole other four tables for it | ||||
|  | ||||
|         C0 = (S[r0 & 255] & 255) ^ ((S[(r1 >> 8) & 255] & 255) << 8) ^ ((S[(r2 >> 16) & 255] & 255) << 16) ^ (S[(r3 >> 24) & 255] << 24) ^ KW[r][0]; | ||||
|         C1 = (S[r1 & 255] & 255) ^ ((S[(r2 >> 8) & 255] & 255) << 8) ^ ((S[(r3 >> 16) & 255] & 255) << 16) ^ (S[(r0 >> 24) & 255] << 24) ^ KW[r][1]; | ||||
|         C2 = (S[r2 & 255] & 255) ^ ((S[(r3 >> 8) & 255] & 255) << 8) ^ ((S[(r0 >> 16) & 255] & 255) << 16) ^ (S[(r1 >> 24) & 255] << 24) ^ KW[r][2]; | ||||
|         C3 = (S[r3 & 255] & 255) ^ ((S[(r0 >> 8) & 255] & 255) << 8) ^ ((S[(r1 >> 16) & 255] & 255) << 16) ^ (S[(r2 >> 24) & 255] << 24) ^ KW[r][3]; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private void decryptBlock(int[][] KW) { | ||||
|         int r0, r1, r2, r3; | ||||
|  | ||||
|         C0 ^= KW[ROUNDS][0]; | ||||
|         C1 ^= KW[ROUNDS][1]; | ||||
|         C2 ^= KW[ROUNDS][2]; | ||||
|         C3 ^= KW[ROUNDS][3]; | ||||
|  | ||||
|         int r = ROUNDS - 1; | ||||
|  | ||||
|         while (r > 1) { | ||||
|             r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[(C1 >> 24) & 255] ^ KW[r][0]; | ||||
|             r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[(C2 >> 24) & 255] ^ KW[r][1]; | ||||
|             r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[(C3 >> 24) & 255] ^ KW[r][2]; | ||||
|             r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[(C0 >> 24) & 255] ^ KW[r--][3]; | ||||
|             C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[(r1 >> 24) & 255] ^ KW[r][0]; | ||||
|             C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[(r2 >> 24) & 255] ^ KW[r][1]; | ||||
|             C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[(r3 >> 24) & 255] ^ KW[r][2]; | ||||
|             C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[(r0 >> 24) & 255] ^ KW[r--][3]; | ||||
|         } | ||||
|  | ||||
|         r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[(C1 >> 24) & 255] ^ KW[r][0]; | ||||
|         r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[(C2 >> 24) & 255] ^ KW[r][1]; | ||||
|         r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[(C3 >> 24) & 255] ^ KW[r][2]; | ||||
|         r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[(C0 >> 24) & 255] ^ KW[r][3]; | ||||
|  | ||||
|         // the final round's table is a simple function of Si so we don't use a whole other four tables for it | ||||
|  | ||||
|         C0 = (Si[r0 & 255] & 255) ^ ((Si[(r3 >> 8) & 255] & 255) << 8) ^ ((Si[(r2 >> 16) & 255] & 255) << 16) ^ (Si[(r1 >> 24) & 255] << 24) ^ KW[0][0]; | ||||
|         C1 = (Si[r1 & 255] & 255) ^ ((Si[(r0 >> 8) & 255] & 255) << 8) ^ ((Si[(r3 >> 16) & 255] & 255) << 16) ^ (Si[(r2 >> 24) & 255] << 24) ^ KW[0][1]; | ||||
|         C2 = (Si[r2 & 255] & 255) ^ ((Si[(r1 >> 8) & 255] & 255) << 8) ^ ((Si[(r0 >> 16) & 255] & 255) << 16) ^ (Si[(r3 >> 24) & 255] << 24) ^ KW[0][2]; | ||||
|         C3 = (Si[r3 & 255] & 255) ^ ((Si[(r2 >> 8) & 255] & 255) << 8) ^ ((Si[(r1 >> 16) & 255] & 255) << 16) ^ (Si[(r0 >> 24) & 255] << 24) ^ KW[0][3]; | ||||
|     } | ||||
| } | ||||
| @@ -1,16 +0,0 @@ | ||||
| package org.telegram.mtproto.secure.aes; | ||||
|  | ||||
| import java.io.IOException; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 12.02.14. | ||||
|  */ | ||||
| public abstract interface AESImplementation { | ||||
|     public void AES256IGEDecrypt(byte[] src, byte[] dest, int len, byte[] iv, byte[] key); | ||||
|  | ||||
|     public void AES256IGEEncrypt(byte[] src, byte[] dest, int len, byte[] iv, byte[] key); | ||||
|  | ||||
|     public void AES256IGEEncrypt(String sourceFile, String destFile, byte[] iv, byte[] key) throws IOException; | ||||
|  | ||||
|     public void AES256IGEDecrypt(String sourceFile, String destFile, byte[] iv, byte[] key) throws IOException; | ||||
| } | ||||
| @@ -1,155 +0,0 @@ | ||||
| package org.telegram.mtproto.secure.aes; | ||||
|  | ||||
| import org.telegram.mtproto.secure.KeyParameter; | ||||
|  | ||||
| import java.io.*; | ||||
|  | ||||
| import static org.telegram.mtproto.secure.CryptoUtils.substring; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 12.02.14. | ||||
|  */ | ||||
| public class DefaultAESImplementation implements AESImplementation { | ||||
|  | ||||
|     @Override | ||||
|     public void AES256IGEDecrypt(byte[] src, byte[] dest, int len, byte[] iv, byte[] key) { | ||||
|         AESFastEngine engine = new AESFastEngine(); | ||||
|         engine.init(false, new KeyParameter(key)); | ||||
|  | ||||
|         int blocksCount = len / 16; | ||||
|  | ||||
|         byte[] curIvX = iv; | ||||
|         byte[] curIvY = iv; | ||||
|         int curIvXOffset = 16; | ||||
|         int curIvYOffset = 0; | ||||
|  | ||||
|         for (int i = 0; i < blocksCount; i++) { | ||||
|             int offset = i * 16; | ||||
|  | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 dest[offset + j] = (byte) (src[offset + j] ^ curIvX[curIvXOffset + j]); | ||||
|             } | ||||
|             engine.processBlock(dest, offset, dest, offset); | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 dest[offset + j] = (byte) (dest[offset + j] ^ curIvY[curIvYOffset + j]); | ||||
|             } | ||||
|  | ||||
|             curIvY = src; | ||||
|             curIvYOffset = offset; | ||||
|             curIvX = dest; | ||||
|             curIvXOffset = offset; | ||||
|  | ||||
|             if (i % 31 == 32) { | ||||
|                 try { | ||||
|                     Thread.sleep(10); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     e.printStackTrace(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void AES256IGEEncrypt(byte[] src, byte[] dest, int len, byte[] iv, byte[] key) { | ||||
|         AESFastEngine engine = new AESFastEngine(); | ||||
|         engine.init(true, new KeyParameter(key)); | ||||
|  | ||||
|         int blocksCount = len / 16; | ||||
|  | ||||
|         byte[] curIvX = iv; | ||||
|         byte[] curIvY = iv; | ||||
|         int curIvXOffset = 16; | ||||
|         int curIvYOffset = 0; | ||||
|  | ||||
|         for (int i = 0; i < blocksCount; i++) { | ||||
|  | ||||
|             int offset = i * 16; | ||||
|  | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 dest[offset + j] = (byte) (src[offset + j] ^ curIvY[curIvYOffset + j]); | ||||
|             } | ||||
|             engine.processBlock(dest, offset, dest, offset); | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 dest[offset + j] = (byte) (dest[offset + j] ^ curIvX[curIvXOffset + j]); | ||||
|             } | ||||
|  | ||||
|             curIvX = src; | ||||
|             curIvXOffset = offset; | ||||
|             curIvY = dest; | ||||
|             curIvYOffset = offset; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void AES256IGEEncrypt(String sourceFile, String destFile, byte[] iv, byte[] key) throws IOException { | ||||
|  | ||||
|         File src = new File(sourceFile); | ||||
|         File dest = new File(destFile); | ||||
|  | ||||
|         AESFastEngine engine = new AESFastEngine(); | ||||
|         engine.init(true, new KeyParameter(key)); | ||||
|  | ||||
|         byte[] curIvX = substring(iv, 16, 16); | ||||
|         byte[] curIvY = substring(iv, 0, 16); | ||||
|  | ||||
|         BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(src)); | ||||
|         BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(dest)); | ||||
|         byte[] buffer = new byte[16]; | ||||
|         int count; | ||||
|         while ((count = inputStream.read(buffer)) > 0) { | ||||
|             byte[] outData = new byte[16]; | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 outData[j] = (byte) (buffer[j] ^ curIvY[j]); | ||||
|             } | ||||
|             engine.processBlock(outData, 0, outData, 0); | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 outData[j] = (byte) (outData[j] ^ curIvX[j]); | ||||
|             } | ||||
|  | ||||
|             curIvX = buffer; | ||||
|             curIvY = outData; | ||||
|             buffer = new byte[16]; | ||||
|  | ||||
|             outputStream.write(outData); | ||||
|         } | ||||
|         outputStream.flush(); | ||||
|         outputStream.close(); | ||||
|         inputStream.close(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void AES256IGEDecrypt(String sourceFile, String destFile, byte[] iv, byte[] key) throws IOException { | ||||
|         File src = new File(sourceFile); | ||||
|         File dest = new File(destFile); | ||||
|  | ||||
|         AESFastEngine engine = new AESFastEngine(); | ||||
|         engine.init(false, new KeyParameter(key)); | ||||
|  | ||||
|         byte[] curIvX = substring(iv, 16, 16); | ||||
|         byte[] curIvY = substring(iv, 0, 16); | ||||
|  | ||||
|         BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(src)); | ||||
|         BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(dest)); | ||||
|         byte[] buffer = new byte[16]; | ||||
|         int count; | ||||
|         while ((count = inputStream.read(buffer)) > 0) { | ||||
|             byte[] outData = new byte[16]; | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 outData[j] = (byte) (buffer[j] ^ curIvX[j]); | ||||
|             } | ||||
|             engine.processBlock(outData, 0, outData, 0); | ||||
|             for (int j = 0; j < 16; j++) { | ||||
|                 outData[j] = (byte) (outData[j] ^ curIvY[j]); | ||||
|             } | ||||
|  | ||||
|             curIvY = buffer; | ||||
|             curIvX = outData; | ||||
|             buffer = new byte[16]; | ||||
|  | ||||
|             outputStream.write(outData); | ||||
|         } | ||||
|         outputStream.flush(); | ||||
|         outputStream.close(); | ||||
|         inputStream.close(); | ||||
|     } | ||||
| } | ||||
| @@ -1,8 +0,0 @@ | ||||
| package org.telegram.mtproto.secure.pq; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 12.02.14. | ||||
|  */ | ||||
| public interface PQImplementation { | ||||
|     public long findDivider(long src); | ||||
| } | ||||
| @@ -1,73 +0,0 @@ | ||||
| package org.telegram.mtproto.secure.pq; | ||||
|  | ||||
| import java.util.Random; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 12.02.14. | ||||
|  */ | ||||
| public class PQLopatin implements PQImplementation { | ||||
|     @Override | ||||
|     public long findDivider(long src) { | ||||
|         return findSmallMultiplierLopatin(src); | ||||
|     } | ||||
|  | ||||
|     private long GCD(long a, long b) { | ||||
|         while (a != 0 && b != 0) { | ||||
|             while ((b & 1) == 0) { | ||||
|                 b >>= 1; | ||||
|             } | ||||
|             while ((a & 1) == 0) { | ||||
|                 a >>= 1; | ||||
|             } | ||||
|             if (a > b) { | ||||
|                 a -= b; | ||||
|             } else { | ||||
|                 b -= a; | ||||
|             } | ||||
|         } | ||||
|         return b == 0 ? a : b; | ||||
|     } | ||||
|  | ||||
|     private long findSmallMultiplierLopatin(long what) { | ||||
|         Random r = new Random(); | ||||
|         long g = 0; | ||||
|         int it = 0; | ||||
|         for (int i = 0; i < 3; i++) { | ||||
|             int q = (r.nextInt(128) & 15) + 17; | ||||
|             long x = r.nextInt(1000000000) + 1, y = x; | ||||
|             int lim = 1 << (i + 18); | ||||
|             for (int j = 1; j < lim; j++) { | ||||
|                 ++it; | ||||
|                 long a = x, b = x, c = q; | ||||
|                 while (b != 0) { | ||||
|                     if ((b & 1) != 0) { | ||||
|                         c += a; | ||||
|                         if (c >= what) { | ||||
|                             c -= what; | ||||
|                         } | ||||
|                     } | ||||
|                     a += a; | ||||
|                     if (a >= what) { | ||||
|                         a -= what; | ||||
|                     } | ||||
|                     b >>= 1; | ||||
|                 } | ||||
|                 x = c; | ||||
|                 long z = x < y ? y - x : x - y; | ||||
|                 g = GCD(z, what); | ||||
|                 if (g != 1) { | ||||
|                     break; | ||||
|                 } | ||||
|                 if ((j & (j - 1)) == 0) { | ||||
|                     y = x; | ||||
|                 } | ||||
|             } | ||||
|             if (g > 1) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         long p = what / g; | ||||
|         return Math.min(p, g); | ||||
|     } | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| package org.telegram.mtproto.secure.pq; | ||||
|  | ||||
| import java.math.BigInteger; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 12.02.14. | ||||
|  */ | ||||
| public class PQSolver { | ||||
|     private static PQImplementation currentImplementation = new PQLopatin(); | ||||
|  | ||||
|     public static void setCurrentImplementation(PQImplementation implementation) { | ||||
|         currentImplementation = implementation; | ||||
|     } | ||||
|  | ||||
|     public static BigInteger solvePq(BigInteger src) { | ||||
|         return new BigInteger("" + currentImplementation.findDivider(src.longValue())); | ||||
|     } | ||||
|  | ||||
|     private PQSolver() { | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -1,84 +0,0 @@ | ||||
| package org.telegram.mtproto.state; | ||||
|  | ||||
| import org.telegram.mtproto.time.TimeOverlord; | ||||
|  | ||||
| import java.util.HashMap; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 7:15 | ||||
|  */ | ||||
| public abstract class AbsMTProtoState { | ||||
|  | ||||
|     public abstract byte[] getAuthKey(); | ||||
|  | ||||
|     public abstract ConnectionInfo[] getAvailableConnections(); | ||||
|  | ||||
|     public abstract KnownSalt[] readKnownSalts(); | ||||
|  | ||||
|     protected abstract void writeKnownSalts(KnownSalt[] salts); | ||||
|  | ||||
|     public void mergeKnownSalts(int currentTime, KnownSalt[] salts) { | ||||
|         KnownSalt[] knownSalts = readKnownSalts(); | ||||
|         HashMap<Long, KnownSalt> ids = new HashMap<Long, KnownSalt>(); | ||||
|         for (KnownSalt s : knownSalts) { | ||||
|             if (s.getValidUntil() < currentTime) { | ||||
|                 continue; | ||||
|             } | ||||
|             ids.put(s.getSalt(), s); | ||||
|         } | ||||
|         for (KnownSalt s : salts) { | ||||
|             if (s.getValidUntil() < currentTime) { | ||||
|                 continue; | ||||
|             } | ||||
|             ids.put(s.getSalt(), s); | ||||
|         } | ||||
|         writeKnownSalts(ids.values().toArray(new KnownSalt[0])); | ||||
|     } | ||||
|  | ||||
|     public void addCurrentSalt(long salt) { | ||||
|         int time = (int) (TimeOverlord.getInstance().getServerTime() / 1000); | ||||
|         mergeKnownSalts(time, new KnownSalt[]{new KnownSalt(time, time + 30 * 60, salt)}); | ||||
|     } | ||||
|  | ||||
|     public void badServerSalt(long salt) { | ||||
|         int time = (int) (TimeOverlord.getInstance().getServerTime() / 1000); | ||||
|         writeKnownSalts(new KnownSalt[]{new KnownSalt(time, time + 30 * 60, salt)}); | ||||
|     } | ||||
|  | ||||
|     public void initialServerSalt(long salt) { | ||||
|         int time = (int) (TimeOverlord.getInstance().getServerTime() / 1000); | ||||
|         writeKnownSalts(new KnownSalt[]{new KnownSalt(time, time + 30 * 60, salt)}); | ||||
|     } | ||||
|  | ||||
|     public long findActualSalt(int time) { | ||||
|         KnownSalt[] knownSalts = readKnownSalts(); | ||||
|         for (KnownSalt salt : knownSalts) { | ||||
|             if (salt.getValidSince() <= time && time <= salt.getValidUntil()) { | ||||
|                 return salt.getSalt(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public int maximumCachedSalts(int time) { | ||||
|         int count = 0; | ||||
|         for (KnownSalt salt : readKnownSalts()) { | ||||
|             if (salt.getValidSince() > time) { | ||||
|                 count++; | ||||
|             } | ||||
|         } | ||||
|         return count; | ||||
|     } | ||||
|  | ||||
|     public int maximumCachedSaltsTime() { | ||||
|         int max = 0; | ||||
|         for (KnownSalt salt : readKnownSalts()) { | ||||
|             max = Math.max(max, salt.getValidUntil()); | ||||
|         } | ||||
|         return max; | ||||
|     } | ||||
| } | ||||
| @@ -1,37 +0,0 @@ | ||||
| package org.telegram.mtproto.state; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 7:26 | ||||
|  */ | ||||
| public class ConnectionInfo { | ||||
|     private int id; | ||||
|     private int priority; | ||||
|     private String address; | ||||
|     private int port; | ||||
|  | ||||
|     public ConnectionInfo(int id, int priority, String address, int port) { | ||||
|         this.id = id; | ||||
|         this.priority = priority; | ||||
|         this.address = address; | ||||
|         this.port = port; | ||||
|     } | ||||
|  | ||||
|     public int getPriority() { | ||||
|         return priority; | ||||
|     } | ||||
|  | ||||
|     public String getAddress() { | ||||
|         return address; | ||||
|     } | ||||
|  | ||||
|     public int getPort() { | ||||
|         return port; | ||||
|     } | ||||
|  | ||||
|     public int getId() { | ||||
|         return id; | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +0,0 @@ | ||||
| package org.telegram.mtproto.state; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 7:16 | ||||
|  */ | ||||
| public class KnownSalt { | ||||
|     private int validSince; | ||||
|     private int validUntil; | ||||
|     private long salt; | ||||
|  | ||||
|     public KnownSalt(int validSince, int validUntil, long salt) { | ||||
|         this.validSince = validSince; | ||||
|         this.validUntil = validUntil; | ||||
|         this.salt = salt; | ||||
|     } | ||||
|  | ||||
|     public int getValidSince() { | ||||
|         return validSince; | ||||
|     } | ||||
|  | ||||
|     public int getValidUntil() { | ||||
|         return validUntil; | ||||
|     } | ||||
|  | ||||
|     public long getSalt() { | ||||
|         return salt; | ||||
|     } | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| package org.telegram.mtproto.state; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 7:21 | ||||
|  */ | ||||
| public class MemoryProtoState extends AbsMTProtoState { | ||||
|  | ||||
|     private KnownSalt[] salts = new KnownSalt[0]; | ||||
|  | ||||
|     private String address; | ||||
|     private int port; | ||||
|     private byte[] authKey; | ||||
|  | ||||
|     public MemoryProtoState(byte[] authKey, String address, int port) { | ||||
|         this.authKey = authKey; | ||||
|         this.port = port; | ||||
|         this.address = address; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public byte[] getAuthKey() { | ||||
|         return authKey; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public ConnectionInfo[] getAvailableConnections() { | ||||
|         return new ConnectionInfo[]{new ConnectionInfo(0, 0, address, port)}; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public KnownSalt[] readKnownSalts() { | ||||
|         return salts; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void writeKnownSalts(KnownSalt[] salts) { | ||||
|         this.salts = salts; | ||||
|     } | ||||
| } | ||||
| @@ -1,80 +0,0 @@ | ||||
| package org.telegram.mtproto.time; | ||||
|  | ||||
| import org.telegram.mtproto.log.Logger; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 02.11.13 | ||||
|  * Time: 21:35 | ||||
|  */ | ||||
| public class TimeOverlord { | ||||
|     private static TimeOverlord instance; | ||||
|  | ||||
|     public static synchronized TimeOverlord getInstance() { | ||||
|         if (instance == null) { | ||||
|             instance = new TimeOverlord(); | ||||
|         } | ||||
|         return instance; | ||||
|     } | ||||
|  | ||||
|     private long nanotimeShift; | ||||
|  | ||||
|     private long timeAccuracy = Long.MAX_VALUE; | ||||
|     protected long timeDelta; | ||||
|  | ||||
|     private TimeOverlord() { | ||||
|         nanotimeShift = System.currentTimeMillis() - System.nanoTime() / 1000; | ||||
|     } | ||||
|  | ||||
|     public long createWeakMessageId() { | ||||
|         return (getServerTime() / 1000) << 32; | ||||
|     } | ||||
|  | ||||
|     public long getLocalTime() { | ||||
|         return System.currentTimeMillis(); | ||||
|     } | ||||
|  | ||||
|     public long getServerTime() { | ||||
|         return getLocalTime() + timeDelta; | ||||
|     } | ||||
|  | ||||
|     public long getTimeAccuracy() { | ||||
|         return timeAccuracy; | ||||
|     } | ||||
|  | ||||
|     public long getTimeDelta() { | ||||
|         return timeDelta; | ||||
|     } | ||||
|  | ||||
|     public void setTimeDelta(long timeDelta, long timeAccuracy) { | ||||
|         this.timeDelta = timeDelta; | ||||
|         this.timeAccuracy = timeAccuracy; | ||||
|     } | ||||
|  | ||||
|     public void onForcedServerTimeArrived(long serverTime, long duration) { | ||||
|         timeDelta = serverTime - getLocalTime(); | ||||
|         timeAccuracy = duration; | ||||
|     } | ||||
|  | ||||
|     public void onServerTimeArrived(long serverTime, long duration) { | ||||
|         if (duration < 0) { | ||||
|             return; | ||||
|         } | ||||
|         if (duration < timeAccuracy) { | ||||
|             timeDelta = serverTime - getLocalTime(); | ||||
|             timeAccuracy = duration; | ||||
|         } else if (Math.abs(getLocalTime() - serverTime) > (duration / 2 + timeAccuracy / 2)) { | ||||
|             timeDelta = serverTime - getLocalTime(); | ||||
|             timeAccuracy = duration; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void onMethodExecuted(long sentId, long responseId, long duration) { | ||||
|         if (duration < 0) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         onServerTimeArrived((responseId >> 32) * 1000, duration); | ||||
|     } | ||||
| } | ||||
| @@ -1,27 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 21:40 | ||||
|  */ | ||||
| public abstract class MTBadMessage extends TLObject { | ||||
|     protected long badMsgId; | ||||
|     protected int badMsqSeqno; | ||||
|     protected int errorCode; | ||||
|  | ||||
|     public long getBadMsgId() { | ||||
|         return badMsgId; | ||||
|     } | ||||
|  | ||||
|     public int getBadMsqSeqno() { | ||||
|         return badMsqSeqno; | ||||
|     } | ||||
|  | ||||
|     public int getErrorCode() { | ||||
|         return errorCode; | ||||
|     } | ||||
| } | ||||
| @@ -1,55 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:47 | ||||
|  */ | ||||
| public class MTBadMessageNotification extends MTBadMessage { | ||||
|  | ||||
|     public static final int CLASS_ID = 0xa7eff811; | ||||
|  | ||||
|     public MTBadMessageNotification(long badMsgId, int badMsqSeqno, int errorCode) { | ||||
|         this.badMsgId = badMsgId; | ||||
|         this.badMsqSeqno = badMsqSeqno; | ||||
|         this.errorCode = errorCode; | ||||
|     } | ||||
|  | ||||
|     public MTBadMessageNotification() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(badMsgId, stream); | ||||
|         writeInt(badMsqSeqno, stream); | ||||
|         writeInt(errorCode, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         badMsgId = readLong(stream); | ||||
|         badMsqSeqno = readInt(stream); | ||||
|         errorCode = readInt(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "bad_msg_notification#a7eff811"; | ||||
|     } | ||||
| } | ||||
| @@ -1,64 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:45 | ||||
|  */ | ||||
| public class MTBadServerSalt extends MTBadMessage { | ||||
|  | ||||
|     public static final int CLASS_ID = 0xedab447b; | ||||
|  | ||||
|     private long newSalt; | ||||
|  | ||||
|     public MTBadServerSalt(long messageId, int seqNo, int errorNo, long newSalt) { | ||||
|         this.badMsgId = messageId; | ||||
|         this.badMsqSeqno = seqNo; | ||||
|         this.errorCode = errorNo; | ||||
|         this.newSalt = newSalt; | ||||
|     } | ||||
|  | ||||
|     public MTBadServerSalt() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public long getNewSalt() { | ||||
|         return newSalt; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(badMsgId, stream); | ||||
|         writeInt(badMsqSeqno, stream); | ||||
|         writeInt(errorCode, stream); | ||||
|         writeLong(newSalt, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         badMsgId = readLong(stream); | ||||
|         badMsqSeqno = readInt(stream); | ||||
|         errorCode = readInt(stream); | ||||
|         newSalt = readLong(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "bad_server_salt#edab447b"; | ||||
|     } | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 8:00 | ||||
|  */ | ||||
| public class MTFutureSalt extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0x0949d9dc; | ||||
|  | ||||
|     private int validSince; | ||||
|     private int validUntil; | ||||
|     private long salt; | ||||
|  | ||||
|     public MTFutureSalt(int validSince, int validUntil, long salt) { | ||||
|         this.validSince = validSince; | ||||
|         this.validUntil = validUntil; | ||||
|         this.salt = salt; | ||||
|     } | ||||
|  | ||||
|     public MTFutureSalt() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     public int getValidSince() { | ||||
|         return validSince; | ||||
|     } | ||||
|  | ||||
|     public int getValidUntil() { | ||||
|         return validUntil; | ||||
|     } | ||||
|  | ||||
|     public long getSalt() { | ||||
|         return salt; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeInt(validSince, stream); | ||||
|         writeInt(validUntil, stream); | ||||
|         writeLong(salt, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         validSince = readInt(stream); | ||||
|         validUntil = readInt(stream); | ||||
|         salt = readLong(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "future_salt#0949d9dc"; | ||||
|     } | ||||
| } | ||||
| @@ -1,80 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
| import org.telegram.tl.TLVector; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 7:58 | ||||
|  */ | ||||
| public class MTFutureSalts extends TLObject { | ||||
|     public static final int CLASS_ID = 0xae500895; | ||||
|  | ||||
|     private long requestId; | ||||
|     private int now; | ||||
|     private TLVector<MTFutureSalt> salts = new TLVector<MTFutureSalt>(); | ||||
|  | ||||
|     public MTFutureSalts(long requestId, int now, TLVector<MTFutureSalt> salts) { | ||||
|         this.requestId = requestId; | ||||
|         this.now = now; | ||||
|         this.salts = salts; | ||||
|     } | ||||
|  | ||||
|     public MTFutureSalts() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     public long getRequestId() { | ||||
|         return requestId; | ||||
|     } | ||||
|  | ||||
|     public int getNow() { | ||||
|         return now; | ||||
|     } | ||||
|  | ||||
|     public TLVector<MTFutureSalt> getSalts() { | ||||
|         return salts; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(requestId, stream); | ||||
|         writeInt(now, stream); | ||||
|         writeInt(salts.size(), stream); | ||||
|         for (MTFutureSalt salt : salts) { | ||||
|             salt.serializeBody(stream); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         requestId = readLong(stream); | ||||
|         now = readInt(stream); | ||||
|         int count = readInt(stream); | ||||
|         salts.clear(); | ||||
|         for (int i = 0; i < count; i++) { | ||||
|             MTFutureSalt salt = new MTFutureSalt(); | ||||
|             salt.deserializeBody(stream, context); | ||||
|             salts.add(salt); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "future_salts#ae500895"; | ||||
|     } | ||||
| } | ||||
| @@ -1,52 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.readInt; | ||||
| import static org.telegram.tl.StreamingUtils.writeInt; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 7:56 | ||||
|  */ | ||||
| public class MTGetFutureSalts extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0xb921bd04; | ||||
|  | ||||
|     private int num; | ||||
|  | ||||
|     public MTGetFutureSalts(int num) { | ||||
|         this.num = num; | ||||
|     } | ||||
|  | ||||
|     public MTGetFutureSalts() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeInt(num, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         num = readInt(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "get_future_salts#b921bd04"; | ||||
|     } | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created by ex3ndr on 16.12.13. | ||||
|  */ | ||||
| public class MTInvokeAfter extends TLObject { | ||||
|     public static final int CLASS_ID = 0xcb9f372d; | ||||
|  | ||||
|     private long dependMsgId; | ||||
|  | ||||
|     private byte[] request; | ||||
|  | ||||
|     public MTInvokeAfter(long dependMsgId, byte[] request) { | ||||
|         this.dependMsgId = dependMsgId; | ||||
|         this.request = request; | ||||
|     } | ||||
|  | ||||
|     public long getDependMsgId() { | ||||
|         return dependMsgId; | ||||
|     } | ||||
|  | ||||
|     public byte[] getRequest() { | ||||
|         return request; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(dependMsgId, stream); | ||||
|         writeByteArray(request, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         throw new UnsupportedOperationException("Unable to deserialize invokeAfterMsg#cb9f372d"); | ||||
|     } | ||||
| } | ||||
| @@ -1,98 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.mtproto.util.BytesCache; | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 20:46 | ||||
|  */ | ||||
| public class MTMessage extends TLObject { | ||||
|     private long messageId; | ||||
|     private int seqNo; | ||||
|     private byte[] content; | ||||
|     private int contentLen; | ||||
|  | ||||
|     public MTMessage(long messageId, int seqNo, byte[] content) { | ||||
|         this(messageId, seqNo, content, content.length); | ||||
|     } | ||||
|  | ||||
|     public MTMessage(long messageId, int seqNo, byte[] content, int contentLen) { | ||||
|         this.messageId = messageId; | ||||
|         this.seqNo = seqNo; | ||||
|         this.content = content; | ||||
|         this.contentLen = contentLen; | ||||
|     } | ||||
|  | ||||
|     public MTMessage() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public long getMessageId() { | ||||
|         return messageId; | ||||
|     } | ||||
|  | ||||
|     public void setMessageId(long messageId) { | ||||
|         this.messageId = messageId; | ||||
|     } | ||||
|  | ||||
|     public int getSeqNo() { | ||||
|         return seqNo; | ||||
|     } | ||||
|  | ||||
|     public void setSeqNo(int seqNo) { | ||||
|         this.seqNo = seqNo; | ||||
|     } | ||||
|  | ||||
|     public byte[] getContent() { | ||||
|         return content; | ||||
|     } | ||||
|  | ||||
|     public void setContent(byte[] content) { | ||||
|         this.content = content; | ||||
|     } | ||||
|  | ||||
|     public int getContentLen() { | ||||
|         return contentLen; | ||||
|     } | ||||
|  | ||||
|     public void setContentLen(int contentLen) { | ||||
|         this.contentLen = contentLen; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(messageId, stream); | ||||
|         writeInt(seqNo, stream); | ||||
|         writeInt(content.length, stream); | ||||
|         writeByteArray(content, 0, contentLen, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         messageId = readLong(stream); | ||||
|         seqNo = readInt(stream); | ||||
|         int size = readInt(stream); | ||||
|         content = BytesCache.getInstance().allocate(size); | ||||
|         readBytes(content, 0, size, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "message"; | ||||
|     } | ||||
| } | ||||
| @@ -1,78 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 8:40 | ||||
|  */ | ||||
| public class MTMessageDetailedInfo extends TLObject { | ||||
|     public static final int CLASS_ID = 0x276d3ec6; | ||||
|  | ||||
|     private long msgId; | ||||
|     private long answerMsgId; | ||||
|     private int bytes; | ||||
|     private int state; | ||||
|  | ||||
|     public MTMessageDetailedInfo(long msgId, long answerMsgId, int bytes, int state) { | ||||
|         this.msgId = msgId; | ||||
|         this.answerMsgId = answerMsgId; | ||||
|         this.bytes = bytes; | ||||
|         this.state = state; | ||||
|     } | ||||
|  | ||||
|     public MTMessageDetailedInfo() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public long getMsgId() { | ||||
|         return msgId; | ||||
|     } | ||||
|  | ||||
|     public long getAnswerMsgId() { | ||||
|         return answerMsgId; | ||||
|     } | ||||
|  | ||||
|     public int getBytes() { | ||||
|         return bytes; | ||||
|     } | ||||
|  | ||||
|     public int getState() { | ||||
|         return state; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(msgId, stream); | ||||
|         writeLong(answerMsgId, stream); | ||||
|         writeInt(bytes, stream); | ||||
|         writeInt(state, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         msgId = readLong(stream); | ||||
|         answerMsgId = readLong(stream); | ||||
|         bytes = readInt(stream); | ||||
|         state = readInt(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "msg_detailed_info#276d3ec6"; | ||||
|     } | ||||
| } | ||||
| @@ -1,74 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
| import org.telegram.tl.TLVector; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.Comparator; | ||||
| import java.util.TreeSet; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 20:53 | ||||
|  */ | ||||
| public class MTMessagesContainer extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0x73f1f8dc; | ||||
|  | ||||
|     private TreeSet<MTMessage> messages = new TreeSet<MTMessage>(new Comparator<MTMessage>() { | ||||
|         @Override | ||||
|         public int compare(MTMessage mtMessage, MTMessage mtMessage2) { | ||||
|             return (int) Math.signum(mtMessage.getMessageId() - mtMessage2.getMessageId()); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     public MTMessagesContainer(MTMessage[] messages) { | ||||
|         Collections.addAll(this.messages, messages); | ||||
|     } | ||||
|  | ||||
|     public MTMessagesContainer() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public TreeSet<MTMessage> getMessages() { | ||||
|         return messages; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeInt(messages.size(), stream); | ||||
|         for (MTMessage message : messages) { | ||||
|             message.serializeBody(stream); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         int size = readInt(stream); | ||||
|         messages.clear(); | ||||
|         for (int i = 0; i < size; i++) { | ||||
|             MTMessage message = new MTMessage(); | ||||
|             message.deserializeBody(stream, context); | ||||
|             messages.add(message); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "msg_container#73f1f8dc"; | ||||
|     } | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLLongVector; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.util.Collections; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:30 | ||||
|  */ | ||||
| public class MTMsgsAck extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0x62d6b459; | ||||
|  | ||||
|     private TLLongVector messages; | ||||
|  | ||||
|     public MTMsgsAck(TLLongVector messages) { | ||||
|         this.messages = messages; | ||||
|     } | ||||
|  | ||||
|     public MTMsgsAck() { | ||||
|         this.messages = new TLLongVector(); | ||||
|     } | ||||
|  | ||||
|     public MTMsgsAck(long[] msgIds) { | ||||
|         this.messages = new TLLongVector(); | ||||
|         for (long id : msgIds) { | ||||
|             this.messages.add(id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public MTMsgsAck(Long[] msgIds) { | ||||
|         this.messages = new TLLongVector(); | ||||
|         Collections.addAll(this.messages, msgIds); | ||||
|     } | ||||
|  | ||||
|     public TLLongVector getMessages() { | ||||
|         return messages; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeTLVector(messages, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         messages = readTLLongVector(stream, context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "msgs_ack#62d6b459"; | ||||
|     } | ||||
| } | ||||
| @@ -1,70 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLLongVector; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.util.Collections; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.readTLLongVector; | ||||
| import static org.telegram.tl.StreamingUtils.writeTLVector; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 8:50 | ||||
|  */ | ||||
| public class MTNeedResendMessage extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0x7d861a08; | ||||
|  | ||||
|     private TLLongVector messages; | ||||
|  | ||||
|     public MTNeedResendMessage(TLLongVector messages) { | ||||
|         this.messages = messages; | ||||
|     } | ||||
|  | ||||
|     public MTNeedResendMessage() { | ||||
|         this.messages = new TLLongVector(); | ||||
|     } | ||||
|  | ||||
|     public MTNeedResendMessage(long[] msgIds) { | ||||
|         this.messages = new TLLongVector(); | ||||
|         for (long id : msgIds) { | ||||
|             this.messages.add(id); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public MTNeedResendMessage(Long[] msgIds) { | ||||
|         this.messages = new TLLongVector(); | ||||
|         Collections.addAll(this.messages, msgIds); | ||||
|     } | ||||
|  | ||||
|     public TLLongVector getMessages() { | ||||
|         return messages; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeTLVector(messages, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         messages = readTLLongVector(stream, context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "msg_resend_req#7d861a08"; | ||||
|     } | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 07.11.13 | ||||
|  * Time: 8:37 | ||||
|  */ | ||||
| public class MTNewMessageDetailedInfo extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0x809db6df; | ||||
|  | ||||
|     private long answerMsgId; | ||||
|     private int bytes; | ||||
|     private int status; | ||||
|  | ||||
|     public MTNewMessageDetailedInfo(long answerMsgId, int bytes, int status) { | ||||
|         this.answerMsgId = answerMsgId; | ||||
|         this.bytes = bytes; | ||||
|         this.status = status; | ||||
|     } | ||||
|  | ||||
|     public MTNewMessageDetailedInfo() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public long getAnswerMsgId() { | ||||
|         return answerMsgId; | ||||
|     } | ||||
|  | ||||
|     public int getBytes() { | ||||
|         return bytes; | ||||
|     } | ||||
|  | ||||
|     public int getStatus() { | ||||
|         return status; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(answerMsgId, stream); | ||||
|         writeInt(bytes, stream); | ||||
|         writeInt(status, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         answerMsgId = readLong(stream); | ||||
|         bytes = readInt(stream); | ||||
|         status = readInt(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "msg_new_detailed_info#809db6df"; | ||||
|     } | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:35 | ||||
|  */ | ||||
| public class MTNewSessionCreated extends TLObject { | ||||
|  | ||||
|     public static final int CLASS_ID = 0x9ec20908; | ||||
|  | ||||
|     private long firstMsgId; | ||||
|     private byte[] uniqId; | ||||
|     private byte[] serverSalt; | ||||
|  | ||||
|     public MTNewSessionCreated(long firstMsgId, byte[] uniqId, byte[] serverSalt) { | ||||
|         this.firstMsgId = firstMsgId; | ||||
|         this.uniqId = uniqId; | ||||
|         this.serverSalt = serverSalt; | ||||
|     } | ||||
|  | ||||
|     public MTNewSessionCreated() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public long getFirstMsgId() { | ||||
|         return firstMsgId; | ||||
|     } | ||||
|  | ||||
|     public byte[] getUniqId() { | ||||
|         return uniqId; | ||||
|     } | ||||
|  | ||||
|     public byte[] getServerSalt() { | ||||
|         return serverSalt; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(firstMsgId, stream); | ||||
|         writeByteArray(uniqId, stream); | ||||
|         writeByteArray(serverSalt, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         firstMsgId = readLong(stream); | ||||
|         uniqId = readBytes(8, stream); | ||||
|         serverSalt = readBytes(8, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "new_session_created#9ec20908"; | ||||
|     } | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:22 | ||||
|  */ | ||||
| public class MTPing extends TLObject { | ||||
|     public static final int CLASS_ID = 0x7abe77ec; | ||||
|  | ||||
|     private long pingId; | ||||
|  | ||||
|     public MTPing(long pingId) { | ||||
|         this.pingId = pingId; | ||||
|     } | ||||
|  | ||||
|     public MTPing() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(pingId, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         pingId = readLong(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "ping#7abe77ec"; | ||||
|     } | ||||
| } | ||||
| @@ -1,62 +0,0 @@ | ||||
| package org.telegram.mtproto.tl; | ||||
|  | ||||
| import org.telegram.tl.TLContext; | ||||
| import org.telegram.tl.TLObject; | ||||
|  | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| import static org.telegram.tl.StreamingUtils.*; | ||||
|  | ||||
| /** | ||||
|  * Created with IntelliJ IDEA. | ||||
|  * User: ex3ndr | ||||
|  * Date: 03.11.13 | ||||
|  * Time: 8:22 | ||||
|  */ | ||||
| public class MTPingDelayDisconnect extends TLObject { | ||||
|     public static final int CLASS_ID = 0xf3427b8c; | ||||
|  | ||||
|     private long pingId; | ||||
|     private int disconnectDelay; | ||||
|  | ||||
|     public MTPingDelayDisconnect(long pingId, int disconnectDelay) { | ||||
|         this.pingId = pingId; | ||||
|         this.disconnectDelay = disconnectDelay; | ||||
|     } | ||||
|  | ||||
|     public MTPingDelayDisconnect() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public long getPingId() { | ||||
|         return pingId; | ||||
|     } | ||||
|  | ||||
|     public int getDisconnectDelay() { | ||||
|         return disconnectDelay; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getClassId() { | ||||
|         return CLASS_ID; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void serializeBody(OutputStream stream) throws IOException { | ||||
|         writeLong(pingId, stream); | ||||
|         writeInt(disconnectDelay, stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void deserializeBody(InputStream stream, TLContext context) throws IOException { | ||||
|         pingId = readLong(stream); | ||||
|         disconnectDelay = readInt(stream); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         return "ping_delay_disconnect#f3427b8c"; | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user