From 0e20ca342f67b547fb181773f7008448fd248019 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=B5=A9=E6=B5=A9?= <1036606149@qq.com> Date: Sun, 29 Dec 2024 22:31:58 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E3=80=91IoT:=20=E6=8F=92=E4=BB=B6=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/enabled.txt | 1 + ...-module-iot-http-plugin-2.2.0-snapshot.jar | Bin 9347 -> 8804 bytes .../plugininfo/PluginInfoController.java | 18 +- .../plugininfo/vo/PluginInfoImportReqVO.java | 19 ++ .../framework/plugin/SpringConfiguration.java | 17 -- ...uration.java => UnifiedConfiguration.java} | 29 +-- .../service/plugininfo/PluginInfoService.java | 11 +- .../plugininfo/PluginInfoServiceImpl.java | 197 ++++++++++-------- .../module/iot/plugin/WelcomePlugin.java | 91 ++++++++ .../yudao-module-iot-http-plugin/pom.xml | 2 + 10 files changed, 258 insertions(+), 127 deletions(-) create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java rename yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/{ServiceRegistryConfiguration.java => UnifiedConfiguration.java} (55%) create mode 100644 yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java diff --git a/plugins/enabled.txt b/plugins/enabled.txt index e69de29bb2..b62400a815 100644 --- a/plugins/enabled.txt +++ b/plugins/enabled.txt @@ -0,0 +1 @@ +http-plugin@0.0.1 diff --git a/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar b/plugins/yudao-module-iot-http-plugin-2.2.0-snapshot.jar index 0300a632ae6d0bd042e974113a7193dc0e578232..28b10d529ce689efb557305c356827c90e42e60e 100644 GIT binary patch literal 8804 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 literal 9347 zcmb_h1yo#Fwyoe0q;Qwu?hxGF-8HzoySuxEpuyeU3JVZ4IKd$aZUGYDlSy|oJ?ZJ0 zzy7~#)qAy8oxRV!=heG!zq1vj!6D!PKZbm2vgSX&{C0qSJj;rz2+~Q)i7_br76t>5 zdkj1DpSx{;{2Bil0D$(-VX}g9l47FDD)h2qs&V6ReT=~1u8b%0|P93!ltsecL>XmAOG}VPW%*Dc(oz1f_R{ z;9EuNScbGx?(XiYv})-uWaKz@@%ZvMy?gxS@{*vw#A4^FymNLrKe0P5Ae7-%EVtmD zxtZHtjYg5u`+czhfTQ1^YXbhbSR>m%s_|>U^Pd40c1Cu_CXRm-i2Ub34;N!YyT1v? z`m1moJ7X7XlfOaX{SC^(&iS8^n2CR0D9L|7+FQGrSv(a21|a_Uw?LJJ4HJ2+fa&9G zS^ql%31??}2}4_BYZFI$BWpt^r%DZ2Z?rk=hwgFm`b8O_S`~WSoA4L&VEIB|)WITP zF9M8F2MQeOxFw<3xxb9jCh8G164+F_H@bfyz_1%2@z-i-Y_!z&%3WF#E>N{XI;`A$ z7`H|oHkG{nay(?(^>yuQ*VoPmH@??i4^uvX)Cg}#zJM|f=2z)VELGYGUCufzB%P)_ zIg^~9M3f?&n-iid9J6Ps>9FPZQ^C3gLJY+c+qN!5U-4=&mr@W{irG=;&3hJv8o$ku z8)V^zh}^oxASte%#k27k1%|Wkaw$t=C!~%jy_QlBXj*=rOe%w|n@=Cq;DaiO*eluSiiM7WMKZ*#DGa`S}OHt>~0 z7ZVn{qo|(CAztKvuRQ$M-2$W*M8`q7x}3 zua!WOkDh&t3hUt<B#N>X4_!xHV1uY|iIpvP!PM{yOuWj$2qYU-fn!xdrqK%+54g4M@sF~o|RAlsA?U14iudp2t$ zSniBN6?6nLP8qkst+#&9Q4q+!$+YVUR78VxAfHgGQCvSUTy)Vk@*HIvD~zl+Ie=_; zF{`v))@mkr)y1a{3Y!!h_i7yHIwY9MMhKk|9(8Rf?4L}}Qk|haEm9PGsaCeaSc(%J zPmPWDYyivmdD*V?`&m`z0FJO%sZ|K=yOwK`>zmV|cpTAu*M3I3sq?T>2nI4MLFh0SAd{*kxQE!mQ#9E7yukPxYTkQinoWLtqXFo;c*63W6?Ik>6;u@!wT4Upok}iR zoRBYTJBWqc$yF+h7x7)hcM+iqE{^-_(Vmmb_E)jdMKx)^<>aN6G-Gn!pE`9O(=7Pv zuxi2AE}3Q?w%xe2)tql&4WQYgQTqT#`G}o*eQ@gpgPPUL7ZCQj zDzUP0FX}_h6;AwnB3ki`iq?vzWW(D&>r?Cxdkf&M;Kq1b2pY+hA%x?~-QnZjsZGdWdwPeoQ`WeWmet`jO65uq zUS#TkEGvj{2jmWte7>N9eVTT#;@^lhs5mzm8MPY#8*# zwPU9!49YKMXl(4>hNpZzL)f{pU)$Kdp5F`cV;-+%R>nwXKK@k9m(RxLgbO*e%|@Y2 zD)8MD_R*=YqDBLy)^(7osYVveu$NOuL4w|d{3<6w4%fP3e%L1bDCXS36nI!BsJ*)s z)V|c!Toxx~F)p%ZBI=ULIpnyd`X$$7zMzZ#HvF^<@yr=leLe)yg;-40?>ODq)|_b+ zTbB_H;|Hyj+Frb-yVdgC7SeBpx**o4bJ z#`HnqqaNEt+1{!0aNX(4+k(n|Xj}Udg2g(kZ{?At>4TrtSZqKSp2B>36mjkeYLZmm zAq_aIlCpXt>nl?@+wLBUCesi|kL`&2IUuj2y!o{wR7B_*u9vi-nP zG;HPgr7_(|%ct(!U3Je@!hOcZ6@+Kzq7#m+lM`1;yAPLvQ3FGfnIS*7Hc>Q+VmTQ~ zW%QfOez=qOfHh1?FPpui0NphBm6M(x)vw(hdu0KK-1>{IpdR6u9iB5qWOa_I@GJM% zG;#X6y2RTP<+o2^d+(+0{h&*|r{Ta( z^5P3TeSN+|y>mTRzlVu*bJ*@T{LVeH%8BY5JmLjG?!>yfHHbDG7ExHJ!fvj_+@DF< zeIX$4trskgetvNl*_lp1se;W_M<}lTt^eL93B0+0o|WR@E5pIi3T`c_3dR);fi89# z%r|fXUTziiD|z}8C}rVu&S871d;F8VoNRu&2XYx|8b9E3;izwloiqpU^)+;XSD3UF zYVJp+ft~%4z7=JN!Qft#D!MJ;&&z{Mln0uIfU7OIhs1aXL!sghh(Ioe*~K__mxSbb zRQk_Drs~FqCF&Rb+f8ALc=Rwd8$$GlA&26NXgo>CXo#V=i18;0g0S2QgBettIffH) zNRDNR=lM06oKcgyq2)C(NFcLCmYvhAy`?P++VzhGu%Bx2#IH?r4(bbJcpwyZxOb3OEvXzS;Mqi@nNEoo zEKOdP>0vM3-Ssrow0@;KjuZ$Hf(1U~)7mJ!gV{oE-Vx%SS&3IaB*7(s%*)ob!fP~y z=bU)(6jZW~dP-{PjDs*MP^ksmz-k!vc3gqld}zEyKQn$7v2WL@w9raOa#eKnSm|s0 zs9Whb9aN0zn?gY}%zd_#L$ftFAmfH13kvmhN9*0nOAP6?b)8udi;lp!K#qWo0IvW- zPd!+k=hr+{)rf*SL&iHSXDbF)g=D&PWL$EV~6QMxUi>m(Vg15 z?wB5<@V)K6j6xEf0m?e=^DJd#9m*aNFHb2(Q@+woINj|b+{;0eS8tzb8$Z-%WkJqF zsN_d4pREk&>z$ICUTiV+TVk{f!KfqTwtumszhqx?==K}pzeb4P(!F2n_iYB&1j6PT z)LsLAe}DO@%FVBfS%$#?04^v1fbG9m3j{hMHp@SxT{oPw>P|gKg7(NDd>~DXtz{V#wCEP>yh*B zn$!D?RyW`8-_P)Sh}Ga5m^7NqBtKr^BWr{qgnj$abJ|%DM;=)JtUfixPaG@$w&8_X@;H3}ZQHNRp z;Uh=1X-<@QZ!(oRw!qp^*g>-7In<1Gz z)ei2mTIFWoXAUxka#rq+wtL@kD{%X3{O0!rzML6{r+pVQh+->kCv~7U@{A+24?Rk( zaMxi2TcT?i;5=8OZIEjc`Gms2yL|a&x;)!CB?7Z84b=q%?xGa|zY7I|prNmxhjh`I zFD@x}>8@fFdWlz{9!HjREBZzg*9WR?*mcG_wL&jKUdFdL5B6MnKj}@avO4sc#I$+n zIY$+-=oO9+K0H2QqWO@^N_Y<+N)413w?{M|b+KKGa;y(Xp*135n(3&?aPK&$*3q&f zBI4mlHiaS<$R9X2ur<7qtQC0%CVhdzGlU1X(Ca8se@yBpqWpgMG`U1Pc(1Xy9!MS+ zGD(jD4?{1l5TZcxyz%o#$Nhvm$Uom2?6=wWq%Z&g<>T8p%m4P)_<3XGsC)ULsbl-f z(aY3j0PDc$@)7}g)?kKOQYkfPSx}C7S@DVKFlvVf2P3A##-=$Lvf+)EHkD|U2CB)K zP17X<#6${?MgH@amqy0m50|(l#~F(&!;QN`cJDL3cFgZ}X7|5+!0rTJ$NnxY1SK3| zO5IkZ$z)5@Ig)NkrK?73VNcv9)h99NqFm~iUwtiHgmPKr;c1 z4hJ6sQXtb1?75~J-fa|q`mEcrcJKk8*YbpVra@Z)=}HVBU+>` z6A|Cm(BKmOW^Q1&ta!N$NAfi++Sddh-)t+%`MRvu)k>@EjniSKMs3x^DqG4-6HCeE z-Qse*^l|aBb0eLDtMV$Xlu7L5;a3~wu)2%<%Kog|2XpYNv#UO6E+rKy9hKx8fDh}) zuvXXv9#}y*sw9}6COnZY@U0FxKmL`06TieBL211XS7P z;LlU%Sa%dIu;z6bz*U*yYN(;-;2GpDe6H6UUroTb$#r< zPn5p5&Gogn*}n&sZ@GQMCnRX+x2I#4BX4OJWs54CXVtHyadT8AK~0oDhbHLBYY2N>dJFM$C)21xbpvJEv`w zPI^mWmVC-A%xdV&n?5MhG7HL-Xx2~N(u%;Fgn2$e&p`8{j3!VG+vXZa`1MSJvyocd zqWLB8yka*3cwN}uLnDRUWS_B&(j~Vg*Nm3bZd;x2Qc^sE03wwtu*KgeA0kdoDQT=U zCiXA54&6VoOO(&^oH`RfO(cRK6TxPeEsfAhm2Oo-jkMco9XST5bddVOl(|kuzmI)B z4v(KVj7MRrjl?jbfT6h*Py>N8!@XDHNL!iIp5*XNXq=#OX%8spHp)0D8bnM7QsC6L z8`~09RjJ72oaW3bP&ftioa%9-+>S zbpL61hUZ<7dO8Pv0p`a%oQTh+(S|H3qk*F{qPbzmn_eh-c{D~2a@Ze-kVK>}GI3OO z%q7P;uU`mz=t@f~kBEHKE=|Hz#)MMZt16O1l*#5uO-<@f}d$$XWE9*;#A3XOdI6Z3k^_C~)^{Aur)I)uhW)fUNmJH7>97_}n~G8{r_< zP%d3UH)=)uhEpfsC{vig^?6=b9OD%q@qt|5gle3cV zU*rzgaIvzm=Hg&j`jQnO33__&qgB~ZpgLc6iZ@@&MDzL&g;mRBcN6zqH)4Ijq(X`c z5)`W-@Do8HxVx?l{>X^NF!hz$H%yxKh&)W6jt$379!IRYq!U|$p3$D{yYE>MbBZVf ztsDb#48_1qVt$NPtnwG6@)+q@VzBO^I_}n-)Zv`ZSZ$K2Gvdw>4PHk~$+W7Q7Y&yS z7)Sw|-@^$g&)>*?^{G#3VACsziVOUdQ7de(JR)<*1Pf^eIQP^UnucXL5Dm8RijPA5bkT;S30-aq<{JFAzMXWLY! ztWJnXky2hYoEAvmHXgy~QWj13s|I1gM?fXf2fT_wOkV2njMonhsQH%-a9X}MO)rv@ zk&I^Of{Q`wo_tj#UZUF|PkE4*K452IS95&G^?eY2AA=ZSUm)|&%9jE9mGX{&{B=~4 zg^Yl+^&`WB*09y)6YCps_bb#2w6OOv27XXgsAMX9ky;8je7OPa8?wcF<4{Niuiz|E zJ!&&Ls6cAgf-oivviC5@#ve77+A(=FF^D%esNyVV2r7}qvV7u(cVW6ly{%Y`J_>$7 z13QkuUYaj#Gz+IbOQ}Om9zhpr=LszkuM0hSC1M?VQW?rr(qI{bzTAXFjB$W9Q0t{I zWI#YgDD(;_r!8ve@R7(X$k(`%GjkGZ0d3gRYRt7NakF zxEsWAJ35IwKkBmB$+H}ruW8bht4X|B4fNlRtovNx-T-lUPod0tV_&}Yw=Dt&=&A(E z&y3ho`%4A-AO+wTd*wr^25&qsAzAbsZ~*GMzuv~(|6oT-hn$^%x7^Szz;MX7^mXQ5 znAHP#bZ#gmoF0X=zs($=5$<*Zy<`&K7}OG2zAcSTc8hZ_F**3@JC`j`w$Pck?q1r~ zOv(V|_EW9~bUunL)Oo~BYFd^cd=ZOl*uc@|`|IcTQprR)87B|-q4Fp4%-5y!k80`R z4?X^?$Aa`II{xrjYz$pZo?7a^1{3}oY-CISo7F)7%I;4M{eN|Hc>Xi^A07nVPg8;J z(H@{Pe{9av{nF|GVHE^X?YzEzG(%V(7a;t9WVW}np?9~jo>Lo-U1kS%9V^2KRS|dc z!$gLt2_~?b`$K5H87EfP%D1T^OC+N5YVIZQ94j?PCVGqKXr=!qE#Gd2+$S1Q^lmD( z@yM0obOgtj<-6%F3Fm1+IWdx&iUs+#rh7QKp@0W9^WdJ@M)`5Bn0`oHVvq*4gQPO5 zj)iO43?$vKQv!-ICtY;HTP#dtQBLB-9%dBF*!TKfJrw4F1lFNRYlvYE>KVY>PO zSPq@y3nxVW`XPLfdX+<-onl|M;JjEf@HXceUi+yl#$wHfo+O9DwhV?0oBM7k$(MyQ zU0Gw0M&z%M&Z(X1L@4pSOH3vqee3vaIlP}UeYyP^N-W57y}9P5wY&NJvX2e2zKz#9 zpp)5ELBbhiFceISL08AtHsRSA4qaz1J3lcwLn481QMx`hf!1I~H|r>o-es9BZ0vxH z_uQl;@`E!Mk!(lnrH#(^!M3Bb-Scp~fWtdLnR1Dkk~(En?YA!QtkWdVcTB{I2z6GT z-`8XEX-ps1-1qk6$ehgRFhMG`;uh@jimwo7OB|BcFqJnFq|4Goso_Q(Z}}4qz#J^c zE-AmkAt&$<7I_CEPW2mIBs(O2%#U1ib2@rU_U_I~u9>^#cz0%Rmq4*EhWcjW<=_@9 zZS!Z?cNdYxMV)yrW(Qf{)N1;3bj}FV;prpbOjS`engSA@=L=er>Lzklw96ARW0KBy zRW^~w1D!$l=ej5U^4V~FM(0WiHf1$%X)D>8vMjVMXbn>Dg~ED+;`C=Vvw}jnlB9vQ z4Oxu-X%h{#I^6l6Ve`1)PcWEx251Ml>myDD_&o>ZSQaqH`EbAzL9E?t@}lDV*S;z$ z@nkk%yWEhGjSjx2AC?w&e&Hr>brnFdR4!hX0?Q9VPIFkw?=>Pm zj5%|`2lr$TT6trjeWj-tM71KwWe;9qsH*9GxvpoDkj# z!u1mY1*SUR0_)U7q+SG6XyLT&mv#D2Sun?QF~01AF=kF=QEW&@C;m>`*e@*eP9h9dO z$H4z(il6 uploadJar( - @RequestParam("id") Long id, - @RequestParam("jar") MultipartFile file) throws Exception { - if (file.isEmpty()) { - throw exception(FILE_IS_EMPTY); - } - pluginInfoService.uploadJar(id, file); + @PostMapping("/upload-file") + @Operation(summary = "上传插件文件") + public CommonResult uploadFile(@Valid PluginInfoImportReqVO reqVO) { + pluginInfoService.uploadFile(reqVO.getId(), reqVO.getFile()); return success(true); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java new file mode 100644 index 0000000000..9216d09ecb --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/plugininfo/vo/PluginInfoImportReqVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +@Schema(description = "管理后台 - IoT 插件上传 Request VO") +@Data +public class PluginInfoImportReqVO { + + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "11546") + private Long id; + + @Schema(description = "插件文件", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "插件文件不能为空") + private MultipartFile file; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java deleted file mode 100644 index d87a94f318..0000000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/SpringConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package cn.iocoder.yudao.module.iot.framework.plugin; - -import org.pf4j.spring.SpringPluginManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; - -@Configuration -public class SpringConfiguration { - - @Bean - @DependsOn("serviceRegistryInitializedMarker") - public SpringPluginManager pluginManager() { - return new SpringPluginManager(); - } - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java similarity index 55% rename from yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java rename to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java index 3450b67fb9..66adc3c9fc 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/ServiceRegistryConfiguration.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/framework/plugin/UnifiedConfiguration.java @@ -1,35 +1,36 @@ package cn.iocoder.yudao.module.iot.framework.plugin; -import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import cn.iocoder.yudao.module.iot.api.ServiceRegistry; +import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi; import lombok.extern.slf4j.Slf4j; +import org.pf4j.spring.SpringPluginManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; -import javax.annotation.PostConstruct; import javax.annotation.Resource; @Slf4j @Configuration -public class ServiceRegistryConfiguration { +public class UnifiedConfiguration { + + private static final String SERVICE_REGISTRY_INITIALIZED_MARKER = "serviceRegistryInitializedMarker"; @Resource private DeviceDataApi deviceDataApi; - @PostConstruct - public void init() { - // 将主程序中的 DeviceDataApi 实例注册到 ServiceRegistry + @Bean(SERVICE_REGISTRY_INITIALIZED_MARKER) + public Object serviceRegistryInitializedMarker() { ServiceRegistry.registerService(DeviceDataApi.class, deviceDataApi); log.info("[init][将 DeviceDataApi 实例注册到 ServiceRegistry 中]"); - } - - /** - * 定义一个标记用的 Bean,用于表示 ServiceRegistry 已初始化完成 - */ - @Bean("serviceRegistryInitializedMarker") // TODO @haohao:1)这个名字,可以搞个 public static final 常量;2)是不是 conditionBefore 啥 - public Object serviceRegistryInitializedMarker() { - // 返回任意对象即可,这里返回 null 都可以,但最好返回个实际对象 return new Object(); } + @Bean + @DependsOn(SERVICE_REGISTRY_INITIALIZED_MARKER) + public SpringPluginManager pluginManager() { + log.info("[init][实例化 SpringPluginManager]"); + return new SpringPluginManager(); + } + } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java index 8671034021..d023791c81 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoService.java @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import jakarta.validation.Valid; import org.springframework.web.multipart.MultipartFile; +import java.util.List; + /** * IoT 插件信息 Service 接口 * @@ -58,7 +60,7 @@ public interface PluginInfoService { * @param id 插件id * @param file 文件 */ - void uploadJar(Long id, MultipartFile file); + void uploadFile(Long id, MultipartFile file); /** * 更新插件的状态 @@ -67,4 +69,11 @@ public interface PluginInfoService { * @param status 状态 */ void updatePluginStatus(Long id, Integer status); + + /** + * 获得启用的插件列表 + * + * @return 插件列表-插件id + */ + List getEnabledPlugins(); } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java index bd7efa8d0c..333d0fa988 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/plugininfo/PluginInfoServiceImpl.java @@ -1,17 +1,13 @@ package cn.iocoder.yudao.module.iot.service.plugininfo; -import cn.hutool.core.io.IoUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoPageReqVO; import cn.iocoder.yudao.module.iot.controller.admin.plugininfo.vo.PluginInfoSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.plugininfo.PluginInfoDO; import cn.iocoder.yudao.module.iot.dal.mysql.plugininfo.PluginInfoMapper; import cn.iocoder.yudao.module.iot.enums.plugin.IotPluginStatusEnum; -import jakarta.annotation.PostConstruct; import jakarta.annotation.Resource; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.pf4j.PluginDescriptor; import org.pf4j.PluginState; @@ -22,11 +18,13 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import org.springframework.web.multipart.MultipartFile; -import java.nio.file.Path; +import java.io.File; +import java.io.IOException; +import java.nio.file.*; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; @@ -47,9 +45,6 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Resource private SpringPluginManager pluginManager; - @Resource - private FileApi fileApi; - @Value("${pf4j.pluginsDir}") private String pluginsDir; @@ -95,6 +90,19 @@ public class PluginInfoServiceImpl implements PluginInfoService { // 删除 pluginInfoMapper.deleteById(id); + // 删除插件文件 + Executors.newSingleThreadExecutor().submit(() -> { + try { + TimeUnit.SECONDS.sleep(1); // 等待 1 秒,避免插件未卸载完毕 + File file = new File(pluginsDir, pluginInfoDO.getFile()); + if (file.exists() && !file.delete()) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile()); + } + } catch (InterruptedException e) { + log.error("[deletePluginInfo][删除插件文件({}) 失败]", pluginInfoDO.getFile(), e); + } + }); + } private PluginInfoDO validatePluginInfoExists(Long id) { @@ -116,73 +124,100 @@ public class PluginInfoServiceImpl implements PluginInfoService { } @Override - public void uploadJar(Long id, MultipartFile file) { - // 1. 校验存在 + public void uploadFile(Long id, MultipartFile file) { + // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 2. 判断文件名称与插件 ID 是否匹配 + // 2. 获取插件 ID String pluginId = pluginInfoDo.getPluginId(); - // 3. 停止卸载旧的插件 - // 3.1. 获取插件信息 + // 3. 停止并卸载旧的插件 + stopAndUnloadPlugin(pluginId); + + // 4. 上传新的插件文件 + String pluginIdNew = uploadAndLoadNewPlugin(file); + + // 5. 更新插件启用状态文件 + updatePluginStatusFile(pluginIdNew, false); + + // 6. 更新插件信息 + updatePluginInfo(pluginInfoDo, pluginIdNew, file); + } + + // 停止并卸载旧的插件 + private void stopAndUnloadPlugin(String pluginId) { PluginWrapper plugin = pluginManager.getPlugin(pluginId); if (plugin != null) { - // 3.2. 如果插件状态是启动的,停止插件 if (plugin.getPluginState().equals(PluginState.STARTED)) { - pluginManager.stopPlugin(pluginId); + pluginManager.stopPlugin(pluginId); // 停止插件 } - // 3.3. 卸载插件 - pluginManager.unloadPlugin(pluginId); + pluginManager.unloadPlugin(pluginId); // 卸载插件 } + } - // 4. 上传插件 - String pluginIdNew; + // 上传并加载新的插件文件 + private String uploadAndLoadNewPlugin(MultipartFile file) { + Path pluginsPath = Paths.get(pluginsDir); try { - String path = fileApi.createFile(pluginsDir, IoUtil.readBytes(file.getInputStream())); - Path pluginPath = Path.of(path); - pluginIdNew = pluginManager.loadPlugin(pluginPath); - } catch (Exception e) { - throw exception(PLUGIN_INSTALL_FAILED); - } - - PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); - if (pluginWrapper == null) { - throw exception(PLUGIN_INSTALL_FAILED); - } - - // 5. 读取配置文件和脚本 - String configJson = ""; - String script = ""; - try (JarFile jarFile = new JarFile(pluginWrapper.getPluginPath().toFile())) { - // 5.1 获取config文件在jar包中的路径 - String configFile = "classes/config.json"; - JarEntry configEntry = jarFile.getJarEntry(configFile); - - if (configEntry != null) { - // 5.2 读取配置文件 - configJson = IoUtil.readUtf8(jarFile.getInputStream(configEntry)); - log.info("configJson:{}", configJson); + if (!Files.exists(pluginsPath)) { + Files.createDirectories(pluginsPath); // 创建插件目录 } - - // 5.3 读取script.js脚本 - String scriptFile = "classes/script.js"; - JarEntry scriptEntity = jarFile.getJarEntry(scriptFile); - if (scriptEntity != null) { - // 5.4 读取脚本文件 - script = IoUtil.readUtf8(jarFile.getInputStream(scriptEntity)); - log.info("script:{}", script); + String filename = file.getOriginalFilename(); + if (filename != null) { + Path jarPath = pluginsPath.resolve(filename); + Files.copy(file.getInputStream(), jarPath, StandardCopyOption.REPLACE_EXISTING); // 保存上传的 JAR 文件 + return pluginManager.loadPlugin(jarPath.toAbsolutePath()); // 加载插件 + } else { + throw exception(PLUGIN_INSTALL_FAILED); } } catch (Exception e) { throw exception(PLUGIN_INSTALL_FAILED); } + } + // 更新插件状态文件 + private void updatePluginStatusFile(String pluginIdNew, boolean isEnabled) { + Path enabledFilePath = Paths.get(pluginsDir, "enabled.txt"); + Path disabledFilePath = Paths.get(pluginsDir, "disabled.txt"); + Path targetFilePath = isEnabled ? enabledFilePath : disabledFilePath; + Path oppositeFilePath = isEnabled ? disabledFilePath : enabledFilePath; + + try { + PluginWrapper pluginWrapper = pluginManager.getPlugin(pluginIdNew); + if (pluginWrapper == null) { + throw exception(PLUGIN_INSTALL_FAILED); + } + String pluginInfo = pluginIdNew + "@" + pluginWrapper.getDescriptor().getVersion(); + List targetLines = Files.exists(targetFilePath) ? Files.readAllLines(targetFilePath) + : new ArrayList<>(); + List oppositeLines = Files.exists(oppositeFilePath) ? Files.readAllLines(oppositeFilePath) + : new ArrayList<>(); + + if (!targetLines.contains(pluginInfo)) { + targetLines.add(pluginInfo); + Files.write(targetFilePath, targetLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } + + if (oppositeLines.contains(pluginInfo)) { + oppositeLines.remove(pluginInfo); + Files.write(oppositeFilePath, oppositeLines, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + } + } catch (IOException e) { + throw exception(PLUGIN_INSTALL_FAILED); + } + } + + // 更新插件信息 + private void updatePluginInfo(PluginInfoDO pluginInfoDo, String pluginIdNew, MultipartFile file) { pluginInfoDo.setPluginId(pluginIdNew); pluginInfoDo.setStatus(IotPluginStatusEnum.STOPPED.getStatus()); pluginInfoDo.setFile(file.getOriginalFilename()); - pluginInfoDo.setConfigSchema(configJson); - pluginInfoDo.setScript(script); + pluginInfoDo.setScript(""); - PluginDescriptor pluginDescriptor = pluginWrapper.getDescriptor(); + PluginDescriptor pluginDescriptor = pluginManager.getPlugin(pluginIdNew).getDescriptor(); + pluginInfoDo.setConfigSchema(pluginDescriptor.getPluginDescription()); pluginInfoDo.setVersion(pluginDescriptor.getVersion()); pluginInfoDo.setDescription(pluginDescriptor.getPluginDescription()); pluginInfoMapper.updateById(pluginInfoDo); @@ -190,52 +225,50 @@ public class PluginInfoServiceImpl implements PluginInfoService { @Override public void updatePluginStatus(Long id, Integer status) { - // 1. 校验存在 + // 1. 校验插件信息是否存在 PluginInfoDO pluginInfoDo = validatePluginInfoExists(id); - // 插件状态无效 + // 2. 校验插件状态是否有效 if (!IotPluginStatusEnum.contains(status)) { throw exception(PLUGIN_STATUS_INVALID); } + // 3. 获取插件ID和插件实例 String pluginId = pluginInfoDo.getPluginId(); PluginWrapper plugin = pluginManager.getPlugin(pluginId); + + // 4. 根据状态更新插件 if (plugin != null) { - if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) && plugin.getPluginState() != PluginState.STARTED) { - // 启动插件 + // 4.1 如果目标状态是运行且插件未启动,则启动插件 + if (status.equals(IotPluginStatusEnum.RUNNING.getStatus()) + && plugin.getPluginState() != PluginState.STARTED) { pluginManager.startPlugin(pluginId); - } else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) && plugin.getPluginState() == PluginState.STARTED) { - // 停止插件 + updatePluginStatusFile(pluginId, true); // 更新插件状态文件为启用 + } + // 4.2 如果目标状态是停止且插件已启动,则停止插件 + else if (status.equals(IotPluginStatusEnum.STOPPED.getStatus()) + && plugin.getPluginState() == PluginState.STARTED) { pluginManager.stopPlugin(pluginId); + updatePluginStatusFile(pluginId, false); // 更新插件状态文件为禁用 } } else { - // 已经停止,未获取到插件 + // 5. 插件不存在且状态为停止,抛出异常 if (IotPluginStatusEnum.STOPPED.getStatus().equals(pluginInfoDo.getStatus())) { throw exception(PLUGIN_STATUS_INVALID); } } + + // 6. 更新数据库中的插件状态 pluginInfoDo.setStatus(status); pluginInfoMapper.updateById(pluginInfoDo); } -// @PostConstruct -// public void init() { -// Executors.newSingleThreadScheduledExecutor().schedule(this::startPlugins, 3, TimeUnit.SECONDS); -// } -// -// @SneakyThrows -// private void startPlugins() { -// for (PluginInfoDO pluginInfoDO : pluginInfoMapper.selectList()) { -// if (!IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) { -// continue; -// } -// log.info("start plugin:{}", pluginInfoDO.getPluginId()); -// try { -// pluginManager.startPlugin(pluginInfoDO.getPluginId()); -// } catch (Exception e) { -// log.error("start plugin error", e); -// } -// } -// } + @Override + public List getEnabledPlugins() { + return pluginInfoMapper.selectList().stream() + .filter(pluginInfoDO -> IotPluginStatusEnum.RUNNING.getStatus().equals(pluginInfoDO.getStatus())) + .map(PluginInfoDO::getPluginId) + .toList(); + } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java new file mode 100644 index 0000000000..18b9c1417d --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/WelcomePlugin.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package cn.iocoder.yudao.module.iot.plugin; + +import cn.iocoder.yudao.module.iot.api.Greeting; +import org.apache.commons.lang.StringUtils; +import org.pf4j.Extension; +import org.pf4j.Plugin; +import org.pf4j.PluginWrapper; +import org.pf4j.RuntimeMode; +import com.sun.net.httpserver.HttpServer; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; + +/** + * 打招呼 测试用例 + */ +public class WelcomePlugin extends Plugin { + + private HttpServer server; + + public WelcomePlugin(PluginWrapper wrapper) { + super(wrapper); + } + + @Override + public void start() { + System.out.println("WelcomePlugin.start()"); + // for testing the development mode + if (RuntimeMode.DEVELOPMENT.equals(wrapper.getRuntimeMode())) { + System.out.println(StringUtils.upperCase("WelcomePlugin")); + } + startHttpServer(); + } + + @Override + public void stop() { + System.out.println("WelcomePlugin.stop()"); + stopHttpServer(); + } + + private void startHttpServer() { + try { + server = HttpServer.create(new InetSocketAddress(9081), 0); + server.createContext("/", exchange -> { + String response = "Welcome to PF4J HTTP Server"; + exchange.sendResponseHeaders(200, response.getBytes().length); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + }); + server.setExecutor(null); + server.start(); + System.out.println("HTTP server started on port 9081"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void stopHttpServer() { + if (server != null) { + server.stop(0); + System.out.println("HTTP server stopped"); + } + } + + @Extension + public static class WelcomeGreeting implements Greeting { + + @Override + public String getGreeting() { + return "Welcome to PF4J"; + } + + } + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml index 200a451b62..1ecf140a47 100644 --- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml +++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml @@ -24,6 +24,7 @@ cn.iocoder.yudao.module.iot.plugin.HttpPlugin 0.0.1 ahh + http-plugin-0.0.1 @@ -104,6 +105,7 @@ ${plugin.class} ${plugin.version} ${plugin.provider} + ${plugin.description} ${plugin.dependencies}