From 5cc6730aed0b8e745d0a91cf14b616563d3404b6 Mon Sep 17 00:00:00 2001 From: scopeInfinity Date: Mon, 8 Aug 2016 22:21:24 +0530 Subject: [PATCH 01/28] Rerun DivvyServer on Crashh --- src/divvyhost/network/DivvyClient.java | 29 ++++++++------- src/divvyhost/network/DivvyServer.java | 37 ++++++++++++++++--- src/divvyhost/network/NetworkManager.java | 44 +++++++++++++++++++---- src/divvyhost/network/Scheduler.java | 2 ++ 4 files changed, 88 insertions(+), 24 deletions(-) diff --git a/src/divvyhost/network/DivvyClient.java b/src/divvyhost/network/DivvyClient.java index 1c4f244..bd710b9 100644 --- a/src/divvyhost/network/DivvyClient.java +++ b/src/divvyhost/network/DivvyClient.java @@ -51,15 +51,17 @@ public DivvyClient(ProjectManager projectManager, String user) { this.user = user; serverDone = new HashSet(); configuration = new Configuration(); - initClient(); - lastScannedIPListIndex = 0; - lastScannedIPSuffix = -1; } private void initClient() { + lastScannedIPListIndex = 0; + lastScannedIPSuffix = -1; client = new Client(Configuration.BUFFER_SIZE_CLIENT1, Configuration.BUFFER_SIZE_CLIENT2); NetworkRegister.register(client); + } + + private void getRemoteObj() { divvyServer = ObjectSpace.getRemoteObject(client, NetworkRegister.RMI_SERVER, ServerInterface.class); } @@ -69,7 +71,8 @@ private void initClient() { */ public boolean scanNetwork() { InetAddress lastScanIP = lastScannedAddress; - + lastScannedIPListIndex = 0; + lastScannedIPSuffix = -1; lastScannedAddress = null; firstScannedServer = null; isLastFreshServer = false; @@ -141,13 +144,12 @@ public Boolean connect() { return false; } try { - if (client!=null) { + if (client==null) { initClient(); } - client.start(); client.connect(Configuration.CLIENT_CONNECT_TIMEOUT, lastScannedAddress, Configuration.PORT_TCP); - + getRemoteObj(); //Verifing Other Server try{ if(divvyServer.isDivvyServer()) { @@ -161,16 +163,17 @@ public Boolean connect() { } } }catch(Exception e) { - log.severe("Invalid Client"); + log.severe("Invalid Server : "+e); } return false; } catch (Exception ex) { log.severe(ex.toString()); - } - if(client!=null) { - client.stop(); - client.close(); + } finally { + if(client!=null) { + client.close(); + client.stop(); + } } return false; } @@ -224,7 +227,7 @@ public void sync() { /** * Find any Server Running on given IP/Subnet - * Note : For now checking for max 254 nodes, on IPv4 Only + * Note : On IPv4 Only * @param address * @param prefixLength * @return isServerFound diff --git a/src/divvyhost/network/DivvyServer.java b/src/divvyhost/network/DivvyServer.java index 3a3f1f4..65b55f0 100644 --- a/src/divvyhost/network/DivvyServer.java +++ b/src/divvyhost/network/DivvyServer.java @@ -11,6 +11,7 @@ import divvyhost.project.ProjectManager; import java.io.BufferedOutputStream; import java.io.IOException; +import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; import java.util.List; @@ -25,7 +26,6 @@ public class DivvyServer { private static final Logger log = Logger.getLogger(DivvyServer.class.getName()); - private ServerConnection connection; private Server server; private String user; @@ -44,8 +44,7 @@ public DivvyServer(ProjectManager projectManager, String user) { @Override protected Connection newConnection() { - connection = new ServerConnection(); - return connection; + return new ServerConnection(); } }; @@ -56,7 +55,11 @@ protected Connection newConnection() { public boolean start() { try { server.bind(Configuration.PORT_TCP); - fastSocket = new ServerSocket(Configuration.PORT_FAST); + try{ + fastSocket = new ServerSocket(Configuration.PORT_FAST); + }catch(BindException e) { + log.info("Fast Socket Already Binded"); + } server.start(); if(fastScanServerEnabled) fastSockerReply(); @@ -74,6 +77,11 @@ private void fastSockerReply() { @Override public void run() { + if(fastScanServerEnabled) { + if(fastSocket == null) { + log.severe("FastSocket is NULL, can't Reply!!!"); + } + } isFastThreadRunning = true; while(isFastThreadRunning) { try { @@ -94,6 +102,25 @@ public void run() { } + /** + * Force Stop Server + */ + public void forceStop() { + isFastThreadRunning = false; + if(server!=null) { + Connection[] connections = server.getConnections(); + for(Connection connection : connections) { + connection.close(); + } + server.stop(); + server.close(); + server.getUpdateThread().stop(); + log.info(">>>>> Foce Stopping"); + } + if(fastThread!=null) + fastThread.stop(); + } + private class ServerConnection extends Connection implements ServerInterface { ServerConnection() { @@ -131,6 +158,6 @@ public String getUser() { log.info("Client taken User"); return user; } - + } } diff --git a/src/divvyhost/network/NetworkManager.java b/src/divvyhost/network/NetworkManager.java index 244f459..56ecc12 100644 --- a/src/divvyhost/network/NetworkManager.java +++ b/src/divvyhost/network/NetworkManager.java @@ -12,7 +12,10 @@ public class NetworkManager { private static final Logger log = Logger.getLogger(NetworkManager.class.getName()); - private DivvyServer divvyServer; + private static DivvyServer divvyServer; + private DivvyClient divvyClient; + private Thread serverThread; + private ProjectManager projectManager; private String user; @@ -21,19 +24,48 @@ public class NetworkManager { public NetworkManager(ProjectManager projectManager, String user) { this.projectManager = projectManager; this.user = user; - divvyServer = new DivvyServer(projectManager, user); - if (!divvyServer.start()) { - log.severe("SERVER CANNOT BE STARTED!!!!!!!!!"); - } + internalScanCounter = 0; + checkServerThread(); + } + + /** + * Recreate Server if Crashed + */ + void checkServerThread() { + if(serverThread == null || !serverThread.isAlive()) { + if (divvyServer!=null) + divvyServer.forceStop(); + if(serverThread!=null) + serverThread.stop(); + serverThread = null; + System.gc(); + serverThread = new Thread("ServerThread"){ + + @Override + public void run() { + divvyServer = new DivvyServer(projectManager, user); + if (!divvyServer.start()) { + log.severe("SERVER CANNOT BE STARTED!!!!!!!!!"); + } + } + + }; + log.info("Server Thread Created!"); + serverThread.start(); + log.info("Server Thread Started!"); + } else log.info("Server Thread is Already Alive"); + log.info("Server Thread Done Check"); } /** * Start Syncing Current Project with others * Currently Checking all Possible Server in One Go */ void startSync() { - DivvyClient divvyClient = new DivvyClient(projectManager, user); internalScanCounter = 0; + if(divvyClient==null) + divvyClient = new DivvyClient(projectManager, user); + while(true) { if (!divvyClient.scanNetwork()) { log.info("No other Server Found on Network"); diff --git a/src/divvyhost/network/Scheduler.java b/src/divvyhost/network/Scheduler.java index 3efcfca..f0c423e 100644 --- a/src/divvyhost/network/Scheduler.java +++ b/src/divvyhost/network/Scheduler.java @@ -37,6 +37,8 @@ private void periodicEvent() { log.info("Scheduler Perdiodic Start"); try{ + log.info("Checking Server Thread"); + networkManager.checkServerThread(); log.info("Going for Sync"); networkManager.startSync(); }catch(Exception e) { From b88622f471154df2dd817c43e384f75070edf000 Mon Sep 17 00:00:00 2001 From: scopeInfinity Date: Thu, 25 Aug 2016 19:50:27 +0530 Subject: [PATCH 02/28] Used java.rmi.* --- build.xml | 3 - libs/kryonet-2.21-all.jar | Bin 336988 -> 0 bytes nbproject/project.properties | 4 +- .../configuration/Configuration.java | 6 +- src/divvyhost/network/DivvyClient.java | 61 +++++--- src/divvyhost/network/DivvyServer.java | 73 +++++----- src/divvyhost/network/NetworkManager.java | 23 ++- src/divvyhost/network/NetworkRegister.java | 134 ------------------ src/divvyhost/network/Scheduler.java | 2 - src/divvyhost/network/ServerInterface.java | 12 +- 10 files changed, 102 insertions(+), 216 deletions(-) delete mode 100644 libs/kryonet-2.21-all.jar delete mode 100644 src/divvyhost/network/NetworkRegister.java diff --git a/build.xml b/build.xml index 38dc38f..a01b415 100644 --- a/build.xml +++ b/build.xml @@ -14,9 +14,6 @@ - - - Q5j(1u-1K*QoA5wmw zxMKgv`8wKhHGCB}sWBp#m~i99T}8aH)*AjFrx|)(S11{J-CWfqo5Hs@mrmdxqcJ90 zHo|9*@YZX;NYlvhNvmuJWcH1ayQmdB6hL+LPPLXtUSbVP1gG?yWA#fwCpA| z8+I+tgp9XDYs@lzVvoLg-KsBrsUAVVjSO{+i2{7aN%6T$Qfd@RRT1ud|WeJQdJ`cdq<_B4$(D2+kRWo!$_#>ZDqR zmCziks)~+dWjAEyxp4*}6s_+h#EX_?b=G6&CUs@CBe~?9NQbqf;oHrphMaFC^zDDR`XtRp z%{t~Ym%`^CtO{$=%mv}LlI{WLgf&L!{BEg`QRKXh(LYAsUmtfbTWa3@nwDL%b#Kt! zcMKjcD?WVv&{Xs(5>vKhfqKJzq@HGmAbfq*l07zBjN71ZCMy5+hpcJW)I0f-nvc1D z@XN#>m+D;8Ek?_x z-eog>PF`*tm|a|(%+UCeqy7u!;zLNG8)Yrz>Ae&ihq(K=9h(cK1R2X;ZSf-C77e#KlXLqR%?cLQ-L&MWfnRG)<6|WLR?eVGew9C$Fgv5N- zZ+w$^e0teSD&c3=x@vaNZFwU<2+^qLiL;7@F^}foYl=?J2)$zNC*X-GMX{&;FnS)> z40Xlz;!EwRdGlS|M;9g)sVNKB4pIK!!si%3azL}&7`c+#6by4y4^d%p& zJa3U&n4)?TfM0I`lKCg3eh=$|gyls^uH2PrsEBS{se|yVHh-KCXTHH=e~pT}!dVNy zo7I{rDu#vSe6`|}0aNOjOU4~%*3j)*MV3@{q8bJ2@2OQiJm=Z|^BkmLi2Tzv{=l>K z5z=^~oP9=I^~6|x8t;P#G+me~W2d$I(`gqSQlu!8Uq_S9jD75xIbZoR#OoyWM`hfn z$K2z`MSGVD;1%QC(U-9?P_nUg-puH8(y=MT_=vUc4!v&K6#aSe4gux zc5|b)NJn8X&j)P*0>RlS6kO3(GV!Td%Ukh-xN*q^&x<*yo=a2)-xrlK40HBhTcjEN zIWb~1irQ-JWY*Bu>BjGN1~wVmv&=(%_i+)YZ&rpoX6A}4q<1UJb&6qneUREO}2 ztnt{Q9Ls8=J{$hk&)>m&dMuyY1wZ9^gvr0v_7mfCYc|&7=Wby_y&58dG7VNF`0D)-~KRQ3jFgT00H z0x}^)o8Zt>iqJcx6>Z$y!JF7!Y1KR+9uSLv|H!o;V5DmdDUXN}2~Xy_nBlk_BVrWv z=t3*H7~*Zyq3}jt7PXz`<5{a9%vZOj=(I$zF(14+c_k>OsFsjt`Gz>lkB`fs_jU9B z-6z|>zL7Me+n$(O(hJkWrk}=o$l+v)%1KY6#Bxv9lx+S-))_`7pI8h!a@&`p9>V8} zLu6>e-`cE<#MFA>|5S@(FrIv}CMdziPx@&4WjiU2fUHmVh!Q@7;YxVR$E1q!YwR2q@vDLXy$mxdlO{;d~z3T_4_bMPYRqKi+a zI7^=%PvNoS@hW7p!lKmf+T*)r%*^xdh{~pD!+_;Xs#K$k-~$-44drb+`YlT zuX|Q8F?S!g1hi(wA#KgNf;`zZGj+2uXFn8j9&Xb5Z5R9Jx+Mn7jH)aBv?P0yG3r?% zYR0$7t`^bLM+wQwCKSwGPNJS?8~T8?OLLW5O_ob71H45-a3m7DG$q9{^{yazkLA~e z29bb(U99Goy6dJdW>UB>h5bOoVVSATGw%~USL4A#t{a-y_D*d;&5CTj^}KR+baDuO zTgkQNG3U-NVj~gl7q5Cp4D1|xZ_*_adtLF|Wkp?b`++YmPffpFvVQ5Taw)-(JlraM zkQLuyHA&?T2k%;KQ`?2YR}JTLxbIH*_$@@VNrs{_**tH&MgFzk^o?ihyXzQ|EaozC zXU@^a#Zwh@n9oAaUU@m1Pw9j!XI9zEOnfdphi#a!h(a)Uh=!Y;I(AuTLGr#gP2$kK zz&<^#2zq(lEM~9mTz4+Tl2#72c8s>oAY1b3SENtAU-Lp&+p$Y%7;)0*JWDuG+vEH# zFe5U{?@m&d3#I|7+kG0VLUcx>2N_xYB+oBQ{176z_R_wl)Zk}1U|5~Sh$!<=m!x(sLX@D!N8BL0m$+7Px0lhVS@k1Nj)M3hW>`Hp3 z;7zp_?(-j%CIpr_KGpWQEyuma(kk>1kv>;;KXd7$)`|z63Zv@T>APF9b5F$Z!;173 zh%dV9EHG89jcVnFsuY*)?wy<4(9p@D1HIfvAPquXec}I;o7z9a>gep@uHo(qF?G;@ zIR1NE%1sR;l{dgg4S3en=kvceZxO5wT^+y5K|PnAE!!&1`MiPC>s5o>^o#Uzkt_F6YHu4*44YVFWu1TV zF!Ul>pEGd|1#73~t>W5z>fm{1dd*Q2*&kvJ_?&BO_O<1PBe)JS$C+K)Ka|=GZ@fFx zLLXeIZz19n@icDk8*+vkcg^%1* zZa>ENiY4;Y6WTLWu@&-Rvfs|! z{K9!nq-lY=W(o7IRlH1BK=pBXdwNPGAvEq&mV_c1GKzy5D919 z46Pv2#aBgb!OaaaYH^Yxdmv?C8f7$7{FwC-+kj)rhXnF~q{-muy{iBwl^&?0`#5{j zGkh7nrV@8=q4(-oAd2(D`_kxo(KoqB9=(YX8~xH{oC&a+M?A-M?~ ztX?wpJbC_KWwo6qPE=c+jRR|Kp_7G-7-!hY(N{0uN~9_(8nefa{(=+1`}ImEcB=O_ z+etb)FYH92&f^kwb*owW54<}n6y8Zje$~E9t-)Gb-jn!Pb*!+tSs`J{ae+wI;8d$< z>78$W)$;j1KIh3otAkZ*7qyinuLYDctzCh9aMJ$C`1l$2?@3r(yk^A@!Bvj&cI3 z`A?JW40W5_pWLyzGTx-~@(r~Vo>o4ykVR3aL1FbWuw&+!FKOcqf1U{gu61%3${L$W zWkTnZUYPvTyChA#_~-35{3JeM$9a~wToHuCj{HO)SPv3YU~hhbW^RE|@u{o-N%9QK z>7g>!wfjTuJA3{7J&lF1s1;D#?A-i#UCT z0l_W0-wo2JwTRCJe*DH=Yv^^xXr)T&xu=8}MkT)>tNTa??9KOXp>PlO9N0=)KLSUGIpOuzEq4JkFzU z-SBO4!iO*oYU6V)^{!ox?Xv~OcJAI9_=D4dgRZreNh^%@>4uIvPrtaj+mMyijU_AX zO3r*#_+?z(xX9xp*QpVFWj)nM1kZSzT*qlADT4ou)Qb_aV27OJo$WVn3+i$`vY2H1 zI#e5TlINLAwCN5?;ccRRoIHt*1((lV_np`6>FV22(Ca_>7=}WoQ6<)CZ8(X3g+{C- zK4nF#3S)39@z%c?vh*f&WN~#VNC(3cO$w9bzGu;?vpa?mjbm2PPJ-wf8Dn^sQ{o9v za-Q26;1E9Peh}S>_CcCtjW8$qO-|hXtRY&x{DzyoCK;I*{ga;6dP={urfmt$dK}*R zdi>K43ch*JOpgc(Ha;5IMt^!9_qoa#1(%X`aGVqx*;Tyl+L%e=R|7&fuxDkC*Yi!K z(!_?+VY#KUHd0kd_c1Brlb{ZujxR6XDTcMV6_+qX6yJl`fnJX`X*a{zt zM_h&O&2TB_E6M>=o!)y94k{WE3K0qh_#X-iHOgJCkqrs(cf{b2L?|G9fO-DC(L+g0 zSx#C?Lz7KOdbb-IW581Re&^-}3781byV{_I)`KSk&_;ZL%YQD-IDCriD2O9@k0B!f z$ps)h2MFNXaqtW5a$o}rxu%ZpHm0DI%l_{h+YYY_`}6E5MrGxvP)Bf=i80v50x932 zCl>S21t*H&dJ|<0siXfoKpma442&=u2vhygzePb2BLABa{^!!>-^X_lykhPszTu|n zN$BE91mqzAgKv8li5ie(sPLs^n0LIC6W~Yzdx7S@2M_o8zs1qC1`(#kK`sm*=_|QQ zauYzJ0H!N?00X}D(;$^7LdnTO?45t#0C-e>7WAuvtpJH12L(j}2JIIeQZzu(oLv?C z2O%tc_O51B63`K&pqvKg#sLF(8TA+-4+T8Y`QR9Rj44taXUEk$o|hUNHJGeQ=bD}xzS47JDIv4 z`4#>sp1ab%Kkz(=~)U*(zykj?|1p~aztXF?09d)Y4)DMP&W z7cg^}1P4A=Vm1L+9?+pF&>{T+5csyDgN!Q$P_d-_=XH@st&o(T&{+YlzUK9j(fk{I zX;?eC{++&5j`@7l2BYW!6CO6!cxsGf6fldNqN&yI8Z3PA&HQ{|bP9lI0TAe&=m(FN z83K@l15XEs;ty^}KPt;X1BVtu za{C{I0j`Xf0~pYd48G9Kj}42d0h}-#^Bg67&HdZnTn49%lA`Truw|Toic#z`p{2 zd+87~3W`@4GH@Fwb`=kIP@9yn_HeX=AP5IG^HkD#0Cj%Ank)=;|43xi5BsR2ca{8O zJ9|IF*Os$FjwlqB6`)GPpfcV5|3%&Nh)6K!))&I`0A?bv5@i_7ftbI=gm;Mm^qTAg zt-|LwGvJm_6u|r4xGh>0}Sx3B=2Bl+rRh#I_|x1$WpwV zkt<4UfFJ`P2s>_y2S~=v4!n=Jk2^%%!xDtH`+jJDj|9E~h}`n4t$+eN0TeCFxXX(U z#(l87@0p0UjhhX^#qku1{RRQB6g2FkNtJcU0Yx}hKpbhR<>2J_i!w-Hjer`ce?)?@ zUxpd}mq$pX1Sf-oFCIPNrJs zL@{f*RuS(x;G1wkDGs(+==l>Fb8W_#U+e<5c;mCV*i9;zZc6dlLoq--6_U z6~hU;)uA;o1mSQj`eqX=P!9nxYe^WXk(@Xn4`;?Bxb%fq(!;^Q2btH(-{|Gy1`IU< zp@H1@&{Ktuinz=GqbE2ag}9BCB*fgt!PNdwT3bESFiwCAv_^@7a`6y6nAcdy2CzTB zkj$tHzJu{jz~!@pb@l=b;dkT*vOG}Lo{b^%H|9+%_@qENEkHS}Fa(o8=?h^+hJEiX zB*@DmQ-zVJSAiCw{mgnWq%qDTBYij!L6ipV=OBNT1r6oaXF$yl2XF|RXMeqbWEj8K z0B8Zt$-`aB+Z^KTZsX(#-!m)|+Es}IUSEJ97B)}`qC3#b-`O|m;vDOGWd{e zHYXJ40bC-G9BlA$OYXoX4(2Kxw~929dS`ByT>vb?7FYy5%={WuK*AEc0<<)SAWqGi zqmZBl<4pjXmV}|%uY53OICi{W+WQ?6{M&i+=MW8NQIO^|kkShHz%D-48pyc#%i63o zXQ;qEFfkp##DuLsywyZT9>mFV&;}x;N&2bi{3;nBsU^arVbn`qWW@K}{6DVkFB~aP z$#U5i;DH7}!NvgBOpz+(-|d_~tAY5An)P#_@M}N~uoy!S1gyY@YP7$d2;x{xT>g_i zFECgJV6d=r5FO+gh}W9K3&N40i58m7?EMCR4sP@a-j4%t%{WK>@{TI{tK3&E zXAdx-pj28P^_2c@2#{e_247^cqkS~cq8iJ8v{Y~p0olFW0GXB)ogA%@Xi4kac@OA2 zRF=Ucg$Zk7Kj!F%r4mM@qPt@ z0UWUkRco;GsqEokhKR?4E7h0}07No?fUU~isYC$r+dh6rF-KeB5lq(Y&AP(-fR|

S16;zPC$k0#Bkamf?#dqa2&!)` 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 othersList = divvyServer.listDetails(); + List

othersList = null; + try { + othersList = divvyServer.listDetails(); + } catch (RemoteException ex) { + } + + if(othersList == null) { + log.info("Failed to Fetch Others List"); + return; + } log.info("Number of Project of Server["+lastScannedAddress.getHostAddress()+"] "+othersList.size()); List
fetchThese = projectManager.processOtherClientList(othersList); log.info("Number of New Project of Server["+lastScannedAddress.getHostAddress()+"] "+fetchThese.size()); for (Details projectDetails : fetchThese) { - Project newProject = divvyServer.getProject(projectDetails.getpID().toString()); + Project newProject = null; + try { + newProject = divvyServer.getProject(projectDetails.getpID().toString()); + } catch (RemoteException ex) { + } if(newProject == null) { log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Fetch :"+projectDetails.getpID() ); @@ -318,7 +332,8 @@ private boolean checkForServer(InetAddress address) { // Timeout for Checking 20ms try { Socket socket = new Socket(); - socket.connect(new InetSocketAddress(address, Configuration.PORT_FAST), 100); + socket.connect(new InetSocketAddress(address, Configuration.PORT_FAST), 200); + System.out.println("Connected"); boolean working = false; if(socket.isConnected()) { if (fastScanEnabled) { diff --git a/src/divvyhost/network/DivvyServer.java b/src/divvyhost/network/DivvyServer.java index 65b55f0..93cfa9b 100644 --- a/src/divvyhost/network/DivvyServer.java +++ b/src/divvyhost/network/DivvyServer.java @@ -1,8 +1,5 @@ package divvyhost.network; -import com.esotericsoftware.kryonet.Connection; -import com.esotericsoftware.kryonet.Server; -import com.esotericsoftware.kryonet.rmi.ObjectSpace; import divvyhost.configuration.Configuration; import static divvyhost.configuration.Configuration.FAST_SCAN_MESSAGE; import static divvyhost.configuration.Configuration.fastScanServerEnabled; @@ -14,6 +11,9 @@ import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; +import java.rmi.Naming; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; import java.util.List; import java.util.UUID; import java.util.logging.Level; @@ -26,10 +26,10 @@ public class DivvyServer { private static final Logger log = Logger.getLogger(DivvyServer.class.getName()); - private Server server; + private ServerConnection server; private String user; - private ServerSocket fastSocket; + private static ServerSocket fastSocket; private Thread fastThread; private boolean isFastThreadRunning; @@ -40,27 +40,15 @@ public DivvyServer(ProjectManager projectManager, String user) { this.user = user; log.info("Server Started for User :"+user); - server = new Server(Configuration.BUFFER_SIZE_SERVER1, Configuration.BUFFER_SIZE_SERVER2){ - - @Override - protected Connection newConnection() { - return new ServerConnection(); - } - - }; - NetworkRegister.register(server); + server = null; } public boolean start() { try { - server.bind(Configuration.PORT_TCP); - try{ - fastSocket = new ServerSocket(Configuration.PORT_FAST); - }catch(BindException e) { - log.info("Fast Socket Already Binded"); - } - server.start(); + server = new ServerConnection(); + Naming.rebind("rmi://127.0.0.1/divvy", server); + rebindFastSocket(); if(fastScanServerEnabled) fastSockerReply(); return true; @@ -70,6 +58,18 @@ public boolean start() { return false; } + private void rebindFastSocket() { + try{ + if(fastSocket==null) + fastSocket = new ServerSocket(Configuration.PORT_FAST); + log.info("Fast Socket Binded"); + }catch(BindException e) { + log.info("Fast Socket Already Binded"); + } catch (IOException ex) { + log.info("Fast Socket Already Binded"); + } + } + private void fastSockerReply() { isFastThreadRunning = false; @@ -79,13 +79,17 @@ private void fastSockerReply() { public void run() { if(fastScanServerEnabled) { if(fastSocket == null) { - log.severe("FastSocket is NULL, can't Reply!!!"); + rebindFastSocket(); + } + if(fastSocket == null) { + log.severe("FastSocket is NULL, can't Reply!!! "); } } isFastThreadRunning = true; while(isFastThreadRunning) { try { Socket socket = fastSocket.accept(); + System.out.println("FASTSOCKET : "+fastSocket); BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); bos.write(FAST_SCAN_MESSAGE.getBytes()); bos.flush(); @@ -105,30 +109,27 @@ public void run() { /** * Force Stop Server */ + @Deprecated public void forceStop() { + log.severe("Calling @Deprecated, forceStop"); + isFastThreadRunning = false; if(server!=null) { - Connection[] connections = server.getConnections(); - for(Connection connection : connections) { - connection.close(); - } - server.stop(); - server.close(); - server.getUpdateThread().stop(); + server = null; log.info(">>>>> Foce Stopping"); } if(fastThread!=null) fastThread.stop(); } - private class ServerConnection extends Connection implements ServerInterface { + private class ServerConnection extends UnicastRemoteObject implements ServerInterface { - ServerConnection() { - new ObjectSpace(this).register(NetworkRegister.RMI_SERVER, this); + ServerConnection() throws RemoteException { + } @Override - public List
listDetails() { + public List
listDetails() throws RemoteException { log.info("Client Requesting List of Projects"); if(projectManager == null) { log.severe("Project Manager NULL"); @@ -138,7 +139,7 @@ public List
listDetails() { } @Override - public Project getProject(String uuid) { + public Project getProject(String uuid) throws RemoteException { log.info("Client Requesting Project "+uuid); if(projectManager == null) { log.severe("Project Manager NULL"); @@ -148,13 +149,13 @@ public Project getProject(String uuid) { } @Override - public boolean isDivvyServer() { + public boolean isDivvyServer() throws RemoteException { log.info("Client Tested isDivvyServer()"); return true; } @Override - public String getUser() { + public String getUser() throws RemoteException { log.info("Client taken User"); return user; } diff --git a/src/divvyhost/network/NetworkManager.java b/src/divvyhost/network/NetworkManager.java index 56ecc12..3b20ae9 100644 --- a/src/divvyhost/network/NetworkManager.java +++ b/src/divvyhost/network/NetworkManager.java @@ -1,6 +1,8 @@ package divvyhost.network; +import divvyhost.configuration.Configuration; import divvyhost.project.ProjectManager; +import java.rmi.RemoteException; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -24,18 +26,25 @@ public class NetworkManager { public NetworkManager(ProjectManager projectManager, String user) { this.projectManager = projectManager; this.user = user; - + try { + java.rmi.registry.LocateRegistry.createRegistry(Configuration.PORT_RPC); + log.info("Created Registry :"+Configuration.PORT_RPC); + } catch (RemoteException ex) { + log.severe(ex.toString()); + log.severe("\nCreatingRegistry Failed!!\n\n"); + } internalScanCounter = 0; - checkServerThread(); + startServerThread(); } /** - * Recreate Server if Crashed + * Start Server Thread */ - void checkServerThread() { - if(serverThread == null || !serverThread.isAlive()) { - if (divvyServer!=null) + void startServerThread() { + if(serverThread == null) { + if (divvyServer!=null) { divvyServer.forceStop(); + } if(serverThread!=null) serverThread.stop(); serverThread = null; @@ -46,7 +55,7 @@ void checkServerThread() { public void run() { divvyServer = new DivvyServer(projectManager, user); if (!divvyServer.start()) { - log.severe("SERVER CANNOT BE STARTED!!!!!!!!!"); + log.severe("\n\nSERVER CANNOT BE STARTED!!!!!!!!!\n\n"); } } diff --git a/src/divvyhost/network/NetworkRegister.java b/src/divvyhost/network/NetworkRegister.java deleted file mode 100644 index de839d6..0000000 --- a/src/divvyhost/network/NetworkRegister.java +++ /dev/null @@ -1,134 +0,0 @@ -package divvyhost.network; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryonet.EndPoint; -import com.esotericsoftware.kryonet.rmi.ObjectSpace; -import divvyhost.project.Data; -import divvyhost.project.Details; -import divvyhost.project.Project; -import divvyhost.project.ProjectManager; -import divvyhost.utils.Pair; -import java.io.Serializable; -import java.lang.reflect.Field; -import java.lang.reflect.Type; -import java.security.PublicKey; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Logger; - -/** - * - * @author scopeinfinity - */ -public class NetworkRegister { - private static final Logger log = Logger.getLogger(NetworkRegister.class.getName()); - - public static int RMI_SERVER = 1; - public static int RMI_CLIENT = 2; - - /** - * Register Classes for kryo - * @param endPoint - */ - static void register(EndPoint endPoint) { - Kryo kryo = endPoint.getKryo(); - ObjectSpace.registerClasses(kryo); - - kryo.register(ClientInterface.class); - kryo.register(ServerInterface.class); - kryo.register(Project.class); - kryo.register(Data.class); - kryo.register(Details.class); - - kryo.register(ArrayList.class); - kryo.register(List.class); - kryo.register(byte[].class); - - kryo.register(PublicKey.class); - - // UUID is not Serializable - // Thus no Member containing UUID should not be passed using kryonet - kryo.register(UUID.class); - - - } - - - /** - * For Recursively Registering Classes - * Maintain Collection of classes already Registered - */ - private static HashMap > alreadyRegistered; - - /** - * Register Class to given EndPoint recursively - * @param endPoint - * @param _class - */ - private static void registerClass(EndPoint endPoint, Kryo kryo, Class _class) { - Set registered; - if (alreadyRegistered == null) { - alreadyRegistered = new HashMap<>(); - } - if (alreadyRegistered.containsKey(endPoint)) - registered = alreadyRegistered.get(endPoint); - else { - registered = new HashSet<>(); - alreadyRegistered.put(endPoint, registered); - } - - Field[] fields = _class.getDeclaredFields(); - ArrayList list = new ArrayList<>(); - if (!registered.contains(_class)) { - list.add(new ClassPair(_class.getCanonicalName(), _class)); - registered.add(_class); - } - - for (Field field : fields) { - String name = field.getName(); - Class classMember = field.getType(); - if(!classMember.isPrimitive()) { - //Need to Register - if (!registered.contains(classMember)) { - list.add(new ClassPair(classMember.getCanonicalName(), classMember)); - registered.add(classMember); - } - } - - } - - //Sorting in Order of ClassName locally in recurstion - Collections.sort(list); - - //Registering Classes in Sorted Order - for (ClassPair classPair : list) { - kryo.register(classPair.getSecond()); - log.info("Register Class : "+classPair.getFirst()); - } - - //Recursive goint in bottom - for (ClassPair classPair : list) { - kryo.register(classPair.getSecond()); - } - - } - - private static class ClassPair extends Pair implements Comparable{ - - public ClassPair(String first, Class second) { - super(first, second); - } - - @Override - public int compareTo(ClassPair other) { - return getFirst().compareTo(other.getFirst()); - } - } - -} - diff --git a/src/divvyhost/network/Scheduler.java b/src/divvyhost/network/Scheduler.java index f0c423e..3efcfca 100644 --- a/src/divvyhost/network/Scheduler.java +++ b/src/divvyhost/network/Scheduler.java @@ -37,8 +37,6 @@ private void periodicEvent() { log.info("Scheduler Perdiodic Start"); try{ - log.info("Checking Server Thread"); - networkManager.checkServerThread(); log.info("Going for Sync"); networkManager.startSync(); }catch(Exception e) { diff --git a/src/divvyhost/network/ServerInterface.java b/src/divvyhost/network/ServerInterface.java index 7bc4a28..fa32fef 100644 --- a/src/divvyhost/network/ServerInterface.java +++ b/src/divvyhost/network/ServerInterface.java @@ -2,36 +2,38 @@ import divvyhost.project.Details; import divvyhost.project.Project; +import java.rmi.Remote; +import java.rmi.RemoteException; import java.util.List; /** * ServerInterface for RMI * @author scopeinfinity */ -public interface ServerInterface { +public interface ServerInterface extends Remote{ /** * Get list of Details of Projects * @return listDetails() */ - public List
listDetails(); + public List
listDetails() throws RemoteException; /** * Get project from UUID * @param uuid * @return project */ - public Project getProject(String uuid); + public Project getProject(String uuid) throws RemoteException; /** * For Confirmation RMI is Working and Server is valid * @return isDivvyServer() */ - public boolean isDivvyServer(); + public boolean isDivvyServer() throws RemoteException; /** * Return User ID, for maintaining connection with other userDivvy Only * @return */ - public String getUser(); + public String getUser() throws RemoteException; } From 742586305cc8cdd4e334a4eae088e09f9481f16a Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Thu, 29 Sep 2016 08:24:04 +0530 Subject: [PATCH 03/28] Custom RPC modules --- .../configuration/Configuration.java | 2 + src/divvyhost/network/DivvyClient.java | 253 +++++++++--------- src/divvyhost/network/DivvyServer.java | 147 ++++++++-- src/divvyhost/network/Message.java | 112 ++++++++ src/divvyhost/network/MessageCall.java | 119 ++++++++ src/divvyhost/network/NetworkManager.java | 27 +- src/divvyhost/network/ServerInterface.java | 10 +- 7 files changed, 512 insertions(+), 158 deletions(-) create mode 100644 src/divvyhost/network/Message.java create mode 100644 src/divvyhost/network/MessageCall.java diff --git a/src/divvyhost/configuration/Configuration.java b/src/divvyhost/configuration/Configuration.java index 206fc53..6e1b281 100644 --- a/src/divvyhost/configuration/Configuration.java +++ b/src/divvyhost/configuration/Configuration.java @@ -30,6 +30,8 @@ public class Configuration { public static int CLIENT_CONNECT_TIMEOUT = 5000; public static long SCHEDULER_REFRESH_TIMER = 15*60*1000; + public static long SERVER_REFRESH_TIMER = 10*1000; + public static long CUSTOM_RPC_TIMEOUT = 10*1000; public static boolean AUTO_EXPORTPROJECT_ONLOAD = false; diff --git a/src/divvyhost/network/DivvyClient.java b/src/divvyhost/network/DivvyClient.java index d0039ce..ea2129f 100644 --- a/src/divvyhost/network/DivvyClient.java +++ b/src/divvyhost/network/DivvyClient.java @@ -22,6 +22,8 @@ import java.rmi.Naming; import java.rmi.NotBoundException; import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; import java.util.Enumeration; import java.util.HashSet; import java.util.List; @@ -37,43 +39,86 @@ public class DivvyClient implements ClientInterface{ private static final Logger log = Logger.getLogger(DivvyClient.class.getName()); - private InetAddress lastScannedAddress; - private ServerInterface divvyServer; - private ProjectManager projectManager; private Configuration configuration; private String user; - private Set serverDone; + private MessageCall divvyServer; + private Socket divvyServerSocket; + + //Set Containing IP Address of any server encountered + private Set serverFound; + + //IP Address of Last Successfull Server + private InetAddress lastScannedAddress; + //Index of IP from configuration file,which is last scanned private int lastScannedIPListIndex; + //Suffix of last IP, which is last scanned private int lastScannedIPSuffix; public DivvyClient(ProjectManager projectManager, String user) { this.projectManager = projectManager; this.user = user; - serverDone = new HashSet(); configuration = new Configuration(); - + + //Not in reset, may be used in some optimization later + serverFound = new HashSet(); + + reset(); } - private void initClient() { + /** + * Reset Object for reuse + */ + public void reset() { lastScannedIPListIndex = 0; lastScannedIPSuffix = -1; + lastScannedAddress = null; + disconnect(); } - private void getRemoteObj() { + /** + * Get Remote Object from RMI + * @ address + * @return gotRemoteObject. + */ + private boolean getRemoteObj(InetAddress address) { try { - divvyServer = (ServerInterface)Naming.lookup("rmi://"+lastScannedAddress.getHostAddress()+"/divvy"); - log.info("Got Server Object : "+lastScannedAddress.getHostAddress()); - return; - } catch (NotBoundException ex) { - log.severe(ex.toString()); - } catch (MalformedURLException ex) { - log.severe(ex.toString()); - } catch (RemoteException ex) { - log.severe(ex.toString()); + // try { +//// if (System.getSecurityManager() != null) { +//// System.setSecurityManager(null); +//// } +//// Registry registry = LocateRegistry.getRegistry(lastScannedAddress.getHostAddress().toString(), Configuration.PORT_RPC); +//// +//// divvyServer = (ServerInterface) registry.lookup("divvy"); +// +//// System.getProperties().put("java.rmi.server.hostname", "); +//// +//// divvyServer = (ServerInterface) Naming.lookup( +//// String.format("rmi://%s:%s/", +//// lastScannedAddress.getHostAddress().toString(), +//// String.valueOf(Configuration.PORT_RPC)) +//// + "divvy"); +// log.info("Got Server Object : "+lastScannedAddress.getHostAddress()); +// log.info("Test : "+divvyServer.isDivvyServer()+"\n\n\n"); +// log.info(""+divvyServer.getUser()+"\n\n\n"); +// +// return true; +// } catch (NotBoundException | RemoteException ex) { +// log.severe(ex.toString()); +// ex.printStackTrace(); +//// } catch (MalformedURLException ex) { +//// log.severe(ex.toString()); +// } +// + divvyServerSocket = new Socket(address, Configuration.PORT_RPC); + divvyServer = new MessageCall(divvyServerSocket); + return true; + } catch (Exception ex) { + log.severe("Server Object get Failed! : "+lastScannedAddress.getHostAddress()); } - log.severe("Server Object get Failed! : "+lastScannedAddress.getHostAddress()); + log.severe("Got Server Object : "+lastScannedAddress.getHostAddress()); + return false; } /** @@ -82,70 +127,22 @@ private void getRemoteObj() { */ public boolean scanNetwork() { InetAddress lastScanIP = lastScannedAddress; - lastScannedIPListIndex = 0; - lastScannedIPSuffix = -1; lastScannedAddress = null; - firstScannedServer = null; - isLastFreshServer = false; - -// try { -// Client client = new Client(); -// lastScannedAddress = client.discoverHost(Configuration.PORT_UCP, Configuration.PORT_SCAN_TIMEOUT); - - //Scanning Network Cards -// Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); -// while(lastScannedAddress==null && networkInterfaces.hasMoreElements()){ -// NetworkInterface networkInterface = networkInterfaces.nextElement(); -// -// for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) { -// if (checkServerOnSubnet(interfaceAddress.getAddress(), interfaceAddress.getNetworkPrefixLength())) { -// log.info("Server Found on "+networkInterface.getDisplayName()); -// break; -// } -// -// } -// -// } -// } catch (SocketException ex) { -// log.severe(ex.toString()); -// } //Using Configuration File - if (checkServerOnSubnet(configuration.getInternalIPs(), configuration.getPrefixLengths(), lastScanIP)) { - log.info("Server Found"); - } - if(firstScannedServer == null) { - log.info("No Server Found"); - return false; - } + if (checkServerOnSubnet(configuration.getInternalIPs(), configuration.getPrefixLengths(), lastScanIP)) { + log.info("Server Found"); + } if(lastScannedAddress == null) { - log.info("No New Server Found, Using already scanned one ["+firstScannedServer+"]"); - lastScannedAddress = firstScannedServer; - serverDone.clear(); - serverDone.add(lastScannedAddress); + log.info("No New Server Found"); + return false; } log.info("Server["+lastScannedAddress.getHostAddress()+"] Found"); return true; } - private boolean isLastFreshServer; - - /** - * Return if Last Scanned Server is New - * @return isNew - */ - public boolean isLastFreshServer() { - return isLastFreshServer; - } - - public void makeServerHistoryClear() { - serverDone.clear(); - isLastFreshServer = false; - lastScannedAddress = null; - firstScannedServer = null; - } /** * Connect if last find Server, Returns null if Server is mine * @return isConnected @@ -156,7 +153,10 @@ public Boolean connect() { return false; } try { - getRemoteObj(); + if(!getRemoteObj(lastScannedAddress)) + { + return false; + } //Verifing Other Server try{ if(divvyServer.isDivvyServer()) { @@ -183,60 +183,76 @@ public Boolean connect() { } /** - * Disconnect connection with server if connecter + * Disconnect connection with server if connected */ - @Deprecated public void disconnect() { + lastScannedAddress = null; + if(divvyServerSocket!=null && divvyServerSocket.isConnected()) + try { + divvyServerSocket.close(); + } catch (IOException ex) { + } + divvyServerSocket = null; + divvyServer = null; } /** * Request Server for project Update */ public void sync() { + if (divvyServer == null) { + log.severe("SYNC failed, proxy interface is null"); + return; + } + List
othersList = null; try { othersList = divvyServer.listDetails(); - } catch (RemoteException ex) { - } - - if(othersList == null) { + } catch (Exception ex) { log.info("Failed to Fetch Others List"); - return; + disconnect(); + return; } + + log.info("Number of Project of Server["+lastScannedAddress.getHostAddress()+"] "+othersList.size()); - List
fetchThese = projectManager.processOtherClientList(othersList); - log.info("Number of New Project of Server["+lastScannedAddress.getHostAddress()+"] "+fetchThese.size()); - for (Details projectDetails : fetchThese) { - - Project newProject = null; - try { - newProject = divvyServer.getProject(projectDetails.getpID().toString()); - } catch (RemoteException ex) { - } - if(newProject == null) - { - log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Fetch :"+projectDetails.getpID() ); - continue; - } - if (!projectManager.canAddThisProject(newProject)) { - log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project, Can't Add this Project :"+projectDetails.getpID() ); - continue; - } - if (!newProject.completeValidation()) { - log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Validation Failed :"+projectDetails.getpID() ); - continue; - } - if (!newProject.save()) { - log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Save : "+newProject.getDetails().getFileName()); - continue; - } - if (!newProject.exportProject()) { - log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Export : "+newProject.getDetails().getFileName()); - continue; + try { + List
fetchThese = projectManager.processOtherClientList(othersList); + log.info("Number of New Project of Server["+lastScannedAddress.getHostAddress()+"] "+fetchThese.size()); + + for (Details projectDetails : fetchThese) { + + Project newProject = null; + try { + newProject = divvyServer.getProject(projectDetails.getpID().toString()); + } catch (Exception ex) { + log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Fetch :"+projectDetails.getpID() ); + continue; + } + if (!projectManager.canAddThisProject(newProject)) { + log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project, Can't Add this Project :"+projectDetails.getpID() ); + continue; + } + if (!newProject.completeValidation()) { + log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Validation Failed :"+projectDetails.getpID() ); + continue; + } + if (!newProject.save()) { + log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Save : "+newProject.getDetails().getFileName()); + continue; + } + if (!newProject.exportProject()) { + log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Export : "+newProject.getDetails().getFileName()); + continue; + } } - + } catch (Exception ex) { + log.info("Failed to Fetch Others List"); + disconnect(); + return; } + } /** @@ -325,7 +341,7 @@ private boolean checkServerOnSubnet(List inetAddresses, List>>>> Foce Stopping"); } @@ -122,14 +158,85 @@ public void forceStop() { fastThread.stop(); } - private class ServerConnection extends UnicastRemoteObject implements ServerInterface { + private class ServerConnection implements ServerInterface { + private Socket clienthandle; + private ObjectInputStream is; + private ObjectOutputStream os; + + ServerConnection() throws Exception { + dotask(); + } - ServerConnection() throws RemoteException { + private void close() { + if(clienthandle != null && clienthandle.isConnected()) + try { + clienthandle.close(); + } catch (IOException ex) { + } + clienthandle = null; + is=null; + os=null; + log.info("Closing Connection"); + } + + private void dotask() throws Exception { + while(true) { + ServerSocket socket = new ServerSocket(Configuration.PORT_RPC); + clienthandle = socket.accept(); + is = new ObjectInputStream(clienthandle.getInputStream()); + os = new ObjectOutputStream(clienthandle.getOutputStream()); + + while(true) { + if(!clienthandle.isConnected()) + break; + Message message = Message.receive(is); + if(SHOW_ALL_MESSAGE_LOG) + log.info("Server Received a Message"); + if(!reply(message,os)) + { + socket.close(); + break; + } + } + } } + + /** + * Reply for a given Message + * @param message + * @param os + * @return hasReply and notTerminated + */ + private boolean reply(Message message, ObjectOutputStream os) { + Message replyblock; + if (message == null) { + close(); + return false; + } else if(message.getType() == Message.TYPE.isDivvyServer) { + replyblock = new Message(Boolean.valueOf(isDivvyServer())); + } else if(message.getType() == Message.TYPE.getUser) { + replyblock = new Message(getUser()); + } else { + close(); + return false; + } + if(!replyblock.send(os)) { + log.severe("Message not send! Closing Connection"); + close(); + return false; + } + return true; + } + + private boolean isRunning() { + if(clienthandle==null || !clienthandle.isConnected()) + return false; + return true; + } @Override - public List
listDetails() throws RemoteException { + public List
listDetails() { log.info("Client Requesting List of Projects"); if(projectManager == null) { log.severe("Project Manager NULL"); @@ -139,7 +246,7 @@ public List
listDetails() throws RemoteException { } @Override - public Project getProject(String uuid) throws RemoteException { + public Project getProject(String uuid) { log.info("Client Requesting Project "+uuid); if(projectManager == null) { log.severe("Project Manager NULL"); @@ -149,16 +256,20 @@ public Project getProject(String uuid) throws RemoteException { } @Override - public boolean isDivvyServer() throws RemoteException { + public boolean isDivvyServer() { log.info("Client Tested isDivvyServer()"); return true; } @Override - public String getUser() throws RemoteException { + public String getUser() { log.info("Client taken User"); return user; } + + + + } } diff --git a/src/divvyhost/network/Message.java b/src/divvyhost/network/Message.java new file mode 100644 index 0000000..15be5d8 --- /dev/null +++ b/src/divvyhost/network/Message.java @@ -0,0 +1,112 @@ +package divvyhost.network; + +import static divvyhost.network.MessageCall.SHOW_ALL_MESSAGE_LOG; +import divvyhost.project.Project; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author scopeinfinity + */ +public class Message implements Serializable { + private static final Logger log = Logger.getLogger(Message.class.getName()); + private static final long serialVersionUID = 6008151131922371591L; + + public enum TYPE {Object,isDivvyServer,getUser}; + + private TYPE type = null; + private Serializable value = null; + + Message(Serializable object) { + this.value = object; + type = TYPE.Object; + } + + Message(TYPE procedure) { + this.value = null; + this.type = procedure; + } + + Message(TYPE procedure, Serializable object) { + this.value = object; + this.type = procedure; + } + + public TYPE getType() { + return type; + } + + public Serializable getValue() { + return value; + } + + /** + * Check if Message is valid + * @return isValid + */ + public boolean isValid() { + if(value!=null || this.type!=TYPE.Object) + return true; + return false; + } + + public static class Signal implements Serializable { + private static final long serialVersionUID = 4854081531922371591L; + enum TYPE {Empty,Terminate}; + private TYPE type; + + public Signal(TYPE type) { + this.type = type; + } + + } + + /** + * Send message via outputStream + * @param os + * @return isSend + */ + public boolean send(ObjectOutputStream oos) { + try { + oos.writeObject(this); + log.info("A message Send"); + return true; + } catch (Exception ex) { + log.severe(ex.toString()); + return false; + } + + } + + /** + * Receive message via inputStream + * @param os + * @return messageObject + */ + public static Message receive(ObjectInputStream ois) { + try { + Message message = (Message) ois.readObject(); + if(message.isValid()) { + if(SHOW_ALL_MESSAGE_LOG) + log.info("A message Received"); + return message; + } + } catch (Exception ex) { + log.severe(ex.toString()); + } + if(SHOW_ALL_MESSAGE_LOG) + log.info("A invalid message Received"); + + return null; + } + + +} diff --git a/src/divvyhost/network/MessageCall.java b/src/divvyhost/network/MessageCall.java new file mode 100644 index 0000000..9af3681 --- /dev/null +++ b/src/divvyhost/network/MessageCall.java @@ -0,0 +1,119 @@ +package divvyhost.network; + +import divvyhost.project.Details; +import divvyhost.project.Project; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.rmi.RemoteException; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author scopeinfinity + */ +public class MessageCall implements ServerInterface { + private static final Logger log = Logger.getLogger(MessageCall.class.getName()); + public static final boolean SHOW_ALL_MESSAGE_LOG = false; + + private Socket socket; + + private ObjectOutputStream outputStream; + private ObjectInputStream inputStream; + + + public MessageCall(Socket socket) throws IOException { + this.socket = socket; + outputStream = new ObjectOutputStream(socket.getOutputStream()); + inputStream = new ObjectInputStream(socket.getInputStream()); + } + + public void close() { + try { + socket.close(); + } catch (IOException ex) { + log.severe(ex.toString()); + } + } + + /** + * Send Message and return reply + * @param message + * @return + */ + private Message process(Message message) { + Message reply = null; + try{ + if(message.send(outputStream)) { + if(SHOW_ALL_MESSAGE_LOG) + log.info("Message send to Server"); + reply = Message.receive(inputStream); + if(reply == null) { + if(socket.isConnected()) { + log.info("Closing Connection from Client"); + socket.close(); + } + } + } + }catch(Exception e) { + log.severe("Process Failed "+e); + try { + socket.close(); + } catch (IOException ex) { + log.severe(e.toString()); + } + } + return reply; + } + + @Override + public List
listDetails() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public Project getProject(String uuid) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean isDivvyServer() throws MessageFailure { + Message r = process(new Message(Message.TYPE.isDivvyServer)); + if(r== null) + throw new MessageFailure("Message Received is NULL"); + if(r.getType() == Message.TYPE.Object) + return (Boolean) r.getValue(); + throw new MessageFailure(Message.TYPE.Object,r.getType()); + } + + @Override + public String getUser() throws MessageFailure{ + Message r = process(new Message(Message.TYPE.getUser)); + if(r== null) + throw new MessageFailure("Message Received is NULL"); + if(r.getType() == Message.TYPE.Object) + return (String) r.getValue(); + throw new MessageFailure(); + } + + static class MessageFailure extends Exception { + + public MessageFailure() { + super("Error in Processing"); + } + + public MessageFailure(String s) { + super("Error in Processing, "+s); + } + + public MessageFailure(Message.TYPE need, Message.TYPE found) { + super("Error in Processing, need "+need+" found "+found); + } + + } +} diff --git a/src/divvyhost/network/NetworkManager.java b/src/divvyhost/network/NetworkManager.java index 3b20ae9..a84c39d 100644 --- a/src/divvyhost/network/NetworkManager.java +++ b/src/divvyhost/network/NetworkManager.java @@ -26,13 +26,13 @@ public class NetworkManager { public NetworkManager(ProjectManager projectManager, String user) { this.projectManager = projectManager; this.user = user; - try { - java.rmi.registry.LocateRegistry.createRegistry(Configuration.PORT_RPC); - log.info("Created Registry :"+Configuration.PORT_RPC); - } catch (RemoteException ex) { - log.severe(ex.toString()); - log.severe("\nCreatingRegistry Failed!!\n\n"); - } +// try { +// java.rmi.registry.LocateRegistry.createRegistry(Configuration.PORT_RPC); +// log.info("Created Registry :"+Configuration.PORT_RPC); +// } catch (RemoteException ex) { +// log.severe(ex.toString()); +// log.severe("\nCreatingRegistry Failed!!\n\n"); +// } internalScanCounter = 0; startServerThread(); } @@ -72,20 +72,17 @@ public void run() { */ void startSync() { internalScanCounter = 0; - if(divvyClient==null) + if (divvyClient==null) divvyClient = new DivvyClient(projectManager, user); + else + divvyClient.reset(); while(true) { if (!divvyClient.scanNetwork()) { - log.info("No other Server Found on Network"); + log.info("Given Scanning range exhausted"); break; } - log.info("Last Server freshOne : "+divvyClient.isLastFreshServer()); - if (!divvyClient.isLastFreshServer()) { - divvyClient.makeServerHistoryClear(); - break; - } //Boolean, null value if ignored Boolean status = divvyClient.connect(); if (status!=null && !status) { @@ -98,7 +95,7 @@ else if(status!=null){ divvyClient.disconnect(); try { Thread.sleep(100); - log.info("Sleep Server"+ ++internalScanCounter); + log.info("Sleep Server "+ ++internalScanCounter); System.out.flush(); System.gc(); } catch (Exception ex) { diff --git a/src/divvyhost/network/ServerInterface.java b/src/divvyhost/network/ServerInterface.java index fa32fef..27afea8 100644 --- a/src/divvyhost/network/ServerInterface.java +++ b/src/divvyhost/network/ServerInterface.java @@ -10,30 +10,30 @@ * ServerInterface for RMI * @author scopeinfinity */ -public interface ServerInterface extends Remote{ +public interface ServerInterface{ /** * Get list of Details of Projects * @return listDetails() */ - public List
listDetails() throws RemoteException; + public List
listDetails() throws MessageCall.MessageFailure; /** * Get project from UUID * @param uuid * @return project */ - public Project getProject(String uuid) throws RemoteException; + public Project getProject(String uuid) throws MessageCall.MessageFailure; /** * For Confirmation RMI is Working and Server is valid * @return isDivvyServer() */ - public boolean isDivvyServer() throws RemoteException; + public boolean isDivvyServer() throws MessageCall.MessageFailure; /** * Return User ID, for maintaining connection with other userDivvy Only * @return */ - public String getUser() throws RemoteException; + public String getUser() throws MessageCall.MessageFailure; } From c9f6df1258f0b7d27f5e9af1aa9853b3525a6f69 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Sun, 16 Oct 2016 21:51:25 +0530 Subject: [PATCH 04/28] Connection Failure Bug Fixed --- nbproject/build-impl.xml | 14 ++++-- nbproject/build-native.xml | 8 ++-- nbproject/genfiles.properties | 4 +- src/divvyhost/network/DivvyClient.java | 32 ------------- src/divvyhost/network/DivvyServer.java | 55 +++++++++++++++------- src/divvyhost/network/Message.java | 12 +++-- src/divvyhost/network/MessageCall.java | 19 ++++++-- src/divvyhost/network/NetworkManager.java | 8 ---- src/divvyhost/network/ServerInterface.java | 2 - 9 files changed, 76 insertions(+), 78 deletions(-) diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml index ca032c4..11b6db5 100644 --- a/nbproject/build-impl.xml +++ b/nbproject/build-impl.xml @@ -192,7 +192,12 @@ is divided into following sections: - + + + + + + @@ -218,6 +223,7 @@ is divided into following sections: + @@ -694,7 +700,7 @@ is divided into following sections: - + @@ -769,7 +775,7 @@ is divided into following sections: - + @@ -796,7 +802,7 @@ is divided into following sections: - + diff --git a/nbproject/build-native.xml b/nbproject/build-native.xml index 75448ad..1aa10a0 100644 --- a/nbproject/build-native.xml +++ b/nbproject/build-native.xml @@ -389,11 +389,9 @@ Portions Copyrighted 2013 Sun Microsystems, Inc. - - - - - + + + diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties index ee6857c..097d620 100644 --- a/nbproject/genfiles.properties +++ b/nbproject/genfiles.properties @@ -4,5 +4,5 @@ build.xml.stylesheet.CRC32=8064a381@1.75.2.48 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. nbproject/build-impl.xml.data.CRC32=32baa53d -nbproject/build-impl.xml.script.CRC32=fd63abd8 -nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 +nbproject/build-impl.xml.script.CRC32=0d03839f +nbproject/build-impl.xml.stylesheet.CRC32=05530350@1.79.1.48 diff --git a/src/divvyhost/network/DivvyClient.java b/src/divvyhost/network/DivvyClient.java index ea2129f..c3c3949 100644 --- a/src/divvyhost/network/DivvyClient.java +++ b/src/divvyhost/network/DivvyClient.java @@ -19,11 +19,6 @@ import java.net.SocketAddress; import java.net.SocketException; import java.net.UnknownHostException; -import java.rmi.Naming; -import java.rmi.NotBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; import java.util.Enumeration; import java.util.HashSet; import java.util.List; @@ -84,33 +79,6 @@ public void reset() { */ private boolean getRemoteObj(InetAddress address) { try { - // try { -//// if (System.getSecurityManager() != null) { -//// System.setSecurityManager(null); -//// } -//// Registry registry = LocateRegistry.getRegistry(lastScannedAddress.getHostAddress().toString(), Configuration.PORT_RPC); -//// -//// divvyServer = (ServerInterface) registry.lookup("divvy"); -// -//// System.getProperties().put("java.rmi.server.hostname", "); -//// -//// divvyServer = (ServerInterface) Naming.lookup( -//// String.format("rmi://%s:%s/", -//// lastScannedAddress.getHostAddress().toString(), -//// String.valueOf(Configuration.PORT_RPC)) -//// + "divvy"); -// log.info("Got Server Object : "+lastScannedAddress.getHostAddress()); -// log.info("Test : "+divvyServer.isDivvyServer()+"\n\n\n"); -// log.info(""+divvyServer.getUser()+"\n\n\n"); -// -// return true; -// } catch (NotBoundException | RemoteException ex) { -// log.severe(ex.toString()); -// ex.printStackTrace(); -//// } catch (MalformedURLException ex) { -//// log.severe(ex.toString()); -// } -// divvyServerSocket = new Socket(address, Configuration.PORT_RPC); divvyServer = new MessageCall(divvyServerSocket); return true; diff --git a/src/divvyhost/network/DivvyServer.java b/src/divvyhost/network/DivvyServer.java index 55f4b76..a4e4827 100644 --- a/src/divvyhost/network/DivvyServer.java +++ b/src/divvyhost/network/DivvyServer.java @@ -14,15 +14,10 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; +import java.io.Serializable; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; -import java.rmi.Naming; -import java.rmi.RMISecurityManager; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.UnicastRemoteObject; import java.util.List; import java.util.UUID; import java.util.logging.Level; @@ -35,6 +30,9 @@ public class DivvyServer { private static final Logger log = Logger.getLogger(DivvyServer.class.getName()); + //Used by ServerConnection + private static ServerSocket socket; + private ServerConnection server; private String user; @@ -67,6 +65,9 @@ public boolean start() { * Check if server not running */ private void checkAndRunServerSocket() { + if(serverThread!=null && serverThread.isAlive()) + return; + serverThread = new Thread("ServerSocket Thread"){ @Override @@ -74,8 +75,10 @@ public void run() { isServerThreadRunning = true; while(isServerThreadRunning) { try { - if(server==null || !server.isRunning()) + if(server==null || !server.socketBinded()){ server = new ServerConnection(); + server.dotask(); + } sleep(Configuration.SERVER_REFRESH_TIMER); } catch (Exception e) { log.severe("Server Socker Failed!\n\n"); @@ -163,11 +166,20 @@ private class ServerConnection implements ServerInterface { private ObjectInputStream is; private ObjectOutputStream os; - ServerConnection() throws Exception { - dotask(); + ServerConnection() { + } + + /** + * Check if Server can still accepts for Incoming Connection + * @return + */ + public boolean socketBinded() { + if(socket == null || socket.isClosed()) + return false; + return true; } - private void close() { + private void disconnect() { if(clienthandle != null && clienthandle.isConnected()) try { clienthandle.close(); @@ -180,8 +192,9 @@ private void close() { } private void dotask() throws Exception { + if(!(socket != null && !socket.isClosed())) + socket = new ServerSocket(Configuration.PORT_RPC); while(true) { - ServerSocket socket = new ServerSocket(Configuration.PORT_RPC); clienthandle = socket.accept(); is = new ObjectInputStream(clienthandle.getInputStream()); os = new ObjectOutputStream(clienthandle.getOutputStream()); @@ -194,7 +207,7 @@ private void dotask() throws Exception { log.info("Server Received a Message"); if(!reply(message,os)) { - socket.close(); + disconnect(); break; } } @@ -211,25 +224,29 @@ private void dotask() throws Exception { private boolean reply(Message message, ObjectOutputStream os) { Message replyblock; if (message == null) { - close(); + disconnect(); return false; } else if(message.getType() == Message.TYPE.isDivvyServer) { replyblock = new Message(Boolean.valueOf(isDivvyServer())); } else if(message.getType() == Message.TYPE.getUser) { replyblock = new Message(getUser()); + } else if(message.getType() == Message.TYPE.getProject) { + replyblock = new Message(getProject((String)message.getValue())); + } else if(message.getType() == Message.TYPE.listDetails) { + replyblock = new Message((Serializable)listDetails()); } else { - close(); + disconnect(); return false; } if(!replyblock.send(os)) { - log.severe("Message not send! Closing Connection"); - close(); + log.severe("Message not send! Disconnecting Connection"); + disconnect(); return false; } return true; } - private boolean isRunning() { + private boolean isConnectToClient() { if(clienthandle==null || !clienthandle.isConnected()) return false; return true; @@ -252,6 +269,10 @@ public Project getProject(String uuid) { log.severe("Project Manager NULL"); return null; } + if(uuid == null) { + log.severe("Client Send UUID null"); + return null; + } return projectManager.getProject(uuid); } diff --git a/src/divvyhost/network/Message.java b/src/divvyhost/network/Message.java index 15be5d8..f45bb16 100644 --- a/src/divvyhost/network/Message.java +++ b/src/divvyhost/network/Message.java @@ -20,7 +20,7 @@ public class Message implements Serializable { private static final Logger log = Logger.getLogger(Message.class.getName()); private static final long serialVersionUID = 6008151131922371591L; - public enum TYPE {Object,isDivvyServer,getUser}; + public enum TYPE {Object,isDivvyServer,getUser,listDetails,getProject}; private TYPE type = null; private Serializable value = null; @@ -77,7 +77,7 @@ public Signal(TYPE type) { public boolean send(ObjectOutputStream oos) { try { oos.writeObject(this); - log.info("A message Send"); + log.info("A message Send "+toString()); return true; } catch (Exception ex) { log.severe(ex.toString()); @@ -96,7 +96,7 @@ public static Message receive(ObjectInputStream ois) { Message message = (Message) ois.readObject(); if(message.isValid()) { if(SHOW_ALL_MESSAGE_LOG) - log.info("A message Received"); + log.info("A message Received "+message); return message; } } catch (Exception ex) { @@ -107,6 +107,12 @@ public static Message receive(ObjectInputStream ois) { return null; } + + @Override + public String toString() { + return "Message{"+type+","+value+"}"; + } + } diff --git a/src/divvyhost/network/MessageCall.java b/src/divvyhost/network/MessageCall.java index 9af3681..5bcd493 100644 --- a/src/divvyhost/network/MessageCall.java +++ b/src/divvyhost/network/MessageCall.java @@ -8,7 +8,6 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.net.Socket; -import java.rmi.RemoteException; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -72,13 +71,23 @@ private Message process(Message message) { } @Override - public List
listDetails() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public List
listDetails() throws MessageFailure { + Message r = process(new Message(Message.TYPE.listDetails)); + if(r== null) + throw new MessageFailure("Message Received is NULL"); + if(r.getType() == Message.TYPE.Object) + return (List
) r.getValue(); + throw new MessageFailure(); } @Override - public Project getProject(String uuid) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public Project getProject(String uuid) throws MessageFailure { + Message r = process(new Message(Message.TYPE.getProject,uuid)); + if(r== null) + throw new MessageFailure("Message Received is NULL"); + if(r.getType() == Message.TYPE.Object) + return (Project) r.getValue(); + throw new MessageFailure(); } @Override diff --git a/src/divvyhost/network/NetworkManager.java b/src/divvyhost/network/NetworkManager.java index a84c39d..b5c11ea 100644 --- a/src/divvyhost/network/NetworkManager.java +++ b/src/divvyhost/network/NetworkManager.java @@ -2,7 +2,6 @@ import divvyhost.configuration.Configuration; import divvyhost.project.ProjectManager; -import java.rmi.RemoteException; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -26,13 +25,6 @@ public class NetworkManager { public NetworkManager(ProjectManager projectManager, String user) { this.projectManager = projectManager; this.user = user; -// try { -// java.rmi.registry.LocateRegistry.createRegistry(Configuration.PORT_RPC); -// log.info("Created Registry :"+Configuration.PORT_RPC); -// } catch (RemoteException ex) { -// log.severe(ex.toString()); -// log.severe("\nCreatingRegistry Failed!!\n\n"); -// } internalScanCounter = 0; startServerThread(); } diff --git a/src/divvyhost/network/ServerInterface.java b/src/divvyhost/network/ServerInterface.java index 27afea8..8db4e7d 100644 --- a/src/divvyhost/network/ServerInterface.java +++ b/src/divvyhost/network/ServerInterface.java @@ -2,8 +2,6 @@ import divvyhost.project.Details; import divvyhost.project.Project; -import java.rmi.Remote; -import java.rmi.RemoteException; import java.util.List; /** From 6333884be91f40da54df902e85f7d2b5412aafac Mon Sep 17 00:00:00 2001 From: Gagan Kumar Date: Sun, 16 Jul 2017 16:44:42 +0530 Subject: [PATCH 05/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b342a87..c98c8e8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Decentralized Hosting : Fully P2P Hosting The Project aims for decentralized Hosting instead of a normal static IP or nameserver based Web Hosting. -Any User can use DivvyHost to upload his HTML website and only he can modify it later on. +Any user can use DivvyHost to upload his HTML website over a intranet and only he can modify it later on. Divvy Client Spreaded Over Intranet having a intranet IP, finds other DivvyClient shares website content which it contains with other, leading to spread of latest data all over intranet. Those HTML website uploaded from any user availabe to everyone even if few of client is down/off/terminated. From 0dd93b8e9a594060e94fdb04eaace8ea8c4c9175 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Mon, 28 Aug 2017 19:57:19 +0530 Subject: [PATCH 06/28] mkdir -p --- wrapper/bin.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wrapper/bin.sh b/wrapper/bin.sh index fc1fb90..39f0dab 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -28,8 +28,8 @@ init; function createAutoStart { filename=~/.config/autostart/Divvy.desktop; - mkdir ~/.config; - mkdir ~/.config/autostart; + mkdir -p ~/.config; + mkdir -p ~/.config/autostart; echo '[Desktop Entry]' > $filename; echo 'Type=Application' >> $filename; @@ -162,4 +162,4 @@ else _help ;; esac -fi \ No newline at end of file +fi From 059174e3da6a9139f02e0285834abb58ed1606a2 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Fri, 1 Sep 2017 13:18:25 +0530 Subject: [PATCH 07/28] Bug Solved : Auto index.html update after refetch --- src/divvyhost/DivvyHost.java | 13 +++++++++++-- src/divvyhost/host/Host.java | 3 ++- src/divvyhost/network/DivvyClient.java | 1 + src/divvyhost/project/ProjectManager.java | 6 ++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/divvyhost/DivvyHost.java b/src/divvyhost/DivvyHost.java index 34ba88c..d0e1647 100644 --- a/src/divvyhost/DivvyHost.java +++ b/src/divvyhost/DivvyHost.java @@ -51,6 +51,11 @@ public DivvyHost() { service.setDivvyHost(this); log.info("Divvy Host Created!"); } + + public void createMainPage() { + projectManager.loadAllProjects(); + hoster.createMainPage(); + } public boolean start() { Configuration configuration = new Configuration(); @@ -78,7 +83,7 @@ public static void main(String[] args) { service = new Service(); DivvyHost divvy = new DivvyHost(); - if(!divvy.checkParameters(Arrays.asList(args))) + if(!divvy.checkParameters(divvy, Arrays.asList(args))) return; if(!divvy.start()) @@ -91,12 +96,16 @@ public static void main(String[] args) { * @param param * @return needToContinue */ - private boolean checkParameters(List params){ + private boolean checkParameters(DivvyHost divvy, List params){ String serviceFlag = null; for (String param : params) { if(param.startsWith("-service=")) serviceFlag = param.substring("-service=".length()); } + if (params.contains("-refresh-html")) { + divvy.createMainPage(); + return false; + } if(!service.start(serviceFlag)) { log.info("Quitting"); return false; diff --git a/src/divvyhost/host/Host.java b/src/divvyhost/host/Host.java index 4adbab4..7173b94 100644 --- a/src/divvyhost/host/Host.java +++ b/src/divvyhost/host/Host.java @@ -100,6 +100,7 @@ public boolean createMainPage() { String securityTagEnd = ""; for (Project project : list) { + log.info("Indexing project "+project.getDetails().getFileName()); sb.append(""+securityTagStart) @@ -124,7 +125,7 @@ public boolean createMainPage() { } catch (IOException ex) { log.severe(ex.toString()); } - log.info("Main Page Createaion Failed!"); + log.info("Main Page Creation Failed!"); return false; } diff --git a/src/divvyhost/network/DivvyClient.java b/src/divvyhost/network/DivvyClient.java index c3c3949..6c3e049 100644 --- a/src/divvyhost/network/DivvyClient.java +++ b/src/divvyhost/network/DivvyClient.java @@ -210,6 +210,7 @@ public void sync() { log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Save : "+newProject.getDetails().getFileName()); continue; } + projectManager.assignProject(newProject); if (!newProject.exportProject()) { log.severe("Server["+lastScannedAddress.getHostAddress()+"] Project Failed to Export : "+newProject.getDetails().getFileName()); continue; diff --git a/src/divvyhost/project/ProjectManager.java b/src/divvyhost/project/ProjectManager.java index 8c1f399..3736c69 100644 --- a/src/divvyhost/project/ProjectManager.java +++ b/src/divvyhost/project/ProjectManager.java @@ -198,6 +198,12 @@ public Project getProject(String pID) { log.severe("Project Not Available : "+pID); return null; } + + public Project assignProject(Project project) { + availableProjects.put(project.getDetails().getpID(), project); + log.severe("Project Added to Repo "+project.getDetails().getpID()); + return null; + } /** * Process other Server List From b294c44f22e6bdb5d060a50a43266db797a4f130 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:02:12 +0530 Subject: [PATCH 08/28] Updated wrapper --- wrapper/bin.cmd | 6 ------ wrapper/bin.sh | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/wrapper/bin.cmd b/wrapper/bin.cmd index 79ce743..5578dc9 100644 --- a/wrapper/bin.cmd +++ b/wrapper/bin.cmd @@ -119,17 +119,11 @@ goto installContinue mkdir %INSTALLDIR% > NUL 2>&1 if %ERRORLEVEL%==0 echo Directory Created %INSTALLDIR% - mkdir %INSTALLDIR%\lib > NUL 2>&1 copy /Y %BASEDIR% %INSTALLDIR% if not %ERRORLEVEL%==0 ( echo Unable to Copy from %BASEDIR% to %INSTALLDIR% EXIT 1 ) - copy /Y %BASEDIR%\lib %INSTALLDIR%\lib - if not %ERRORLEVEL%==0 ( - echo Unable to Copy from %BASEDIR%\lib to %INSTALLDIR%\lib - EXIT 1 - ) call:createAutoStart diff --git a/wrapper/bin.sh b/wrapper/bin.sh index 39f0dab..d06c766 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -103,7 +103,7 @@ function install { sed "s|^: ;BASEDIR.*|: ;BASEDIR\=$HOME/Divvy|g" < "$BASEDIR/bin.sh" > "$HOME/Divvy/bin.sh" chmod +x "$HOME/Divvy/bin.sh" - cp -r "$BASEDIR/lib/" "$HOME/Divvy/" + cp -r "$BASEDIR/Conf" "$HOME/Divvy/" 2> /dev/null cp "$BASEDIR/$JAR_FILE" "$HOME/Divvy/DivvyHost.jar" createAutoStart; From 36a3fdb5bdb042537361cd595b7a5f94c280c0ff Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:14:35 +0530 Subject: [PATCH 09/28] Removed oraclejdk7 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c4774e4..0eb49a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,5 @@ os: - linux jdk: - oraclejdk8 - - oraclejdk7 + - openjdk8 + - openjdk7 From 20b280cfd26bc8af1f5b9feeab5137dab735b798 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:17:12 +0530 Subject: [PATCH 10/28] Increased timeout in travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0eb49a5..df9ff53 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ script: ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ~/Divvy/bin.sh stop + - sleep 10 - | ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } From 69c59fe983473dd7ec2d55a962049a28ceab835b Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:29:26 +0530 Subject: [PATCH 11/28] Direct kill --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index df9ff53..8de20f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,17 @@ script: - bash ./dist/bin.sh install - cd ~ - ~/Divvy/bin.sh start - - sleep 30 + - sleep 10 - | ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ~/Divvy/bin.sh stop + - cat /tmp/divvy.pid - sleep 10 - | ~/Divvy/bin.sh -test 2>&1 | - grep "Another Instance is Running" || { echo "Still Running"; exit 1; } - - echo "Running and Stopping Working Fine"; + grep "Another Instance is Running" || { echo "Still Running"; kill -9 `cat /tmp/divvy.pid` ; exit 1; } + - echo "Execution and Termination Working Fine"; os: - linux From 8066d84baa3125490246ced64a8d21f9ced2c02f Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:38:48 +0530 Subject: [PATCH 12/28] Attempt 2, Bug : Termination failed on travis --- .travis.yml | 12 ++++-------- wrapper/bin.sh | 3 +-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8de20f4..be84800 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,12 @@ script: - bash ./dist/bin.sh install - cd ~ - ~/Divvy/bin.sh start - - sleep 10 - - | - ~/Divvy/bin.sh -test 2>&1 | - grep "Another Instance is Running" || { echo "Not Running"; exit 1; } + - sleep 5 + - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ~/Divvy/bin.sh stop - cat /tmp/divvy.pid - - sleep 10 - - | - ~/Divvy/bin.sh -test 2>&1 | - grep "Another Instance is Running" || { echo "Still Running"; kill -9 `cat /tmp/divvy.pid` ; exit 1; } + - sleep 5 + - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; kill -9 `cat /tmp/divvy.pid` ; exit 1; } - echo "Execution and Termination Working Fine"; os: diff --git a/wrapper/bin.sh b/wrapper/bin.sh index d06c766..a1adf57 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -74,8 +74,7 @@ function _help { # Start DivvyHost function start { pushd $BASEDIR; - nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & - echo $! > $PID_FILE; + nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & echo $! > $PID_FILE; popd echo "DivvyHost Started Called" } From ee1cc46d02435702fabdfbb0cf5e7dd5d6920b45 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:49:08 +0530 Subject: [PATCH 13/28] Reverted bin.sh --- wrapper/bin.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wrapper/bin.sh b/wrapper/bin.sh index a1adf57..39f0dab 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -74,7 +74,8 @@ function _help { # Start DivvyHost function start { pushd $BASEDIR; - nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & echo $! > $PID_FILE; + nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & + echo $! > $PID_FILE; popd echo "DivvyHost Started Called" } @@ -102,7 +103,7 @@ function install { sed "s|^: ;BASEDIR.*|: ;BASEDIR\=$HOME/Divvy|g" < "$BASEDIR/bin.sh" > "$HOME/Divvy/bin.sh" chmod +x "$HOME/Divvy/bin.sh" - cp -r "$BASEDIR/Conf" "$HOME/Divvy/" 2> /dev/null + cp -r "$BASEDIR/lib/" "$HOME/Divvy/" cp "$BASEDIR/$JAR_FILE" "$HOME/Divvy/DivvyHost.jar" createAutoStart; From 7d7478396289ed28b72f573ef7df0460c477f115 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:53:06 +0530 Subject: [PATCH 14/28] Complete Revert back to 059174e3da6a --- .travis.yml | 17 +++++++++-------- wrapper/bin.cmd | 6 ++++++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index be84800..c4774e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,17 +4,18 @@ script: - bash ./dist/bin.sh install - cd ~ - ~/Divvy/bin.sh start - - sleep 5 - - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } + - sleep 30 + - | + ~/Divvy/bin.sh -test 2>&1 | + grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ~/Divvy/bin.sh stop - - cat /tmp/divvy.pid - - sleep 5 - - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; kill -9 `cat /tmp/divvy.pid` ; exit 1; } - - echo "Execution and Termination Working Fine"; + - | + ~/Divvy/bin.sh -test 2>&1 | + grep "Another Instance is Running" || { echo "Still Running"; exit 1; } + - echo "Running and Stopping Working Fine"; os: - linux jdk: - oraclejdk8 - - openjdk8 - - openjdk7 + - oraclejdk7 diff --git a/wrapper/bin.cmd b/wrapper/bin.cmd index 5578dc9..79ce743 100644 --- a/wrapper/bin.cmd +++ b/wrapper/bin.cmd @@ -119,11 +119,17 @@ goto installContinue mkdir %INSTALLDIR% > NUL 2>&1 if %ERRORLEVEL%==0 echo Directory Created %INSTALLDIR% + mkdir %INSTALLDIR%\lib > NUL 2>&1 copy /Y %BASEDIR% %INSTALLDIR% if not %ERRORLEVEL%==0 ( echo Unable to Copy from %BASEDIR% to %INSTALLDIR% EXIT 1 ) + copy /Y %BASEDIR%\lib %INSTALLDIR%\lib + if not %ERRORLEVEL%==0 ( + echo Unable to Copy from %BASEDIR%\lib to %INSTALLDIR%\lib + EXIT 1 + ) call:createAutoStart From fcd4fbc9f6e3a4ee6aba5d4d80448a7db6f50ec5 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 05:03:20 +0530 Subject: [PATCH 15/28] Divvy Stop using ps, grep, awk and kill --- .travis.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index df9ff53..6a62665 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,8 +8,7 @@ script: - | ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - - ~/Divvy/bin.sh stop - - sleep 10 + - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" | awk '{print $2}' | xargs kill - | ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } @@ -19,5 +18,4 @@ os: - linux jdk: - oraclejdk8 - - openjdk8 - - openjdk7 + - oraclejdk7 From bb481dcbcb2602997a39e9977b4ef72400bb441f Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:29:26 +0530 Subject: [PATCH 16/28] Direct kill --- .travis.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6a62665..fad3867 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,18 +4,20 @@ script: - bash ./dist/bin.sh install - cd ~ - ~/Divvy/bin.sh start - - sleep 30 - - | - ~/Divvy/bin.sh -test 2>&1 | + - sleep 10 + - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } + - ps aux + - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" | awk '{print $2}' | xargs kill - - | - ~/Divvy/bin.sh -test 2>&1 | + - sleep 10 + - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } - - echo "Running and Stopping Working Fine"; + - echo "Execution and Termination Working Fine"; os: - linux jdk: - oraclejdk8 - - oraclejdk7 + - openjdk8 + - openjdk7 From 43b0c4e1a6af87589349c958da1814fb74ad6ee3 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:38:48 +0530 Subject: [PATCH 17/28] Attempt 2, Bug : Termination failed on travis --- .travis.yml | 4 +++- wrapper/bin.sh | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index fad3867..fdad6b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,10 +9,12 @@ script: grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ps aux - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" - - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" | awk '{print $2}' | xargs kill - sleep 10 - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } + - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" | awk '{print $2}' | xargs kill + - sleep 5 + - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; kill -9 `cat /tmp/divvy.pid` ; exit 1; } - echo "Execution and Termination Working Fine"; os: diff --git a/wrapper/bin.sh b/wrapper/bin.sh index d06c766..a1adf57 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -74,8 +74,7 @@ function _help { # Start DivvyHost function start { pushd $BASEDIR; - nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & - echo $! > $PID_FILE; + nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & echo $! > $PID_FILE; popd echo "DivvyHost Started Called" } From 36bc39efe02c5c631ce7138728c64f311cc0f9a8 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:49:08 +0530 Subject: [PATCH 18/28] Reverted bin.sh --- wrapper/bin.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wrapper/bin.sh b/wrapper/bin.sh index a1adf57..39f0dab 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -74,7 +74,8 @@ function _help { # Start DivvyHost function start { pushd $BASEDIR; - nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & echo $! > $PID_FILE; + nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & + echo $! > $PID_FILE; popd echo "DivvyHost Started Called" } @@ -102,7 +103,7 @@ function install { sed "s|^: ;BASEDIR.*|: ;BASEDIR\=$HOME/Divvy|g" < "$BASEDIR/bin.sh" > "$HOME/Divvy/bin.sh" chmod +x "$HOME/Divvy/bin.sh" - cp -r "$BASEDIR/Conf" "$HOME/Divvy/" 2> /dev/null + cp -r "$BASEDIR/lib/" "$HOME/Divvy/" cp "$BASEDIR/$JAR_FILE" "$HOME/Divvy/DivvyHost.jar" createAutoStart; From e841e9e6b99aaf499a2eae2a0d054fdf00079523 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 04:53:06 +0530 Subject: [PATCH 19/28] Complete Revert back to 059174e3da6a --- .travis.yml | 3 +-- wrapper/bin.cmd | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fdad6b2..01d9964 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,5 +21,4 @@ os: - linux jdk: - oraclejdk8 - - openjdk8 - - openjdk7 + - oraclejdk7 diff --git a/wrapper/bin.cmd b/wrapper/bin.cmd index 5578dc9..79ce743 100644 --- a/wrapper/bin.cmd +++ b/wrapper/bin.cmd @@ -119,11 +119,17 @@ goto installContinue mkdir %INSTALLDIR% > NUL 2>&1 if %ERRORLEVEL%==0 echo Directory Created %INSTALLDIR% + mkdir %INSTALLDIR%\lib > NUL 2>&1 copy /Y %BASEDIR% %INSTALLDIR% if not %ERRORLEVEL%==0 ( echo Unable to Copy from %BASEDIR% to %INSTALLDIR% EXIT 1 ) + copy /Y %BASEDIR%\lib %INSTALLDIR%\lib + if not %ERRORLEVEL%==0 ( + echo Unable to Copy from %BASEDIR%\lib to %INSTALLDIR%\lib + EXIT 1 + ) call:createAutoStart From 07545823737152069d2e7dcfa576a90e931775ff Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 05:10:18 +0530 Subject: [PATCH 20/28] Attempt 2 --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 01d9964..fdad6b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,4 +21,5 @@ os: - linux jdk: - oraclejdk8 - - oraclejdk7 + - openjdk8 + - openjdk7 From a2f938be3b4dc1d4ce50bb77612428bba16178df Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 05:13:55 +0530 Subject: [PATCH 21/28] attempt 3 --- .travis.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 01d9964..9ddd357 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,17 +8,18 @@ script: - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ps aux - - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" - sleep 10 - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } - - ps aux | grep "java -jar [Dd]ivvy[Hh]ost" | awk '{print $2}' | xargs kill + - ~/Divvy/bin.sh stop - sleep 5 - - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; kill -9 `cat /tmp/divvy.pid` ; exit 1; } + - ps aux + - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } - echo "Execution and Termination Working Fine"; os: - linux jdk: - oraclejdk8 - - oraclejdk7 + - openjdk8 + - openjdk7 \ No newline at end of file From 08d33d918f7d1a8d571b0507ed8766cfe37a3f4a Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 05:19:50 +0530 Subject: [PATCH 22/28] Removed forcequit from travis --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9ddd357..760770c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,7 @@ script: - ~/Divvy/bin.sh stop - sleep 5 - ps aux - - ~/Divvy/bin.sh -test 2>&1 | grep "Another Instance is Running" || { echo "Still Running"; exit 1; } - - echo "Execution and Termination Working Fine"; + - echo "Divvy installation and execution is Working"; os: - linux From 4e1faad06b9d65aab74190f1e55ff4f419337399 Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 05:24:26 +0530 Subject: [PATCH 23/28] removed unnecessary line from .travis.yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 760770c..df315e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,6 @@ script: grep "Another Instance is Running" || { echo "Not Running"; exit 1; } - ps aux - sleep 10 - - ~/Divvy/bin.sh -test 2>&1 | - grep "Another Instance is Running" || { echo "Still Running"; exit 1; } - ~/Divvy/bin.sh stop - sleep 5 - ps aux From 011cb89882f65a632c546bcdbc334a4ddc6c535e Mon Sep 17 00:00:00 2001 From: scopeinfinity Date: Tue, 5 Sep 2017 05:26:24 +0530 Subject: [PATCH 24/28] Reverted better wrapper --- wrapper/bin.cmd | 6 ------ wrapper/bin.sh | 5 ++--- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/wrapper/bin.cmd b/wrapper/bin.cmd index 79ce743..5578dc9 100644 --- a/wrapper/bin.cmd +++ b/wrapper/bin.cmd @@ -119,17 +119,11 @@ goto installContinue mkdir %INSTALLDIR% > NUL 2>&1 if %ERRORLEVEL%==0 echo Directory Created %INSTALLDIR% - mkdir %INSTALLDIR%\lib > NUL 2>&1 copy /Y %BASEDIR% %INSTALLDIR% if not %ERRORLEVEL%==0 ( echo Unable to Copy from %BASEDIR% to %INSTALLDIR% EXIT 1 ) - copy /Y %BASEDIR%\lib %INSTALLDIR%\lib - if not %ERRORLEVEL%==0 ( - echo Unable to Copy from %BASEDIR%\lib to %INSTALLDIR%\lib - EXIT 1 - ) call:createAutoStart diff --git a/wrapper/bin.sh b/wrapper/bin.sh index 39f0dab..a1adf57 100755 --- a/wrapper/bin.sh +++ b/wrapper/bin.sh @@ -74,8 +74,7 @@ function _help { # Start DivvyHost function start { pushd $BASEDIR; - nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & - echo $! > $PID_FILE; + nohup java -jar "$JAR_FILE" -nogui &> $LOG_FILE & echo $! > $PID_FILE; popd echo "DivvyHost Started Called" } @@ -103,7 +102,7 @@ function install { sed "s|^: ;BASEDIR.*|: ;BASEDIR\=$HOME/Divvy|g" < "$BASEDIR/bin.sh" > "$HOME/Divvy/bin.sh" chmod +x "$HOME/Divvy/bin.sh" - cp -r "$BASEDIR/lib/" "$HOME/Divvy/" + cp -r "$BASEDIR/Conf" "$HOME/Divvy/" 2> /dev/null cp "$BASEDIR/$JAR_FILE" "$HOME/Divvy/DivvyHost.jar" createAutoStart; From f00011edb5e4a9ae9d0e486a7ecb58ab58666a15 Mon Sep 17 00:00:00 2001 From: Gagan Kumar Date: Tue, 13 Mar 2018 15:19:51 +0530 Subject: [PATCH 25/28] Images --- images/snap_controller.png | Bin 0 -> 16375 bytes images/snap_project.png | Bin 0 -> 26349 bytes images/snap_web.png | Bin 0 -> 13562 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/snap_controller.png create mode 100644 images/snap_project.png create mode 100644 images/snap_web.png diff --git a/images/snap_controller.png b/images/snap_controller.png new file mode 100644 index 0000000000000000000000000000000000000000..5b6d974317de54e2d9e73dfd0e3d8d0512918ff9 GIT binary patch literal 16375 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�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⁡f3*#F3XoECZ=*P{*x6VOd?q@iIulmX{*0Cz2cuo^J0PF{{tK ztQgvzUnPamU;|_70KQ*V6`Z18gCT&?D}=Z&a@xitK8X$YhZ}3-s2v#VXF{XoD@+x3 zJ}>Y_yy2AIp;p3yZ#=uU_(BduR#Rs={{_ayD2R#?R8A7g!Fk%SRc0Osik;E zw$d;hKtHVN1*~RM5|*6arrY3Ne~8jpXHYl&?pJeZSF_g2gQj@;UII`uVZ&nRt3Z2@ zY)T55_7vf4B?Fo5!qmE4lxs7N2pL&#+E^cobzyqqNo`|&?YNgo_?Ua7hnnu49gZ|z(8{pXXx zm6;HMs~LveJUsdho(aZaBBSgjndMz(+O>6l0pNEKPLdDTH^uxQBSR2-^TTR{?9217 z2zf77(dXZymeQ-+skkHRW8|`bWd-|8vX*0{@7kYxOZBaKrWOA=i9;#_qgoB2>G%Uh zht-taM+DQwl|3$Bt9L%X7Qbi@)z}f)0JMNVDQ@&D&3~fd@@{OD|Mqq|l`ml+i7Qhf zS+~efbK$X=#LOCgYHCMH7+p)8?erh&RE=+2127PkV$B z(iQJn$3jJVuVDGygHcUJ^-u1H_V(Lao2I3-H~S{525v1>No1iV;n@ZGUOqb;$+O5N zmU6Diq&HUIoARPVx{&!LdUJ+UG$*|j56MVW8lAdr@Ft_s?#1y!oCkI|)CxZ|c;vp;Y~HdxJXp;)mg?>^B(Bq^6KMIl9oa4v{bsQ|3rC>t5=u=cI2RJ$!$!`<~RW)1i7qU->3|8zxY{fEug5`JTa{+-7!m2Qu6+Cpqhl<7@4cx!5rojlxLOG`;!zC3M5!+lta z+r8?tQ=>UnNo*{7vyGvB2!-G#yDd(#p(hFS<)2cq(-l4rV`h69?8%#U_}`g}?bqLt*; zt7%>Gbe@m1%xot1_<^wqEDN#dg%j6qoFSWc)y~%E<=t2>39rtXku>GIyP4w+?+IID zje3#dg!P|-G9o^^tr8Y47Ny0b?m=_R;h%5E#00=aMQf*0F=h}NnU<83c$qtvkT>BjIdbNOya34fdGz83p*9=hZmyd%$zJk$o~CWHU25##z%~|TT1E+-2>HA2!LRrzBMLzv zszt@9R1lYRRqR-m@S36iGl!!afRT0qVe^QZrK41!$<(2o->_n`hWA0Nf~$}!gsl<9 zi|o|VaNL<*hz?JsxAHJsi!RpKVgWzCY2pv-mklHC631lpNG%TwHr*6yD#ApE+- zcR60b;}9-C=*Oo=NjbM(mz)$iq&)Fs)mr@2E$FC1HCCWfO#A(6;)(Zl*6Dq zH4bwyjpe_w=mmC~t?s!+TjV*Qh&NklwL3mO&bw?E%H;u2dB}x(2qKD{4PVX**03He zNGRH!V*>!9LDZK4U+$2!*jgF*F*K=vOdxWeK1GCF0;nh~c3%YmaxzKs!iWXRfY~Hv zD&zoP)plIX53u=gQhAhmAOKL=mK5yz#;>$M#NFR!PQVIKBuni4;gcuzB1KO+LBarl zUT!A5^mB-vSX;X|VXW06&Bj{TRxuCNVhi=VAv|DwBCD)?sDf+BP|tUZ$@}Tl-h^1K zB|AY|_%PBs!~60}e2R`y*P+L++H>4!($@66yFJoKJ@1?TtQv&cI$};qDaaE9*B0w| zD|vkLZ}tpV7nC)+&orc;&CQ*#gr**im+pN3wEV@m4-+0Hx57vlXS)j2KPe6-tSx)> z&Ehl$JS~T(8&K{C%#ZC)F^q-0@9oBe>H^K#mh2D_q~Hls9EAo z)!cJ`6j1q2%1`zp?=)iqp7wD~r-21>kz8Q8jIx`r^<~hDI&Nnn#tW4x6V-KYk($j)R?-Fx} z!L!YN*!FIFOjnc#x7X1|hMx0m`bP3SaX^U0pWV4}r> zGW`e-=P>TevFIBAhFaH2U0jN*+0me(UFaYCCDm|{jFfk^Y0JGvgf|*;4tqV5oABW4 z3-W*;OO%2H^Hlu%7TaP^=p*<-3e$tr{o2<-1D^NtQypsHRkG%uLqI)kwAIcmKh3<2 z64PXv^|4(h9c}d4dSe!snWf*{Xbt1)rarA=Jh)cvvJW^%o6xaXO9p6~ z@8CCtYQT6W$>{8o2NVfAxnm{`qVV<&!)C0tkNv_o2(ow}cYl*- zcT@zZy#B65VW&|X>axlwqY&ch3;#g9;LBEf1B?f9Qp#KPWQ}v|6a$+8-2Ck2ZdWfW zA8yr)eM-pDbi$AWe}g;r{TWBNqF{*U_{?BqI7Qmtkq>eqm8(29S#oPPE-DbFx_FR9 zhR!CqHBSlB_9UQiU?EszAEs1~f$`B?Ghstq+nlFYd*Ax_FvJ-Y++Qu;Lf$lQaQg;b zc6-e1+*C)_6S2MRyAD_r@P^x%-SU2uDw54G?Z=xIyb@$di&*oL^t|3jBa|d;ktI*sqt;Z}WWRDFq9HE>phDB$^t6BGkD{w~9~xJLB&D5h z1Mc7 zKD&HbJ@691cXP-IHui>uc*QsOl?Yz_y(f5LmM*u(e>ahr|MagWLW&f>vK5KKZT!Rz z-^^Yip6C4a^vu5>IsU?s|9#nZVMtD^0C5dk`Mse1wn2_t?ccJ$1^(4Ps`ab*6{3&s zu-jhxm#V-23@gZc0RS{1mtzIWSBOs9g4aI#t^OPSn7BS(IJ}({`aiAt-Di-+KX&)O z9s8f*xN~99-@E=Ty8Lp4lIX}e$E*vRGUIZ7FUcLP|0Me#TmLr7e^Zvx9?vjO6NTwn%YrHBt85+PX4ChpM&H7WdprBiLZrJ(BdJovCs-id7 zK{KyJ9_DCoyL&=xG@!Hh8DX+M>rwG%LBuoc`pE8GQQVA}leKmJvbCejJS%(op~?Ed z@%o!*xg&SpAfLT)Jlx=UJ{f3Ndcq4`StXIo*Abix@kl#fs17+@oV2sL?1MwXmqj;%!ik^FkWimiO0ajm zI~4Lw2JD73rj=Di>VDo;lt`05uqi@G63ct>M=5BQ!ROTj0cg{k2vZgI%j_UA_w)oOmMHkj3?@A?E$*9IN5z@ zYowE>GTEYJTX!1uMXaUbJx-FPDXtUYM)~5fP|LLL7*nM6cWTNA9EByeYO^zl7?_Rj ziW2RnHphCNY44t2=`qsExd;Z81U?;BtEV@{kTeFSr!U3Btr0SmHP>!5n^ z^k_c?-%+_$Y)&1=d60BQD`x2g%@xb z@uujfk1iYBbx7dxedU*<#R<=_b`zd)191Pf3ThD5kW_!m(nfb6#oFuFQzc$s*Ayb^ zD?u&Lfcv10RXX5gwR=bLahq{mNxCn}ye}j}TI7=gGk=5T^TRMEai>iz67~`CN=GNL z$FbUToM~Wy0h=xT)ca((F70f(d9neHW~|HSo;@kwZX-=ArlFTyPufm-AGWETbkdiW zxtPpp^FF(=ymKR%PP--_^B9drk7h(Tc zvnnYwq0~%0VyX6aA$O$iLYcj0X{q55;=t*; z0A1F)jvKVm!PTQ9d%(&SGdN!eYZcexldC%2@};e}OX8q9TkDfl z`5VByqt$SHywYoH%{c5T(|s=G?g5zrR>%n*GmIUi+8Cby$yAhY9P?;!ILCf@K@bFL zEY>R98m>_#&2xbzrP>Wvu|~H9PPDRDqIi2%_An=H`GTqgdZr9_pt+^_F!KQz1-%Jn zgvoqmVvr@BLqO*j2KqP9O?A4Y&C_H(m0EAZT*T7FILXUa~+Idro?v;@F!N* z`tYD)@Y}kOwPxI{P{-v0z+zbx7j`%jdwiewo}1wW z^D2|odN3ME^Xb)Lb?4KFCXvfVn4#}hy5AH-5TkYJo*wm&)V{6fm4o=PM!T`kH_T)~6i`Q*K;z&B3eY9};sPQY_p@%~TA6qvuJ+cvDU5fRiBpK{r4B z>mpu0_jcISygGKML7*Lv;PV$rBs3=3-i;iF+Rq-S8N?%mUzOm60gWaSgD`>UX@n%fqHYFwHcw%z>{&VfB zS0RWyC(@m#QQB7*=CY-ADlA!(kawYK8n&ts&`HhNkRd+g$Jz50(M<+w&1K)xv+PQ% z$z5syM)M$}ALaHZp9}F@Wv~!S!lmLPZyT5?t(QgJw;=5C%U<8o?8ni zL8E&L4@%-DQ?xTk0&usa-m3Lqm+xl?0(#2wBRV5CQ@LA9M$l}k69_y0io;B(R*^ots^mA z)RHhhfrS*Y!>aJDF(nq(vou5-%viCNleKLg*DkmQyv~Gg7j;Q_Qh#XM-@wY(P;RjO zE0=mGwRnoHn(hbJ{iCgw3haTgqV!D!OT2<&@+u?sbK~Ys-Ld%~$lk4pKgC=Puo{%4 zinczq`El~C5g;*8V@z?zIMut-xl(!n;2QMee*{E32vf|AGmEnfO(bpea++o!UPWn9 zs0+P#3(3DSUZx`Ff{6AxP@nqPxgxsVJFns4P6aMSY3J?C+o<_<9vikdzeY(nM7?*6 zSiPI4T_~2@C3e8t)z!rom7Da;+a8K1yB$&4k8{-xL_GbV5ucnqyEU&qxi)m2 z*?q|*dfudq7S0ZeGT zbRB%JZ1!}uE|TH2@J&=wM&+@@niSmKkwUCwe{G^q#%7s;p1ZAak*TZyBvbxk(wxOf zK~%$-s7co{f?uTpWV^s@R71EHF&Vv;@%GPA>Q(1)YRJlBwa+zrkW-1;S09tsd?-w>U=P`&2wWoqF|pUU}uvC=> zY5h@;W4-zoJ^oO)w~Y4?+Su7NJGl=6wJY_vh!NzvHHK_eqGR11N7COni(a8&)?oz^ zi=coE&Jx>W8iYbYy_>7+8G0V#rqaL zC**O_-B&$y+rji^E^>i&gV-24qe5uax(_X>MOyrD?zzA6bC-A3`M@z9f>T=CIm&I2 z=js|fQKK-y&eHZEyj=hEWN+NTpSH22or#)&yQ~}sly#p=EeiLnGwj~FA-lZ~cL56; zZfjD69Zlu}7rT|~CD;yu9E@pq_(ap#RFtGEg@PPlB0G`Be{-hWa!@;S*^zWqFfi#AjD^m~%i8Y8Q~mlrL-a;1W#&2>1mtINUZ zgZ@)nETW1ZC4qFTiFHxC;e|gCra!)F!hb>%__A_iuoUml@pgOzNVh>dczH#5b)vB@ zy<2fjQxfcHTQ_MwplmR|4wm|4@@Ee9RDmHr{^m30moA!9=31K$j4r^b>OBlq@CMy& z=8+<=Vh!tqQm%Jif%}uS?+(Ln3=spzI%?@i5Bmq?8^O0KUj*0*6(P`N)26z>uTp?t znc?1*CXJaEK})iGZw-Ahw)9lM1`BQ5tGIZKc(hrF#sxuL4XhM*2BIdM5yo%_(0{sgx!Iy%l&t_$xz(v$2tb`Wwnnqpzo$Ou!P892+vVS#z zjX5daP+=lw$qn*op^WCYuauSfI5;?Xc!ZPsOv=ZdGYT&LdJRhB`%HS=jE#*o@<*I8 z&Moe#2(9&>xJq)3*INAbEid|!m%eD&*?IqLyvAuQK{p{~Waxu&)*N%fSYgOv$Uax$ z56xfFOobSnV4`=(u6<}W6FNCQrng$d{3PDuL(CrCStBXeDXhX&F>0`@ifxMDo_HMh z_{p!DD}cOkg|!dKX^wGxmjka@>KhO~F9ZY{K_h~!cv;|q3eeXh_qhX&3RY{|3m0ktQvGlmz$Q-POG4b<`X(O-iT~k?kU@Wv2ap|bgQ#094}UytY7S`=US!QPJ^@( bJ(t1_jk3tJR^$`Ug8;J9N|2)GZ{PnHX-tU< literal 0 HcmV?d00001 diff --git a/images/snap_web.png b/images/snap_web.png new file mode 100644 index 0000000000000000000000000000000000000000..33c2c1a98ce13643ae8ad67003921799f774aa17 GIT binary patch literal 13562 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 Date: Tue, 13 Mar 2018 16:23:52 +0530 Subject: [PATCH 26/28] Update README.md --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index c98c8e8..43c40ee 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,33 @@ Divvy Client Spreaded Over Intranet having a intranet IP, finds other DivvyClien cd /path/to/DivvyDistribution/ bash bin.sh -run +### Usage + +- DivvyHost is supposed to be started at boottime. To manually start the service use +``` +divvy start +``` + +- To make UI visible at any point time +``` +divvy -show +``` + +- Create new project + - ![Project Init](./images/snap_controller.png) + +- Project List + - ![Project List Page](./images/snap_project.png) + +- Update Project Content + - Goto `/path/to/divvy/Hosted/3b3b1fce-5118-46a3-a0a3-54f733242d51` (For ex. `~/Divvy/Hosted/3b3b1fce-5118-46a3-a0a3-54f733242d51`) + - Host HTML website in current directory + - From UI, select the project and `PULL` it. + +- Web Hosting + - Goto 'http://mydivvyserverip:9999' and see website hosted. + - ![Web Hosting](./images/snap_web.png) + From 55ceacdb24f82717ccce09f99b838f390239707e Mon Sep 17 00:00:00 2001 From: Gagan Kumar Date: Tue, 13 Mar 2018 16:32:46 +0530 Subject: [PATCH 27/28] Update README.md --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 43c40ee..13234e3 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,15 @@ divvy -show - Web Hosting - Goto 'http://mydivvyserverip:9999' and see website hosted. - ![Web Hosting](./images/snap_web.png) + +- Project List with keep on syncing with other divvyhost server within the network. +- Configurations can be editable from `/path/to/divvy/Conf/conf.properties` +``` +#Sample Divvy Host Configuration +#Tue Mar 13 15:12:31 IST 2018 +MAX_SIZE_ON_DISK_MB=200 +INTERNAL_IP=172.16.156.0/24,127.0.0.1/31 +``` From 6672c32cfbd7905638310887aca8f5f961a87c82 Mon Sep 17 00:00:00 2001 From: Gagan Kumar Date: Tue, 13 Mar 2018 16:33:09 +0530 Subject: [PATCH 28/28] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 13234e3..8648f88 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ divvy -show - ![Web Hosting](./images/snap_web.png) - Project List with keep on syncing with other divvyhost server within the network. -- Configurations can be editable from `/path/to/divvy/Conf/conf.properties` +- Configurations can be edited from `/path/to/divvy/Conf/conf.properties` ``` #Sample Divvy Host Configuration #Tue Mar 13 15:12:31 IST 2018