/* * Copyright 2015 Shashank Tulsyan <shashaank at neembuu.com>. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package neembuu.uploader.external; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.LinkedList; import neembuu.reactivethread.CompletionCallback; import neembuu.reactivethread.ReactiveThread; import static neembuu.reactivethread.Utils.waitTill; import neembuu.uploader.api.AppLocationProvider; import neembuu.uploader.api.accounts.AccountsProvider; import neembuu.uploader.external.UpdateProgressUI.Content; import neembuu.uploader.external.UploaderPlugin.LocallyPresent; import neembuu.uploader.versioning.ShowUpdateNotification; /** * * @author Shashank */ public class UpdatesAndExternalPluginManager { private final Path updateLocation; private final AppLocationProvider alp; private final ShowUpdateNotification sun; //private final AccountsProvider ap; private final UpdateProgressUI upui; private volatile Index i; public UpdatesAndExternalPluginManager( Path home, AppLocationProvider alp, ShowUpdateNotification sun,final AccountsProvider ap, final UpdateProgressUI upui) { this.updateLocation = home.resolve("external"); this.sun = sun; this.alp = alp; //this.ap = ap; this.upui = upui; } private void updateIndex()throws Exception{ final Content c = upui.addContent("Updating list of supported file host"); final ReactiveThread rt1= ReactiveThread.create(new Runnable() { @Override public void run() { try{ HttpUtil.update("http://www.neembuu.com/uploader/updates/v3.1/update.zip", updateLocation.resolve("update.zip"),c); ReactiveThread.get().updateProgress(0.7d); ZipFSClassLoader.quickExtract(updateLocation.resolve("update.zip")); CheckMajorUpdate cu = new CheckMajorUpdate(updateLocation, sun); cu.check(); }catch(Exception a){throw new IllegalStateException(a);} } }, new CompletionCallback() { @Override public void completed(ReactiveThread rt) {c.done();} @Override public void canceled(ReactiveThread rt) {c.done();} @Override public void progressed(ReactiveThread rt) {c.setProgress(rt.getProgress());} }); rt1.start(); if(!waitTill(rt1, 20*1000, 300, 0.6)){ rt1.cancel(); } } public void initIndex()throws Exception{ try{ Files.createDirectories(updateLocation); }catch(Exception a){ //ignore } long startUpdate = System.currentTimeMillis(); System.out.println("fetching updates "); updateIndex(); long span = System.currentTimeMillis() - startUpdate; System.out.println("done updates index - time taken = "+span); i = new Index(updateLocation.resolve("index.json")); LinkedList<Runnable> updateOperations = new LinkedList<>(); for (SmallModuleEntry sme : i.getSmallModuleEntrys()) { LocallyPresent locallyPresent = UploaderPlugin.locallyPresent(updateLocation, sme); if(locallyPresent!=LocallyPresent.ABSENT){ if(sme.isDead()){ deleteLocal(sme); // dead plugins get cleaned. :D }else { updateOperations.add(loadInNewThread(sme)); } } } ReactiveThread rt = ReactiveThread.create(CompletionCallback.DUMMY, "Updating all plugins", updateOperations.toArray(new Runnable[updateOperations.size()])); rt.setDaemon(true); rt.start(); } private Runnable loadInNewThread(final SmallModuleEntry sme){ return new Runnable() { @Override public void run() { load(sme); } }; } public Path getUpdateLocation() { return updateLocation; } public Index getIndex() { if(i==null)throw new IllegalStateException("initIndex() first"); return i; } private void deleteLocal(SmallModuleEntry sme){ Path localCopyPath = UploaderPlugin.getLocalPath(updateLocation, sme); try{ Files.deleteIfExists(localCopyPath); }catch(IOException a){ a.printStackTrace(); } } public final UploaderPlugin load(SmallModuleEntry sme){ return load(sme,0); } private UploaderPlugin load(SmallModuleEntry sme,int cnt){ synchronized (sme){ if(sme.up!=null){ if(!sme.up.intitalized()){ ReactiveThread rt = sme.up.rt; if(rt==null){ if(cnt > 3)return sme.up; return load(sme,cnt+1); } try { waitTill(rt, 3000, 100, 1d); } catch (InterruptedException ex) {} } return sme.up; } UploaderPlugin up = new UploaderPlugin(sme, updateLocation); sme.up = up; } final Content c = upui.addContent(sme.getName()); try{sme.up.create(c);}catch(Exception a){ System.out.println("for plugin "+sme.getName()); a.printStackTrace(); c.done(); return null; //if this happens, the check box should get unchecked //map.remove(entry.getKey()); //<< this is not going to work } return load(sme,cnt+1); } public void unloadAndDelete(SmallModuleEntry sme) { UploaderPlugin up; synchronized (this){ up = sme.up; sme.up = null;// deactivate initiated here if(up==null){ Path zipPath = UploaderPlugin.getLocalPath(updateLocation, sme); if(Files.exists(zipPath)){ try{ Files.delete(zipPath); } catch(Exception a){ System.out.println("could not delete unactive plugin "+sme.getName()); } } return; } } try{up.destroy();}catch(Exception a){ System.out.println("could not destory plugin "+sme.getName()); a.printStackTrace(); } } }