From e25d3a425d0472e299f58fd30f0ddfad7c5fc6e3 Mon Sep 17 00:00:00 2001 From: GustavoHMDS Date: Fri, 9 Oct 2026 03:18:04 -0300 Subject: [PATCH] =?UTF-8?q?WIP:=20Refatora=C3=A7=C3=A3o=20pronta,=20falta?= =?UTF-8?q?=20testes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/misc.xml | 1 - .idea/vcs.xml | 1 + pitiupi.mpChat/.idea/workspace.xml | 85 ++++ pitiupi.screenCast/.idea/modules.xml | 8 + pitiupi.screenCast/.idea/workspace.xml | 34 +- pitiupi.screenCast/build/built-jar.properties | 6 +- .../screenCast/GUI/ScreenCastMenu.class | Bin 1644 -> 766 bytes .../screenCast/GUI/ScreenCastWindow.class | Bin 5897 -> 5757 bytes .../screenCast/net/ScreenCastMessage.class | Bin 925 -> 937 bytes .../screenCast/plugin/ScreenCastPlugin.class | Bin 2459 -> 2042 bytes pitiupi.screenCast/src/.idea/.gitignore | 5 + pitiupi.screenCast/src/.idea/misc.xml | 6 + pitiupi.screenCast/src/.idea/modules.xml | 8 + pitiupi.screenCast/src/.idea/vcs.xml | 6 + pitiupi.screenCast/src/pitiupi.screenCast.iml | 2 +- .../screenCast/GUI/ScreenCastMenu.java | 19 +- .../screenCast/GUI/ScreenCastWindow.java | 15 +- .../screenCast/net/ScreenCastMessage.java | 3 +- .../screenCast/plugin/ScreenCastPlugin.java | 46 +- pitiupi/docs/PluginTutorial.md | 8 +- pitiupi/nbproject/build-impl.xml | 8 +- pitiupi/src/pitiupi/GUI/MainWindow.java | 38 +- .../pitiupi/control/ConnectionManager.java | 67 +-- .../control/plugins/PluginManager.java | 24 - .../src/pitiupi/models/ConnectionData.java | 44 ++ .../pitiupi/models/Messages/InfoMessage.java | 50 -- .../src/pitiupi/models/Messages/InfoType.java | 9 - pitiupi/src/pitiupi/models/Plugin.java | 11 +- .../pitiupi/net/tcp/ConnectionFactory.java | 229 --------- .../src/pitiupi/net/tcp/HandshakeMessage.java | 30 -- pitiupi/src/pitiupi/net/tcp/SocketTCP.java | 456 ------------------ pitiupi/src/pitiupi/net/tcp/TcpClient.java | 34 ++ .../src/pitiupi/net/tcp/TcpConnection.java | 171 ------- .../pitiupi/net/tcp/TcpConnectionManager.java | 264 ---------- pitiupi/src/pitiupi/net/tcp/TcpFactory.java | 188 ++++++++ pitiupi/src/pitiupi/net/tcp/TcpHandshake.java | 36 ++ .../pitiupi/net/tcp/TcpHandshakeResponse.java | 15 + pitiupi/src/pitiupi/net/tcp/TcpManager.java | 163 +++++++ pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java | 70 +++ pitiupi/src/pitiupi/net/tcp/TcpServer.java | 61 +++ pitiupi/src/pitiupi/plugin/Pitiupi.java | 12 +- 41 files changed, 870 insertions(+), 1363 deletions(-) create mode 100644 pitiupi.mpChat/.idea/workspace.xml create mode 100644 pitiupi.screenCast/.idea/modules.xml create mode 100644 pitiupi.screenCast/src/.idea/.gitignore create mode 100644 pitiupi.screenCast/src/.idea/misc.xml create mode 100644 pitiupi.screenCast/src/.idea/modules.xml create mode 100644 pitiupi.screenCast/src/.idea/vcs.xml create mode 100644 pitiupi/src/pitiupi/models/ConnectionData.java delete mode 100644 pitiupi/src/pitiupi/models/Messages/InfoMessage.java delete mode 100644 pitiupi/src/pitiupi/models/Messages/InfoType.java delete mode 100644 pitiupi/src/pitiupi/net/tcp/ConnectionFactory.java delete mode 100644 pitiupi/src/pitiupi/net/tcp/HandshakeMessage.java delete mode 100644 pitiupi/src/pitiupi/net/tcp/SocketTCP.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpClient.java delete mode 100644 pitiupi/src/pitiupi/net/tcp/TcpConnection.java delete mode 100644 pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpFactory.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpHandshake.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpHandshakeResponse.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpManager.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java create mode 100644 pitiupi/src/pitiupi/net/tcp/TcpServer.java diff --git a/.idea/misc.xml b/.idea/misc.xml index b1566b1..9bc6d9a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 35eb1dd..67cb988 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/pitiupi.mpChat/.idea/workspace.xml b/pitiupi.mpChat/.idea/workspace.xml new file mode 100644 index 0000000..d889ae4 --- /dev/null +++ b/pitiupi.mpChat/.idea/workspace.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + "associatedIndex": 6 +} + + + + { + "keyToString": { + "ModuleVcsDetector.initialDetectionPerformed": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", + "RunOnceActivity.git.unshallow": "true", + "git-widget-placeholder": "update/mpChat", + "ignore.virus.scanning.warn.message": "true", + "kotlin-language-version-configured": "true", + "last_opened_file_path": "C:/Users/extre/OneDrive/Documentos/Faculdade/2026_02/Monitoria/Pitiupi/pitiupi.mpChat", + "project.structure.last.edited": "Modules", + "project.structure.proportion": "0.15", + "project.structure.side.proportion": "0.2", + "settings.editor.selected.configurable": "preferences.keymap" + } +} + + + + + + + + + + 1790904201925 + + + + \ No newline at end of file diff --git a/pitiupi.screenCast/.idea/modules.xml b/pitiupi.screenCast/.idea/modules.xml new file mode 100644 index 0000000..81367dd --- /dev/null +++ b/pitiupi.screenCast/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/pitiupi.screenCast/.idea/workspace.xml b/pitiupi.screenCast/.idea/workspace.xml index 0438088..c43b589 100644 --- a/pitiupi.screenCast/.idea/workspace.xml +++ b/pitiupi.screenCast/.idea/workspace.xml @@ -5,10 +5,9 @@ - - - - + + + + + + + + + + + - - - - - - - - - diff --git a/pitiupi.screenCast/build/built-jar.properties b/pitiupi.screenCast/build/built-jar.properties index 1f21a31..a338b51 100644 --- a/pitiupi.screenCast/build/built-jar.properties +++ b/pitiupi.screenCast/build/built-jar.properties @@ -1,6 +1,6 @@ -#Tue, 29 Sep 2026 11:04:58 -0300 +#Wed, 07 Oct 2026 15:36:37 -0300 -C\:\\Users\\Gustavo\\OneDrive\\Documentos\\Faculdade\\2026_2\\Monitoria\\pitiupi\\pitiupi.screenCast= +C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi.screenCast= -C\:\\Users\\Gustavo\\OneDrive\\Documentos\\Faculdade\\2026_2\\Monitoria\\pitiupi\\pitiupi= +C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi= diff --git a/pitiupi.screenCast/build/classes/pitiupi/screenCast/GUI/ScreenCastMenu.class b/pitiupi.screenCast/build/classes/pitiupi/screenCast/GUI/ScreenCastMenu.class index 4c002f112524930cac724e89e79f82f91994c23b..b38ee9aa455f3cc259e18e24500f2a0f936a96e2 100644 GIT binary patch delta 414 zcmZ9I-%0{O6vn^VRcF=Jay9#}20>=TUV0aV)Kx-YFR*OGGPTW$&PLEhm)%9-ixl(+ zy66FVmYzX6t5VU;Ip^bi-)|1{WslR{&++>QfCDsgFko_|Y^0H4X!oU-abLO@(WwZB zZda(7Y8-0mdqe$C?)zFs>S61)kV6r39P>6xa7M?*Udcj*A>Z={La0WEvZFiWzR4ri z38jC|zyqOA#Fb{KG`Ek=yi3mwJr%e;J&-CGU7MRX*nman0SpfEuxT=BPGf;;mDC|^ zlYOrB2G-hn0e>Q8V3BH(yg(T#RFI{_5~=Fcjb*HmqTGbah_;H%jM*j+qg}Q&drPWa5dM}H4lPGp${m%PAZAr2W@h>Q_s1^)OV|jb1pxy=6Rl`t=={tN_>tuuO8b+w zz9H-~L))CRrJ835#1q*N+7U7kHqil-VWK3JESIF^UOmm8!~y}S{hqlSvcNYWt_!x&+R z@SKv4{Z6>Mj$0IYhSm7x1#7WV3BL?}s4Q_HY-KG}p)%4_!WM2y=NdC{8{@=;=ksTe z8OCZl{1+gR)dJozF^M>Jl^_`I`Injt_SrQ1!$@Mvz_f|Gm|>W_Vlx@S)Ud4dxZs!Za8_zh-ez}xtUabbtnTuP;CD9mu^+P}9#dmAVQQh$x za+((kn^K7sgSlqYhNKJJ^Mq$$jUK2bP0lONz#E34i$m!l^tHe!HKB!ey#+D-3evBb zem|-nM(?Nv+9$HUAW)5)O@0SUPMyF=#;#QmN&ZCFhwtb)L2vRKdSinX+|)mkKX41E zU^J<%3MRI{Rx$6>-!aMwTKpio5ke0l=*1xV=oRRvTmyJc)&q*@^)uoj9+3siRvFS< z>Y1tWS|CgF4^bK;SV5wmM*lkiv1rFo16=47E`+CeMlb0Y4xAc=H^;`};ed z+*S8hjd|kjqfY}^PV@Jf+ve+o;aGTNFia@!NN;_E{Ud$hh;Lth*t@G03GtUwc2P#m%!Cn zDPObJHD61xw{YyCAr))4z;y~2Z7|roUB_yIGwIYwEZpzw4i6}+8yg$ANK zLhN~E+VpOLJ*XszVNO-3b9B|#P>A!n7a!8`VSzhv=erKAvNt;J#z%DABk)mtOpe*( z#@)DAU>`mq%k>4?eZ+a}%&x33aX&t#Xqt1|=>UqIGlI=(3ICG3|wjWWmM_==7v1PtbKsJ^N+@o za96GKn>dDVsc65ga=*^6a{pa?PsjHKet;A5jjVunianR}atbaraT2E$^AFkK%8pFU zCzUo<_2_t3-fI>aXYicj`mub%EGcirPX&I4UEG~)zdN|8B{~w}Y_{ST0>8ws>2ah@tRl^-ljF$4*$&d&gi<+IFO?^94wQSGHsXK`nkA@&JWe}Rm^6nfb*d8N zrRpPhI`c`ZQ-yZiIoqz&TtXRd%j8SBuDAhh8 zaTWn;p`nhaqYqBZMLy=?tRkiq;J^4EpIBAW5b-UK&9s>pSe}@+*Xt@spvXH7Pr!B2 zBrcx7Oz%^eX-#0ZTD?b61um{ywm(l@xE3dHxpz8_=D;MDO~B8ht-NiUKs(d@{Iw_0 znP&I9u2Jj>tYWqvW?M6X0B_d^@-*aGF^L-z*mORwMaX8S7P6a*IGn{ipD#ltE=N5Y zu@qM@(oH0Bg#8#67>>R1FT@s+v1FPJG*xk=b(cf?z#Z^`V8{*_&;7} zAKqXw4VGGk{+pQ`bhA$?2ksPRHy%Kq+NDnk+>23Zepdt8*>M$hfI6mdduL55Z&PvH z)m6)$=1k$^4cauM!cI@%lWuJi4>Z`+$!$yEz0Q0#X-NIEojv1YM;AFdT9kdn_ds5@%D1O;D^eB_3Xn2?wT7I@{J7nrZ@|PSfm$i{79|g7fDq> z8+2w|f^!V3h1nMn@y^OZRb(M6hf<3o(#Xbvw;`A8q%$7}mk!**kEX$Vsf=aA`X;W_ zDa)^unF}I8*-YXtrCZ~y%V5bp(>NBWPT=WDe6zD=3g79P#>qhKB%V>IoCzp6e$-&I zF0vQcQ;Ge_qg;ZV<^p>HKX1_8I!iyFz^}*POkFG3et&qcoyO0dRyT^S?*2TE!UoM{ zB+-i};d5(g`~+6>%sI$FY)`JKdR@Xr3WT{(1{jP8!!U>nZkc+1qn9Gag*(D>J6LLn z(H&*ko0;n-=GukbxFrec^*mmdqL^~X$>3I@o^pAb+2gEiCFPNeaj4+GbNMubG0o#d zDeSGRB9GB6U@Bvj>4!Z@?D-wS4l1M~#$HwJLfFo+W?hG&L+UuDQ?ZVdI?k}Fy4Mxe z32TN5PTIk^3l=rCQ~BUxNKH-QWyEGC@YnaL_S<+2?!KT+MaC^brF0Q%vQinlW1)+w aoL6oyn$34J=@R~G_{QX$TJq66xZeT8QAY;= delta 3003 zcmai030PFu75>l6oA-t{7X}6q1`srgz_5&pXbW)zHxN+cmcf{29G@_VGlUsj8sj9< zCbdgid)r!VYg)S)lO`=O3{+cd_ck@LizZ#u+I>&DrcIOBb7w}dY4i2tn|JTK_dnZz z7T(LXhw9BIUO96Pz%rV5*z8N>g`$y&6^e(Wk#IS{S#Tmpz>Qpj*)tR#7cTuT;T7Yz&DtWitVHt#CZT|^GCLIAIWTC&VmAfZ2LdfO z`MOY`2s$Ar90|u;84-{+(LGMwKya?>4G!}0A`|79A>crn@?@q!C932as;Ml8PoM_1%7ztR zXZ15L);5Ax)m^>O!=Bd*_%TbKprErHa|9YNSGsHq^mzjF@jBUMtEDD+hpl+>jRZ$m zbTHm)Vj&h8SS+vvE%ISoo3@ltC}-OX-6mRLS01boScx`SX0M}Fvcq1Q-JU-05?GBj za>!oeY{g9i>#$xvXs=IfBv$Ei*}ztUCv_U!9rrI~TqMS&VIqiaiZY9k>!@mLtKO(=_XzYN zEG=!Owu4Y1*XkwmAx${@uv38}@|@P74+z|jLHUB#;_SvQf!)|6mpB?ry75MVJCy5s zC>RM@{U+LRr@($BGHpmV4{9#*wV zD5@IojffTZcXHKp!!=iTYYQ%1c+$Xw@;Re;#zTbsR0hIPf7|M1dqUQL>P{1%z#|48 z75F5M%Q|P7YZ#9iI4$rvM&w3kcg`rr418MP49=<=b7vLG%g##AFg`1A4xb~~`=dRC z)+%|$>6MjPHQMJ1rLs7u)HHDfUljNfzAX1;6-_yhud0x~#-&oVxkcsr34FuA1%W5= zlpM|qXy4>kljpMwSn?vit-#-rb!JibF6feu|$N__@F@@Jso$InUXS zUkm&Ozm=0*_5AXCfj{7nvfVYGoAh~sKjF{vkgIWV%LMzcJ=Vq(bPX~wyiPykT1T2; zko$Cfwu`hWio8elQW?lOKDFHKph|8DsuEO2oR*kUQOmZqQspS?0)_$bwCc0-iKB)%vNGhf`|h9!jm;!Mu9$7yK23zopLp&UhZD zy!XHbky?2&^Xg=b126FNAN;n1aduw4zEO~`W(0<>b_CfzPu>VTzGMQEhxyiqfAX^! zIzQ{7@yN@`7Gn61?%9K^>69Y+n+M>c-QY!~({*21c=L1j~8b&fAU= zbn^9b{&gm?HiKU7*`Ux#Y+_h9!)_VD7TyK}c^dNU7)2t@{wpl z37VPj8_~#fdodPa6+buf><;m;?!hw7!EzkHiWCFsXb)x>AT^OP(cZ@jZLGMlpPd-m&c(9Stn#s6tL*t%6Q_mP=lXezI0{mhman!4g;(;cIdhTAfhamE>l{pVF=N1d}vdDJs z&mP>2a4L+IFc`Ox?8Iy{x`711#ubtoh!WpUsu`Af+p7vng#OyD+bBEh(H z#7OKVXlC+PEP8U6&9L$V2(eZZ#Td5>Gmvm93!yn#?@R6lr33IQib}k%OS+QZjY2b)~^9Gd~xM(18 ziQA+8MRo0lef%1np;I2%)L_rl`BGM;5-EI4SVa=g{f}xtzytB%b!{rf-4ZmFrm-eF h-M~6*G@WKBT__={=EDk_$-h~AWO5D6rUq(+_up2MhPnU% diff --git a/pitiupi.screenCast/build/classes/pitiupi/screenCast/net/ScreenCastMessage.class b/pitiupi.screenCast/build/classes/pitiupi/screenCast/net/ScreenCastMessage.class index dc8a7ea26b95b1e4f03cc4086d68875edca92d3e..c1c6cb9cf2a14ef07037430e8b6dab6fff8bbb63 100644 GIT binary patch delta 99 zcmbQszLI@{q=bAyW=UpgL8g9geoAUivA%C=adBdLYVk(ZdyK3i3@i+ylR22&c*TJ% z2?kCENd`U!smaky0gMWh*D%?#sxz=MXiR>`i_@% diff --git a/pitiupi.screenCast/build/classes/pitiupi/screenCast/plugin/ScreenCastPlugin.class b/pitiupi.screenCast/build/classes/pitiupi/screenCast/plugin/ScreenCastPlugin.class index b26bee9dd227c82c34b55127f064982464dae879..447b00a4b9377d964b1b4cdc4faf2dc3b8173a26 100644 GIT binary patch literal 2042 zcmah~Yi}Dx6g^|7S=-qrscVO}0qV33^&|1R(DLYpl;AdPz)phJzQ5%RZ&BoVJTvJ)oAJiDi>`;axrWr4Aa$5-yqQ{ zSYxP0WGR^z_foyk<*sWC_#B$h6tq;_!21mIPmE(j8+*dkI>PlBGWKJJYt@eb-ZZR% z_VC~d?|XVJcom20vaN2axP=cHE;zi;#WC;2ofy(FtS1|MlQ!B6!%Umb5yL`9SbTRp zJmAjP#(_z1iXFRenEQq!J&Sa;+WE`I)gIc-mWpEq@`-OFMq4lRMb%v zkf(sHv3F!UR4$tDbH^1no$9l+*g52uCmst%6XXb(v* zMhX&VWqXT(Wq4zUB<{Qxu#u`x+caEvqY<;kP2^Ww9vgq6Z_JGU@R!V5ajN!=_P?uRYJ`f8RAmVO_6toi_?Sld83g@=Ml}e)ZRoUO*ubYW zO7J>8Wn8wX{7jEDbU6jh#?Z|P(EMp=Wg_&>1nAsp=;}o1XA_`jPebbyp<6f~?)5t| zO&WQ*{sIe+8YejSJ4%gTap?srkLtgnbb>3-v6@&ok1U02WM7M}>>Gair65J<2PMPj zX!|DKrGL$gZ)z(vb+*{}1M8<{-b%@w4fAaK-rpzO1MGxy4=J1EFE?JI@go)+f1}Zr zGS{Bt11U1=*EtY*n?&j;kxjDR75b)9n|y&UeYxdWZW$ePiD1{qvl2}o(lmp;{{bkO B?hyb0 literal 2459 zcmah~TT|Oc7(MF?vK8`Q~zrPc0tzUw*bKmYmVR{(4HHUb~~3Ib6C(ZRUhKWl3JXv-9CO4jKCL89@g;vyG zMbLq6nP?BgN^HwP6?Dxs^ipzF*EGsl=vqeA)B|p$u9$4pgmV_ph0%u_3i_kCi2;U$ zFDcL)?wlIP)wcrQjCBxJS6wqBC5pMKFkAS@La$sYc0f zixAI6FoID9V^Q42J2V0(n$xUCCm0m9Sd_sSZp5}E0Zx+DSAr<;MDC{IIR)=B3|Z6= zdUEB|SqXYHiGE0U24mKa8?14~@1CAC`J*3EUjrWIYQ zFqZK^!NVxhSZNVs_Oxp9GHFV$ktF--#Z$j_4WZd1NJa1nYYNt**uY~a4J(=(fFWe+ zG%*@3Lu(W3yX52vK31?5MF!iBlh!~)n2HQr(kK&qbXFMKg`C^Gyi`7+b7vg3k{ta6 zR`nuh=-3h(->#MSx$#upFVRl-mR?XxIn@yI+ujVAhoVXX@KV_SNHj%R9&mG8EtAtQ ztxR^)@P#55F!Obj#(%6}^#-kDs{IX{Cj1R=F+%tPri~pNgKJ(pQq+jNZY-IoNAj_>iTiJO=vll%CPL0iGd8 zUkuOjn4S_mO>b%E?^b@KS2J|D3F>#DpLsyTm!V^x(7Xrq+GXg3C-idCh8+;@`R?o2cnjD8QOG$iazf*`5|I!}aZhZ<$v;n5zktA6enqB*x)eGY41?KbT*ttBcwWeW(Tz2Uc#)ry( DV!csu diff --git a/pitiupi.screenCast/src/.idea/.gitignore b/pitiupi.screenCast/src/.idea/.gitignore new file mode 100644 index 0000000..b58b603 --- /dev/null +++ b/pitiupi.screenCast/src/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/pitiupi.screenCast/src/.idea/misc.xml b/pitiupi.screenCast/src/.idea/misc.xml new file mode 100644 index 0000000..75fa691 --- /dev/null +++ b/pitiupi.screenCast/src/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pitiupi.screenCast/src/.idea/modules.xml b/pitiupi.screenCast/src/.idea/modules.xml new file mode 100644 index 0000000..ace7c68 --- /dev/null +++ b/pitiupi.screenCast/src/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/pitiupi.screenCast/src/.idea/vcs.xml b/pitiupi.screenCast/src/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/pitiupi.screenCast/src/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pitiupi.screenCast/src/pitiupi.screenCast.iml b/pitiupi.screenCast/src/pitiupi.screenCast.iml index 937cc1c..35850c2 100644 --- a/pitiupi.screenCast/src/pitiupi.screenCast.iml +++ b/pitiupi.screenCast/src/pitiupi.screenCast.iml @@ -6,6 +6,7 @@ + @@ -15,6 +16,5 @@ - \ No newline at end of file diff --git a/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastMenu.java b/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastMenu.java index 93abd86..44a453d 100644 --- a/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastMenu.java +++ b/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastMenu.java @@ -4,28 +4,29 @@ */ package pitiupi.screenCast.GUI; +import pitiupi.models.Menus.MulticastMenus.MulticastActionMenu; + import java.awt.event.ActionEvent; -import javax.swing.JMenu; /** * * @author flavio */ -public class ScreenCastMenu extends JMenu { +public class ScreenCastMenu extends MulticastActionMenu { private final ScreenCastWindow screenCastWindow; - private final javax.swing.JMenuItem menuItem; public ScreenCastMenu(ScreenCastWindow screenCastWindow) { this.screenCastWindow = screenCastWindow; - this.setText("Screen Cast"); - menuItem = new javax.swing.JMenuItem(); - menuItem.setText("ScreenCast Window"); - menuItem.addActionListener(this::chatMenuActionPerformed); - this.add(menuItem); } - private void chatMenuActionPerformed(ActionEvent ae) { + @Override + public void onClick() { this.screenCastWindow.setVisible(true); } + + @Override + public String getText() { + return "Screen Cast"; + } } diff --git a/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastWindow.java b/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastWindow.java index cfd0022..c288ef2 100644 --- a/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastWindow.java +++ b/pitiupi.screenCast/src/pitiupi/screenCast/GUI/ScreenCastWindow.java @@ -7,6 +7,7 @@ package pitiupi.screenCast.GUI; import pitiupi.control.ConnectionManager; import pitiupi.control.GuiManager; +import pitiupi.plugin.Pitiupi; import pitiupi.screenCast.control.AlarmClock; import pitiupi.screenCast.control.ImageTransformation; import pitiupi.screenCast.control.ScreenShot; @@ -22,8 +23,6 @@ import java.util.logging.Logger; import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; -import pitiupi.GUI.MainWindow; -import pitiupi.net.Message; /** * @@ -40,13 +39,11 @@ public class ScreenCastWindow extends javax.swing.JFrame { public final static int TIME = 1000; private float compressRatio; - private final ConnectionManager connectionManager; - private final GuiManager guiManager; - public ScreenCastWindow(ConnectionManager connectionManager, GuiManager guiManager) { - this.connectionManager = connectionManager; - this.guiManager = guiManager; + private final Pitiupi pitiupi; + public ScreenCastWindow(Pitiupi pitiupi) { + this.pitiupi = pitiupi; this.compressRatio = 0.5f; this.initComponents(); } @@ -96,9 +93,9 @@ public class ScreenCastWindow extends javax.swing.JFrame { BufferedImage image = ScreenShot.takeAShot(); BufferedImage rescaled = ImageTransformation.resize(image, 1024, 768); byte[] byteImage = ImageTransformation.compress(rescaled, compressRatio); - ScreenCastMessage message = new ScreenCastMessage(this.connectionManager.getUserName(), byteImage); + ScreenCastMessage message = new ScreenCastMessage(pitiupi.getUserName(), byteImage); - if (!connectionManager.sendUdpMulticast(message)) this.compressRatio -= 0.1f; + if (!pitiupi.sendUdpMulticast(message)) this.compressRatio -= 0.1f; } catch (AWTException | IOException ex) { Logger.getLogger(AlarmClock.class.getName()).log(Level.SEVERE, null, ex); } diff --git a/pitiupi.screenCast/src/pitiupi/screenCast/net/ScreenCastMessage.java b/pitiupi.screenCast/src/pitiupi/screenCast/net/ScreenCastMessage.java index 99b4ae1..c820e01 100644 --- a/pitiupi.screenCast/src/pitiupi/screenCast/net/ScreenCastMessage.java +++ b/pitiupi.screenCast/src/pitiupi/screenCast/net/ScreenCastMessage.java @@ -5,7 +5,8 @@ */ package pitiupi.screenCast.net; -import pitiupi.net.Message; + +import pitiupi.models.Messages.Message; /** * diff --git a/pitiupi.screenCast/src/pitiupi/screenCast/plugin/ScreenCastPlugin.java b/pitiupi.screenCast/src/pitiupi/screenCast/plugin/ScreenCastPlugin.java index 50641a6..139da7b 100644 --- a/pitiupi.screenCast/src/pitiupi/screenCast/plugin/ScreenCastPlugin.java +++ b/pitiupi.screenCast/src/pitiupi/screenCast/plugin/ScreenCastPlugin.java @@ -4,14 +4,12 @@ */ package pitiupi.screenCast.plugin; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import pitiupi.GUI.MainWindow; -import pitiupi.control.ConnectionManager; -import pitiupi.control.GuiManager; -import pitiupi.net.Message; -import pitiupi.plugin.Plugin; +import java.util.List; + +import pitiupi.models.Menus.MenuCategory; +import pitiupi.models.Messages.Message; +import pitiupi.models.Plugin; +import pitiupi.plugin.Pitiupi; import pitiupi.screenCast.GUI.ScreenCastMenu; import pitiupi.screenCast.GUI.ScreenCastWindow; import pitiupi.screenCast.net.ScreenCastMessage; @@ -20,7 +18,7 @@ import pitiupi.screenCast.net.ScreenCastMessage; * * @author flavio */ -public class ScreenCastPlugin implements Plugin { +public class ScreenCastPlugin extends Plugin { private ScreenCastWindow screenCastWindow; @@ -45,28 +43,20 @@ public class ScreenCastPlugin implements Plugin { } @Override - public void createPlugin(ConnectionManager connectionManager, GuiManager guiManager) { - this.screenCastWindow = new ScreenCastWindow(connectionManager, guiManager); - guiManager.addMenu(new ScreenCastMenu(screenCastWindow)); + public void createPlugin(Pitiupi pitiupi) { + this.screenCastWindow = new ScreenCastWindow(pitiupi); + pitiupi.createMenu(MenuCategory.Streaming, new ScreenCastMenu(screenCastWindow)); } @Override - public void receiveMessage(byte[] message) { - ByteArrayInputStream bis = new ByteArrayInputStream(message); - ObjectInputStream ois; - try { - ois = new ObjectInputStream(bis); - if (ois.readObject() instanceof ScreenCastMessage msg) { - this.screenCastWindow.receiveScreenCastMessage(msg); - } - } catch (IOException | ClassNotFoundException ex) { - System.out.println(ex.toString()); + public List> getMessages() { + return List.of(ScreenCastMessage.class); + } + + @Override + public void receiveMessage(Message message) { + if (message instanceof ScreenCastMessage msg) { + this.screenCastWindow.receiveScreenCastMessage(msg); } } - - @Override - public Message getMessage() { - return new ScreenCastMessage(); - } - } diff --git a/pitiupi/docs/PluginTutorial.md b/pitiupi/docs/PluginTutorial.md index 9734902..b7ff62e 100644 --- a/pitiupi/docs/PluginTutorial.md +++ b/pitiupi/docs/PluginTutorial.md @@ -66,15 +66,15 @@ A classe `Pitiupi` é a interface que o seu plugin vai receber quando for criado Envia uma mensagem multicast, retorna `boolean` indicando se teve sucesso. -### boolean sendUdpUnicast(Message message, InetAddress address) +### boolean sendUdpUnicast(Message message, InetAddress receiverAddress) Envia uma mensagem unicast via udp para o endereço fornecido, retorna `boolean` indicando se teve sucesso. -### boolean sendTcp(Message message, InetAddress address) +### boolean sendTcp(Message message, InetAddress receiverAddress) Envia uma mensagem unicast via tcp para o endereço fornecido, retorna `boolean` indicando se teve sucesso. -### [REF] TcpConnection connectTcp(InetAddress address, String senderId, String receiverId) +### [REF] TcpConnection connectTcp(InetAddress receiverAddress, String senderId, String receiverId) Pede uma conexão tcp privada para o seu plugin com outro usuário, para utilizar essa funcionalidade é necessário implementar alguns métodos opcionais em Plugin. Maisinformações serão discutidas na seção TcpConnection. @@ -157,7 +157,7 @@ Esse método é chamado quando o Pitiupi precisa entregar uma `TcpConnection` ao ### [REF] receiveBytes(TcpConnection connection, byte[] bytes) -Esse método é chamado para entregar as mensagens recebidas por um `TcpConnection`, o tcpConnection no parametro indica qual a fonte da mensagem. +Esse método é chamado para entregar as mensagens recebidas por um `TcpConnection`, o tcpPitiupi no parametro indica qual a fonte da mensagem. ### [REF] onSocketClosed(TcpConnection connection) diff --git a/pitiupi/nbproject/build-impl.xml b/pitiupi/nbproject/build-impl.xml index adb5cae..77411c7 100644 --- a/pitiupi/nbproject/build-impl.xml +++ b/pitiupi/nbproject/build-impl.xml @@ -700,7 +700,7 @@ is divided into following sections: - + @@ -843,7 +843,7 @@ is divided into following sections: - + @@ -882,7 +882,7 @@ is divided into following sections: - + @@ -1434,7 +1434,7 @@ is divided into following sections: - + diff --git a/pitiupi/src/pitiupi/GUI/MainWindow.java b/pitiupi/src/pitiupi/GUI/MainWindow.java index 87c4495..b3cad43 100644 --- a/pitiupi/src/pitiupi/GUI/MainWindow.java +++ b/pitiupi/src/pitiupi/GUI/MainWindow.java @@ -12,6 +12,7 @@ import pitiupi.control.plugins.PluginManager; import javax.swing.*; import java.awt.*; +import java.net.UnknownHostException; /** * Janela principal da aplicação. @@ -33,9 +34,9 @@ public class MainWindow extends JFrame { private JLabel status; OnlineUsersPanel onlineUsersPanel; - private final ConnectionManager connectionManager; - private final PluginManager pluginManager; - private final GuiManager guiManager; + private ConnectionManager connectionManager; + private PluginManager pluginManager; + private GuiManager guiManager; /** * Cria a janela principal da aplicação. @@ -44,21 +45,34 @@ public class MainWindow extends JFrame { * @param port porta utilizada na comunicação multicast. */ public MainWindow(String userName, int port) { - initMenu(); + try { + initMenu(); - pluginManager = new PluginManager(); - connectionManager = new ConnectionManager(this, userName, pluginManager, port); + pluginManager = new PluginManager(); + connectionManager = new ConnectionManager(userName, pluginManager, port); - initUserPanel(); - initStatusPanel(); + initUserPanel(); + initStatusPanel(); - guiManager = new GuiManager(this, menuBar, onlineUsersPanel); + guiManager = new GuiManager(this, menuBar, onlineUsersPanel); - loadPlugins(); + loadPlugins(); - this.pack(); + this.pack(); - this.setSize(new java.awt.Dimension(1024, 768)); + this.setSize(new java.awt.Dimension(1024, 768)); + } + catch (UnknownHostException e) { + JOptionPane.showMessageDialog( + null, + "Ocorreu um erro abrindo a conexão TCP, verifique sua rede. \n" + + "Se o problema persistir entre em contato com a equipe do Pitiupi.", + "Erro na conexão TCP", + JOptionPane.ERROR_MESSAGE + ); + + System.exit(0); + } } private void initMenu() { diff --git a/pitiupi/src/pitiupi/control/ConnectionManager.java b/pitiupi/src/pitiupi/control/ConnectionManager.java index 56a24d8..4edbc42 100644 --- a/pitiupi/src/pitiupi/control/ConnectionManager.java +++ b/pitiupi/src/pitiupi/control/ConnectionManager.java @@ -2,46 +2,54 @@ package pitiupi.control; import pitiupi.GUI.MainWindow; import pitiupi.control.plugins.PluginManager; +import pitiupi.models.ConnectionData; import pitiupi.models.Messages.HeartbeatMessage; import pitiupi.models.Messages.Message; -import pitiupi.net.tcp.SocketTCP; -import pitiupi.net.tcp.TcpConnection; +import pitiupi.net.tcp.TcpClient; +import pitiupi.net.tcp.TcpManager; +import pitiupi.net.tcp.TcpServer; import pitiupi.net.udp.SocketUDP; +import java.io.IOException; import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.logging.Level; +import java.util.logging.Logger; public class ConnectionManager { - private final String pitiupiIdentifier; - private final PluginManager pluginManager; private final HeartbeatManager heartbeatManager; - private SocketTCP socketTCP; + private TcpManager tcpManager; private SocketUDP socketUDP; private String username; + private InetAddress address; private int port; - public ConnectionManager(MainWindow main, String username, PluginManager pluginManager, int port) { + public ConnectionManager(String username, PluginManager pluginManager, int port) throws UnknownHostException { this.pluginManager = pluginManager; this.username = username; + this.address = InetAddress.getLocalHost(); this.port = port; - pitiupiIdentifier = "Pitiupi.Alice.2026"; - reconnect(); heartbeatManager = new HeartbeatManager(this); heartbeatManager.start(); } - public TcpConnection connectPluginTcp(InetAddress destinationAdress, String senderId, String receiverId) { - return socketTCP.createPrivateConnection(destinationAdress, senderId, receiverId); + public TcpClient connectToTcpServer(ConnectionData serverData, String pluginId) { + return tcpManager.getClient(serverData, pluginId, username); + } + + public TcpServer getTcpServer(String pluginId) { + return tcpManager.getServer(pluginId, username, address, port); } public boolean sendTcp(Message message, InetAddress destinationAddress) { - return socketTCP.send(message, destinationAddress); + return tcpManager.send(message, destinationAddress, port); } public boolean sendUdpUnicast(Message message, InetAddress destinationAddress) { @@ -63,7 +71,7 @@ public class ConnectionManager { return false; } - public void broadcastLocal(byte[] message) { + public void receiveMessage(byte[] message) { pluginManager.handleMessage(message); } @@ -84,30 +92,35 @@ public class ConnectionManager { return port; } - public String getIdentifier(){ - return this.pitiupiIdentifier; - } - private void reconnect() { - if (this.socketUDP != null) { - this.socketUDP.close(); - } - if (this.socketTCP != null) { - this.socketTCP.close(); - } + try { + if (this.socketUDP != null) { + this.socketUDP.close(); + } + if (this.tcpManager != null) { + this.tcpManager.closeManager(); + } - this.socketUDP = new SocketUDP(this, pluginManager); - this.socketTCP = new SocketTCP(this, pluginManager); + this.socketUDP = new SocketUDP(this, pluginManager); + this.tcpManager = new TcpManager(port, this::receiveMessage); - this.socketUDP.start(); - this.socketTCP.start(); + this.socketUDP.start(); + this.tcpManager.start(); + } + catch (Exception ex) { + Logger.getLogger(ConnectionManager.class.getName()).log(Level.SEVERE, null, ex); + } } public String getUserName() { return this.username; } + public InetAddress getAddress() { + return this.address; + } + public void setUserName(String userName) { this.username = userName; } -} +} \ No newline at end of file diff --git a/pitiupi/src/pitiupi/control/plugins/PluginManager.java b/pitiupi/src/pitiupi/control/plugins/PluginManager.java index 60f29f4..7dc38e2 100644 --- a/pitiupi/src/pitiupi/control/plugins/PluginManager.java +++ b/pitiupi/src/pitiupi/control/plugins/PluginManager.java @@ -5,7 +5,6 @@ import pitiupi.Main; import pitiupi.control.ConnectionManager; import pitiupi.control.GuiManager; import pitiupi.models.Messages.Message; -import pitiupi.net.tcp.TcpConnection; import pitiupi.models.Plugin; import java.io.ByteArrayInputStream; @@ -67,29 +66,6 @@ public class PluginManager { return null; } - public void handleMessageFromConnection(TcpConnection connection, byte[] msg) { - Plugin plugin = getPlugin(connection.getReceiver()); - if (plugin == null) return; - - plugin.receiveBytes(connection, msg); - } - - public boolean handleConnection(TcpConnection connection, String receiverId) { - Plugin plugin = getPlugin(receiverId); - if (plugin == null) return false; - - plugin.receivePrivateConnection(connection); - - return false; - } - - public void handleDisconnection(TcpConnection connection, String receiverId) { - Plugin plugin = getPlugin(receiverId); - if (plugin == null) return; - - plugin.onSocketClosed(connection); - } - public void loadPlugins(ConnectionManager connectionManager, GuiManager guiManager) { File pluginDir = new File("plugins"); File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar")); diff --git a/pitiupi/src/pitiupi/models/ConnectionData.java b/pitiupi/src/pitiupi/models/ConnectionData.java new file mode 100644 index 0000000..5348b22 --- /dev/null +++ b/pitiupi/src/pitiupi/models/ConnectionData.java @@ -0,0 +1,44 @@ +package pitiupi.models; + +import java.io.Serializable; +import java.net.InetAddress; +import java.util.UUID; + +public class ConnectionData implements Serializable { + private final UUID uuid; + private final int port; + private final String ownerName; + private final InetAddress ownerAddress; + private final String plugin; + private final boolean isServer; + + public ConnectionData(String ownerName, InetAddress ownerAddress, String plugin, int port, boolean isServer) { + uuid = UUID.randomUUID(); + + this.port = port; + this.ownerName = ownerName; + this.ownerAddress = ownerAddress; + this.plugin = plugin; + this.isServer = isServer; + } + + public UUID getUuid() { + return uuid; + } + + public int getPort() { + return port; + } + public String getOwnerName() { + return ownerName; + } + public InetAddress getOwnerAddress() { + return ownerAddress; + } + public String getPlugin() { + return plugin; + } + public boolean isServer() { + return isServer; + } +} diff --git a/pitiupi/src/pitiupi/models/Messages/InfoMessage.java b/pitiupi/src/pitiupi/models/Messages/InfoMessage.java deleted file mode 100644 index b95a758..0000000 --- a/pitiupi/src/pitiupi/models/Messages/InfoMessage.java +++ /dev/null @@ -1,50 +0,0 @@ -package pitiupi.models.Messages; - -import pitiupi.net.tcp.TcpConnection; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -public class InfoMessage extends Message { - private final InfoType type; - private final String message; - - public InfoMessage(String message, InfoType type) { - this.message = message; - this.type = type; - } - - public String getMessage() { - return message; - } - - public InfoType getType() { - return type; - } - - public static void sendSystemInfo(TcpConnection connection, InfoType type, String description) { - try { - InfoMessage error = new InfoMessage(description, type); - connection.send(error.toByteArray()); - } catch (IOException ex) { - Logger.getLogger(InfoMessage.class.getName()).log(Level.WARNING, null, ex); - } - } - - public static InfoMessage parseSystemInfo(byte[] bytes) { - try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bis)) { - - Object object = ois.readObject(); - if (object instanceof InfoMessage) { - return (InfoMessage) object; - } - } catch (IOException | ClassNotFoundException ex) { - Logger.getLogger(InfoMessage.class.getName()).log(Level.WARNING, null, ex); - } - return null; - } -} diff --git a/pitiupi/src/pitiupi/models/Messages/InfoType.java b/pitiupi/src/pitiupi/models/Messages/InfoType.java deleted file mode 100644 index ddcaa04..0000000 --- a/pitiupi/src/pitiupi/models/Messages/InfoType.java +++ /dev/null @@ -1,9 +0,0 @@ -package pitiupi.models.Messages; - -public enum InfoType { - CONNECTION_REJECTED, - RECEIVER_NOT_FOUND, - MESSAGE_REJECTED, - INTERNAL_ERROR, - CONNECTION_CLOSED, -} diff --git a/pitiupi/src/pitiupi/models/Plugin.java b/pitiupi/src/pitiupi/models/Plugin.java index f28e62b..52145c4 100644 --- a/pitiupi/src/pitiupi/models/Plugin.java +++ b/pitiupi/src/pitiupi/models/Plugin.java @@ -5,7 +5,6 @@ package pitiupi.models; import pitiupi.plugin.Pitiupi; import pitiupi.models.Messages.Message; -import pitiupi.net.tcp.TcpConnection; import java.util.List; @@ -50,13 +49,5 @@ public abstract class Plugin { public abstract void receiveMessage(Message message); public boolean receiveAllTypes() {return false;} - public boolean receivePrivateConnection(TcpConnection connection) { - return false; - } - public boolean receiveBytes(TcpConnection connection, byte[] bytes) { - return false; - } - public boolean onSocketClosed(TcpConnection connection) { - return false; - } + } diff --git a/pitiupi/src/pitiupi/net/tcp/ConnectionFactory.java b/pitiupi/src/pitiupi/net/tcp/ConnectionFactory.java deleted file mode 100644 index 07f1482..0000000 --- a/pitiupi/src/pitiupi/net/tcp/ConnectionFactory.java +++ /dev/null @@ -1,229 +0,0 @@ -package pitiupi.net.tcp; - -import pitiupi.models.Messages.Message; -import pitiupi.models.Messages.InfoMessage; -import pitiupi.models.Messages.InfoType; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Fábrica responsável pela criação e configuração de conexões TCP. - * - *

