package im.actor.core.modules.api; import im.actor.core.modules.ModuleContext; import im.actor.core.modules.api.entity.CursorStoredRequest; import im.actor.core.modules.api.entity.PersistentStorage; import im.actor.core.modules.api.entity.StoredRequest; import im.actor.core.modules.ModuleActor; import im.actor.core.network.RpcCallback; import im.actor.core.network.RpcException; import im.actor.core.network.parser.Request; import im.actor.core.network.parser.Response; import im.actor.runtime.Storage; import im.actor.runtime.storage.KeyValueStorage; public class PersistentRequestsActor extends ModuleActor { private static final String STORAGE = "persistent_requests"; private KeyValueStorage storage; private PersistentStorage requestsStorage; public PersistentRequestsActor(ModuleContext context) { super(context); } @Override public void preStart() { super.preStart(); storage = Storage.createKeyValue(STORAGE); requestsStorage = new PersistentStorage(); byte[] data = storage.loadItem(0); if (data != null) { try { requestsStorage = PersistentStorage.fromBytes(data); } catch (Throwable t) { t.printStackTrace(); } } // Restarting requests for (StoredRequest r : requestsStorage.getRequests()) { performRequest(r); } for (CursorStoredRequest r : requestsStorage.getCursorRequests()) { if (r.getRequest() != null) { performCursorRequest(r.getRequest().getRequest(), r.getName(), r.getCurrentKey()); } } } private void onNewRequest(Request request) { StoredRequest storedRequest = new StoredRequest(request); requestsStorage.getRequests().add(storedRequest); performRequest(storedRequest); // Saving storage saveStorage(); } private void onNewCursorRequest(String name, long key, Request request) { // Checking if request is valid CursorStoredRequest cursorStoredRequest = requestsStorage.findCursorRequest(name); if (cursorStoredRequest != null) { if (cursorStoredRequest.getCurrentKey() >= key) { return; } requestsStorage.getCursorRequests().remove(cursorStoredRequest); } cursorStoredRequest = new CursorStoredRequest(name, key, new StoredRequest(request)); requestsStorage.getCursorRequests().add(cursorStoredRequest); performCursorRequest(request, name, key); // Saving storage saveStorage(); } private void performCursorRequest(Request request, final String name, final long key) { request(request, new RpcCallback() { @Override public void onResult(Response response) { requestCompleted(name, key); } @Override public void onError(RpcException e) { // Remove even when error requestCompleted(name, key); } }); } private void requestCompleted(String name, long key) { CursorStoredRequest s = requestsStorage.findCursorRequest(name); if (s.getCurrentKey() == key) { requestsStorage.getCursorRequests().remove(s); requestsStorage.getCursorRequests().add(new CursorStoredRequest(name, key, null)); saveStorage(); } } private void performRequest(final StoredRequest request) { request(request.getRequest(), new RpcCallback() { @Override public void onResult(Response response) { requestCompleted(request); } @Override public void onError(RpcException e) { // Remove even when error requestCompleted(request); } }); } private void requestCompleted(StoredRequest request) { requestsStorage.getRequests().remove(request); saveStorage(); } private void saveStorage() { storage.addOrUpdateItem(0, requestsStorage.toByteArray()); } @Override public void onReceive(Object message) { if (message instanceof PerformRequest) { onNewRequest(((PerformRequest) message).getRequest()); } else if (message instanceof PerformCursorRequest) { PerformCursorRequest cursorRequest = (PerformCursorRequest) message; onNewCursorRequest(cursorRequest.getName(), cursorRequest.getKey(), cursorRequest.getRequest()); } else { super.onReceive(message); } } public static class PerformRequest { private Request request; public PerformRequest(Request request) { this.request = request; } public Request getRequest() { return request; } } public static class PerformCursorRequest { private String name; private long key; private Request request; public PerformCursorRequest(String name, long key, Request request) { this.name = name; this.key = key; this.request = request; } public String getName() { return name; } public long getKey() { return key; } public Request getRequest() { return request; } } }