mirror of
https://github.com/fabianonline/telegram_backup.git
synced 2024-12-26 06:45:33 +00:00
Removed libraries.
This commit is contained in:
parent
2ccdff9d87
commit
3f5fd7787c
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
Loading…
Reference in New Issue
Block a user