Esta classe centraliza o estabelecimento de conexões de saída e a - * configuração de conexões recebidas. Antes de uma conexão ser considerada - * válida, é realizado um handshake entre os peers para identificar o remetente, - * o destinatário e se a conexão é privada.

- * - *

Durante o handshake é utilizado um timeout menor, definido por - * {@link #HANDSHAKE_TIMEOUT}. Após a validação bem-sucedida, a conexão passa - * a utilizar o timeout padrão definido por {@link #STANDARD_TIMEOUT}.

- */ -public class ConnectionFactory { - private static final int HANDSHAKE_TIMEOUT = 1000; - private static final int STANDARD_TIMEOUT = 300_000; - - /** - * Cria uma conexão TCP de saída com o peer de destino e realiza o handshake - * necessário para validá-la. - * - *

A conexão é configurada com os identificadores do remetente e do - * destinatário e com o tipo indicado pelo parâmetro {@code isPrivate}. - * Após o estabelecimento do socket, o método envia um - * {@link HandshakeMessage} e aguarda uma resposta válida.

- * - *

Se o handshake for validado com sucesso, o timeout da conexão é - * alterado de {@link #HANDSHAKE_TIMEOUT} para {@link #STANDARD_TIMEOUT} - * e a conexão é retornada. Caso contrário, {@code null} é retornado.

- * - * @param address endereço IP do peer de destino. - * @param port porta TCP na qual o peer de destino está aguardando conexões. - * @param sender identificador do remetente da conexão. - * @param receiver identificador do destinatário da conexão. - * @param isPrivate {@code true} se a conexão deve ser privada; - * {@code false} se deve ser pública. - * @return a conexão TCP estabelecida e validada ou {@code null} caso - * não seja possível estabelecer ou validar a conexão. - */ - public static TcpConnection createConnection(InetAddress address, int port, String sender, String receiver, boolean isPrivate) { - try { - TcpConnection connection; - - Socket socket = new Socket(address, port); - connection = new TcpConnection(socket); - connection.setSender(sender); - connection.setReceiver(receiver); - connection.setPrivate(isPrivate); - - HandshakeMessage handshake = new HandshakeMessage(isPrivate, sender, receiver); - - connection.send(handshake.toByteArray()); - HandshakeMessage handshakeResponse = validateConnection(connection); - - if (handshakeResponse == null) { - return null; - } - - connection.setTimeout(STANDARD_TIMEOUT); - - return connection; - } - catch (IOException ex) { - Logger.getLogger(ConnectionFactory.class.getName()).log(Level.SEVERE, null, ex); - } - return null; - } - - /** - * Configura uma conexão TCP recebida e valida o handshake enviado pelo - * peer remoto. - * - *

O handshake recebido é utilizado para obter e configurar os - * identificadores do remetente e do destinatário, bem como o tipo da - * conexão. Após a validação bem-sucedida, o timeout da conexão é alterado - * para {@link #STANDARD_TIMEOUT}.

- * - *

O {@link Socket} recebido deve representar uma conexão TCP já aceita - * pelo servidor.

- * - * @param socket socket TCP correspondente à conexão recebida. - * @return a conexão TCP configurada e validada ou {@code null} caso - * o handshake seja inválido ou não possa ser processado. - */ - public static TcpConnection receiveConnection(Socket socket) { - try { - TcpConnection connection; - - connection = new TcpConnection(socket); - - HandshakeMessage handshake = validateConnection(connection); - - if (handshake == null) return null; - - connection.send(handshake.createResponse().toByteArray()); - - connection.setSender(handshake.getSender()); - connection.setReceiver(handshake.getReceiver()); - connection.setPrivate(handshake.isPrivate()); - - connection.setTimeout(STANDARD_TIMEOUT); - - return connection; - } - catch (IOException ex) { - Logger.getLogger(ConnectionFactory.class.getName()).log(Level.SEVERE, null, ex); - } - return null; - } - - /** - * Aguarda e valida a mensagem de handshake de uma conexão TCP. - * - *

Durante a validação, a conexão utiliza {@link #HANDSHAKE_TIMEOUT} - * como limite para o recebimento do handshake. A mensagem recebida deve - * ser uma instância de {@link Message} e, especificamente, de - * {@link HandshakeMessage}. Mensagens de sistema ou mensagens de outros - * tipos são rejeitadas.

- * - *

Quando o handshake é recebido, seus campos de remetente e destinatário - * são validados por {@link #validateHandshake(HandshakeMessage, TcpConnection)}. - * Caso a validação seja bem-sucedida, o próprio handshake é retornado.

- * - *

Em caso de timeout, mensagem inválida ou erro durante o processamento, - * uma mensagem de sistema apropriada pode ser enviada ao peer e - * {@code null} é retornado.

- * - * @param connection conexão TCP da qual o handshake será recebido. - * @return o {@link HandshakeMessage} validado ou {@code null} caso o - * handshake não seja recebido ou seja inválido. - */ - private static HandshakeMessage validateConnection(TcpConnection connection) { - try { - connection.setTimeout(HANDSHAKE_TIMEOUT); - byte[] bytes = connection.receive(); - - ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - ObjectInputStream ois = new ObjectInputStream(bis); - - Object object = ois.readObject(); - - if (object instanceof Message message) { - InfoMessage sysInfo = InfoMessage.parseSystemInfo(bytes); - if (sysInfo != null) return null; - - - if (message instanceof HandshakeMessage handshake) { - return (validateHandshake(handshake, connection)) ? handshake : null; - } - } - - InfoMessage.sendSystemInfo( - connection, - InfoType.CONNECTION_REJECTED, - "The message was not from an allowed type." - ); - } - catch (SocketTimeoutException ex) { - InfoMessage.sendSystemInfo( - connection, - InfoType.CONNECTION_REJECTED, - "No handshake was received within the allowed time." - ); - } - catch (ClassNotFoundException | IOException ex) { - Logger.getLogger(ConnectionFactory.class.getName()).log(Level.SEVERE, null, ex); - - InfoMessage.sendSystemInfo( - connection, - InfoType.INTERNAL_ERROR, - "The server could not process the handshake." - ); - } - - return null; - } - - /** - * Valida os identificadores presentes em uma mensagem de handshake. - * - *

O remetente e o destinatário devem estar presentes e não podem ser - * vazios ou conter apenas espaços em branco. Quando um dos identificadores - * é inválido, uma mensagem de rejeição é enviada ao peer e a validação - * falha.

- * - * @param handshake mensagem de handshake a ser validada. - * @param connection conexão associada ao handshake, utilizada para enviar - * uma mensagem de rejeição quando necessário. - * @return {@code true} se os identificadores do remetente e do destinatário - * forem válidos; {@code false} caso contrário. - */ - private static boolean validateHandshake(HandshakeMessage handshake, TcpConnection connection) { - String sender = handshake.getSender(); - String receiver = handshake.getReceiver(); - - if (sender == null || sender.isBlank()) { - InfoMessage.sendSystemInfo( - connection, - InfoType.CONNECTION_REJECTED, - "Invalid Sender: " + sender + "." - ); - return false; - } - if (receiver == null || receiver.isBlank()) { - InfoMessage.sendSystemInfo( - connection, - InfoType.CONNECTION_REJECTED, - "Invalid Receiver: " + receiver + "." - ); - return false; - } - - return true; - } -} diff --git a/pitiupi/src/pitiupi/net/tcp/HandshakeMessage.java b/pitiupi/src/pitiupi/net/tcp/HandshakeMessage.java deleted file mode 100644 index 625deb4..0000000 --- a/pitiupi/src/pitiupi/net/tcp/HandshakeMessage.java +++ /dev/null @@ -1,30 +0,0 @@ -package pitiupi.net.tcp; - -import pitiupi.models.Messages.Message; - -class HandshakeMessage extends Message { - private final boolean isPrivate; - private final String sender; - private final String receiver; - - - public HandshakeMessage(boolean isPrivate, String sender, String receiver) { - this.isPrivate = isPrivate; - this.sender = sender; - this.receiver = receiver; - } - - public boolean isPrivate() { - return isPrivate; - } - public String getSender() { - return sender; - } - public String getReceiver() { - return receiver; - } - - public HandshakeMessage createResponse() { - return new HandshakeMessage(isPrivate, receiver, sender); - } -} diff --git a/pitiupi/src/pitiupi/net/tcp/SocketTCP.java b/pitiupi/src/pitiupi/net/tcp/SocketTCP.java deleted file mode 100644 index 688f638..0000000 --- a/pitiupi/src/pitiupi/net/tcp/SocketTCP.java +++ /dev/null @@ -1,456 +0,0 @@ -package pitiupi.net.tcp; - -import pitiupi.control.ConnectionManager; -import pitiupi.control.plugins.PluginManager; -import pitiupi.models.Messages.Message; -import pitiupi.models.Messages.InfoMessage; -import pitiupi.models.Messages.InfoType; - -import java.io.*; -import java.net.*; -import java.util.Objects; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Gerencia a comunicação TCP da aplicação. - * - *

Mantém conexões persistentes com os peers e reutiliza essas conexões - * para o envio de mensagens. As mensagens recebidas são encaminhadas aos - * plugins, que são responsáveis por interpretá-las.

- * - *

Novas conexões são aceitas pelo servidor e cada conexão possui uma - * tarefa própria para receber mensagens, permitindo que múltiplas conexões - * sejam mantidas simultaneamente.

- * - *

As conexões são associadas aos endereços dos peers e podem ser - * encerradas quando um peer deixa de estar ativo.

- * - * @author Gustavo - */ -public class SocketTCP extends Thread { - private final Logger logger; - - private final ExecutorService connectionExecutor = Executors.newCachedThreadPool(); - - private final ConnectionManager connectionManager; - - private final PluginManager pluginManager; - - private final TcpConnectionManager tcpConnectionManager; - - private ServerSocket serverSocket; - private InetAddress address; - - private volatile boolean running = true; - - /** - * Cria o servidor TCP da aplicação. - * - *

O servidor é criado na porta definida pela aplicação. As conexões - * com os peers são estabelecidas sob demanda durante o envio ou aceitas - * quando iniciadas por outros peers.

- * - * @param connectionManager interface de conexão da aplicação, usada para obter a porta, - * o identificador local e os plugins disponíveis. - */ - public SocketTCP(ConnectionManager connectionManager, PluginManager pluginManager) { - this.connectionManager = connectionManager; - this.pluginManager = pluginManager; - - logger = Logger.getLogger(getClass().getName()); - tcpConnectionManager = new TcpConnectionManager(); - - try { - serverSocket = new ServerSocket(connectionManager.getPort()); - address = InetAddress.getByName(InetAddress.getLocalHost().getHostAddress()); - } catch (IOException ex) { - System.out.println("There is no socket connection. Sorry."); - System.out.println(ex.toString()); - } - } - - /** - * Envia uma mensagem por meio de uma conexão TCP pública com o peer de destino. - * - *

A conexão pública existente para o endereço informado é reutilizada. - * Caso não exista uma conexão válida, uma nova conexão é estabelecida antes - * do envio. Falhas durante o estabelecimento ou envio são registradas na - * saída padrão e não são propagadas ao chamador.

- * - * @param msg mensagem que será enviada. - * @param destinationAddress endereço IP do peer que receberá a mensagem. - */ - public boolean send(Message msg, InetAddress destinationAddress) { - try { - TcpConnection connection = getPublicConnection( - destinationAddress, - connectionManager.getIdentifier(), - connectionManager.getIdentifier() - ); - - if (connection == null) { - System.out.println("Could not establish TCP connection."); - return false; - } - connection.send(msg.toByteArray()); - } catch (Exception ex) { - System.out.println("Could not send TCP message."); - System.out.println(ex.toString()); - return false; - } - return true; - } - - /** - * Estabelece uma conexão TCP privada com um plugin específico do peer de destino. - * - *

A conexão é criada como privada e passa a ser gerenciada pelo - * {@link TcpConnectionManager}. O método também inicia a tarefa responsável - * por receber os dados dessa conexão.

- * - * @param destinationAddress endereço IP do peer de destino. - * @param senderId identificador do remetente da conexão. - * @param receiverId identificador do plugin que receberá os dados. - * @return a conexão privada estabelecida ou {@code null} quando a criação - * da conexão falhar. - * @throws IllegalArgumentException se o endereço de destino for o endereço - * local desta instância. - */ - public TcpConnection createPrivateConnection(InetAddress destinationAddress, String senderId, String receiverId) { - return establishOutgoingConnection(destinationAddress, senderId, receiverId, true); - } - - /** - * Obtém uma conexão TCP pública existente com o peer de destino ou estabelece - * uma nova caso não exista uma conexão válida. - * - *

As conexões públicas são gerenciadas pelo {@link TcpConnectionManager}. - * O método primeiro verifica se já existe uma conexão pública registrada - * para o endereço de destino e, caso ela exista e não esteja fechada, - * reutiliza-a. Caso contrário, uma nova conexão pública é estabelecida, - * registrada no {@link TcpConnectionManager} e disponibilizada para uso.

- * - *

O acesso ao método é sincronizado para evitar que múltiplas threads - * estabeleçam simultaneamente conexões públicas para o mesmo peer.

- * - * @param destinationAddress endereço IP do peer de destino. - * @param senderId identificador usado como remetente no estabelecimento da conexão. - * @param receiverId identificador usado como destinatário no estabelecimento da conexão. - * @return uma conexão pública válida ou {@code null} caso não seja possível - * estabelecê-la. - */ - private synchronized TcpConnection getPublicConnection(InetAddress destinationAddress, String senderId, String receiverId) { - TcpConnection connection; - - connection = tcpConnectionManager.getPublicConnection(destinationAddress); - if (connection != null && !connection.isClosed()) return connection; - - connection = establishOutgoingConnection(destinationAddress, senderId, receiverId, false); - - return connection; - } - - /** - * Aguarda e aceita novas conexões TCP. - * - *

Cada socket aceito é encaminhado para processamento assíncrono, - * interpretado como uma {@link TcpConnection}, registrado pelo - * {@link TcpConnectionManager} e associado ao receptor adequado.

- */ - private void receive() { - while (running) { - - try { - Socket socket = serverSocket.accept(); - acceptIncomingConnection(socket); - - } catch (IOException ex) { - if (!running) { - break; - } - - System.out.println("Error accepting TCP connection."); - System.out.println(ex.toString()); - } - } - } - - /** - * Estabelece uma conexão TCP de saída com outro peer. - * - *

O método impede conexões com o próprio endereço local, cria a conexão - * por meio da {@link ConnectionFactory}, registra-a no gerenciador de - * conexões e inicia uma tarefa para receber dados continuamente.

- * - * @param destinationAddress endereço IP do peer de destino. - * @param sender identificador do remetente. - * @param receiver identificador do destinatário. - * @param isPrivate {@code true} para uma conexão destinada a um plugin - * específico; {@code false} para uma conexão pública. - * @return a conexão estabelecida ou {@code null} se a - * {@link ConnectionFactory} não conseguir criá-la. - * @throws IllegalArgumentException se o destino for o endereço desta máquina. - */ - private TcpConnection establishOutgoingConnection(InetAddress destinationAddress, String sender, String receiver, boolean isPrivate) { - if (address.equals(destinationAddress)) { - System.out.println("Failed to get socket."); - throw new IllegalArgumentException("Connections to the local host are forbidden."); - } - - TcpConnection connection = ConnectionFactory.createConnection(destinationAddress, connectionManager.getPort(), sender, receiver, isPrivate); - if (connection == null) return null; - - saveConnection(connection); - - connectionExecutor.submit(() -> { - startReceiver(connection); - }); - - return connection; - } - - /** - * Agenda o processamento de uma conexão TCP recebida. - * - *

A conexão é interpretada pela {@link ConnectionFactory}, registrada - * no gerenciador e associada a uma tarefa de recepção. O processamento é - * executado de forma assíncrona pelo executor compartilhado.

- * - * @param socket socket aceito pelo {@link ServerSocket}. - */ - private void acceptIncomingConnection(Socket socket) { - connectionExecutor.submit(() -> { - TcpConnection connection = ConnectionFactory.receiveConnection(socket); - if (connection == null) return; - - saveConnection(connection); - startReceiver(connection); - }); - } - - /** - * Registra uma conexão no gerenciador de acordo com seu tipo. - * - *

Conexões privadas são armazenadas na coleção de conexões privadas; - * as demais são armazenadas na coleção de conexões públicas.

- * - * @param connection conexão que será registrada. - */ - private void saveConnection(TcpConnection connection) { - if (connection.isPrivate()) { - tcpConnectionManager.addPrivateConnection(connection); - } - else { - tcpConnectionManager.addPublicConnection(connection); - } - } - - /** - * Seleciona e inicia o receptor adequado para uma conexão. - * - *

Conexões públicas são tratadas pelo receptor de mensagens públicas. - * Conexões privadas destinadas ao próprio sistema são tratadas - * separadamente; as demais são encaminhadas ao plugin identificado como - * destinatário. Quando solicitado, o plugin também é notificado sobre o - * estabelecimento da conexão.

- * - * @param connection conexão cujo fluxo de entrada será processado. - */ - private void startReceiver(TcpConnection connection) { - - if (!connection.isPrivate()) { - publicConnectionReceiver(connection); - return; - } - - if (connection.getReceiver().equals(connectionManager.getIdentifier())) { - systemConnectionReceiver(connection); - return; - } - - if (pluginManager.handleConnection(connection, connection.getReceiver())) - privateConnectionReceiver(connection); - else { - InfoMessage.sendSystemInfo( - connection, - InfoType.RECEIVER_NOT_FOUND, - "This peer does not have the plugin: " + connection.getReceiver() - ); - } - - } - - /** - * Processa continuamente as mensagens recebidas em uma conexão pública. - * - *

As mensagens são desserializadas e, quando são instâncias de - * {@link Message}, encaminhadas a todos os plugins da aplicação. Mensagens - * de controle do sistema podem encerrar a conexão ou registrar uma - * condição de erro.

- * - *

O método também trata timeouts e erros de I/O, removendo a conexão - * do {@link TcpConnectionManager} quando ela deixa de ser utilizável.

- * - * @param connection conexão pública da qual as mensagens serão recebidas. - */ - private void publicConnectionReceiver(TcpConnection connection) { - while (running) { - try { - byte[] bytes = connection.receive(); - - InfoMessage sysMessage = InfoMessage.parseSystemInfo(bytes); - - if (sysMessage == null) { - pluginManager.handleMessage(bytes); - continue; - } - - switch (sysMessage.getType()) { - case CONNECTION_CLOSED, INTERNAL_ERROR -> { - tcpConnectionManager.closeConnection(connection); - return; - } - case MESSAGE_REJECTED -> { - logger.log(Level.SEVERE, "Somehow sent something that was not an Message"); - } - default -> {} - } - } - catch (SocketTimeoutException ex) { - if (connection.hasTimedOut()) { - tcpConnectionManager.closeConnection(connection, "Connection timeout"); - return; - } - } - catch (IOException ex) { - tcpConnectionManager.closeConnection(connection); - } - } - } - - /** - * Processa os dados recebidos em uma conexão privada e os encaminha - * ao plugin destinatário. - * - *

Dados que não representam mensagens de controle são entregues - * diretamente ao {@link PrivateConnectionPlugin}. Mensagens de controle - * relacionadas ao encerramento ou a erros internos provocam a notificação - * do plugin e o fechamento da conexão.

- * - * @param connection conexão privada da qual os dados serão recebidos. - */ - private void privateConnectionReceiver(TcpConnection connection) { - while (running) { - try { - byte[] message = connection.receive(); - InfoMessage sysMessage = InfoMessage.parseSystemInfo(message); - - if (sysMessage == null) { - pluginManager.handleMessageFromConnection(connection, message); - continue; - } - - switch (sysMessage.getType()) { - case CONNECTION_CLOSED, INTERNAL_ERROR -> { - pluginManager.handleDisconnection(connection, connection.getReceiver()); - tcpConnectionManager.closeConnection(connection); - } - default -> { - continue; - } - } - } - catch (SocketTimeoutException ex) { - if (connection.hasTimedOut()) { - tcpConnectionManager.closeConnection(connection, "Connection timeout"); - return; - } - } - catch (IOException ex) { - tcpConnectionManager.closeConnection(connection); - } - } - } - - /** - * Processa mensagens recebidas em uma conexão destinada ao próprio sistema. - * - *

Atualmente, mensagens destinadas ao sistema são apenas verificadas - * quanto ao seu formato de controle. Não há processamento adicional de - * mensagens de sistema neste método.

- * - * @param connection conexão destinada ao identificador da própria aplicação. - */ - private void systemConnectionReceiver(TcpConnection connection) { - while (running) { - try { - byte[] message = connection.receive(); - try (ByteArrayInputStream bis = new ByteArrayInputStream(message); - ObjectInputStream ois = new ObjectInputStream(bis)) { - - InfoMessage sysMessage = InfoMessage.parseSystemInfo(message); - if (sysMessage != null) continue; - - //TODO: Ainda não existem mensagens trocadas entre o sistema. - } - - } - catch (SocketTimeoutException ex) { - if (connection.hasTimedOut()) return; - } - catch (IOException ex) { - tcpConnectionManager.closeConnection(connection); - } - } - } - - /** - * Encerra uma conexão TCP e registra o motivo informado. - * - *

Quando nenhuma descrição é fornecida, é utilizado um motivo padrão. - * O fechamento efetivo da conexão é delegado ao {@link TcpConnectionManager}.

- * - * @param connection conexão que será encerrada. - * @param description motivo do encerramento; pode ser {@code null}. - */ - public void disconnect(TcpConnection connection, String description) { - tcpConnectionManager.closeConnection( - connection, - Objects.requireNonNullElse(description, "No reason provided") - ); - } - - @Override - public void run() { - receive(); - } - - /** - * Encerra o servidor TCP e libera os recursos associados. - * - *

Interrompe o laço de aceitação de conexões, fecha o - * {@link ServerSocket}, encerra todas as conexões gerenciadas e interrompe - * as tarefas do executor.

- * - *

Após a chamada, esta instância não deve ser reutilizada para aceitar - * novas conexões.

- */ - public void close() { - running = false; - - if (serverSocket != null) { - try { - serverSocket.close(); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - - tcpConnectionManager.closeAllConnections("The peer must have closed the application or changed ports"); - - connectionExecutor.shutdownNow(); - } -} \ No newline at end of file diff --git a/pitiupi/src/pitiupi/net/tcp/TcpClient.java b/pitiupi/src/pitiupi/net/tcp/TcpClient.java new file mode 100644 index 0000000..5fb070e --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpClient.java @@ -0,0 +1,34 @@ +package pitiupi.net.tcp; + +import pitiupi.models.ConnectionData; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.net.Socket; + +public final class TcpClient extends TcpPitiupi { + private final ConnectionData clientData; + private final ConnectionData serverData; + + TcpClient( + ConnectionData clientData, + ConnectionData serverData, + Socket socket, + DataInputStream input, + DataOutputStream output) + { + + super(socket, input, output); + + this.clientData = clientData; + this.serverData = serverData; + } + + public ConnectionData getServerData() { + return serverData; + } + + public ConnectionData getClientData() { + return clientData; + } +} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpConnection.java b/pitiupi/src/pitiupi/net/tcp/TcpConnection.java deleted file mode 100644 index be7c0e4..0000000 --- a/pitiupi/src/pitiupi/net/tcp/TcpConnection.java +++ /dev/null @@ -1,171 +0,0 @@ -package pitiupi.net.tcp; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; - -/** - * Representa uma conexão TCP ativa com um peer remoto. - * - *

A conexão permite o envio e recebimento de mensagens, além de manter - * informações sobre o endereço remoto e metadados da conexão, como remetente, - * destinatário e se a conexão é privada.

- * - * @author Gustavo - */ -public class TcpConnection { - - private final Socket socket; - private final DataInputStream input; - private final DataOutputStream output; - private final InetAddress address; - private String sender; - private String receiver; - private boolean isPrivate; - private volatile long lastActivity; - private long timeout; - - /** - * Cria uma conexão TCP a partir de um socket existente. - * - * @param socket socket utilizado para a comunicação - * @throws IOException se não for possível obter os fluxos de entrada ou saída - * do socket - */ - TcpConnection(Socket socket) throws IOException { - this.socket = socket; - this.input = new DataInputStream(socket.getInputStream()); - this.output = new DataOutputStream(socket.getOutputStream()); - this.address = socket.getInetAddress(); - this.lastActivity = System.currentTimeMillis(); - this.timeout = 300_000; // 5 minutos - } - - /** - * Envia uma mensagem pela conexão. - * - *

A mensagem é enviada precedida pelo seu tamanho, permitindo que o - * receptor determine quantos bytes devem ser lidos.

- * - * @param message mensagem a ser enviada - * @throws IOException se ocorrer um erro durante o envio - */ - public synchronized void send(byte[] message) throws IOException { - output.writeInt(message.length); - output.write(message); - output.flush(); - updateLastActivity(); - } - - /** - * Recebe uma mensagem da conexão. - * - *

Primeiro lê o tamanho da mensagem e, em seguida, lê aquantidade - * correspondente de bytes.

- * - * @return mensagem recebida - * @throws IOException se o tamanho da mensagem for inválido ou se a conexão - * for encerrada antes que a mensagem seja completamente recebida - */ - byte[] receive() throws IOException { - int length = input.readInt(); - - if (length < 0) throw new IOException("Invalid message length."); - - byte[] message = input.readNBytes(length); - - if (message.length != length) { - throw new IOException("Connection closed before receiving the complete message."); - } - - updateLastActivity(); - - return message; - } - - /** - * Verifica se o socket da conexão está fechado. - * - * @return {@code true} se o socket estiver fechado; - * {@code false} caso contrário - */ - public boolean isClosed() { - return socket.isClosed(); - } - - /** - * Fecha o socket da conexão. - * - * @throws IOException se ocorrer um erro ao fechar o socket - */ - void close() throws IOException { - socket.close(); - } - - /** - * Retorna o endereço do peer remoto conectado. - * - * @return endereço IP do peer remoto - */ - public InetAddress getAddress() { - return address; - } - - /** - * Atualiza o instante da última atividade da conexão. - */ - private void updateLastActivity() { - lastActivity = System.currentTimeMillis(); - } - - /** - * Define o tempo limite de leitura do socket. - * - * @param timeout tempo limite, em milissegundos - * @throws SocketException se ocorrer um erro ao definir o tempo limite - */ - void setTimeout(int timeout) throws SocketException { - socket.setSoTimeout(timeout); - this.timeout = timeout; - } - - /** - * Verifica se a conexão ficou inativa pelo tempo limite configurado. - * - *

A verificação é baseada no instante da última atividade registrada - * durante o envio ou recebimento de uma mensagem.

- * - * @return {@code true} se a conexão estiver inativa há pelo menos 5 minutos; - * {@code false} caso contrário - */ - boolean hasTimedOut() { - return System.currentTimeMillis() - lastActivity >= timeout; - } - - public String getReceiver() { - return receiver; - } - - public String getSender() { - return sender; - } - - public boolean isPrivate() { - return isPrivate; - } - - void setSender(String sender) { - this.sender = sender; - } - - void setReceiver(String receiver) { - this.receiver = receiver; - } - - void setPrivate(boolean aPrivate) { - isPrivate = aPrivate; - } -} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java b/pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java deleted file mode 100644 index 81b29ad..0000000 --- a/pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java +++ /dev/null @@ -1,264 +0,0 @@ -package pitiupi.net.tcp; - -import pitiupi.models.Messages.InfoType; -import pitiupi.models.User; -import pitiupi.control.PeerListener; -import pitiupi.models.Messages.InfoMessage; - -import java.io.IOException; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; - -/** - * Gerencia as conexões TCP estabelecidas com os peers da aplicação. - * - *

As conexões públicas são armazenadas individualmente por endereço IP, - * enquanto as conexões privadas são agrupadas por endereço, permitindo que - * um mesmo peer mantenha múltiplas conexões privadas simultaneamente.

- * - *

Além de manter o registro das conexões ativas, esta classe é responsável - * por encerrá-las quando necessário e por remover do gerenciamento as - * conexões que forem fechadas. Também acompanha as alterações na lista de - * peers ativos para encerrar conexões associadas a peers que deixaram de - * estar disponíveis.

- */ -class TcpConnectionManager implements PeerListener { - private final Logger logger; - private final Map publicConnections; - private final Map> privateConnections; - - /** - * Cria um gerenciador de conexões TCP vazio. - */ - public TcpConnectionManager() { - publicConnections = new ConcurrentHashMap<>(); - privateConnections = new ConcurrentHashMap<>(); - - logger = Logger.getLogger(getClass().getName()); - } - - /** - * Obtém a conexão pública registrada para um determinado peer. - * - * @param address endereço IP do peer. - * @return a conexão pública registrada para o endereço ou {@code null} - * caso não exista uma conexão pública registrada. - */ - - public TcpConnection getPublicConnection(InetAddress address) { - return publicConnections.get(address); - } - - /** - * Registra uma conexão privada associada a um peer. - * - *

Um mesmo peer pode possuir múltiplas conexões privadas. Por isso, - * as conexões são armazenadas em uma lista associada ao endereço do - * peer.

- * - * @param connection conexão privada a ser registrada. - */ - public void addPrivateConnection(TcpConnection connection) { - List connections = - privateConnections.computeIfAbsent(connection.getAddress(), e -> new ArrayList<>()); - - synchronized (connections) { - connections.add(connection); - } - } - - /** - * Registra uma conexão pública associada a um peer. - * - *

Cada peer pode possuir apenas uma conexão pública registrada. - * Quando já existe uma conexão pública para o endereço da nova conexão, - * a conexão anterior é encerrada e substituída pela nova.

- * - * @param connection nova conexão pública a ser registrada. - */ - - public void addPublicConnection(TcpConnection connection) { - TcpConnection oldConnection = publicConnections.put(connection.getAddress(), connection); - if (oldConnection != null && oldConnection != connection) { - closeConnection(oldConnection); - } - } - - /** - * Envia uma mensagem de encerramento ao peer e fecha a conexão. - * - *

A mensagem enviada informa o motivo do encerramento antes que a - * conexão seja removida do gerenciamento e fechada.

- * - * @param connection conexão TCP a ser encerrada. - * @param reason motivo do encerramento que será informado ao peer. - */ - public void closeConnection(TcpConnection connection, String reason) { - InfoMessage.sendSystemInfo(connection, InfoType.CONNECTION_CLOSED, reason); - closeConnection(connection); - } - - /** - * Remove uma conexão do gerenciamento e encerra seu socket. - * - *

Para conexões privadas, a conexão é removida da lista associada ao - * endereço do peer. Caso essa seja a última conexão privada do endereço, - * a lista também é removida do mapa.

- * - *

Para conexões públicas, a conexão é removida do mapa somente se - * ainda for a conexão registrada para seu endereço.

- * - *

Se a conexão já estiver fechada ou for {@code null}, nenhuma ação - * adicional de fechamento é realizada.

- * - * @param connection conexão TCP a ser removida e encerrada. - */ - - public void closeConnection(TcpConnection connection) { - if (connection == null) return; - if (connection.isPrivate()) { - List connections = privateConnections.get(connection.getAddress()); - - if (connections != null) { - synchronized (connections) { - connections.remove(connection); - - if (connections.isEmpty()) privateConnections.remove(connection.getAddress(), connections); - } - } - } - else publicConnections.remove(connection.getAddress(), connection); - - try { - if (!connection.isClosed()) { - connection.close(); - } - } catch (IOException ex) { - logger.log(Level.SEVERE, "Error closing TCP connection", ex); - } - } - - /** - * Envia uma mensagem de encerramento para todas as conexões de um peer - * e, em seguida, fecha essas conexões. - * - * @param address endereço IP do peer cujas conexões serão encerradas. - * @param reason motivo do encerramento informado ao peer. - */ - public void closeByAdress(InetAddress address, String reason) { - List connections = privateConnections.get(address); - for (TcpConnection connection : connections) { - InfoMessage.sendSystemInfo(connection, InfoType.CONNECTION_CLOSED, reason); - } - closeByAdress(address); - } - - /** - * Fecha e remove todas as conexões associadas a um determinado endereço. - * - *

Tanto a conexão pública quanto todas as conexões privadas associadas - * ao endereço são encerradas e removidas do gerenciamento.

- * - * @param address endereço IP do peer cujas conexões serão encerradas. - */ - public void closeByAdress(InetAddress address) { - TcpConnection publicConnection = publicConnections.remove(address); - - if (publicConnection != null) { - try { - publicConnection.close(); - } - catch (IOException ex) { - logger.log(Level.SEVERE, "Error closing TCP connection", ex); - } - - } - - List connections = privateConnections.remove(address); - - if (connections != null) { - synchronized (connections) { - for (TcpConnection connection : connections) { - try { - connection.close(); - } - catch (IOException ex) { - logger.log(Level.SEVERE, "Error closing TCP connection", ex); - } - } - connections.clear(); - } - } - } - - /** - * Envia uma mensagem de encerramento para todas as conexões privadas - * gerenciadas e, em seguida, fecha todas elas. - * - * @param reason motivo do encerramento informado aos peers. - */ - public void closeAllConnections(String reason) { - for (List connections : privateConnections.values()) { - for (TcpConnection connection : connections) { - InfoMessage.sendSystemInfo(connection, InfoType.CONNECTION_CLOSED, reason); - } - } - closeAllConnections(); - } - - /** - * Fecha e remove todas as conexões públicas e privadas gerenciadas. - * - *

Após a execução, não devem permanecer conexões registradas nos - * mapas de conexões deste gerenciador.

- */ - - public void closeAllConnections() { - for (TcpConnection connection : publicConnections.values()) { - closeConnection(connection); - } - - synchronized (privateConnections) { - for (List connectionsList : privateConnections.values()) { - for (TcpConnection connection : connectionsList) { - closeConnection(connection); - } - privateConnections.clear(); - } - } - } - - /** - * Atualiza as conexões de acordo com os peers atualmente ativos. - * - *

Os endereços presentes na lista de peers são utilizados como - * referência para determinar quais conexões ainda devem permanecer - * ativas. Conexões públicas e privadas associadas a endereços que não - * estão mais presentes na lista de peers são encerradas e removidas.

- * - * @param peers lista atualizada de peers ativos. - */ - - @Override - public void onPeersChanged(List peers) { - Set activePeers = peers.stream().map(User::getAddress).collect(Collectors.toSet()); - - for (InetAddress address : publicConnections.keySet()) { - if (!activePeers.contains(address)) { - closeByAdress(address); - } - } - for (InetAddress address : privateConnections.keySet()) { - if (!activePeers.contains(address)) { - closeByAdress(address); - } - } - } -} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpFactory.java b/pitiupi/src/pitiupi/net/tcp/TcpFactory.java new file mode 100644 index 0000000..fe5d488 --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpFactory.java @@ -0,0 +1,188 @@ +package pitiupi.net.tcp; + +import pitiupi.models.ConnectionData; + +import java.io.*; +import java.net.InetAddress; +import java.net.Socket; +import java.util.logging.Level; +import java.util.logging.Logger; + +final class TcpFactory { + private static final int HANDSHAKE_TIMEOUT = 1000; + private static final int DISABLE_TIMEOUT = 0; + + TcpManager manager; + + TcpFactory(TcpManager manager) { + this.manager = manager; + } + + TcpPitiupi createPitiupiConnection(InetAddress receiverAddress, int port) { + Socket socket = null; + try { + socket = new Socket(receiverAddress, port); + DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); + DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); + + sendHandshake(dataOutputStream); + socket.setSoTimeout(HANDSHAKE_TIMEOUT); + TcpHandshakeResponse response = receiveHandshakeResponse(dataInputStream); + socket.setSoTimeout(DISABLE_TIMEOUT); + + if (response.getSucess()) return new TcpPitiupi(socket, dataInputStream, dataOutputStream); + } + catch (IOException | ClassNotFoundException e) { + Logger.getLogger(TcpFactory.class.getName()).log(Level.SEVERE, null, e); + } + + if (socket != null) tryClose(socket); + return null; + } + + TcpClient createClient(ConnectionData serverData, String pluginIdentifier, String username, InetAddress receiverAddress, int port) { + Socket socket = null; + try { + socket = new Socket(receiverAddress, port); + DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); + DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); + + ConnectionData clientData = new ConnectionData( + username, + receiverAddress, + pluginIdentifier, + port, + false); + + sendHandshake(dataOutputStream, serverData, clientData); + socket.setSoTimeout(HANDSHAKE_TIMEOUT); + TcpHandshakeResponse response = receiveHandshakeResponse(dataInputStream); + socket.setSoTimeout(DISABLE_TIMEOUT); + + if (response.getSucess()) return new TcpClient(clientData, serverData, socket, dataInputStream, dataOutputStream); + } + catch (IOException | ClassNotFoundException e) { + Logger.getLogger(TcpFactory.class.getName()).log(Level.SEVERE, null, e); + } + + if (socket != null) tryClose(socket); + return null; + } + + TcpServer createServer(String pluginIdentifier, String username, InetAddress receiverAddress, int port) { + ConnectionData data = new ConnectionData( + username, + receiverAddress, + pluginIdentifier, + port, + true); + + return new TcpServer(data); + } + + TcpPitiupi createFromReceiver(Socket socket) throws IOException { + DataOutputStream dataOutputStream = null; + DataInputStream dataInputStream = null; + + try { + dataOutputStream = new DataOutputStream(socket.getOutputStream()); + dataInputStream = new DataInputStream(socket.getInputStream()); + + socket.setSoTimeout(HANDSHAKE_TIMEOUT); + TcpHandshake tcpHandshake = receiveHandshake(dataInputStream); + socket.setSoTimeout(DISABLE_TIMEOUT); + + if (tcpHandshake.isPrivate()) { + ConnectionData clientData = tcpHandshake.getClientData(); + ConnectionData serverData = tcpHandshake.getServerData(); + + if (manager.findServer(serverData) == null) { + sendHandshakeResponse(false, dataOutputStream); + tryClose(socket); + return null; + } + + sendHandshakeResponse(true, dataOutputStream); + return new TcpClient(clientData, serverData, socket, dataInputStream, dataOutputStream); + } + else { + sendHandshakeResponse(true, dataOutputStream); + return new TcpPitiupi(socket, dataInputStream, dataOutputStream); + } + } + catch (IOException | ClassNotFoundException e) { + Logger.getLogger(TcpFactory.class.getName()).log(Level.SEVERE, null, e); + } + + sendHandshakeResponse(false, dataOutputStream); + tryClose(socket); + return null; + } + + private void sendHandshake(DataOutputStream output, ConnectionData serverData, ConnectionData clientData) throws IOException { + TcpHandshake handshake = TcpHandshake.createPrivate(serverData, clientData); + byte[] message = handshake.toByteArray(); + + sendMessage(message, output); + } + + private void sendHandshake(DataOutputStream output) throws IOException { + TcpHandshake handshake = TcpHandshake.createPublic(); + byte[] message = handshake.toByteArray(); + + sendMessage(message, output); + } + + private void sendHandshakeResponse(boolean success, DataOutputStream output) throws IOException { + TcpHandshakeResponse response = new TcpHandshakeResponse(success); + + byte[] message = response.toByteArray(); + sendMessage(message, output); + } + + private void sendMessage(byte[] message, DataOutputStream output) throws IOException { + output.writeInt(message.length); + output.write(message); + output.flush(); + } + + private TcpHandshake receiveHandshake(DataInputStream input) throws IOException, ClassNotFoundException { + byte[] msg = receiveMessage(input); + + if (byteToObject(msg) instanceof TcpHandshake handshake) return handshake; + else throw new IOException("Not a handshake"); + } + + private TcpHandshakeResponse receiveHandshakeResponse(DataInputStream input) throws IOException, ClassNotFoundException { + byte[] msg = receiveMessage(input); + + if (byteToObject(msg) instanceof TcpHandshakeResponse response) return response; + else throw new IOException("Not a handshake"); + } + + private byte[] receiveMessage(DataInputStream input) throws IOException { + int length = input.readInt(); + if (length < 0) throw new IOException("Invalid length"); + + byte[] msg = input.readNBytes(length); + if (msg.length != length) throw new IOException("Socket closed while receiving data"); + + return msg; + } + + private Object byteToObject(byte[] bytes) throws IOException, ClassNotFoundException { + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInput in = new ObjectInputStream(bais); + + return in.readObject(); + } + + public void tryClose(Socket socket) { + try { + socket.close(); + } + catch (IOException ex) { + Logger.getLogger(TcpFactory.class.getName()).log(Level.WARNING, null, ex); + } + } +} \ No newline at end of file diff --git a/pitiupi/src/pitiupi/net/tcp/TcpHandshake.java b/pitiupi/src/pitiupi/net/tcp/TcpHandshake.java new file mode 100644 index 0000000..497c129 --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpHandshake.java @@ -0,0 +1,36 @@ +package pitiupi.net.tcp; + +import pitiupi.models.ConnectionData; +import pitiupi.models.Messages.Message; + +final class TcpHandshake extends Message { + private final boolean isPrivate; + private final ConnectionData serverData; + private final ConnectionData clientData; + + private TcpHandshake(boolean isPrivate, ConnectionData serverData, ConnectionData clientData) { + this.isPrivate = isPrivate; + this.serverData = serverData; + this.clientData = clientData; + } + + static TcpHandshake createPrivate(ConnectionData serverData, ConnectionData clientData) { + return new TcpHandshake(true, serverData, clientData); + } + + static TcpHandshake createPublic() { + return new TcpHandshake(false, null, null); + } + + public boolean isPrivate() { + return isPrivate; + } + + public ConnectionData getServerData() { + return serverData; + } + + public ConnectionData getClientData() { + return clientData; + } +} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpHandshakeResponse.java b/pitiupi/src/pitiupi/net/tcp/TcpHandshakeResponse.java new file mode 100644 index 0000000..2f65220 --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpHandshakeResponse.java @@ -0,0 +1,15 @@ +package pitiupi.net.tcp; + +import pitiupi.models.Messages.Message; + +class TcpHandshakeResponse extends Message { + private final boolean sucess; + + TcpHandshakeResponse(boolean sucess) { + this.sucess = sucess; + } + + public boolean getSucess() { + return sucess; + } +} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpManager.java b/pitiupi/src/pitiupi/net/tcp/TcpManager.java new file mode 100644 index 0000000..7427e10 --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpManager.java @@ -0,0 +1,163 @@ +package pitiupi.net.tcp; + +import pitiupi.models.ConnectionData; +import pitiupi.models.Messages.Message; + +import java.io.*; +import java.net.*; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Consumer; +import java.util.logging.Level; +import java.util.logging.Logger; + +public final class TcpManager extends Thread{ + private final TcpFactory tcpFactory; + + private final Map servers; + private final Map connections; + private final ExecutorService connectionExecutor; + private final ServerSocket serverSocket; + + private final Consumer handleMessage; + + private boolean isRunning; + + public TcpManager(int port, Consumer handleMessage) throws IOException { + servers = new ConcurrentHashMap<>(); + connections = new ConcurrentHashMap<>(); + + tcpFactory = new TcpFactory(this); + + connectionExecutor = Executors.newCachedThreadPool(); + + serverSocket = new ServerSocket(port); + this.handleMessage = handleMessage; + } + + public TcpServer getServer(String pluginIdentifier, String username, InetAddress userAddress, int port) { + TcpServer tcpServer = tcpFactory.createServer(pluginIdentifier, username, userAddress, port); + servers.put(tcpServer.getConnectionData(), tcpServer); + + return tcpServer; + } + + public TcpClient getClient(ConnectionData serverData, String pluginIdentifier, String username) { + return tcpFactory.createClient(serverData, pluginIdentifier, username, serverData.getOwnerAddress(), serverData.getPort()); + } + + private TcpPitiupi createConnection(InetAddress receiverAddress, int port) { + TcpPitiupi tcpPitiupi = tcpFactory.createPitiupiConnection(receiverAddress, port); + + manageConnectionList(tcpPitiupi, receiverAddress); + startConnectionReceiver(tcpPitiupi); + + return tcpPitiupi; + } + + public boolean send(Message message, InetAddress receiverAddress, int port) { + TcpPitiupi tcpPitiupi = findConnection(receiverAddress); + if (tcpPitiupi == null || tcpPitiupi.isClosed()) tcpPitiupi = createConnection(receiverAddress, port); + try { + tcpPitiupi.send(message.toByteArray()); + return true; + } + catch (IOException ex) { + Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, ex); + return false; + } + } + private void receive() { + while (isRunning) { + Socket socket = null; + + try { + socket = serverSocket.accept(); + processConnection(socket); + } + catch (SocketException e) { + if (isRunning) { + Logger.getLogger(TcpManager.class.getName()).log(Level.SEVERE, "Erro no servidor TCP.", e); + } + } + catch (IOException e) { + Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, "Erro ao aceitar conexão.", e); + } + } + } + + private void processConnection(Socket socket) { + try { + TcpPitiupi tcpPitiupi = tcpFactory.createFromReceiver(socket); + + if (tcpPitiupi == null) return; + + if (tcpPitiupi instanceof TcpClient client) { + ConnectionData serverData = client.getServerData(); + TcpServer tcpServer = servers.get(serverData); + + tcpServer.addClient(client); + } + else { + manageConnectionList(tcpPitiupi, socket.getInetAddress()); + startConnectionReceiver(tcpPitiupi); + } + } catch (IOException e) { + Logger.getLogger(TcpClient.class.getName()).log(Level.SEVERE, null, e); + } + } + + public void closeManager() { + try { + isRunning = false; + serverSocket.close(); + } + catch (IOException e) { + Logger.getLogger(TcpManager.class.getName()).log(Level.WARNING, null, e); + } + + servers.clear(); + connections.clear(); + } + + public void closeServer(TcpServer tcpServer) { + ConnectionData serverData = tcpServer.getConnectionData(); + if (serverData.isServer()) servers.remove(serverData); + + tcpServer.close(); + } + + private TcpPitiupi findConnection(InetAddress receiverAddress) { + return connections.get(receiverAddress); + } + public TcpServer findServer(ConnectionData serverData) { + return servers.get(serverData); + } + + private void manageConnectionList(TcpPitiupi tcpPitiupi, InetAddress receiverAddress) { + TcpPitiupi oldPitiupiConnection = connections.put(receiverAddress, tcpPitiupi); + if (oldPitiupiConnection != null) { + tcpFactory.tryClose(oldPitiupiConnection.getSocket()); + } + } + private void startConnectionReceiver(TcpPitiupi tcpPitiupi) { + connectionExecutor.submit(() -> { + while (!tcpPitiupi.isClosed()) { + try { + handleMessage.accept(tcpPitiupi.receive()); + } catch (IOException e) { + Logger.getLogger(TcpManager.class.getName()).log(Level.SEVERE, null, e); + break; + } + } + }); + } + + @Override + public void run() { + isRunning = true; + receive(); + } +} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java b/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java new file mode 100644 index 0000000..e9bb3a1 --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpPitiupi.java @@ -0,0 +1,70 @@ +package pitiupi.net.tcp; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; + +class TcpPitiupi { + protected final Socket socket; + + protected final DataInputStream input; + protected final DataOutputStream output; + + public TcpPitiupi(Socket socket, DataInputStream input, DataOutputStream output) { + this.socket = socket; + this.input = input; + this.output = output; + } + + /** + * Envia uma mensagem pela conexão. + * + *

A mensagem é enviada precedida pelo seu tamanho, permitindo que o + * receptor determine quantos bytes devem ser lidos.

+ * + * @param message mensagem a ser enviada + * @throws IOException se ocorrer um erro durante o envio + */ + public void send(byte[] message) throws IOException { + output.writeInt(message.length); + output.write(message); + output.flush(); + } + + /** + * Recebe uma mensagem da conexão. + * + *

Primeiro lê o tamanho da mensagem e, em seguida, lê aquantidade + * correspondente de bytes.

+ * + * @return mensagem recebida + * @throws IOException se o tamanho da mensagem for inválido ou se a conexão + * for encerrada antes que a mensagem seja completamente recebida + */ + public byte[] receive() throws IOException { + int length = input.readInt(); + + if (length < 0) throw new IOException("Invalid message length."); + + byte[] message = input.readNBytes(length); + + if (message.length != length) { + throw new IOException("Connection closed before receiving the complete message."); + } + + return message; + } + + public boolean isClosed() { + return socket.isClosed(); + } + + Socket getSocket() { + return socket; + } + + public void close() throws IOException { + socket.close(); + } +} diff --git a/pitiupi/src/pitiupi/net/tcp/TcpServer.java b/pitiupi/src/pitiupi/net/tcp/TcpServer.java new file mode 100644 index 0000000..5b21623 --- /dev/null +++ b/pitiupi/src/pitiupi/net/tcp/TcpServer.java @@ -0,0 +1,61 @@ +package pitiupi.net.tcp; + +import pitiupi.models.ConnectionData; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; +import java.util.logging.Logger; + +public final class TcpServer { + private final ConnectionData connectionData; + + private final BlockingQueue buffer; + private final Map clients; + + TcpServer(ConnectionData connectionData) { + this.connectionData = connectionData; + + this.buffer = new LinkedBlockingQueue<>(); + this.clients = new ConcurrentHashMap<>(); + } + + void addClient(TcpClient tcpClient) { + buffer.add(tcpClient); + clients.put(tcpClient.getClientData(), tcpClient); + } + + public TcpClient receive() { + try { + return buffer.take(); + } + catch (InterruptedException e) { + Logger.getLogger(TcpServer.class.getName()).log(Level.SEVERE, null, e); + return null; + } + } + + public List getClients() { + return clients.keySet().stream().toList(); + } + + public ConnectionData getConnectionData() { + return connectionData; + } + + void close() { + for (TcpClient tcpClient : clients.values()) { + try { + tcpClient.close(); + } catch (IOException e) { + Logger.getLogger(TcpServer.class.getName()).log(Level.WARNING, null, e); + } + } + buffer.clear(); + clients.clear(); + } +} diff --git a/pitiupi/src/pitiupi/plugin/Pitiupi.java b/pitiupi/src/pitiupi/plugin/Pitiupi.java index 071de18..bbbec22 100644 --- a/pitiupi/src/pitiupi/plugin/Pitiupi.java +++ b/pitiupi/src/pitiupi/plugin/Pitiupi.java @@ -2,10 +2,12 @@ package pitiupi.plugin; import pitiupi.control.ConnectionManager; import pitiupi.control.GuiManager; +import pitiupi.models.ConnectionData; import pitiupi.models.Menus.Menu; import pitiupi.models.Menus.MenuCategory; import pitiupi.models.Messages.Message; -import pitiupi.net.tcp.TcpConnection; +import pitiupi.net.tcp.TcpClient; +import pitiupi.net.tcp.TcpServer; import java.net.InetAddress; @@ -31,8 +33,12 @@ public class Pitiupi { return connectionManager.sendTcp(message, address); } - public TcpConnection connectTcp(InetAddress address, String senderId, String receiverId) { - return connectionManager.connectPluginTcp(address, senderId, receiverId); + public TcpServer openTcpServer(String pluginId) { + return connectionManager.getTcpServer(pluginId); + } + + public TcpClient connectToTcpServer(ConnectionData connectionData, String pluginId) { + return connectionManager.connectToTcpServer(connectionData, pluginId); } public String getUserName() {