package im.actor.core.modules.file; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.HashMap; import im.actor.core.api.ApiFileLocation; import im.actor.core.api.ApiFileUrlDescription; import im.actor.core.api.rpc.RequestGetFileUrls; import im.actor.core.api.rpc.ResponseGetFileUrls; import im.actor.core.modules.ModuleContext; import im.actor.core.modules.ModuleActor; import im.actor.runtime.Log; import im.actor.runtime.actors.ActorCancellable; import im.actor.runtime.actors.ask.AskMessage; import im.actor.runtime.function.Consumer; import im.actor.runtime.promise.Promise; import im.actor.runtime.promise.PromiseFunc; import im.actor.runtime.promise.PromiseResolver; public class FileUrlLoader extends ModuleActor { private HashMap<Long, Promise<String>> requestedFiles = new HashMap<>(); private ArrayList<RequestedFile> pendingFiles = new ArrayList<>(); private boolean isExecuting = false; private ActorCancellable checkCancellable; public FileUrlLoader(ModuleContext context) { super(context); } public void checkQueue() { if (isExecuting) { return; } if (pendingFiles.size() == 0) { return; } final ArrayList<RequestedFile> destFiles = new ArrayList<>(pendingFiles); pendingFiles.clear(); isExecuting = true; ArrayList<ApiFileLocation> locations = new ArrayList<>(); for (RequestedFile f : destFiles) { Log.d("FileUrlLoader", "api: " + f.getFileId()); locations.add(new ApiFileLocation(f.getFileId(), f.getAccessHash())); } api(new RequestGetFileUrls(locations)).then(responseGetFileUrls -> { outer: for (RequestedFile f : destFiles) { for (ApiFileUrlDescription urlDescription : responseGetFileUrls.getFileUrls()) { if (f.getFileId() == urlDescription.getFileId()) { Log.d("FileUrlLoader", "resp: " + f.getFileId()); // TODO: Implement Timeouts f.getResolver().result(urlDescription.getUrl()); continue outer; } } } isExecuting = false; scheduleCheck(); }).failure(e -> { for (RequestedFile f : destFiles) { f.getResolver().error(e); } isExecuting = false; scheduleCheck(); }); } public Promise<String> askUrl(final long fileId, final long accessHash) { Log.d("FileUrlLoader", "request: " + fileId); if (requestedFiles.containsKey(fileId)) { return requestedFiles.get(fileId); } final Promise<String> res = new Promise<>((PromiseFunc<String>) resolver -> { pendingFiles.add(new RequestedFile(fileId, accessHash, resolver)); scheduleCheck(); }); requestedFiles.put(fileId, res); return res; } private void scheduleCheck() { if (checkCancellable != null) { checkCancellable.cancel(); } checkCancellable = schedule(new CheckQueue(), 50); } // // Messages // @Override public Promise onAsk(Object message) throws Exception { if (message instanceof AskUrl) { AskUrl askUrl = (AskUrl) message; return askUrl(askUrl.getFileId(), askUrl.getAccessHash()); } else { return super.onAsk(message); } } @Override public void onReceive(Object message) { if (message instanceof CheckQueue) { checkQueue(); } else { super.onReceive(message); } } private static class RequestedFile { private final long fileId; private final long accessHash; private final PromiseResolver<String> resolver; public RequestedFile(long fileId, long accessHash, PromiseResolver<String> resolver) { this.fileId = fileId; this.accessHash = accessHash; this.resolver = resolver; } public long getFileId() { return fileId; } public long getAccessHash() { return accessHash; } public PromiseResolver<String> getResolver() { return resolver; } } public static class AskUrl implements AskMessage<String> { private long fileId; private long accessHash; public AskUrl(long fileId, long accessHash) { this.fileId = fileId; this.accessHash = accessHash; } public long getFileId() { return fileId; } public long getAccessHash() { return accessHash; } } private static class CheckQueue { } }