From 25e80b908a5948fb9425d03f6fa486102ae7f043 Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Thu, 4 Jun 2020 01:36:03 +0800 Subject: [PATCH 01/41] add contact and message mock methods in MockPuppet --- .../io/github/wechaty/grpc/GrpcPuppet.kt | 2 +- .../main/kotlin/io/github/wechaty/MockData.kt | 2 +- .../kotlin/io/github/wechaty/MockPuppet.kt | 105 +++++++++++++----- .../src/main/resources/image/mock.png | Bin 0 -> 38438 bytes .../io/github/wechaty/schemas/Contact.kt | 6 +- 5 files changed, 84 insertions(+), 31 deletions(-) create mode 100644 wechaty-puppet-mock/src/main/resources/image/mock.png diff --git a/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt b/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt index a19cc37..170b79e 100644 --- a/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt +++ b/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt @@ -398,7 +398,7 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { payload.avatar = response.avatar payload.city = response.city payload.friend = response.friend - payload.gender = ContractGender.getByCode(response.gender.number) + payload.gender = ContactGender.getByCode(response.gender.number) payload.name = response.name payload.province = response.province payload.signature = response.signature diff --git a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockData.kt b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockData.kt index 32c2873..c563cd9 100644 --- a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockData.kt +++ b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockData.kt @@ -21,7 +21,7 @@ class MockData { contactPayload.avatar = faker.avatar().toString() contactPayload.city = faker.address().city() contactPayload.friend = true - contactPayload.gender = ContractGender.Male + contactPayload.gender = ContactGender.Male contactPayload.name = faker.name().firstName() contactPayload.province = faker.address().state() contactPayload.signature = faker.lorem().sentence() diff --git a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt index e0afcf5..5f519a7 100644 --- a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt +++ b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt @@ -2,6 +2,7 @@ package io.github.wechaty import io.github.wechaty.filebox.FileBox import io.github.wechaty.schemas.* +import io.github.wechaty.utils.JsonUtils import org.slf4j.LoggerFactory import java.util.* import java.util.concurrent.CompletableFuture @@ -131,105 +132,157 @@ class MockPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { } override fun contactAlias(contactId: String, alias: String?): Future { - log.info("MockPuppet contactAlias($contactId,$alias)") + log.info("MockPuppet getContactAvatar($contactId,$alias)") return CompletableFuture.completedFuture(null) } override fun getContactAvatar(contactId: String): Future { - log.info("MockPuppet contactAvatar($contactId)") - TODO("Not yet implemented") + log.info("MockPuppet getContactAvatar($contactId)") + return CompletableFuture.completedFuture(FileBox.fromFile("image/mock.png", "mock.png")) } override fun setContactAvatar(contactId: String, file: FileBox): Future { - TODO("Not yet implemented") + return CompletableFuture.completedFuture(null) } override fun contactList(): Future> { - TODO("Not yet implemented") + log.info("MockPuppet contactList()") + + return CompletableFuture.completedFuture(listOf()) } override fun contactRawPayload(contractId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet contactRawPayload($contractId)") + val contactPayload = ContactPayload(contractId) + contactPayload.name = "mock name" + return CompletableFuture.completedFuture(contactPayload) } override fun contactRawPayloadParser(rawPayload: ContactPayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet contactRawPayloadParser($rawPayload)") + val contactPayload = ContactPayload(rawPayload.id) + contactPayload.avatar = "mock-avatar-data" + contactPayload.gender = ContactGender.Unknown + contactPayload.name = rawPayload.name + contactPayload.type = ContactType.Unknown + return CompletableFuture.completedFuture(contactPayload) } override fun friendshipAccept(friendshipId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet friendshipAccept($friendshipId)") + + return CompletableFuture.completedFuture(null) } override fun friendshipAdd(contractId: String, hello: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet friendshipAdd($contractId,$hello)") + + return CompletableFuture.completedFuture(null) } override fun friendshipSearchPhone(phone: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet friendshipSearchPhone($phone)") + + return CompletableFuture.completedFuture(null) } override fun friendshipSearchWeixin(weixin: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet friendshipSearchWeixin($weixin)") + + return CompletableFuture.completedFuture(null) } override fun friendshipRawPayload(friendshipId: String): Future { - TODO("Not yet implemented") + val friendshipPayload = FriendshipPayload() + friendshipPayload.id = friendshipId + return CompletableFuture.completedFuture(friendshipPayload) } override fun friendshipRawPayloadParser(rawPayload: FriendshipPayload): Future { - TODO("Not yet implemented") + return CompletableFuture.completedFuture(rawPayload) } override fun messageContact(messageId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageContact($messageId)") + return CompletableFuture.completedFuture("fake-id") } override fun messageFile(messageId: String): Future { - TODO("Not yet implemented") + return CompletableFuture.completedFuture(FileBox.fromBase64("cRH9qeL3XyVnaXJkppBuH20tf5JlcG9uFX1lL2IvdHRRRS9kMMQxOPLKNYIzQQ==", "mock-file$messageId.txt")) } override fun messageImage(messageId: String, imageType: ImageType): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageImage($messageId,$imageType)") + return CompletableFuture.completedFuture(FileBox.fromQRCode("fake-qrcode")) } override fun messageMiniProgram(messageId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageMiniProgram($messageId)") + val miniProgramPayload = MiniProgramPayload() + miniProgramPayload.title = "mock title for $messageId" + return CompletableFuture.completedFuture(miniProgramPayload) } override fun messageUrl(messageId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageUrl($messageId)") + return CompletableFuture.completedFuture(UrlLinkPayload("mock title for $messageId", "https://mock.url")) } override fun messageSendContact(conversationId: String, contactId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageSendContact($conversationId,$contactId)") + + return CompletableFuture.completedFuture(null) } override fun messageSendFile(conversationId: String, file: FileBox): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageSendFile($conversationId,$file)") + + return CompletableFuture.completedFuture(null) } override fun messageSendMiniProgram(conversationId: String, miniProgramPayload: MiniProgramPayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageSendMiniProgram($conversationId,${JsonUtils.write(miniProgramPayload)})") + + return CompletableFuture.completedFuture(null) } override fun messageSendText(conversationId: String, text: String, mentionList: List?): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageSendText($conversationId,$text,${JsonUtils.write(mentionList ?: "")})") + + return CompletableFuture.completedFuture(null) } override fun messageSendUrl(conversationId: String, urlLinkPayload: UrlLinkPayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageSendUrl($conversationId,${JsonUtils.write(urlLinkPayload)})") + + return CompletableFuture.completedFuture(null) } override fun messageRecall(messageId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageRecall($messageId)") + + return CompletableFuture.completedFuture(false) } override fun messageRawPayload(messageId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageRawPayload($messageId)") + val messagePayload = MessagePayload(messageId) + messagePayload.fromId = "from_id" + messagePayload.text = "mock message text" + messagePayload.toId = "to_id" + return CompletableFuture.completedFuture(messagePayload) } override fun messageRawPayloadParser(rawPayload: MessagePayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet messageRawPayloadParser($rawPayload)") + val messagePayload = MessagePayload(rawPayload.id) + messagePayload.fromId = rawPayload.fromId + messagePayload.mentionIdList = listOf() + messagePayload.text = rawPayload.text + messagePayload.timestamp = Date().time + messagePayload.toId = rawPayload.toId + messagePayload.type = MessageType.Text + return CompletableFuture.completedFuture(messagePayload) } override fun roomInvitationAccept(roomInvitation: String): Future { diff --git a/wechaty-puppet-mock/src/main/resources/image/mock.png b/wechaty-puppet-mock/src/main/resources/image/mock.png new file mode 100644 index 0000000000000000000000000000000000000000..c66f597483420cb72c92dc3f0f8502541f0da0da GIT binary patch literal 38438 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

p|1Eb`dU^V=ReY4asl6foZgayg_nbtY{({8vt z*Ix3-7V8rmyklHbsgM8I;FuECp#8eYq*2FIEfo}{ zGk3@pxX|*oFOaf1&TlM@hIDiPSWh8&cEXC&h8=Lm+bqvJ;u53Ma6Cd%uK@W9eh8Q2 zIRKR#^uExT-3oRN5ENd15BrEuT|cx~dk_p>=u+_;9^CFZNK2%((n$K9KkmV^4drJ? zi+lQCXbsbjoN&6-P8aK2m5y=KUF{}`{Bc{j1T9P)fy#XGjz_^ES!WZ9g8&L^=-Zi6lkM&lFX0Vsn1`4Zs1_6u&z)0+!lPRE}tSf_#h4|0jv?DpDU#8l!8+GjUD~ZPL zl3iYEZT(E}5)HawWd2+-O*s&F16wSN#RLk9V!m$Zi0b>@oCr|((tm^(sAgAb9x)Iki=lrXzJjiQr3VE%C3HP=TJfB*@+l_K93>J~lWm%>;h zE^ISbwc$0#ih^Y%>Zq(2p_tU7V|xx)_RyEZKA&F)_*2{UrX8A@?(lE69jM~Zs9A*c z7vsC)xQ|U|-gO?R8ue3CNZ&pACnp1gAd5;*L6iqDiK5oL+|;RBfyc3uRDhkS-aySI zQI~aMyX}U|8<9Qh(%{%LlWD5wlWRo|-(%64L#H+s;nNcaNz-9FB-52OR?}ilct5ne z{s^TjDDg?FrfdV$+O8Yp{idTo!KSg}-0VkV73>Fdjd`7>8Gjp6ty!ZDEka{lQIC}l zfxkSKcu#S}Za)THO9!1?*f7{ldg1)*9vxH>UeQk;HTsHVqLBk?P}Aabr}Yi0U*FBX6n}?1B&2^CQp$)iUAa50 z^8RyLO}G#WrZ9(IIn0=NzT%(x@}yfcU+j9_0Gf&s1-Cl2FTru}jE*f8cDa;LPCnl|N^DE&hn^{x&^e4Q?A<&82 z^9sido%2T2wX9RFa}iTnc@e0UfNXI*h!o2v?>D4)8cgcl8yWIW6~2WIqdfsq+Y8~u zse(06O^-CL+b~SpPFh6O!WtUF^f(xm;s(T9(JYEa_`@&stAbV?KCIUSOm#pvs_0mVynx3S}f4 zu^?JocEEMqe0g+ienV2J03B~l_G_<) zT@Fr)NEU+P#d1|T$2a7O_*!ED{7{znoExZQVu#d3XO$$hIn3svYYBJwu zkA3I%_@JY)s{<|2w1*-Hc2S6lGxo`@eb}Ux>IpuBZ+=m+r&!#)Q_7JR9DIc7?Bc*r zGZq{IZL^kQU%*_rsu>4Lz`wHu+j#;5mUuau;(mHR4_P6~M3)x@QNwxt8dki< zKJ^^Yt^}|w)L#m>*=+q}-t&hoFl$amV?Od;b+8z#_Yj%6J#g@IdYYBdutZA1*QM-e zYqm();F(D=eOW@XM@FRGz=pa`#aQte*#|rwaYJ+8H9%Rv^l?V#11#`FE%C4YMS=8D zgq6DClZ}L&Z8L=p?_dgwq8b-r;-FjFx6eF&Gw_O0!ODlK(LJ*anx>C^R_GNT9*AzK z&lmQ4Wo^Gck_E<_$KQQJ(3W4b3u=Jw*q`=KJR!o@rsFm4P31}y)JS9LryuyY$EXER z?Eyc&;mgRyc|+LlGRlP?OSr&|`MGblR5WiGbCD5KeD5{QlQ+VS6kVeBA(WhZt>dL@ zZu_Yxlh`rqlk6|L*L-RQekeZq8D|~fcV+VBc#}W{^lXE z2!Qh_?rSwKboCtk3dL8`oQ?0g|gKqbUZw(zq=`c*}wPsn~ccof-Ld@zEyH$Tlo-q zdcb*tB}-Hz?~=tSG+05?4vuDe-?Q5c_q{3-#AfpBnYQ0`FawvHps{G_-BL?zcd@8O+owj1ONp^qK*Z%_87w>^3*HHFJ+mAm#^ba6k& zL%IjL6-B=l&F}o%77i02nBF*)N9#|v-koiLSrvX4A3_z3X^Yar@oEjo6V)ME)fj?* zD!#X*1Mqi3g%Ou42$ADrYHHzTx6}R4Uj^KMxO83mCd4b(NSnLA*y6L!!|Lqc84>z- zYta;+3?)iSpBjoY3naTcJqZ`l^qKwoWwcAl3i|tReT1u+@eu@2Hj#-df84P{s;E-` zd)$TBemGf@#N)tDz?*;0*LxAJo9W%JBU4{%KsQmU_h+ooU_)uK(mr9PLhOGVj2cRZ z(=UW)XfP9n-!d7(Q>laPn$PFpj*RH#AO z_DdtLBxD(|n{icq79vLN-oGo-$fVW^b9g`0MCQih3}@kw^YL=fqX26uIqZGwh=b_nSr5A z(<6^Ci^Dc{rX6r$-51v!B4(15&0q_4cb*^|VTJnMGU)SP<+F~Qw06tm` z@e&7O_$VW|eva!@6Cb)NsO8bV)g5a)^P;a)U_xu&!C*AQ+JnLdH)9f@@ z&;>55vM>FJGx0mCTh)o4aXPx@A{N_sG;n^~FYHkf3dED&Pc@J!TvL+B7`A@RZ@Z;= zGtxNO!YqJ2MEB3BNkjqCC|}3sDQ1TL?#3?ucuh1|UjV%UMST%@uGIS-aW)opa=>pD zO%3P<{FvD{N45)Oz4}ii*nrJLM{jeTKd7D{Cj7kZHnpE<;^yNjXfQ&EVN$~1|q-PCrIUOJ|*g?*wcAMN0#_qol`#~l)OScTEu z!7y*1h+>jf=2{Q z1NmO2w)-CZ_~HKdrn{RyO8+Qa31+y`eBrSyLC2soIi?~2iL5^-qJ~fPR;ikPP3`=_ zt%@(h{kF85qpVr0>lJsM=gZN0FRBJ;?e(|%;F*)dWv^q5E1&JaBC0J;g~(7|;CWoc zuyo~$M7(|KEXUJuS?YVdBEc0>gp%K(7se3jF*Hbjyv=%UPjM^YPo3pp<#kAe%L^*j zt;LNSUGPn?ip;*tb@ic4Ogo`ziV}OhZHYY25#W;mTKU-x!K4#ICRgs?JWS51Bv;NO z0>)b@w^^SrrcLGu+oVU`&T%$cMn^)HQaN@$Q+?Br5Xz1jG0K+}=2lUmd}xPG_yTG; zO@v@*h5P4|^0;hX=7AcLkGJ8K!%?{80NIRfU9c8~n~nX=!QOKc}a^zlUswgZDGq zy)YMP{gYOkzwWZqH|7U=j#O3U2kU3p{}zx?lQ?M&{eagqh z^X}H%Mj$&sKOdu@pkQZobX4|;z2E+8Z*}sW{yJ}tI>l4tQ z$U1a&w#V1m-7R<+b}yAD=8%R$LJT<1^-JKoWaMYz`q2Rr+Qz{OM!5PCtl%?w;b5RmEu#Z86x!sU~74vYI zDx*mk9e?`8N9l_F#$J@P<%I$lLcHHZZ-`ET-61u`jxE+_yYndP2L}hHEyA3fheUxW z@dWG3GQKBoU+Ucsv+Pmn? zhD7Su`){tVZS(T-vP@F{a3nRj?Wpor!d?ImRhtvbU2YPqT#OF?IFTiM(e_@9-KhF@ z^Cuu4)Hu60tD`?=aN%!-F-68VFj1ZqMZzxFe0#YSMq=b2kBr_AKq}t5!+!RtJ&^lH z-Lx73*Y^skbOc|fmHk3H2XDE~LQxQ`!q@rV_WyYA&;n1x?C>f-<(1kVZO*6&uh@(D zA=#1{-}R7opIob~08N0%^XKBYB!j>G*0)F~%|iu;tjw-#`K~wuk|NVY622I9%h%y= zZFlEB)`fki>mUH#pqdGS2QX9pmfOUm_3?6%AzA>}k_-5ez{M?19kWcJ8 z?<2&ANY0THD0?f;a$~$LcZHKzhB-}%Xq#>+!{;R1@}par%5@}H_It(R&y3|juiy#~*0BkCHw_^>iouf5#amx-bG@&)T={wz-okX%9 zjfHP_YFUm5fois*3G$3IfqRY7G28XYinl(j3UW&7M;p;%Hqg+UeTq~ zy0o3u{9FN!!JY;OT;r^=10p`R5OSi&twD8t;6Z-!7qSavsCMo8Yme7bR1Z<3{(3q& z?Zv%+^_5gvQBjW1Z0H%E^IXp(>krSyp1$@vMey{0wKO+heKs{5L&2x7Z(xA57;-T} z9-HQMK1aDxkHgZw%kT!2!NLJ`megpROk{?F)cXxixaPeZG6|C%SnIz6+m?j6286tJ zv6AivQn*k*;KfsDq6{7p=6c@;LRr}Bg{;eA^m$0?h7gjJjV)Kk)QtFT^trcBPz(9j^&Uda&U zkCm!(LV4kyOq$|*weR0|*z5Ygvv_QNa8MgiPo`03&b(OBXRS~B&3}=-N-h!@W%IF22IJFs#vh5d%I9!rK5BXurfE}` z(I+Cl*90mta&AL8o~?Dlbml4?j5=!aIr_)rKTA5Q3S;&_D3?ZHc58)kb`Ac+D-HSsJ#58D=i z!Hgit5OWcTtU2i@R0HE&{K~6;|Eh-FIWIXPk8bj@!PF!SAj2e*q^8r63q`{A7elQ# zr?Xer>nv}#)YYQbkq3o~K|d~FMkMYCAJ;wkh9ZIsrK91cI%=1M#nd@cBBii_@YX|` zzqBJ65qb*5wPkdgGntmwWYXxLQNrr9>SjXm0KF{y_p0e#p?z?kd=MBCS2uI zQ=hBpA9xZXrcc0QEu(<(Y>%x8qVxXLBz7aiyzS9F1nxv3?9~L4*^wrGU`MkZlkXWx zd#rzSGJIBLd7~TktF6ywh>II9#Kvu8y!&Jv$ZA((Xsno=6%rc}qORw;+uV9uV6C#%&`$ zh64412j9)QeET0`m50q4=<7d5QqpYdCAvJt9zh4cKH&(}SbI4v1_ywDX(yG{Mu1+= z%?Y{0;YyZ&kaylF3#NRKhj2jQMM27I^E8&^UcG0%kQKE@oL#Fly&d^eU^$pNl~&Up z#olthfvmg32*;)M{WPz8lw0S_$*Vk3gtvlt&dd%8YbFqAKTy#BaMvnt!2iSg+J`^z zX%CXYeM#)>=_k51wj!NDqBpyZdr&M~T#@WB?LkWywspjmx##QW>Ge){mQk8nmN;6f zjB@A!kuB0RIb{~0A9A==9S;n(4Kv#xPh>*eQxr_nK!hv8pjfU z0)ts)^gU;=NQ7&oN2RQ_%6|}Q$1uhze}oKOH0TS5u>U6Y4TL8kBowv7RHRX)S!+99 z$i6@6bh5X2Hw%G4ntK@;A4PvC{3t5B*zwC1et;|&nCu1(&yXZKfwq3%PX$^So8eF1@^kSbV8}rqisukuxd5Nq+2WY;Q&RQUL z-cLeFv1P4yxPY~>A0188J6ArHo&kJ$N52m1eymL8qk3d3jTy|%^yil0NF&4O;qQ-# z?^ek|m={G%_t{8AO400g>`g6gjg7D94+TY7g(~Le+l>6Qf6J6O0|Xwt;FCv#dHEW6 zyp9eyUMGgcF@-kB{U`38cDv81hov&y(|rGg>^-r3|IS0gA?aiY;XiMEi2NWSMkHnQ zKnSAv%Aq=NAq)0*pzF2%FPT&A0htqhBp~z8r?=7UM{B@Sa65l#q_Y^0QNrV{T*=a| zj|6!)U_AEjd-UJ$DeHSx3B`YB!X+sK#s;}Qdz?NtR^*>k#X_Wb$J8CfjT2pqveD4s zb7~{n?!Jy)v0;0iPc|R%|3pNHASR#dw2e5@ZO$_FW6|DGpo3`ExNTtI*(WsAS zm${*pmAym_kgEMOuyeMf8<$c;SHkTG{R6ps_|jg$IC$XxqUGYu^!RotQ&6+ znf40uk`p4xpnBW>3ecX$Qj_M+uZjTMy_#<30^TffsmBl{r)1&4dtTLTcLbk_LSkh{ zMwrFMdPy{vfeTjCv}IfaUN9SI|4K3lKQ<-r^G5Tx`+le-9SXj%$0ax^sNCK&_!Tvn z1P*_Ja(qDu<@nk=Fkm^zvhsa5@^rY&#OvN?-_FD*9Zy@f!6JE64NF`09iN<4=Y|ce zf-v>XclfA?-}EpK*9(XZSy9@~Loq7R8Oq8}DqCVmI;Ouvii%g(>F9|!u@Pd2P~H@m zy)nUE%eS0%isH2`(;W&6jT;{=r(d0Hf2G~?ko^RYrafpPwFFPLE*^b5{b2zuWfvLj zS&yDpdtnBAHbQa@RrKrpmPAdH0Rc9XJj5A0p19Ugy#W-hd}@`OxlHw@$x}#m;3O~; zQw0VGCT7mYRqDwxYMvyoinzlQ-T|Ax@E@0gZV53Pb|-pY5UOJ#pl)zFKNeGXtidQK z)sa9&mV;bzCir48_pWjyn6?PS>$gpe)1wM@2%wn5tIRINK?}dH!AQ$A=L4xg7v?7t zyw*ma&&g2>3rT(CxNOcUsgmeAov%ajnpciUbr;=s68YI;oj#oOHoRRX=)6iTrh_E8 zLf9?gv3BBo3it-VN%OHl>M82uw$D_|GN{DmpnvmA1bq|5qDWG>xDe-v;8b5F>D z=hy3&iS@@zFMs^3D*dG}EaLppYsh563&xSi^w&Yt$Xq82#TN%TH!5+lAmK6Fo}0_H z*NLfL963G=9NnI3?4s66iHMLyS?J1nsk6XhVj4PLbgUF_zQVsxS_TLSCIr6%=xgs< z82*cx&)i2W&Fc_b460n3)cMzqru5jPXgEwKYzlb5b-j>c%dNB7@}61{I8TfqH3Xm9 z3lEhVMLMFMn5Cbd897(K=H}pGWlH_J2<8dIT3>Y5Oz{oXBn z?zq_DPew6ASfCXT#XAeSM*m&Q1weC|zEGB2?-ro3LT4-?OI)kK)Gd`W@qT4Qk4J#X zqC&A1LIoR|9e*XyvWVT51Tqvz76i_A84iyK&)&;9#Vt9X_6KumO1R*o99tfyavCk} zCgp(!2FWj*0D_v2Al%G~;>t3p#5{_M0|nIwp+qa|T|WDf({0=ouEkXqbM4$QWH;;6u=z zFOl9k9B*CJj^=0;|D}*7<{NyxinY6KQ+05ORqOtiR6vd&`(Onu_H4xsKu1k!89VcG z;>i0H2>8X z6h2Fjx9WHDz457;#zJKb0aQVfVgc=CPHjUg_De&A#Yc&NgIhK9V*_g0X)ji*%0UG@ zoxvQ~X6VW`8tstHWjHR22rC_EWg>>3x8=?i*jxTtPXMC&&EQ(z2=9k2jA7I&r>{cW4?2*Bhv2DvHdt!z1^89K3ed0 z7Z=8D9aJCv$*_-XL__J=#fZ&H_B6A0;Ht?#EmAZU&mW!|BfV$nPvjfcF$NBJQ2y2S!j?EOmJ)Ien4jM{i zAeBrZ=o^cDA563a!gD%nPPm%>GdfueqNa4?gGuhZ)6ZF7(RkLpwGKEH4SI7vF9xUf zbxRS1cKM2}`)uS|$cv*Nq`05SH7W5~m|LhTtSoIsd@ zb|OFUKf%Iz?SF*2D+QMt-!cb@t4#g~TzL1+(m)t>yRT5o71Z)dr40>$Jw;(pNJ(O8 zByv3k8bjOt-BG0#;w9vP!06|2MR9Km`cT%jT^r1-)00A>IWi$Be4teM`f|XFDI&&u zvnlOGSPyWk7*c91>XgnPrWv^#++N&BJgCRJwH3efF-USCxIw8Aw4l}QUr*Wqd-gU} zUo@Xu-x2nzoUGNpx?kvi`;bG&IfhcoWaWFT$b21dou!}zAGMWV&JiXduaWQ>HMDPu zJl`DJ_}tjz$UwIqC*7$dp@;8b?;lctniIR~9d~)dd&l>q@uu_Ub`qFe^c%guBY225 zBrpAYs}mh<+<;%@jq681onW96XyI+F{o@6amrbq#SJDS(K^q<{vu^Aa;Y+5@e=#!BbNA)N1{X%ap-fY_~ zS%cw#UCwUWpD3-#NIT5;8b6vvs4wdR`@0bB1HaQcW9=_j9wo=EzS%RqJCt}RKhEMX zOIpR3BmO*3R{8l$Bcl6SNYji{qGT^TC*^>o;v#(FFe@Z+@VhTJ~OC7x`)(Gmox|sq5WDefN)^8im#zhhVy?cOd zUp?qbv^VowiTyxq#w~{Z`QVk6b}6y91PR}mN*Ni7aOIzkfZbEsg{AFt30`HV9%VHU8oFl2i1VAh|oMjWY&f_zD?zrUE&8y-A>1IMjH5Z?-$0C z82Ug2fDMAL*4xK95>R(N1k|pDN@?(EP4Uu5nr>Av3Xm|bO}!HOyX!&XSSGlCnS<;n z%u=zSfsPeg03AMvYXK~{?;NtV0s9+x9(G#(^qI%(rr^3CuC zhA=%EB2;K-@;g+Z30fj-iq88uTe(izIUVce%6=-JNfD?Ng&n2Oet6grQe^P=d%aaj z&|TMahk)zXkECW#X3i;w2;pXOrgTDr^o)wz%B4H|&;h2R`PHmR-O8DQvlR(T6|j%y z)-3Bu&k@xC&ByiVlV|NNL8fTpct5Q$k2xyYZ_h1xqME3a7?9UV?vo4Oo#pG>B{IXJ zk8flYoaffAFktOmvhIz_*40GcZUtQ>SeWf<7Q|%5C%=qR5-c?a^7Ud@2J@{*eNMxW z3UbJRf^~;-eVWc$#L1kwCN`_E5>bUu@EJDS+ivue$Ll-vb~nkMFU=oj`d&-v`M-F+ z$Ltv^`K&20CuJM7@S&U17%W5-oi8K(U0?un6=j{C01++)Yo)WLh+o!hcX6x4i=|-p za>1GNYPY?e>=#kN=wKawIx=4BjMXy=PlweHP&Vs;2qedKBpvFfIPf4E6OhBPJ!gDl zNkNM-a29DsTP5F(GhYbm-MJ>JyQey?sX0jU!(E%37{pA>{XIRTxy&%UiDW&;71Qk@ zlSswSYF>WQq41yIUE)uurCKNyHO5s%U_DcZ4L%wnGQTT-^c^*sgBw?6VXpz`(RP|< zz`#0L0Eu05py>e*BgR5cf-Xbq1Z)MZTACpJP&{u{>P15GKZA2_=m!&7U95?|quVMb0)Pn1Ms$NUC z##?|o{x<(3)b{j;-WYErZ6h&@DyAI6#IoIm%x4zAD(w-YW`EO?9P|15GX&`+%)_8D z!@P>^wz8`c%7D(g(AZ~*{Nm5NIq<{d{*JF;lF}DP<9=_@VviiZ;MdR5c?x3~gG~H*aOV}<=<%5iX~Jes1KR|uk?{sMsgk0PY@6Ap8|HhI ztcxfkNEp8sg@>T#{k2I9G`BHJb8=BqSlc)Cx2=&>?P9H-G+gY>$oR~k9-)DtNde|$ zROH>|Y4=47kB6P#8r1-|@s7&*H+GAc^m-kj=)&q`K~A>#2ujoPw8*EOS9SFiU?8Gm zTq@LM`Dh+1i|d!0Qzj~8n4jE~XEnCReUeqTS_l+-wCH{imXPQFoJCh*ClxGSyZTJ- z9ds;ji1CXgHPAUr`1ybW_ejEIv)>H|^ZpbDtl-`88k18ax4cv@ovvt=TRA48u2jIR zcCM*?Ih|bmZQZgn0>`SMUiI;?|VOGLsTk!yl{>u z?V$}jb|(Q+|D68vz_B%p;kzvVu;cvf^hWiNgU^TOT$4 zkP5Q^e6u!ChPQil`P%oI5+u>B&*rm#hB?rxjZ>R9mfD^jar=nLqNK&S#={nPin4Tw7{S@zzbt2{ zx%JnD8v1ne6fnLMM>VmvdEqfYRxACUYROlXM27JA?H5vWO9~rVOK3XEji$Hok)hYv z;pgm`ll)M%X_`Rc=_lO@%oIjGNU$KI>Oul)23;#x4OhQ&)^ z;4kXg*qIEymip+oG}U}PmkYgHGUantoR1#I!h1mNR~Y3bV{1Q|jrmWL7fCG>#QhIA zlP?FlAOxFq!*bu;S^qNt|3x)$V<(BO*tqV{K3TiAM67HM5O99WrFpWPz1&afi%1b6 z{n5L^{q16&<2X=?%}IT-{PyiFkVgx=Q3%%yoZmvooeJOnAX=AeAZr|Z%Py$$=Z&~iIqNu ziz$_6W!-J@7G3XwZmXaA2(Pl?2MN8B09;K5Gjmq{DR5iCCz$eo#gOv%9?($x4Qvp- znyp6&X&PP*F~_5P!(x&QbO~7Sd`xe4p({y&SbvO|AwS%!hda4#J#&V7;Tf<7Ty2$~ zguO|YgzZ`Y>LWK7X~-?m-G2n#SbHqs)fXv9Flil=$#9g;D^&~fbv`yeN>QeU>=NL* z6FJ24j81917fXs=;%}lUP}2zGLYD&AcLqT0CMkXK1?I9Gs|8O}rv;{7hZ*4v{kBtt zC<=~CJspqb2URqvV&ph}1BO_M{Tc#;(|r+B?MmB}FdE%It4X>NHxn`5rxZ?F4j)4& zvhQKWE?fi?-xXy7-uM>*HUqTc<|@;BU?Y-f8yK%Vk8j?PV6C)10{kJ`;IV_f-FksJ zD^eSC6cpz-jblIblx*sFYnNljSg3C)h>llwwtIa{5>^P%hk0FROQYWw@IG4m>{Kh~ zc)Tnj-inD};@@359o1Ap`?mDAG;PZa-KzLv$Z>JkKB=TY(eOMJtw|@KIoWThw~|Nv zXn*%e6WN_kuKz7@t7Di`f(o+RXA~-no8h;)RniFFQtACHWVMrC@VWTOPw1_2yp!Cr z`aerr!WH;KxZ3kGM9?+OOxZQz@B4P^;=SqjBD3i-^>)36cy3O-FLuz!P(3c3^T!qx-0Xo0q|5m#~So)7ZIN!iDsZfGFB!4mVd8r{qEZ1qGxrV(dCa8RfhYj$FVIWEwJS7Fiq%vlR=v8p^_>Z5m7JUUS5)_q}2!prfEJ=<}3orS4l z(0gI`uT~BhgpJOqVmFY~Vdx(8CQ*RUr3|o(P5^DEmPfzr87w3%ty!W&(oqa>&)E4r zx(e|Su=%{s*KIdymC$dQXRCA*NAMm%p3!A)Wv|D?&fikCR!97ZCpo~LmB3b$fNDm- zyqO)u0+Z(|I53>YFz+X5eD6u#f>?U(m28px#X3t0&;aPP^45r%zc34X|8@c1`NY*z za_lrWkVs$+v&5{IS75EeQg6*xD`ls+FG=?;8Gv|t^4P=VwI15|iGimww^(I$!C67W z5Z$;vp97d@w&BAw5z)pD5fy*S!R>%EmW_VLs}C-ex1z-rwauD8BDxL*o~Fyr<{_`S zcVQsWIS_aqM=QPx}~S6%X#vwMUnEaN7J&D z-M^fCzG*MF{`+(mW4m2pk#Tf@36j%bay4A;rL{d=jVD#OlAS$#YPL<#iicFb;b?am zD3QoNYbTwm{qo4>HR?GQLQ~*(Qh0OcUY~o2WmSy^%C1|t&rE{O;KKYwcVFk579k}) zUM*Gpr&>dc=IUS{EN39(lC!CZ;vVMeS80?d4Mlz(s`B0YoF$wkEBo<6gIT%OClz$5 z`9%scBHj={ahGR>t=-#-gMR;hHs@)SW+xfIqKeiw{hpbPGWtosm6Lf}D?3m`Y)#M^ zoIMJ1XtMWmzOl_yhnIOBRrVK*ir-!`JLQErysd92&-5yN~%!?91x>B9{PYVvymFF76 zHR|j=Rm~X_w znR3bNNH=|D47UUyg&}*x3 zu(qs|P*wl~TLk)UYa5j9jD(J;Q8@O|=b{TwjVyR&w78(3i2E$n*0pCw%~)1N%$7}s zk>60_*3*$A-O)*|yfx8*k>aCY1sAyPW5Eq73^o1-Xbm%pxYOfm4r&#f>Xi%ZjPj14 z(vTHhr+qV8mq)~V(?6o1usP9F1sb<~77D+8$~3p@$SFe&3;!yEl?)9(8#vs|#~UQ; z^hcz635ephhvYN}3e2BcTTN#uQq#;fMUsZpfL$NE-`ws|SmXEmq& zd8Po#`r2;4;i~Ry?`BK!+H*J%K1U}V=vHNsIcXnU3A;u`;Xjr7Xw*n*Q`5yX5n+X? zyQ&LwWjlES{Jc3CGb`UVlFYHUTYp`SCE7^yq=wd=4|<(7pEw1egjsXX*HQC zFeatxfJ9Bw#u0C~OBz#9o6CrM_`-tNj@7yo3pWLye6$|^B7)+(d%QOCTynOB8V?m_ z#Osb|T{}88awHos-Rs^%-t#`rVY)tR9~5H0ECcq0C&QFxW#G#@Sd|H zKMZJAMm}>qy)+VZF1Oi+0=P8BLte8*jh2_MXCFD)&<-e*)m#5Q{)TrwuxhralNhnV znTb%dpAgrw`vc6&oQf-?hccZLvOCccCH*+(iy7{_;&U#^f=38+o<6a z- zhh(iu1F?9C; zLo>j4@b|p$^?cv;{Q>8keRkY??{%+xtwta}27=emPiqllNwEe>_1 z`r#)6g_DEgzPthfgXB$uusxLRpO$8B3Eyb@7JR3*T-LP1XMFYWJl9as5$iL9`@ej@ zKmII{I_tifB=*ip?+xv6Ez6ljf?`Nj@skve9WXIKE#j*{S-`DOQZcBzaWAns~q1 zy>^}k>|C34-oDiZe~h(&GFMuUb3=Hf<&;Nfx}KhRE5Om?t|qcNX2=j1^q0w{SrQPW-jipTxox?`J z$!6!n_tjNGHC6ZzEWgvsg&&{?&aGn-o)$Jqn0fN|GQ7fB}Y57W9NZw#w!njrZT)MVK6kiCw7j=8rQ(A((U9VB^@a4FpUS-mw=5iP_O7zSJ z!6&*<_A#II(ch{!I-dlvQgDW_w-|;;wbHnmX#7h`OB==nKC&+1` zq;*+)AK*`+g@3NqE{hz7c^`7MQ>Nb=ZlE6X<8~6vxa$^^-Ot@*KmK*|0qva5U2o8_ zB2ve_&uW&OcD7}uTSjP(y(#j?C|Zi}oIwd=i-D&vLm63%Z^N~p9s$Q?xE1qr=-qrI zgbnhJW*VT{o%?X~Jt;Q6bz&1MGNi9;JJXM89F{L%JL{n)KVAM7^;5p*DC19je1!YY z64@KJnn$&$*@e{Lf;nT(Zy9%@jnUZlY)#zp1+zDwGv~DSm6oFZ%;S8Bj2wE=&SubT zJa~=Va*X0}EArk;E0Vw=*d-sh64dp~Zc9F}S47TJw+Z$+(i5YMu(oO^aBeM#gb+O1 zy;WGJbXBZOY73hjuH_$Auu>&(#`i(fMWLbQLeYduN4nQQ_us437JB?HUVFEBX4rss zmVqA^Kba=v09)K8|D6wED^Nb9FFYM|%Xq=Ol8}rQlp^w1b6S-L_RTL1YwZv}@;gh} z=Vs#wnX6&aUC}%9?soqMjLpn5YTqonp&Ty^dqv`P!I&pcw=d*1w4bIAh7H5SUTUHo zM)P+MJ~`AD{Iy59H~1u@cTa{ph?M+bP^`ffbmCFAI}_}}l1_P@U04{D&^yr)Y9?hOwd z3ZSV{k9VVXGJHg>^K}e;^so@!kN@whg#8bX9<#GKZVkK0&UJ6w7`*w+m`M7|oYP#B z!#X&yZM3&@dHMA5zu)?Zjp{)ua=NQD>07XWnQkHIvvh1LF<#p^t|xAgc?WJ@VK|qze|uETuzR7oMo)d>-I_SGWOD4KB49!z(`+PJp{;w zZ{)YdYA>399h!OPQSVPYb%1g)~vhp_n_O}Zdx!H zE`$UpUJiQDN>G1j(!H|!uIqdF!$J%m6fk{a`v@VTl6>$!_`<@L%d2t*HsX|;Zc-KD zuUG;ddLd@8d+QU+i#5!rf6yT?645PT`}@Cn_Yq~Jj04{Z!7fTlzHy@>FyHNThYYF2 zTLM|Un6~{kJ^_aae7ap6=eSCako+MM)F7Yq3Fg;Gon{qR~4+new-- z!0M@2NExmz{#_9$cJikCh{EZK%~*s6oZlfMxmV(Wt)vp;HzWWQmlFZILe>q-G1-Ls zHG-&R&hoP4o;+^}vrZT(W*4zCTxO{+YMXKR$S#4|pu+sib7;ITooI$OSlrCA{wydn zXNxn0B#p67!)NMf2Rb;+uje=-vzQS9O%xa*!>fN_nK2c-li_5}M?4e%lLt$9Oiey+ z5rKX&pE|>9K6B!lXcR-Wc%9hX&&8VaB|18q_6?3%-!CS7Rvn0w$5yIqit-V;uj+l| zMZ7w%-d^(8Ud588VY2HbqhKlMEqU3Az15DpO0~rrv1c==VTfNJ%dzV8zont}k!R!! z=f@~2$31Fsm)|O`pq89qqlHa@`>UFej%-{07d{j}om=PO=+nDlfgXA)Iqz6-X!BDK zRaxMJtB8x6ViWUpc6)!2j#A-jhG**8O)VvF^{o5Uh=oVSOc%7N;9XsO>kR$Y6_7C;wAQJmradEC&SkALQtwhES)pkv%P6o%{sfx{%AUx zzN}^5JM&=+Gb(zLlLLNC^5z-4pnF_9n~fEXyMlV^;3OMxHsO&Hv`vAGz+mTO#8A2cm;*Uy8#kUP)=wGYlw@+*-0{4_!q(|&(x%U$$e{bs zPw(K&g-xCgi(u#Uaqo+80py|Xz{|r7MEf^J%BN2a6Gc5CZ3_zvf?Qmc?>~P0Xo9~; zNZEe)Y$Dp+obRN4z^j{W&b>PG40)JOwc)` zs7lx-H=X_1YHG*w*UC7CPKv?yP1VY5sR5Z-V%5;mjtaX()tOJ^ARm>pRmE+1=E_(q z{0PhMrS~%I)@BUYhNSSft*1*n+b9DA0=k$p(uG|jBK9j1(NkYaZ|G;(+6i0M`=<)K zYoU0Xp1-TbOOz*@?FXACD`CZZpLG&+oX%c1OP7piX-@um8?0rJmB=sLCam^;HaxJV_cwYQ{Jy5zXUX~! zrWkUV_YC*oLf65vd8J&nX*ikU4$+ZVsh|$0D2UH8IQ7Fw;I{?i6Bc*KxsIcoR$j%x#v!NuIm@4_CpPBGt*+gk zC{Bk-wq0YzwFZ`}$gI7IKe!GnlZUfaGDw{)=?F>_6O(jB1%=yDOCEPeH)(`1jxF;G zL`!mv%9@sLyR!@3IZLCRiMX)48IG`*5ivrLJHb6YrQL-xy$3>b6XA{-Ns3W+%#Wm4 z47^z7zGR8?H(5zU&TM+pJURVI>KD~jznWryScj>LQ!2MrPbydLE99HC@?$fVGgS2u zkt58{A7==LTD9Dm`jpy+C$3J|t?+fnr!l5z+Y)ej@%bXSfrvG4U8YgWuAqKX4s2A0 zH|)AqUNoDj(Dp?GpuQ^RN7K=>=gvA_OULw&9NYAJm!YGTX8ndpv-yRE#*;iJqhHvr zF|!X`1YjFBGU<`eqwUu`%p`!Xc12$6me04kfX^+^wLd*dbo3Bus-@=t(;Xn@*Rjl2 zr5hh1Wc6YW>_T&8yJK?0V$yQzgj1@zHX3p)32W+o8uDj50s)VruVbO5UFF38YkRqL z?jXtVmVKUN8D&2;TZe^bS3uau9UbOvMGmub6VO@V{#k#p+iref*&)x&XWgi79y&Ir z!gaT(qEUVE!?(lYiqnpTlBipnDj&!Bj}1kS1&aQS0c|Pjbbz(WG-Fv!kNbgbWEv*S zt{8b4OTe#R!>)-YO2t1B9Oinu<1%V_Xz@M)4Xmn+@suU`ZnWx_Yj6qJo&p60v}96O zQzbery)D(XlMLw0xrgQ*mxB}?#gDk(&Ye`{fZ87tnY*PMn2;kl-hPp~uaUk;ZI)2{ z1{mn-lkEiu(+Ie*qPsb8I^h(uO`C3deVjEtCl)1`M<}{UNmy*WKQD^NbdhK> zd?A{3W>Qe;NhEIw4N! zmW5Zl0td2k0_hi$*e_3>xEKd=ugafAc;;r9-L6uY5*b>UZtphh{6Y?<%OaH{!w zm&EXd&eluu;WnR71de2~-5z{YQ{=6er5y%}-}d8hzSA=@3Io-g{du*ti4Zc4=ZU+}n?$_)qsyIj+&PU_yqyLu4`-6U+S46-izJL_e!~rUB z4DHgqQ31U+3!vgo!u_tYYp%xH_w&v5s(6w4zL~_O0wqw_rM-h6Ofl)md2_q>g@s`i zve8wu#O!xw0}$-D1!<_A^e4zE>++JuW1>Tb`FKi7xRY>nKZK(T_v|U50RWA!s7v|NVBjV>j=z z_OC5AT^B)bKWiC^4AzN!j5*mQbBqF4pY*K&#HHm_!z+h6J-Bx=Z`4B6hH0rtzo0Vy zX&19g)xDy2A0Lgd^_6}Q0&9VtkJ=n4Qp?G_P|?>ey)dCEJ~djyPc=Egc|Fqr)UMC~ z>xvY2h#RQypp*ONn8amfbz)!;{{6c^A@o%ESPpdkJ%YB9>~o$OD2MwgJ_pUL38Ap3 z8qQtYV~39pPj1XwdCr}ay#1Cx@? zjJ3B`?3bHaVeToeX~9DlLEeZ0@U&N1_u~xyRruG6vaX8Vk7Hz!GKiq-K@ zn`Sx50ETDVvIs^)Y;5cr4m(kLDn6-tJ?O1T;GS@z&^O`Thdh%&*6eKK6e~ZA#KSE#jbdAO$xo5 zCp-xayBevxvj>Zi5V#u$3YADVA!%QjFo)wkU!jq?Y*s18L{JU(x+k3JC{}(n>LDiJD8lV^X>v zINWzgo0_93LY5HAtra~|6()PBJ)KkT;86`lSclER_XG|lQgMO<;h_dz>Moz{OMZ$` zllQ=>!-BiJ8J7Tm`o8Q={*175pvfr&dEU2i)ZnM=<%PUq$U1(hiatp4ld+OWgRd$M ztC=Kif1e8M{M3~d@^aV-UtgcJln}^;cGYCzRp$uMl0}kq4a1&*bE!j3bvBD??>2i1 zXxp34neU61+-ioM1=nqcrgLPCXS~^O+=e{PmnyhthhpbOtO}JqkD6SBqa)5l8J7vl z=>$SQ_Ofkn;V0u)ndOyLWIJWyT1^KiwW@QdS58S)^20Y)S68=}mp^9$ikf(rW$f-A z9z$G73fga<#PS&hzq-uAVyncnX$GyN3(r6eYE_tw%-U>WlKVkXTTBn&sM+_0H%*Zp zVvL$m<{dMwd@UU&(xyTbsrM51=JoW}R$&)6P*hKS{AZlKlo(d5~unHim)wR72g+2NmwS{ zXuRb(@?>fcdK!be*MEGSgW9oZS$S?)$mVU`j9@`6Yk)l zG1C|v$`_5#lUvo(aZJ_-QZ2*}1v{IU6mqiTUfn2GF`<$sO~=Xd{$&eL7+C%G!@qz- z>EDb&fa^Xs+$!pR0m{VAp8MX;Rev4tdj0yfWKj+%$uyTsm8qf=&2c3)FR$v18LGJz zEMCQ~bK4i}luAF=MB?XagK_3l(&d7I8|;+4_KQZpo|2a2y{#*J5p2zsRNC9)ENB5T ze?{m6ihxIfFhgc3u}`jYP}a5F4=mBEG3FkD>A+oYVBrtH{nk9lu)1}!Ho_qSzPWo7WL?CfkS3&Rb7lE>394O?J{72??q_&9J^W+x^xsxBqpYckxPl$$k@4{|rKcp`vu0 zq{{n!8xUd^c7>(hQlSBo1{}{>FjU*rIpRIHFsk+gHNLyQA;rQ9Dde@9uxx!5Wj}b| z1XQ`|k+SIuoUQl9deYI+v3GWMF4TG7xV(-t*0bsC?#`0zw3CvO>OO9cX!4-vSt%cu zgP2B!T;++iB(+=~=}hIUd_LC;kpq<<4Jj?GC(D4BZ)cHOnXC6#&Ku@QJvmz$@P-o8x z_6wqx(|ynKu4>&krBkFXnYVMO*iM)9~Rw6hRzO448v#je6&$kA|rC zEt#vy=J3J!P-ilg!~lr8#L+hTDaQ5d+G{Rpk*9{_x#n3Ljp(NDQVLoT&W=h{$q*jh z-9fSBmL%_^3kQVtnt2szh?3EnwzIHR{%3dN2&+ly<;Gw*WwYlc{+M_E(oxdMM*lrl?9B`53>D)(Uw3!XS#Byy%9dsE zM(F)V#O#u5$}@53jhAFqvh=yODckEr9ohw%GyUg?zHzuHDvWYuQzK;FZ9`dE84&m7 z=tvcIO*w}z*&bb7l*Ro1-Jl7NOCFGphEw|eW_8RQKk^s~UKusF6h=luc# zI7;lDL59)@fBo^4_@#BlcRSzxtS%)U`->k;-ydJxyl?t(gX)+??5Pl;zHgL1aQ@x5 z!FhW2Qjv_Z)3qoXS$dmrC`?}neZ&_KZJ6`Ooxb<8j09nHpa>c6HC>i2{av*TBt@!ZmtqX;Nq-2oM)=+A&R2WGcg;Qi?B<2haKY2t5@7VVm>CK?^ z7ZBbf4L()3jnp1yUqjobSWEe8raASnyU8i%%!5&^ZJbl=YfSH;=1L8-A~k*ARqPbK@5J$3nW;{ACzLzxnMNNXuaA7APt9#?w2e@emBtmh4|4~~b`;5{ z2@DO4tK|l@4Lc4mufD*RFqb!PCrN#0s2F~yq=1sRu>_6~*Jpe8yh)!laxB-l0}K2~GPUMZTIn#yI4NMJSQ7OUjfJp6_#PA-MSkF#$l?+>kVTUE6o9Vw zlW`XOM4UpEX5Ac_{&+&vXj^ZjHjJ>NVX%p_c_}m?r~$jN^mc6gK(}P~?5W-AOo`kS zlVOB(7RDx^(vJ2N5V<*wq#tzvSNB|QdY{-5M(cSH{e7Qhu%CL<-F!Tyx_;`NG+7Ce?sx6Lq`WKBE8F^AESUKDC93^VpD1$hXkaP5666}^ zdwYYk5~opeT&z0lP;;cWqF7Jlz5$5Je{a||eoQUTQK9E2zT{)y`WXZ{E>)d9VUH_NIWV}i`40cir}rSjF14sbit1?A|Eo+j6O^-cwKshS zA5CcRU9#^}e&_uu-Rz2tBjm9suz9y&eq}ObT#S_<>`#N(E=3mGqHPiq5-Loj)CXL7 z+-IV_#_8c^M?>tAPmD4O<%bD6pQa8hZ-oOD=ySUrJKBBIQRby&6FlOo&9p~@9ZIdp zwOMKzYv3GpSbobDS0o14%`~P$$7qh0&0fWJUh)6s?BrBD)O40dS-k;Hce>uksvT`g zcx~MeJLyy#upvLJAgBhuG#bGx)=h-K2w9p%f(W-M2b zk*?G-)*^3%zQJqB0=9>3y82S{-e~r0bHCOT^oM z7mFq$uYZa!817LnvOAU`nXnl1b^&>rvJ^u=%Q}>GW+htftpQ|}&cPij;b6!{!-44}UafKqrBV7K`8bGr?{;Jg(kJ$U%z6RWyhg(l&Y#S zp_C>*>dP!U^$uy4O#fp$+FjVPM0r&UY_69raIv|+3tQ5vZreT2^N3?1V)Ga8(bxZ0 zR@Zh7y!(@w$2{e^FDR41HRr%1qa7&?wC<#d+*=JU#YE>ZKyYJ9;iavtQ?(cRAj(A(pMi{_ zaduow#9mrtx_8U=IKNQ1@6{6gtVsJRv)28LAiTNr#A0XF5tt3d0H^c4PEGOHJ(j&09(k|^M0 zY^2ff{-A`^6=%ALeXfT@>pa<*v&%OB0ppdcHP_#!9pMGWrsMg%K|Fk34j_A8mX?B^eOqXH4`FOzKxlqZZr3{pUr{ ze?}G?1^t3FGw*o660yrsxF_GEgL0MQy3=>B-Llv*n?^3SoD<@P25@Q%UNeD6MXQyc>#5|g{kFWtf8ihbs*a*jT|{nSM}BoKLH_(?vvmx^TvN; zqo5Gp-5H4hC9 z;fLH3gb5A^I&P}T$;%5D1}r~QHJp6fX09)sI}%C&1oCCeTU47ayQ{~Xx?*dqetbkM9UJUoXDzmG`SoJ%!bh}}!$!U*mhM{iz043^!M zDIntCQzr)eL_%&RUGH@#3|pzpmyhx?1OOWhD6h#+(u=;lFz@^jmt;{Z+38uI`MtEI z)dhWDC@_1)#dX(4*^+P*))=lsfnx?~e?rOSr;R6*Y5BUD*ICH3j>t$w-b+trgl}07 zPC#T|PjYqED--z-_J|ZtlVGFyI{RQiUr?z3Y;&;2^fd$Ll+SJNv)H{7 zK^}Dk%O|jrDW-`qiJSr#lrKv1@;HDSip>H(VSoArCCmGYOWVzWe;dM=F|yP8C_%Mw+iIO9-2`BS^I5#Agq4;m6ayd>-Yekx@`qw;yu$*&CSiV(NI39aP64+ zvmiPHO{KETZ_37RLj2Qm`U1QU1%mR=nI^O`^&x2en4*gkF}}RsD~lHBlCzl_eUD!g z*6Ro-QmsDt{58MnQC{!?3vg;EfqQ<%Y3IYlr?kx1D5Lf^0-RV1@(Tg&r=y{78mGHO zW$K%0vz)|_Ny(i929K>|dQCpc0i(!!t&7p~;JH(dH}e?u?ZLN2>a+9i1SgO6)WFY} z7}|hzoB6uq9H-Gwc4K^(QHE8n)tT?=RGz&IX_ihe!V*F<=2Q6g22SGG+=DYxf#f2}x>RHS_fYCyozEZTSpF$*nmS)ptSfsg2 zOF|q4kz3;T6~BeWeZ2{inOs!p;7}eQwtCL^`LI#(8INp^eLMK~o$rtNH|y#I2xqBD zNT!tKSptx>44W(bnjTw^PE`aGhHf5~=m@BNz>v-(`PGBN58=-gVg72+tV;IoCq>2c z_{I8Thivhd%-YP%a~1K^#o#uQYUdquOu$zPu+-5;N!=U+tZE9r%N{uUtp5FR@reP9 zAa*lJ^Iv1?WOm+DtnUcG$z?omf)SJ%)l4yCB? zIOYhb@Y9L>?*W54595QBnF|F(-JXJg9tND0vVqICPJAIAwa8^Ops~6)hRuDGX7JbC z#`^uDATg^zBn%Do0WsF82%7#U2KRrS%U@qNjoYlr!wu%n$zC$+_r@%*7iQw7BxZG_ z1flYw!u%py)gMINW}bRK*!~p!T;JY)6R@&5oX+k7Y6J|kw25&UpY@K+3&ssR8w`Ti zKI(2WHw3(mW}bmUADV{2GVd2fCCo7OOesa+xEJ8AydcJ{Mf^3@_Ee-F=iMpCBc{Xx zT$HxK|NTkE$jIjvExjg>nsjm-rB6T1j1x1csIP_##ufirs0Rex#=@EADDi3^#sZs9YKaAy^Kak%lLQ559SzG2l+@IB z$sZYrs2zU~F3gGb|!+e7ze1SP}STaW=Y9UH4_ zYqbSeh^$xCpe_i>09YeIBv{bLWngRUM}|HM#y{_}e0L|{vtK9jm8-RI9vYnO<>fVj zbib{xp0MNfJ#;pHmK>MYKUp30+Ukz?{v#=>GcFd<1kOv2NZ9x3W4ZW$&tvn^gTwxf z)k^A8v$xJbx-ATHKvYA9vpKABi91lWZ)dzWNClqBr3315V6ULMecjL6X;%Yhg<9G` zk<+B~KCS|%1f|Nq(0u%qwbmYt%xbi7KytP^fX$QSTND5p{y{HI%C3)GWZ@q{d%+#t zg)p~txrS`+U&cjz!b#(*M8*i6ui!Adr4F9B^<}&nGOAr8U;}q{^g~5<%TkC-6lcOM zeQYGk>1UpU!kUeM_o|@?xgEWPK%b-9^V`gq@0XIWOr_WMR;`?4IFz1Ed{HVvQ!PY+ z--gbD`l?MY1Su(m$SWa1=uKHDmrv4B2No_oA=k^btJ*cM-(fUSH{sz-O=X3(3VfAs zhZveXG`!DZB^L$-=qJi?K*9(5<=y;BSdoBV@)jBH!li<5*Ez|+)_@2&U=h^EPoNjc zRj$W)&s4!={Y8beWtl!6i%i#Da{}AFi3&%6qf{_(Fuzp*SQSqoQWA&%+CNuef)x;- zvgiqK@?c_O(wNAvnf}poBJffX@n*rr)eMLdvympg3lt!hux)E(bwSW)7KC;TlV_-ks3qvwYtG&wIiCD zu|{~a4grK79R4uYR|U(PD!z`p9H?6l~I3TL|0Bc zgA07V2^TNz5a9mx9n4}0N z%yCX{EjFM0Y#Sdw6v%lK)qt_h^c5Qe-w7;e?D^odmM`lH3_lK^^b*g*@W==X2)wkE z8?e8=xw(iL;pt}3oen5^LT@Z&qBte)=Fadgy~AjUcG$m!^=6l4*M*4S5m^iSQw;g` z6A1P3@(LK?$v16wCE}ZrbTFxo@y85BRP?>y7Ytf$@%43@Wh3S~%$dkU`juOZkf}qqG~bh3X}t-bGSDH-O-DaFJhK`F1P@HIts^JB{*=pPZZi%ItrRJK^)_(!Y?O z?u4gC(6wj}tV%31Z!btYqB z;67o_FE;cmeNUv%R!U3}zAq{on~J~C#;@Fz#t&n3Jl+8l)C63{&wb}Sq zdr(I-;lB0+XVDk*uRFc898diNALFWFq-(*&S(g4RjZ$06%tUH8Fn~YKyzm|ef*KPI z@$=`VnpNg_HjqdoBO}D~k>MZ@;@$XyE5H^6LE_f6hmU6rWb{}T5@QY=>gpP&XPd{X z>JsMl2gqQK_;1m?BH&7YsI!<3nw?)L?4X@c5ZoIR|H{Yv>S|^`_mi)y+OZ-f3VURD zr~`=x(J5$mc|KwU%)OZxpoo7{{k5A?ETfXk3VXklq-3%3Cqa@`<$P?d6QXUD*UOKG zMf^M$QS#eUM^k);uigBJ;G-yo?|FWqlgf8gS68N1`Rg)odOJLk=Vs8F>ajjcg!`As zX^3yOYtSGSaeLPUURWjUeCgz5>2*yM9RK7FkrI`Cna?3^{IvR$-{1^qKLcxcTdtu_ zIj45mg9X}EK7c|BIqi&Lyep$5CazIHy*>K2K~J(hH{$H+!UxL3D4#nX9FtHq!R{Sp z5j$pROs4D};sz}-&hmyp4psKtL#D_=u++wy6(>{6GAB5EWKDj&6k0-n? z6_apK4*Wgh5BKQar5`{3sd_K6mUxBXG!qGU2|j^fPz08Y@<#$)b0Pqx2(X_Vk2-gi#{eTc^R=M;0uD}IdAotItyE~&thk=mCu=kM8dGl~`# z`LM#H1y=^+P1@;}?A+?Ui(qAN$L~2m@7TS(2}L)km}$%;aVs45ph|a(>MnvJN@RQo zWu=*yXzWJyB=h$8RZtC&8%Z|qFtDy9U0!*K>ooheiq@mp;XN)*9$ez*4SREO0UC6WoIrt@I4^+mdRV)Fgr2t)cHekiUX3#@%^UI25f5Oyw_b1 zr&zJCouS0|1fr)uQ9OX$#}AB#lOaOE(%@W$6F1U!@9dC;PBwz){d1=%ohglt@F?}q zwLdP+8OYp7oo_1j`WK%2g(>CM4fx|H2Y}nU46RQi=pLfdSO5kNWt#W77D|)4lT)=# z&q9eLUOjUwrXI`&L)>l1`g!=lqwT4zHRtyZbAktWzl~}Jl-lmsCs~0lo~9;vf8L22>;6uBc~>OcyEsYSf=Q!md=eQm$K30{NOIwq@Y<5;d~y2j9!L^>)< zHr7_SUCkYu9Q+kJnK+e{cY?OY4b1gkn#v9<$C!6ti1Os$ii;aG~o=N1_q|10)2KUjYLQt~+I zWuyWm>dPFEX0tzkKCO*Oy#C@pxp$eZ%V663RzbeY<8+Vnz1HEUkk@<~wD>yIuRj@I zE||vdp1p=SpU@;RH|OZpuZEd_PI2DV_I`g0PKwMQ)>+Cx21n9rgur6s<5p+*x$kG`kgW>zeY z^M8H>n7P1$umV^rnhQw9O!V`$xe%Rj#qNT41y+sSb*qT52{vzqTQpi+*AQHNVmW%xS3u zOpC6wR$vnt>jHMfAHRm*xo(R0DW;1x<&2v0^!l+PVw$`U<%G3CTO)#(E|fQGX@g3N zy0dS_$_qty>Y22q`7|1br4HI6zxqivHdfu{Sy*KMGBYniG}?8@Kx?lYF7(;mD{CQn=et{wmnJ7GTbHX@iTJzjHEUkAOw?cZqz=`=sy<0beIk|l z8yA`po&-3FoX<~?KC@J+!`e^G%Sb9${&5wWhn2SRD-=B)Ih15&rPu#X`|@)yfJh&G zqN>;6WPjOme@Pt6p7=PRTomT(Pi6yQFB?^^xQTk`8T_i_0QO0(F`-%aQEDvahBf9dWzFR0^G+SiCcjo5kjgZIS?-T zFy+}Qqk)w`KQ#KnOV)>TKsb!^30|)L^N_8q^ ze8~mP+gyrvlYqpKrKeztL=g{J)jgyUb0MeE!+rMucDaz#wx9PX^HD;Sev6NHf>~^Q z{~nH+!RZaUw@YcQ(xf5mH~5H#f$J|*{$4HrWW3LUSq1jAmMKyS)mO4R`IB@}b=i|Y zulT+ibaDye51c{q2}^9a=GJYLh#G4a!bO=Q(|n1rnWs+YK^GY3*x@IqMcyM(29UX5W~2bDfdTtt`>+a$e*)B(ptEgSj>GNI ztnufbHg?<3rJrcxjMS6}XbFX6puKSs?q?l2qpog*6R=2o?0z~72o^fMnu5=UcmA^J zUC%}NaobWN!>QYe6x{60vI#Nu`yEI{QDMr!TISh+(fp!tdaM`H40pELYk`HHEfsvl zRwocABX~de89Msw?Va~TNv%-2! zD_Q)t-Iw>!^w4s!t}_wxPRcvxfYIohzkl}orji%x7cJ!h3ks1#qq!^v^PbJ*#BYL^ zxjmPa-@Emn`!c!E1a{j-p&;ScnV7yd2qPq)#Ao$VvPyA1c*E60Tn8|IZyXqN;?Kv-g zKesn-KQzN4K3QQ6vzk6!g=3Y`qYJ%*3I8mZ> zd|w0|?1^Fa`$`ZmUtjs3Fz@k9j~Y?}8qG+^&C0N63JMBgft=)fwFw@V>p2&DmT=tH zue-ks{joJL0;aO@U0eUm!=3J@b#kTC&~bjpA5qc7;iUTgv4}up0dY3YlxgP(y)dD! z$Zu}n*DN5+x`#ASAshe#%+JI8X9MvX{2!#pA)9;-wn{CLBYW%`wP z*sCjyMZNVvc^OnKWMdDE?WC!3^IGVyy}*2p^$6{my@Hz^A>!CwVC;`H*7~(0=lp-L zo}udL;6rz##RGipOu*nhQKqZ`03Kd3l%T>>lqBv; zKJ7SQ|D(OY472my7wx6s?8%UK}D@r&r=T(c7BNwmRQ@^fUrIH)`%E0X*XX5E6wL`KDU^A^3r$LQv0MIXYN4*md&?V;YU8^9jOXQafVRC> zG1~5BOn36SyV@!O*0o-rq#$t4J zbt!@KNZ{G_BtLkLM-s2mglzJoX$0c!WwE_l=*xjGPQtZ6)L7$6U)Y5F^Q9=K{~rVT z-r3pNqjntjmw2GF1bvU4gP@>C@>2o;90da4Dh$d4#hf=JtPM>VfePCY`6g@tRA~)1 z{LhA7GDD+Gf8qG{VyU~_vq?2ikyWGPuy&RG*+9M~@k|i8O-RX$>h1Hl<*)v8im!Yq zp152NBq$g67(8C&pN`=;u`aNH-VdgB0O06@_lS4k11kFcF{%QM&*iI_ zfeHN@t4SrUgF-U#=^H!%xqHv7)Gex3 zs#~uCWOF7L({ceXVcIn^)TUqfwFtl~JgM*#j=Qew1px;l6%uG0{ zQIXOw6Pp~hD z$hO(%aJ?ucmRMp={LhW!p6GFLzaUKsu?5DPv8XA}YMvGYs$R zrtg7K0NDK}-v^!t)cVg`3k!=7pugh2VRad_kWo>2D=v(b$)rDPbW`4}Q;8vqya2K` z{H{Lu{{z-R?q;wR^ny(9w#zbOt}`N9OaVET&AgzN=T)Jxt!#h zh0QfahjNXBLQ-MNEw{={lS@)4VT7#_P2^VY6N~Nl`R+Kqe*W}&eLwqrpU?Ao_Uw7T z-_L^^eed=JNQN?boXeLkF^;8M??JJI9BK@r(li)f5O4 z^0{u_(1RaFM@B|2QE_fQ1Kqh+4-J(~Pn@vtE7+IcT-ht!P)L6I)~HSc@Xm^3n2?G2 zDDlxDLFjP4rDgl->v_@uDaTq|(U2Srq`*=iiG%Inif+-4%l9F-dp~2sZKo4(eZq5VUhU6bNSN+H>-?%QnU5@}FpGYFgWt*|Vdk=oLA%u;4K3&MUf< zKgV9>?xGS!7c`0g(9oQE6K5iy`cc-V-lPF7a5DX%1H7q1Q^I(4)?{_8!I-zY&4=rp}Fh8qB)HWZ={pZ6Wq9P#{Jo_G%ABu+zZg#e1z|sI3Gr4I^S-yuANGYTmVXksw2gGB z3>8hk!3+P3vpCW4xUjIq5+m4?D*M2QO=M+}w6=ffG9TAi+{v+8`paxlos$7Yi2Rd` zfJE7&b@QZuP#i(tin5+w^_<$Bcl&?R5U!rV{m+KXB;m*E{9KaxT*W;f+QEyK~<9FHH=TTV?Z zc_Xw7V3OVT>~JU7WW)&v(mD+_7aSz;A;p8%&=143l*-D=<;J?&Cjj~u?s2}a{nzUh za0!sOCW+J+BN)at*h2#+XPRUbSF)Lfdl&_4OjYk)}Hgo@uWpu^x ziPm7DbrWC7xo|?cOB)H?F?CvF=bCsC8pOxGud8E`(2W>pJaa{kgqPd3oppCVMyJ># zMEs>)RD6%@lP}F}?fG>kdK%T{dAMK_7ncnZ=5cY~Ly^eSPoMs#9b%q<_Ht{ z-zT_{5LFMM)Kc%R?LHQdDRe3apHqhDd)mX?*`@ z+m5oA-P+;srYRKyNCH-UepW{qTZqT?c4kl zKbTcKpn>VmJr)gz!C?LOC`Ad;jt5E(wd}pAQ}OiD=%CrUY){IG z>WS2O-9an(ty&3wtP=zbp)z_);V^YJ(^l#FcwP%cu$PKl>v(+XPIK}85NsKl@{3;O zV4l^I*Z5l6)?(naD#O3sTV0O15gSEGl{l_eRj+`JqnKtBv0crcSIJa?q-PLbtzMC* z89n+QU3_koCHJSd%Vus>VNOI%d!9)wqJ-Uzv#^#fV0Om*xIA4ye)YA}dIe8E<{<@pQr3Kyk`X>!O}bRpy%QMe1_Va6T!wxds5-TueJ=iVs5Y4b ziCSoo*A@RA!+`wtLdswbrosuPF>^ zWfAm}hqIWmAK%Y@uL}y~zJOz-%f;w%S1mJ@s6a?0UJ*-5qFwaVB|ltzuhCk|8A<2E z_^%o@YXhC0;3TB+Qb}sgce6MNt zJBn(>11OT3ZTTK|v!c~D(PT;;q)|84+ChPU?2pI)`t_|nyV1SUt|e&n?V%v#oSJA2 z#qzQ7t!iZdl;|_rWl&4MtnbinqtSZRV8n3&K42J9Vi3`jgr{|kimreDrzOKHF1wnl zhVT3Tr#y>Bq+!i=fxK#OSUYp_P)y3WP3{jD)YF@KS=z9~VM4%P0D^uC;V^ z%>{C+e*ztN`!pDRc%J|q*A-BG)e(MlfsYUF%5}abT0cKer#u(%7^`fDxiX+qdWxP) z=`JIJgD&fot3F1fj8Up+pQRrA&SqBWM;)^X#_z14kC;5_2wHMX#dIfeSOHY?&@KGl z0I#c9a{gs6+%ZVzQDNNtd%km*HaZQ07-ASZ;M)7dwn=UYP5sGH<9&Jx2uf>x<&H?+ z@Y_TfDBw^Yy-d>)D00Ww==6r~n}EOE8J6K#Gog_Yt0*@2<yn3LPd8D@6d-QtCPCgYdF)}I<}1^;G3ymH06) zHavYk5M36fFbck-BA;WZIIY=+x@Mlxu85`8h0fqCqtJO@VF{&yfHe+V7eMv#2rHeo z%SD4l*=>EYmE{a>woYXpzQ1wf0|5Z#-o!T<3}Z$O8e)Khez^~+{I>-0i==Qsgo#HYW&& zdtDQ>rxa$&5{qo*^{qmRwKr_B*dH&zRM>VV0JFV~jg312P&)lGVB(w$Nd3LUM;8FY zKa)r#mJ>nGoS4X_uvw>Yp`5qByFpm=#n(9h*OmnA!h-jSnES}u z7Xyp-YJiyT_s}ph9L{xXO+latg!Bt)q&phpOXM@28@OR40 L%C!8rOVs}WyDoq< literal 0 HcmV?d00001 diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Contact.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Contact.kt index a67e320..e2725ee 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Contact.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Contact.kt @@ -1,11 +1,11 @@ package io.github.wechaty.schemas -enum class ContractGender(var code: Int) { +enum class ContactGender(var code: Int) { Unknown(0), Male(1), Female(2); companion object { - fun getByCode(code: Int): ContractGender { + fun getByCode(code: Int): ContactGender { val values = values() for (value in values) { if (value.code == code) { @@ -46,7 +46,7 @@ class ContactQueryFilter { } class ContactPayload(val id:String) { - var gender: ContractGender? = null + var gender: ContactGender? = null var type: ContactType? = null var name: String? = null var avatar: String? = null From 344a0a3e392a14a7e173b8a392c95114e0cfef3b Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Sat, 6 Jun 2020 20:44:20 +0800 Subject: [PATCH 02/41] finish MockPuppet and add PuppetManager --- .../kotlin/io/github/wechaty/MockPuppet.kt | 80 ++++++++++++++----- .../main/kotlin/io/github/wechaty/Wechaty.kt | 3 +- .../kotlin/io/github/wechaty/user/Room.kt | 8 +- .../wechaty/user/manager/PuppetManager.kt | 30 +++++++ .../kotlin/io/github/wechaty/user/RoomTest.kt | 62 +++++++++----- 5 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt diff --git a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt index 5f519a7..aae327a 100644 --- a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt +++ b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt @@ -286,79 +286,121 @@ class MockPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { } override fun roomInvitationAccept(roomInvitation: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomInvitationAccept($roomInvitation)") + + return CompletableFuture.completedFuture(null) } override fun roomInvitationRawPayload(roomInvitationId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomInvitationRawPayload($roomInvitationId)") + + return CompletableFuture.completedFuture(null) } override fun roomInvitationRawPayloadParser(rawPayload: RoomInvitationPayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet rromInvitationRawPayloadParser(${JsonUtils.write(rawPayload)})") + return CompletableFuture.completedFuture(rawPayload) } override fun roomAdd(roomId: String, contactId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomAdd($roomId,$contactId)") + return CompletableFuture.completedFuture(null) } override fun roomAvatar(roomId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomAvatar($roomId)") + + val roomPayload = this.roomPayload(roomId).get() + if (roomPayload.avatar != null) { + return CompletableFuture.completedFuture(FileBox.fromUrl(roomPayload.avatar!!, "room-avatar")) + } + log.warn("MockPuppet roomAvatar() avatar not found,use the chatie default.") + return CompletableFuture.completedFuture(qrCodeForChatie()) } override fun roomCreate(contactIdList: List, topic: String?): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomCreate($contactIdList,$topic)") + return CompletableFuture.completedFuture("mock_room_id") } override fun roomDel(roomId: String, contactId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomDel($roomId,$contactId)") + return CompletableFuture.completedFuture(null) } override fun roomList(): Future> { - TODO("Not yet implemented") + log.info("MockPuppet roomList()") + + return CompletableFuture.completedFuture(listOf()) } override fun roomQRCode(roomId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomQRCode($roomId)") + return CompletableFuture.completedFuture("$roomId mock qrcode") } override fun roomQuit(roomId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomQuit($roomId)") + return CompletableFuture.completedFuture(null) } override fun roomTopic(roomId: String): Future? { - TODO("Not yet implemented") + log.info("MockPuppet roomTopic($roomId)") + return CompletableFuture.completedFuture("mock room topic") } override fun roomTopic(roomId: String, topic: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomTopic($roomId,$topic)") + return CompletableFuture.completedFuture(null) } override fun roomRawPayload(roomId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomRawPayload($roomId)") + val roomPayload = RoomPayload(roomId) + roomPayload.memberIdList = listOf() + roomPayload.ownerId = "mock_room_owner_id" + roomPayload.topic = "mock topic" + return CompletableFuture.completedFuture(roomPayload) } override fun roomRawPayloadParser(roomPayload: RoomPayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomRawPayloadParser(${JsonUtils.write(roomPayload)})") + val payload = RoomPayload(roomPayload.id) + payload.ownerId = roomPayload.id + payload.adminIdList = listOf() + payload.memberIdList = listOf() + payload.topic = "mock topic" + return CompletableFuture.completedFuture(payload) } override fun getRoomAnnounce(roomId: String): Future { - TODO("Not yet implemented") + return CompletableFuture.completedFuture("mock announcement for $roomId") } override fun setRoomAnnounce(roomId: String, text: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet setRoomAnnounce($roomId,$text)") + return CompletableFuture.completedFuture(null) } override fun roomMemberList(roomId: String): Future> { - TODO("Not yet implemented") + log.info("MockPuppet roomMemberList($roomId)") + return CompletableFuture.completedFuture(listOf()) } override fun roomMemberRawPayload(roomId: String, contactId: String): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomMemberRawPayload($roomId,$contactId)") + val roomMemberPayload = RoomMemberPayload() + roomMemberPayload.avatar = "mock-avatar-data" + roomMemberPayload.id = "xx" + roomMemberPayload.name = "mock-name" + roomMemberPayload.roomAlias = "yy" + + return CompletableFuture.completedFuture(roomMemberPayload) } override fun roomMemberRawPayloadParser(rawPayload: RoomMemberPayload): Future { - TODO("Not yet implemented") + log.info("MockPuppet roomMemberRawPayloadParser(${JsonUtils.write(rawPayload)})") + return CompletableFuture.completedFuture(rawPayload) } companion object { diff --git a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt index 12877d5..462981a 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt @@ -118,7 +118,8 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : } private fun initPuppet() { - this.puppet = GrpcPuppet(puppetOptions) +// this.puppet = GrpcPuppet(puppetOptions) + this.puppet = PuppetManager.resolveInstance(wechatyOptions).get() initPuppetEventBridge(puppet) } diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index 6b93140..6376a72 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt @@ -73,12 +73,16 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { is String -> { var mentionList = listOf() if (varList.isNotEmpty()) { - varList.forEach { + val list = varList[0] + if (list !is List<*>){ + throw Exception("room say contact args not valid") + } + list.forEach { if (it !is Contact) { throw Exception("mentionList must be contact when not using String array function call.") } } - mentionList = varList.toList() + mentionList = list as List val mentionAlias = mentionList.map { contact -> val alias = alias(contact as Contact) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt new file mode 100644 index 0000000..658ae9d --- /dev/null +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt @@ -0,0 +1,30 @@ +package io.github.wechaty.user.manager + +import io.github.wechaty.MockPuppet +import io.github.wechaty.Puppet +import io.github.wechaty.WechatyOptions +import io.github.wechaty.grpc.GrpcPuppet +import io.github.wechaty.utils.JsonUtils +import org.slf4j.LoggerFactory +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Future + +class PuppetManager { + + companion object { + private val log = LoggerFactory.getLogger(MockPuppet::class.java) + + @JvmStatic + fun resolveInstance(wechatyOptions: WechatyOptions): Future { + log.info("PuppetManager resolveInstance(${JsonUtils.write(wechatyOptions)})") + + return if ("wechaty-puppet-hostie" == wechatyOptions.puppet) { + CompletableFuture.completedFuture(GrpcPuppet(wechatyOptions.puppetOptions!!)) + } else { + CompletableFuture.completedFuture(MockPuppet(wechatyOptions.puppetOptions!!)) + } + } + } + + +} diff --git a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt index 09fb26b..5e0699d 100644 --- a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt +++ b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt @@ -1,58 +1,80 @@ package io.github.wechaty.user +import io.github.wechaty.MockPuppet +import io.github.wechaty.Puppet import io.github.wechaty.Wechaty +import io.github.wechaty.WechatyOptions +import io.github.wechaty.schemas.PuppetOptions +import io.github.wechaty.utils.MockitoHelper import org.junit.After import org.junit.Before import org.junit.Ignore import org.junit.Test import org.mockito.ArgumentMatchers +import org.mockito.Mock import org.mockito.Mockito -import org.mockito.Mockito.`when` -import org.mockito.Mockito.verify -import io.github.wechaty.utils.MockitoHelper +import org.mockito.Mockito.* /** * @author renxiaoya * @date 2020-05-29 */ +const val EXPECTED_ROOM_ID = "roomId" +const val EXPECTED_ROOM_TOPIC = "test-topic" +const val EXPECTED_CONTACT_1_ID = "contact1" +const val EXPECTED_CONTACT_1_ALIAS = "little1" +const val EXPECTED_CONTACT_2_ID = "contact2" +const val EXPECTED_CONTACT_2_ALIAS = "big2" class RoomTest { - lateinit var mockWechaty: Wechaty + lateinit var wechaty: Wechaty lateinit var room: Room + lateinit var puppet: Puppet + @Before fun setUp() { - //TODO(create a mock puppet for unit test) - //these can not fill the inner field in wechaty.To resolve it,I may define a mock puppet for unit test - mockWechaty = Mockito.mock(Wechaty::class.java) - room = Mockito.mock(Room::class.java) + puppet = MockPuppet(PuppetOptions()) + val wechatyOptions = WechatyOptions() + wechatyOptions.name = "MockWechaty" + wechatyOptions.puppet = "wechaty-puppet-mock" + wechatyOptions.puppetOptions = PuppetOptions() + wechaty = Wechaty.instance(wechatyOptions) +// wechaty = spy(wechaty) + wechaty.start() + room = wechaty.roomManager.load(EXPECTED_ROOM_ID) + room.sync() } @After fun tearDown() { - + wechaty.stop() } @Test // ignore temporary because it doesn't work for now @Ignore fun say() { - `when`(room.alias(MockitoHelper.anyObject())).thenReturn("test-alias") - val msgId = "test_msgId" - `when`(mockWechaty.getPuppet().messageSendText(ArgumentMatchers.anyString() - , ArgumentMatchers.anyString() - , ArgumentMatchers.anyList()).get()).thenReturn(msgId) - val msg = Mockito.mock(Message::class.java) - `when`(mockWechaty.messageManager.load(msgId)).thenReturn(msg) + val contact1 = wechaty.contactManager.load(EXPECTED_CONTACT_1_ID) + val contact2 = wechaty.contactManager.load(EXPECTED_CONTACT_2_ID) + contact1.sync() + contact2.sync() +// `when`(room.alias(MockitoHelper.anyObject())).thenReturn("test-alias") +// val msgId = "test_msgId" +// `when`(wechaty.getPuppet().messageSendText("test-conversation-id" +// , "test-text" +// , listOf("test-mentioned")).get()).thenReturn(msgId) +// val msg = Mockito.mock(Message::class.java) +// `when`(wechaty.messageManager.load(msgId)).thenReturn(msg) +// val text = "test-text" - val contact1 = Contact(mockWechaty, "contact1") - val contact2 = Contact(mockWechaty, "contact2") - val contact3 = Contact(mockWechaty, "contact3") +// val contact3 = Contact(wechaty, "contact3") + - verify(room.say(text, listOf(contact1, contact2, contact3))) + room.say(text, listOf(contact1, contact2)) } } From bd116641ad35fc9174b4ab2f39dc14baa5c82f85 Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Sat, 6 Jun 2020 22:03:29 +0800 Subject: [PATCH 03/41] modify room test --- wechaty/pom.xml | 2 +- .../wechaty/user/manager/PuppetManager.kt | 2 +- .../kotlin/io/github/wechaty/user/RoomTest.kt | 30 ++++++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/wechaty/pom.xml b/wechaty/pom.xml index 468fc06..f709d9f 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -33,7 +33,7 @@ io.github.wechaty wechaty-puppet-mock ${project.version} - test + diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt index 658ae9d..5ad71ef 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt @@ -12,7 +12,7 @@ import java.util.concurrent.Future class PuppetManager { companion object { - private val log = LoggerFactory.getLogger(MockPuppet::class.java) + private val log = LoggerFactory.getLogger(PuppetManager::class.java) @JvmStatic fun resolveInstance(wechatyOptions: WechatyOptions): Future { diff --git a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt index 5e0699d..a9dcb5a 100644 --- a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt +++ b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt @@ -5,6 +5,7 @@ import io.github.wechaty.Puppet import io.github.wechaty.Wechaty import io.github.wechaty.WechatyOptions import io.github.wechaty.schemas.PuppetOptions +import io.github.wechaty.user.manager.MessageManager import io.github.wechaty.utils.MockitoHelper import org.junit.After import org.junit.Before @@ -14,6 +15,9 @@ import org.mockito.ArgumentMatchers import org.mockito.Mock import org.mockito.Mockito import org.mockito.Mockito.* +import org.mockito.Spy +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Future /** * @author renxiaoya @@ -62,19 +66,23 @@ class RoomTest { contact1.sync() contact2.sync() -// `when`(room.alias(MockitoHelper.anyObject())).thenReturn("test-alias") -// val msgId = "test_msgId" -// `when`(wechaty.getPuppet().messageSendText("test-conversation-id" -// , "test-text" -// , listOf("test-mentioned")).get()).thenReturn(msgId) -// val msg = Mockito.mock(Message::class.java) -// `when`(wechaty.messageManager.load(msgId)).thenReturn(msg) -// - val text = "test-text" -// val contact3 = Contact(wechaty, "contact3") + val spyWechaty: Wechaty = spy(wechaty) + val spyRoom:Room = spy(room) + val spyPuppet:Puppet = spy(puppet) + `when`(spyRoom.alias(contact1)).thenReturn("test-contact1-alias") + `when`(spyRoom.alias(contact2)).thenReturn("test-contact2-alias") + val msgId = "test_msgId" + `when`(spyWechaty.getPuppet()).thenReturn(spyPuppet) + `when`(spyPuppet.messageSendText("test-conversation-id" + , "contact1 contact2" + , listOf("test-mentioned"))).thenReturn(CompletableFuture.completedFuture(msgId)) + val msg = mock(Message::class.java) + val spyMessageManager:MessageManager = spy(wechaty.messageManager) + `when`(spyMessageManager.load(msgId)).thenReturn(msg) - room.say(text, listOf(contact1, contact2)) + val text = "test-text" + spyRoom.say(text, listOf(contact1, contact2)) } } From fd8e8120c0fec2eb55d89ff5b0edf7ba750b2e8f Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Wed, 10 Jun 2020 17:04:47 +0800 Subject: [PATCH 04/41] finish MockPuppet and add test method for say with mention list --- .../kotlin/io/github/wechaty/MockPuppet.kt | 2 +- .../kotlin/io/github/wechaty/user/Room.kt | 5 +-- .../kotlin/io/github/wechaty/user/RoomTest.kt | 35 +++++-------------- 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt index bcb09fb..f3b9aac 100644 --- a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt +++ b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt @@ -250,7 +250,7 @@ class MockPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageSendText(conversationId: String, text: String, mentionList: List?): Future { log.info("MockPuppet messageSendText($conversationId,$text,${JsonUtils.write(mentionList ?: "")})") - return CompletableFuture.completedFuture(null) + return CompletableFuture.completedFuture("mock-msg-$conversationId") } override fun messageSendUrl(conversationId: String, urlLinkPayload: UrlLinkPayload): Future { diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index 3661675..2b5bd87 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt @@ -75,10 +75,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { is String -> { var mentionList = listOf() if (varList.isNotEmpty()) { - val list = varList[0] - if (list !is List<*>){ - throw Exception("room say contact args not valid") - } + val list = varList[0] as? List<*> ?: throw Exception("room say contact args not valid") list.forEach { if (it !is Contact) { throw Exception("mentionList must be contact when not using String array function call.") diff --git a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt index a9dcb5a..8cfdfe7 100644 --- a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt +++ b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt @@ -5,19 +5,12 @@ import io.github.wechaty.Puppet import io.github.wechaty.Wechaty import io.github.wechaty.WechatyOptions import io.github.wechaty.schemas.PuppetOptions -import io.github.wechaty.user.manager.MessageManager -import io.github.wechaty.utils.MockitoHelper import org.junit.After +import org.junit.Assert import org.junit.Before -import org.junit.Ignore import org.junit.Test -import org.mockito.ArgumentMatchers -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.Mockito.* -import org.mockito.Spy -import java.util.concurrent.CompletableFuture -import java.util.concurrent.Future +import org.mockito.Mockito.`when` +import org.mockito.Mockito.spy /** * @author renxiaoya @@ -29,6 +22,7 @@ const val EXPECTED_CONTACT_1_ID = "contact1" const val EXPECTED_CONTACT_1_ALIAS = "little1" const val EXPECTED_CONTACT_2_ID = "contact2" const val EXPECTED_CONTACT_2_ALIAS = "big2" + class RoomTest { lateinit var wechaty: Wechaty @@ -45,7 +39,6 @@ class RoomTest { wechatyOptions.puppet = "wechaty-puppet-mock" wechatyOptions.puppetOptions = PuppetOptions() wechaty = Wechaty.instance(wechatyOptions) -// wechaty = spy(wechaty) wechaty.start() room = wechaty.roomManager.load(EXPECTED_ROOM_ID) @@ -58,31 +51,19 @@ class RoomTest { } @Test - // ignore temporary because it doesn't work for now - @Ignore - fun say() { + fun sayStringWithMentionList() { val contact1 = wechaty.contactManager.load(EXPECTED_CONTACT_1_ID) val contact2 = wechaty.contactManager.load(EXPECTED_CONTACT_2_ID) contact1.sync() contact2.sync() - val spyWechaty: Wechaty = spy(wechaty) - val spyRoom:Room = spy(room) - val spyPuppet:Puppet = spy(puppet) + val spyRoom: Room = spy(room) `when`(spyRoom.alias(contact1)).thenReturn("test-contact1-alias") `when`(spyRoom.alias(contact2)).thenReturn("test-contact2-alias") - val msgId = "test_msgId" - `when`(spyWechaty.getPuppet()).thenReturn(spyPuppet) - `when`(spyPuppet.messageSendText("test-conversation-id" - , "contact1 contact2" - , listOf("test-mentioned"))).thenReturn(CompletableFuture.completedFuture(msgId)) - val msg = mock(Message::class.java) - val spyMessageManager:MessageManager = spy(wechaty.messageManager) - `when`(spyMessageManager.load(msgId)).thenReturn(msg) - val text = "test-text" - spyRoom.say(text, listOf(contact1, contact2)) + val resMsg = spyRoom.say(text, listOf(contact1, contact2)).get() + Assert.assertEquals((resMsg as Message).id, "mock-msg-$EXPECTED_ROOM_ID") } } From 9daa1bb3f5f67ad8f42e0666c32eaf229afb6e33 Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Thu, 11 Jun 2020 20:42:07 +0800 Subject: [PATCH 05/41] modify PuppetManager use reflections --- wechaty/pom.xml | 23 +++++---- .../io/github/wechaty/WechatyOptions.kt | 3 +- .../wechaty/user/manager/PuppetManager.kt | 47 +++++++++++++++++-- .../kotlin/io/github/wechaty/user/RoomTest.kt | 2 +- 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/wechaty/pom.xml b/wechaty/pom.xml index 7e430e8..f959279 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -63,14 +63,16 @@ - - - - - - - - + + org.apache.logging.log4j + log4j-core + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + @@ -110,6 +112,11 @@ junit test + + org.reflections + reflections + 0.9.12 + diff --git a/wechaty/src/main/kotlin/io/github/wechaty/WechatyOptions.kt b/wechaty/src/main/kotlin/io/github/wechaty/WechatyOptions.kt index 50c0b56..d930bf7 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/WechatyOptions.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/WechatyOptions.kt @@ -9,7 +9,8 @@ class WechatyOptions { var name:String = "Wechaty" - var puppet:String = "wechaty-puppet-hostie" +// var puppet:String = "wechaty-puppet-hostie" + var puppet:String = "io.github.wechaty.grpc.GrpcPuppet" var puppetOptions:PuppetOptions? = null diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt index 5ad71ef..f8cbf6d 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt @@ -4,11 +4,15 @@ import io.github.wechaty.MockPuppet import io.github.wechaty.Puppet import io.github.wechaty.WechatyOptions import io.github.wechaty.grpc.GrpcPuppet +import io.github.wechaty.schemas.PuppetOptions import io.github.wechaty.utils.JsonUtils +import org.reflections.Reflections import org.slf4j.LoggerFactory import java.util.concurrent.CompletableFuture import java.util.concurrent.Future +const val REFLECTION_BASE_PACKAGE = "io.github.wechaty" + class PuppetManager { companion object { @@ -18,13 +22,48 @@ class PuppetManager { fun resolveInstance(wechatyOptions: WechatyOptions): Future { log.info("PuppetManager resolveInstance(${JsonUtils.write(wechatyOptions)})") - return if ("wechaty-puppet-hostie" == wechatyOptions.puppet) { - CompletableFuture.completedFuture(GrpcPuppet(wechatyOptions.puppetOptions!!)) - } else { - CompletableFuture.completedFuture(MockPuppet(wechatyOptions.puppetOptions!!)) +// return if ("io.github.wechaty.grpc.GrpcPuppet" == wechatyOptions.puppet) { +// CompletableFuture.completedFuture(GrpcPuppet(wechatyOptions.puppetOptions!!)) +// } else { +// CompletableFuture.completedFuture(MockPuppet(wechatyOptions.puppetOptions!!)) +// } + val reflections = Reflections(REFLECTION_BASE_PACKAGE) + val subTypes: Set<*> = reflections.getSubTypesOf(Puppet::class.java) + + for (subType in subTypes) { + val subTypeClass = subType as Class<*> + if (wechatyOptions.puppet == subTypeClass.canonicalName) { + val declaredConstructor = subTypeClass.getDeclaredConstructor(PuppetOptions::class.java) + return CompletableFuture.completedFuture(declaredConstructor.newInstance(wechatyOptions.puppetOptions!!) as Puppet) + } } + throw RuntimeException("instant puppet implementation error. Please check your wechatyOptions.puppet") } } } + +fun main() { +// val serviceLoader:ServiceLoader = ServiceLoader.load(Puppet::class.java) +// for (puppet in serviceLoader) { +// println(puppet) +// } + +// val kClass:KClass = Puppet::class +// print(kClass) + val reflections: Reflections = Reflections("io.github.wechaty") + val subTypes: Set<*> = reflections.getSubTypesOf(Puppet::class.java) + for (subType in subTypes) { + val subTypeClass = subType as Class<*> + if ("io.github.wechaty.grpc.GrpcPuppet" == subTypeClass.canonicalName) { + + val declaredConstructor = subTypeClass.getDeclaredConstructor(PuppetOptions::class.java) + + val newInstance = declaredConstructor.newInstance(PuppetOptions()) + + } + } + +} + diff --git a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt index 8cfdfe7..50886d0 100644 --- a/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt +++ b/wechaty/src/test/kotlin/io/github/wechaty/user/RoomTest.kt @@ -36,7 +36,7 @@ class RoomTest { puppet = MockPuppet(PuppetOptions()) val wechatyOptions = WechatyOptions() wechatyOptions.name = "MockWechaty" - wechatyOptions.puppet = "wechaty-puppet-mock" + wechatyOptions.puppet = "io.github.wechaty.MockPuppet" wechatyOptions.puppetOptions = PuppetOptions() wechaty = Wechaty.instance(wechatyOptions) wechaty.start() From ab8fda72da0eb096e7ac259541b6628a2fcd6bf2 Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Fri, 12 Jun 2020 19:29:09 +0800 Subject: [PATCH 06/41] puppetOptions add name to manage name by itself.And remove puppet implementations from wechaty pom,just only dependents puppet --- examples/pom.xml | 8 +- pom.xml | 18 ++ .../io/github/wechaty/grpc/GrpcPuppet.kt | 257 +++++++++--------- .../kotlin/io/github/wechaty/MockPuppet.kt | 4 + wechaty-puppet/src/main/kotlin/Puppet.kt | 42 +-- .../github/wechaty/schemas/PuppetOptions.kt | 1 + wechaty/pom.xml | 17 +- .../main/kotlin/io/github/wechaty/Wechaty.kt | 1 - .../wechaty/user/manager/PuppetManager.kt | 44 +-- 9 files changed, 196 insertions(+), 196 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index d708add..a15aef4 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -17,6 +17,7 @@ UTF-8 true 0.10.1 + 0.1.3-SNAPSHOT @@ -24,7 +25,12 @@ io.github.wechaty wechaty - 0.1.3-SNAPSHOT + ${wechaty.version} + + + io.github.wechaty + wechaty-puppet-hostie + ${wechaty.version} org.apache.logging.log4j diff --git a/pom.xml b/pom.xml index 60779cd..4fb6f82 100644 --- a/pom.xml +++ b/pom.xml @@ -76,6 +76,24 @@ slf4j-api 1.7.30 + + org.apache.logging.log4j + log4j-core + 2.13.1 + test + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.13.1 + test + + + com.lmax + disruptor + 3.4.2 + test + org.apache.commons diff --git a/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt b/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt index fb1c7c6..f7202d4 100644 --- a/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt +++ b/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt @@ -35,27 +35,26 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { private val client: OkHttpClient = OkHttpClient() private var grpcClient: PuppetGrpc.PuppetBlockingStub? = null - private var grpcAsyncClient:PuppetGrpc.PuppetStub? = null + private var grpcAsyncClient: PuppetGrpc.PuppetStub? = null // private var finishLatch:CountDownLatch? = null - private fun discoverHostieIp():Pair{ + private fun discoverHostieIp(): Pair { val token = puppetOptions!!.token val request: Request = Request.Builder() - .url(CHATIE_ENDPOINT + token) - .build() + .url(CHATIE_ENDPOINT + token) + .build() - client.newCall(request).execute().use { - response -> + client.newCall(request).execute().use { response -> val string = response.body!!.string() val readValue = JsonUtils.readValue>(string) val ip = readValue["ip"] ?: error("cannot get ip by token, check token"); - val port = readValue["port"] ?:"8788" + val port = readValue["port"] ?: "8788" - return Pair(ip,port) + return Pair(ip, port) } } @@ -99,7 +98,7 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { try { if (logonoff()) { - emit(EventEnum.LOGOUT,EventLogoutPayload(getId()!!,"logout")) + emit(EventEnum.LOGOUT, EventLogoutPayload(getId()!!, "logout")) this.setId(null) } @@ -125,6 +124,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { return CompletableFuture.completedFuture(null) } + override fun setPuppetName() { + puppetOptions!!.name = "io.github.wechaty.grpc.GrpcPuppet" + } override fun unref() { @@ -135,15 +137,15 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { private fun startGrpcClient(): Future { val endPoint = puppetOptions?.endPoint - val discoverHostieIp:Pair + val discoverHostieIp: Pair discoverHostieIp = if (StringUtils.isEmpty(endPoint)) { discoverHostieIp() - }else{ + } else { val split = StringUtils.split(endPoint, ":") - if(split.size == 1) { - Pair(split[0],"8788") - }else{ - Pair(split[0],split[1]) + if (split.size == 1) { + Pair(split[0], "8788") + } else { + Pair(split[0], split[1]) } } @@ -153,7 +155,7 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { exitProcess(1) } val newFixedThreadPool = newFixedThreadPool(16) - channel = ManagedChannelBuilder.forAddress(discoverHostieIp.first,NumberUtils.toInt(discoverHostieIp.second)).usePlaintext().executor(newFixedThreadPool).build() + channel = ManagedChannelBuilder.forAddress(discoverHostieIp.first, NumberUtils.toInt(discoverHostieIp.second)).usePlaintext().executor(newFixedThreadPool).build() grpcClient = PuppetGrpc.newBlockingStub(channel) grpcAsyncClient = PuppetGrpc.newStub(channel) @@ -161,15 +163,15 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { } private fun startGrpcStream() { - val streamObserver = object :StreamObserver{ + val streamObserver = object : StreamObserver { override fun onNext(event: Event.EventResponse?) { onGrpcStreamEvent(event!!) } override fun onError(t: Throwable?) { - log.error("error of grpc",t) - val payload = EventResetPayload(t?.message ?:"") - emit(EventEnum.RESET,payload) + log.error("error of grpc", t) + val payload = EventResetPayload(t?.message ?: "") + emit(EventEnum.RESET, payload) } override fun onCompleted() { @@ -179,7 +181,7 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { } val request = Event.EventRequest.newBuilder().build() - grpcAsyncClient!!.event(request,streamObserver) + grpcAsyncClient!!.event(request, streamObserver) } @@ -202,15 +204,15 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { } catch (e: Exception) { log.error("logout() rejection: %s", e) } finally { - emit(EventEnum.LOGOUT,EventLogoutPayload(getId()!!,"logout")) + emit(EventEnum.LOGOUT, EventLogoutPayload(getId()!!, "logout")) } return CompletableFuture.completedFuture(null) } override fun ding(data: String?) { val request = Base.DingRequest.newBuilder() - .setData(data) - .build() + .setData(data) + .build() CompletableFuture.runAsync { try { @@ -223,8 +225,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun contactSelfName(name: String): Future { val request = Contact.ContactSelfNameRequest.newBuilder() - .setName(name) - .build() + .setName(name) + .build() return CompletableFuture.supplyAsync { grpcClient!!.contactSelfName(request) null @@ -244,8 +246,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun contactSelfSignature(signature: String): Future { val request = Contact.ContactSelfSignatureRequest.newBuilder() - .setSignature(signature) - .build() + .setSignature(signature) + .build() return CompletableFuture.supplyAsync { grpcClient!!.contactSelfSignature(request) @@ -256,9 +258,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun tagContactAdd(tagId: String, contactId: String): Future { val request = Tag.TagContactAddRequest.newBuilder() - .setId(tagId) - .setContactId(contactId) - .build() + .setId(tagId) + .setContactId(contactId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.tagContactAdd(request) @@ -270,8 +272,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun tagContactDelete(tagId: String): Future { val request = Tag.TagContactDeleteRequest.newBuilder() - .setId(tagId) - .build() + .setId(tagId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.tagContactDelete(request) return@supplyAsync null @@ -281,14 +283,14 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun tagContactList(contactId: String): Future> { val stringValue = StringValue.newBuilder() - .setValue(contactId) - .build() + .setValue(contactId) + .build() return CompletableFuture.supplyAsync { val request = Tag.TagContactListRequest.newBuilder() - .setContactId(stringValue) - .build() + .setContactId(stringValue) + .build() val contactList = grpcClient!!.tagContactList(request) contactList.idsList } @@ -306,9 +308,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun tagContactRemove(tagId: String, contactId: String): Future { val request = Tag.TagContactRemoveRequest.newBuilder() - .setId(tagId) - .setContactId(contactId) - .build() + .setId(tagId) + .setContactId(contactId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.tagContactRemove(request) @@ -322,8 +324,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { return CompletableFuture.supplyAsync { val request = Contact.ContactAliasRequest.newBuilder() - .setId(contactId) - .build() + .setId(contactId) + .build() val response = grpcClient!!.contactAlias(request) val alias = response.alias return@supplyAsync alias.value @@ -334,9 +336,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { val stringValue = StringValue.newBuilder().setValue(alias).build() val request = Contact.ContactAliasRequest.newBuilder() - .setId(contactId) - .setAlias(stringValue) - .build() + .setId(contactId) + .setAlias(stringValue) + .build() return CompletableFuture.supplyAsync() { grpcClient!!.contactAlias(request) @@ -347,8 +349,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun getContactAvatar(contactId: String): Future { val request = Contact.ContactAvatarRequest.newBuilder() - .setId(contactId) - .build() + .setId(contactId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.contactAvatar(request) @@ -365,9 +367,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { val value = StringValue.newBuilder().setValue(toJsonString) val request = Contact.ContactAvatarRequest.newBuilder() - .setId(contactId) - .setFilebox(value) - .build() + .setId(contactId) + .setFilebox(value) + .build() return CompletableFuture.supplyAsync { grpcClient!!.contactAvatar(request) @@ -389,8 +391,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun contactRawPayload(contractId: String): Future { val request = Contact.ContactPayloadRequest.newBuilder() - .setId(contractId) - .build() + .setId(contractId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.contactPayload(request) @@ -419,8 +421,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun friendshipAccept(friendshipId: String): Future { val request = Friendship.FriendshipAcceptRequest.newBuilder() - .setId(friendshipId) - .build() + .setId(friendshipId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.friendshipAccept(request) @@ -431,9 +433,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun friendshipAdd(contractId: String, hello: String): Future { val request = Friendship.FriendshipAddRequest.newBuilder() - .setContactId(contractId) - .setHello(hello) - .build() + .setContactId(contractId) + .setHello(hello) + .build() return CompletableFuture.supplyAsync { grpcClient!!.friendshipAdd(request) @@ -445,8 +447,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun friendshipSearchPhone(phone: String): Future { val request = Friendship.FriendshipSearchPhoneRequest.newBuilder() - .setPhone(phone) - .build() + .setPhone(phone) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.friendshipSearchPhone(request) @@ -456,8 +458,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun friendshipSearchWeixin(weixin: String): Future { val request = Friendship.FriendshipSearchWeixinRequest.newBuilder() - .setWeixin(weixin) - .build() + .setWeixin(weixin) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.friendshipSearchWeixin(request) @@ -468,8 +470,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun friendshipRawPayload(friendshipId: String): Future { val request = Friendship.FriendshipPayloadRequest.newBuilder() - .setId(friendshipId) - .build() + .setId(friendshipId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.friendshipPayload(request) @@ -493,8 +495,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageContact(messageId: String): Future { val request = Message.MessageContactRequest.newBuilder() - .setId(messageId) - .build() + .setId(messageId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageContact(request) response.id @@ -504,8 +506,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageFile(messageId: String): Future { val request = Message.MessageFileRequest.newBuilder() - .setId(messageId) - .build() + .setId(messageId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageFile(request) @@ -519,9 +521,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { val imageType1 = Message.ImageType.forNumber(imageType.code) val request = Message.MessageImageRequest.newBuilder() - .setId(messageId) - .setType(imageType1) - .build() + .setId(messageId) + .setType(imageType1) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageImage(request) @@ -534,8 +536,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageMiniProgram(messageId: String): Future { val request = Message.MessageMiniProgramRequest.newBuilder() - .setId(messageId) - .build() + .setId(messageId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageMiniProgram(request) @@ -548,8 +550,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageUrl(messageId: String): Future { val request = Message.MessageUrlRequest.newBuilder() - .setId(messageId) - .build() + .setId(messageId) + .build() return CompletableFuture.supplyAsync { @@ -564,9 +566,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageSendContact(conversationId: String, contactId: String): Future { val request = Message.MessageSendContactRequest.newBuilder() - .setContactId(contactId) - .setConversationId(conversationId) - .build() + .setContactId(contactId) + .setConversationId(conversationId) + .build() return CompletableFuture.supplyAsync { @@ -583,9 +585,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { log.debug("json size is {}", fileJson.length) val request = Message.MessageSendFileRequest.newBuilder() - .setConversationId(conversationId) - .setFilebox(fileJson) - .build() + .setConversationId(conversationId) + .setFilebox(fileJson) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageSendFile(request) @@ -597,9 +599,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageSendMiniProgram(conversationId: String, miniProgramPayload: MiniProgramPayload): Future { val request = Message.MessageSendMiniProgramRequest.newBuilder() - .setConversationId(conversationId) - .setMiniProgram(JsonUtils.write(miniProgramPayload)) - .build() + .setConversationId(conversationId) + .setMiniProgram(JsonUtils.write(miniProgramPayload)) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageSendMiniProgram(request) @@ -610,9 +612,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageSendText(conversationId: String, text: String, mentionList: List?): Future { val request = Message.MessageSendTextRequest.newBuilder() - .setConversationId(conversationId) - .setText(text) - .build() + .setConversationId(conversationId) + .setText(text) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageSendText(request) @@ -624,9 +626,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageSendUrl(conversationId: String, urlLinkPayload: UrlLinkPayload): Future { val request = Message.MessageSendUrlRequest.newBuilder() - .setConversationId(conversationId) - .setUrlLink(JsonUtils.write(urlLinkPayload)) - .build() + .setConversationId(conversationId) + .setUrlLink(JsonUtils.write(urlLinkPayload)) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageSendUrl(request) @@ -638,8 +640,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun messageRecall(messageId: String): Future { val request = Message.MessageRecallRequest.newBuilder() - .setId(messageId) - .build() + .setId(messageId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.messageRecall(request) @@ -674,8 +676,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomInvitationAccept(roomInvitation: String): Future { val request = RoomInvitation.RoomInvitationAcceptRequest.newBuilder() - .setId(roomInvitation) - .build() + .setId(roomInvitation) + .build() return CompletableFuture.supplyAsync { grpcClient!!.roomInvitationAccept(request) @@ -686,8 +688,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomInvitationRawPayload(roomInvitationId: String): Future { val request = RoomInvitation.RoomInvitationPayloadRequest.newBuilder() - .setId(roomInvitationId) - .build() + .setId(roomInvitationId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomInvitationPayload(request) @@ -716,9 +718,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomAdd(roomId: String, contactId: String): Future { val request = Room.RoomAddRequest.newBuilder() - .setContactId(contactId) - .setId(roomId) - .build() + .setContactId(contactId) + .setId(roomId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.roomAdd(request) @@ -730,8 +732,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomAvatar(roomId: String): Future { val request = Room.RoomAvatarRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { @@ -747,9 +749,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomCreate(contactIdList: List, topic: String?): Future { val request = Room.RoomCreateRequest.newBuilder() - .setTopic(topic) - .addAllContactIds(contactIdList) - .build() + .setTopic(topic) + .addAllContactIds(contactIdList) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomCreate(request) @@ -762,9 +764,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomDel(roomId: String, contactId: String): Future { val request = Room.RoomDelRequest.newBuilder() - .setId(roomId) - .setContactId(contactId) - .build() + .setId(roomId) + .setContactId(contactId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.roomDel(request) @@ -787,8 +789,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomQRCode(roomId: String): Future { val request = Room.RoomQRCodeRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { @@ -801,8 +803,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomQuit(roomId: String): Future { val request = Room.RoomQuitRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { grpcClient!!.roomQuit(request) @@ -814,8 +816,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomTopic(roomId: String): Future? { val request = Room.RoomTopicRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomTopic(request) @@ -830,9 +832,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { val value = StringValue.newBuilder().setValue(topic) val request = Room.RoomTopicRequest.newBuilder() - .setId(roomId) - .setTopic(value) - .build() + .setId(roomId) + .setTopic(value) + .build() return CompletableFuture.supplyAsync { grpcClient!!.roomTopic(request) @@ -843,8 +845,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomRawPayload(roomId: String): Future { val request = Room.RoomPayloadRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomPayload(request) @@ -867,8 +869,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun getRoomAnnounce(roomId: String): Future { val request = Room.RoomAnnounceRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomAnnounce(request) @@ -883,9 +885,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { val value = StringValue.newBuilder().setValue(text) val request = Room.RoomAnnounceRequest.newBuilder() - .setId(roomId) - .setText(value) - .build() + .setId(roomId) + .setText(value) + .build() return CompletableFuture.supplyAsync { grpcClient!!.roomAnnounce(request) @@ -898,8 +900,8 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomMemberList(roomId: String): Future> { val request = RoomMember.RoomMemberListRequest.newBuilder() - .setId(roomId) - .build() + .setId(roomId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomMemberList(request) @@ -912,9 +914,9 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { override fun roomMemberRawPayload(roomId: String, contactId: String): Future { val request = RoomMember.RoomMemberPayloadRequest.newBuilder() - .setId(roomId) - .setMemberId(contactId) - .build() + .setId(roomId) + .setMemberId(contactId) + .build() return CompletableFuture.supplyAsync { val response = grpcClient!!.roomMemberPayload(request) @@ -1029,7 +1031,6 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { } - companion object { private val log = LoggerFactory.getLogger(GrpcPuppet::class.java) } diff --git a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt index f3b9aac..9e47bbb 100644 --- a/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt +++ b/wechaty-puppet-mock/src/main/kotlin/io/github/wechaty/MockPuppet.kt @@ -72,6 +72,10 @@ class MockPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { return CompletableFuture.completedFuture(null) } + override fun setPuppetName() { + puppetOptions!!.name = "io.github.wechaty.MockPuppet" + } + override fun logout(): Future { log.info("MockPuppet logout()") val id = getId() ?: throw Exception("logout before login?") diff --git a/wechaty-puppet/src/main/kotlin/Puppet.kt b/wechaty-puppet/src/main/kotlin/Puppet.kt index c3ab433..e2cc4b8 100644 --- a/wechaty-puppet/src/main/kotlin/Puppet.kt +++ b/wechaty-puppet/src/main/kotlin/Puppet.kt @@ -98,8 +98,8 @@ abstract class Puppet : EventEmitter { on(EventEnum.RESET, object : PuppetResetListener { override fun handler(payload: EventResetPayload) { - log.debug("get a reset message") - if(rateLimiter.tryAcquire()){ + log.debug("get a reset message") + if (rateLimiter.tryAcquire()) { reset(payload.data) } @@ -155,7 +155,7 @@ abstract class Puppet : EventEmitter { override fun handler(vararg any: Any) { - log.debug("class Type is {}",any[0].javaClass.name) + log.debug("class Type is {}", any[0].javaClass.name) listener.handler(any[0] as EventDongPayload) @@ -226,7 +226,7 @@ abstract class Puppet : EventEmitter { override fun handler(vararg any: Any) { - log.debug("class Type is {}",any[0].javaClass.name) + log.debug("class Type is {}", any[0].javaClass.name) listener.handler(any[0] as EventScanPayload) @@ -264,7 +264,7 @@ abstract class Puppet : EventEmitter { override fun handler(vararg any: Any) { - log.debug("class Type is {}",any[0].javaClass.name) + log.debug("class Type is {}", any[0].javaClass.name) listener.handler(any[0] as EventHeartbeatPayload) @@ -291,6 +291,7 @@ abstract class Puppet : EventEmitter { abstract fun start(): Future abstract fun stop(): Future + abstract fun setPuppetName() open fun unref() { } @@ -348,6 +349,7 @@ abstract class Puppet : EventEmitter { * contactSelf */ abstract fun contactSelfName(name: String): Future + abstract fun contactSelfQRCode(): Future abstract fun contactSelfSignature(signature: String): Future @@ -362,6 +364,7 @@ abstract class Puppet : EventEmitter { * */ abstract fun tagContactAdd(tagId: String, contactId: String): Future + abstract fun tagContactDelete(tagId: String): Future abstract fun tagContactList(contactId: String): Future> abstract fun tagContactList(): Future> @@ -373,6 +376,7 @@ abstract class Puppet : EventEmitter { * */ abstract fun contactAlias(contactId: String): Future + abstract fun contactAlias(contactId: String, alias: String?): Future abstract fun getContactAvatar(contactId: String): Future abstract fun setContactAvatar(contactId: String, file: FileBox): Future @@ -422,39 +426,39 @@ abstract class Puppet : EventEmitter { return@supplyAsync list } - val stream = list?.stream()?.map{contactPayload(it).get()} - if(StringUtils.isNotBlank(query.name)){ + val stream = list?.stream()?.map { contactPayload(it).get() } + if (StringUtils.isNotBlank(query.name)) { stream?.filter { StringUtils.equals(query.name, it.name) } } - if(StringUtils.isNotBlank(query.alias)){ + if (StringUtils.isNotBlank(query.alias)) { stream?.filter { StringUtils.equals(query.alias, it.alias) } } - if(StringUtils.isNotBlank(query.id)){ + if (StringUtils.isNotBlank(query.id)) { stream?.filter { StringUtils.equals(query.alias, it.alias) } } - if(StringUtils.isNotBlank(query.weixin)){ + if (StringUtils.isNotBlank(query.weixin)) { stream?.filter { StringUtils.equals(query.alias, it.alias) } } - if(query.nameReg != null){ - stream?.filter{ + if (query.nameReg != null) { + stream?.filter { query.nameReg!!.matches(it.name ?: "") } } - if(query.aliasReg != null){ - stream?.filter{ + if (query.aliasReg != null) { + stream?.filter { query.aliasReg!!.matches(it.alias ?: "") } } @@ -468,7 +472,7 @@ abstract class Puppet : EventEmitter { } } - fun ContactPayloadFilterFactory(query:ContactQueryFilter):ContactPayloadFilterFunction{ + fun ContactPayloadFilterFactory(query: ContactQueryFilter): ContactPayloadFilterFunction { val clz = query::class.java val fields = clz.fields @@ -490,13 +494,11 @@ abstract class Puppet : EventEmitter { } - - protected fun contactPayloadCache(contactId: String): ContactPayload? { val contactPayload = cacheContactPayload.getIfPresent(contactId) - log.debug("contactPayload is {} by id {}", contactPayload,contactId) + log.debug("contactPayload is {} by id {}", contactPayload, contactId) return contactPayload } @@ -529,6 +531,7 @@ abstract class Puppet : EventEmitter { * */ abstract fun friendshipAccept(friendshipId: String): Future + abstract fun friendshipAdd(contractId: String, hello: String): Future abstract fun friendshipSearchPhone(phone: String): Future abstract fun friendshipSearchWeixin(weixin: String): Future @@ -594,6 +597,7 @@ abstract class Puppet : EventEmitter { */ abstract fun messageContact(messageId: String): Future + abstract fun messageFile(messageId: String): Future abstract fun messageImage(messageId: String, imageType: ImageType): Future abstract fun messageMiniProgram(messageId: String): Future @@ -790,6 +794,7 @@ abstract class Puppet : EventEmitter { * */ abstract fun roomAdd(roomId: String, contactId: String): Future + abstract fun roomAvatar(roomId: String): Future abstract fun roomCreate(contactIdList: List, topic: String?): Future @@ -809,6 +814,7 @@ abstract class Puppet : EventEmitter { */ abstract fun getRoomAnnounce(roomId: String): Future + abstract fun setRoomAnnounce(roomId: String, text: String): Future abstract fun roomMemberList(roomId: String): Future> diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/PuppetOptions.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/PuppetOptions.kt index 765780b..a607dc0 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/PuppetOptions.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/PuppetOptions.kt @@ -5,5 +5,6 @@ class PuppetOptions { var timeout: Long? = null var token: String? = null var puppetOptionKey: String? = null + var name: String = "DEFAULT" } diff --git a/wechaty/pom.xml b/wechaty/pom.xml index f959279..9184a3d 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -23,17 +23,11 @@ ${project.version} - - io.github.wechaty - wechaty-puppet-hostie - ${project.version} - - io.github.wechaty wechaty-puppet-mock ${project.version} - + test @@ -75,10 +69,11 @@ - - - - + + com.lmax + disruptor + test + org.slf4j diff --git a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt index 6441e98..2dd9310 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt @@ -4,7 +4,6 @@ package io.github.wechaty; import io.github.wechaty.eventEmitter.Event import io.github.wechaty.eventEmitter.EventEmitter import io.github.wechaty.eventEmitter.Listener -import io.github.wechaty.grpc.GrpcPuppet import io.github.wechaty.io.github.wechaty.schemas.EventEnum import io.github.wechaty.listener.* //import io.github.wechaty.memorycard.MemoryCard diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt index f8cbf6d..c60e152 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt @@ -1,12 +1,11 @@ package io.github.wechaty.user.manager -import io.github.wechaty.MockPuppet import io.github.wechaty.Puppet import io.github.wechaty.WechatyOptions -import io.github.wechaty.grpc.GrpcPuppet import io.github.wechaty.schemas.PuppetOptions import io.github.wechaty.utils.JsonUtils import org.reflections.Reflections +import org.reflections.util.ClasspathHelper import org.slf4j.LoggerFactory import java.util.concurrent.CompletableFuture import java.util.concurrent.Future @@ -22,48 +21,19 @@ class PuppetManager { fun resolveInstance(wechatyOptions: WechatyOptions): Future { log.info("PuppetManager resolveInstance(${JsonUtils.write(wechatyOptions)})") -// return if ("io.github.wechaty.grpc.GrpcPuppet" == wechatyOptions.puppet) { -// CompletableFuture.completedFuture(GrpcPuppet(wechatyOptions.puppetOptions!!)) -// } else { -// CompletableFuture.completedFuture(MockPuppet(wechatyOptions.puppetOptions!!)) -// } - val reflections = Reflections(REFLECTION_BASE_PACKAGE) + val reflections = Reflections(ClasspathHelper.forPackage(REFLECTION_BASE_PACKAGE, Thread.currentThread().contextClassLoader)) val subTypes: Set<*> = reflections.getSubTypesOf(Puppet::class.java) - for (subType in subTypes) { - val subTypeClass = subType as Class<*> - if (wechatyOptions.puppet == subTypeClass.canonicalName) { - val declaredConstructor = subTypeClass.getDeclaredConstructor(PuppetOptions::class.java) - return CompletableFuture.completedFuture(declaredConstructor.newInstance(wechatyOptions.puppetOptions!!) as Puppet) - } + if (subTypes.size > 1) { + throw RuntimeException("expect one puppet,but found ${subTypes.size}") } - throw RuntimeException("instant puppet implementation error. Please check your wechatyOptions.puppet") + val clazz = subTypes.first() as Class<*> + val declaredConstructor = clazz.getDeclaredConstructor(PuppetOptions::class.java) + return CompletableFuture.completedFuture(declaredConstructor.newInstance(wechatyOptions.puppetOptions!!) as Puppet) } } } -fun main() { -// val serviceLoader:ServiceLoader = ServiceLoader.load(Puppet::class.java) -// for (puppet in serviceLoader) { -// println(puppet) -// } - -// val kClass:KClass = Puppet::class -// print(kClass) - val reflections: Reflections = Reflections("io.github.wechaty") - val subTypes: Set<*> = reflections.getSubTypesOf(Puppet::class.java) - for (subType in subTypes) { - val subTypeClass = subType as Class<*> - if ("io.github.wechaty.grpc.GrpcPuppet" == subTypeClass.canonicalName) { - - val declaredConstructor = subTypeClass.getDeclaredConstructor(PuppetOptions::class.java) - - val newInstance = declaredConstructor.newInstance(PuppetOptions()) - - } - } - -} From 7d4b1c268585804ed070bbfa37a95a7bab6989b5 Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Sat, 13 Jun 2020 02:53:25 +0800 Subject: [PATCH 07/41] reduce rejections version and fix contactSearch and messageSearch method in Puppet --- pom.xml | 5 ++++ wechaty-puppet/src/main/kotlin/Puppet.kt | 30 +++++++++---------- wechaty/pom.xml | 2 -- .../wechaty/user/manager/PuppetManager.kt | 7 ++++- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/pom.xml b/pom.xml index 4fb6f82..8aeb858 100644 --- a/pom.xml +++ b/pom.xml @@ -168,6 +168,11 @@ javafaker 1.0.2 + + org.reflections + reflections + 0.9.10 + diff --git a/wechaty-puppet/src/main/kotlin/Puppet.kt b/wechaty-puppet/src/main/kotlin/Puppet.kt index e2cc4b8..a91cdc1 100644 --- a/wechaty-puppet/src/main/kotlin/Puppet.kt +++ b/wechaty-puppet/src/main/kotlin/Puppet.kt @@ -426,39 +426,39 @@ abstract class Puppet : EventEmitter { return@supplyAsync list } - val stream = list?.stream()?.map { contactPayload(it).get() } + var stream = list?.stream()?.map { contactPayload(it).get() } if (StringUtils.isNotBlank(query.name)) { - stream?.filter { + stream = stream?.filter { StringUtils.equals(query.name, it.name) } } if (StringUtils.isNotBlank(query.alias)) { - stream?.filter { + stream = stream?.filter { StringUtils.equals(query.alias, it.alias) } } if (StringUtils.isNotBlank(query.id)) { - stream?.filter { + stream = stream?.filter { StringUtils.equals(query.alias, it.alias) } } if (StringUtils.isNotBlank(query.weixin)) { - stream?.filter { + stream = stream?.filter { StringUtils.equals(query.alias, it.alias) } } if (query.nameReg != null) { - stream?.filter { + stream = stream?.filter { query.nameReg!!.matches(it.name ?: "") } } if (query.aliasReg != null) { - stream?.filter { + stream = stream?.filter { query.aliasReg!!.matches(it.alias ?: "") } } @@ -650,46 +650,46 @@ abstract class Puppet : EventEmitter { messagePayload(it).get() } - val stream = messagePayloadList.stream() + var stream = messagePayloadList.stream() if (StringUtils.isNotEmpty(query.fromId)) { - stream.filter { + stream = stream.filter { StringUtils.equals(it.fromId, query.fromId) } } if (StringUtils.isNotEmpty(query.id)) { - stream.filter { + stream = stream.filter { StringUtils.equals(it.id, query.id) } } if (StringUtils.isNotEmpty(query.roomId)) { - stream.filter { + stream = stream.filter { StringUtils.equals(it.roomId, query.roomId) } } if (StringUtils.isNotEmpty(query.toId)) { - stream.filter { + stream = stream.filter { StringUtils.equals(it.toId, query.toId) } } if (StringUtils.isNotEmpty(query.text)) { - stream.filter { + stream = stream.filter { StringUtils.equals(it.text, query.text) } } if (query.textReg != null) { - stream.filter { + stream = stream.filter { query.textReg!!.matches(it.text ?: "") } } if (query.type != null) { - stream.filter { + stream = stream.filter { query.type == it.type } } diff --git a/wechaty/pom.xml b/wechaty/pom.xml index 9184a3d..d0739db 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -110,9 +110,7 @@ org.reflections reflections - 0.9.12 - diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt index c60e152..1bb0ed9 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt @@ -6,6 +6,7 @@ import io.github.wechaty.schemas.PuppetOptions import io.github.wechaty.utils.JsonUtils import org.reflections.Reflections import org.reflections.util.ClasspathHelper +import org.reflections.util.ConfigurationBuilder import org.slf4j.LoggerFactory import java.util.concurrent.CompletableFuture import java.util.concurrent.Future @@ -21,8 +22,12 @@ class PuppetManager { fun resolveInstance(wechatyOptions: WechatyOptions): Future { log.info("PuppetManager resolveInstance(${JsonUtils.write(wechatyOptions)})") - val reflections = Reflections(ClasspathHelper.forPackage(REFLECTION_BASE_PACKAGE, Thread.currentThread().contextClassLoader)) + val reflections = Reflections(ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(REFLECTION_BASE_PACKAGE, Thread.currentThread().contextClassLoader))) + val subTypes: Set<*> = reflections.getSubTypesOf(Puppet::class.java) + if (subTypes.isEmpty()) { + throw java.lang.RuntimeException("expect one puppet,but can not found any one.") + } if (subTypes.size > 1) { throw RuntimeException("expect one puppet,but found ${subTypes.size}") From ba35f5f739ee9841a2ea74a290f33cd86101e1f7 Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Sat, 13 Jun 2020 10:45:25 +0800 Subject: [PATCH 08/41] upgrade version to 0.1.4-SNAPSHOT --- README.md | 6 ++++++ pom.xml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 28a7970..361f90c 100644 --- a/README.md +++ b/README.md @@ -278,6 +278,12 @@ mvn install wechaty ### master +### v0.1.4 (June 13 2020) +1. use `PuppetManager` to manage multi puppet implementations. +2. add mock puppet. +3. remove puppet implementations from wechaty pom. Which implementation to use depends on which implementation jar in your pom. +4. fix some bugs. + ### v0.1.3 (June 6 2020) 1. support plugins! diff --git a/pom.xml b/pom.xml index 8aeb858..1a4659d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.wechaty wechaty-parent pom - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT kotlin-wechaty From a4d92d4a3caa4e5ce6ab61cae1ec799c379f87ef Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Sat, 13 Jun 2020 11:07:55 +0800 Subject: [PATCH 09/41] back to 0.1.3-SNAPSHOT temperary --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1a4659d..8aeb858 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.wechaty wechaty-parent pom - 0.1.4-SNAPSHOT + 0.1.3-SNAPSHOT kotlin-wechaty From edf7f31c9561248bd81f73a391685ea830bf25af Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sat, 13 Jun 2020 13:29:23 +0800 Subject: [PATCH 10/41] update 0.1.4 --- examples/pom.xml | 2 +- pom.xml | 2 +- wechaty-puppet-hostie/pom.xml | 2 +- wechaty-puppet-mock/pom.xml | 2 +- wechaty-puppet/pom.xml | 2 +- wechaty/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index a15aef4..aa04158 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -17,7 +17,7 @@ UTF-8 true 0.10.1 - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT diff --git a/pom.xml b/pom.xml index 8aeb858..1a4659d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.wechaty wechaty-parent pom - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT kotlin-wechaty diff --git a/wechaty-puppet-hostie/pom.xml b/wechaty-puppet-hostie/pom.xml index c901eb3..c691c40 100644 --- a/wechaty-puppet-hostie/pom.xml +++ b/wechaty-puppet-hostie/pom.xml @@ -4,7 +4,7 @@ io.github.wechaty wechaty-parent - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT 4.0.0 wechaty-puppet-hostie diff --git a/wechaty-puppet-mock/pom.xml b/wechaty-puppet-mock/pom.xml index 815109c..5091b52 100644 --- a/wechaty-puppet-mock/pom.xml +++ b/wechaty-puppet-mock/pom.xml @@ -5,7 +5,7 @@ wechaty-parent io.github.wechaty - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT 4.0.0 diff --git a/wechaty-puppet/pom.xml b/wechaty-puppet/pom.xml index 1a4508f..c78acd0 100644 --- a/wechaty-puppet/pom.xml +++ b/wechaty-puppet/pom.xml @@ -4,7 +4,7 @@ io.github.wechaty wechaty-parent - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT 4.0.0 wechaty-puppet diff --git a/wechaty/pom.xml b/wechaty/pom.xml index d0739db..728e0d1 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -4,7 +4,7 @@ io.github.wechaty wechaty-parent - 0.1.3-SNAPSHOT + 0.1.4-SNAPSHOT 4.0.0 wechaty From d5f1b868d9779052842b7d8ec0ff70698ba815c5 Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sat, 13 Jun 2020 13:36:19 +0800 Subject: [PATCH 11/41] update 0.1.4 --- examples/pom.xml | 5 +++ .../java/io/github/wechaty/example/Main.java | 5 --- pom.xml | 40 +++++++++---------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index aa04158..933c802 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -66,6 +66,11 @@ java-wechaty-plugin-contrib 1.0.0-SNAPSHOT + + org.apache.commons + commons-lang3 + 3.10 + diff --git a/examples/src/main/java/io/github/wechaty/example/Main.java b/examples/src/main/java/io/github/wechaty/example/Main.java index 41975a8..4a0f34e 100644 --- a/examples/src/main/java/io/github/wechaty/example/Main.java +++ b/examples/src/main/java/io/github/wechaty/example/Main.java @@ -1,12 +1,7 @@ package io.github.wechaty.example; -import io.github.wechaty.LoginListener; -import io.github.wechaty.MessageListener; import io.github.wechaty.Wechaty; -import io.github.wechaty.filebox.FileBox; -import io.github.wechaty.io.github.wechaty.schemas.EventEnum; -import io.github.wechaty.user.Contact; import io.github.wechaty.user.Room; import io.github.wechaty.utils.QrcodeUtils; import okhttp3.OkHttpClient; diff --git a/pom.xml b/pom.xml index 1a4659d..2e72301 100644 --- a/pom.xml +++ b/pom.xml @@ -179,26 +179,26 @@ - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - --pinentry-mode - loopback - - - - - + + + + + + + + + + + + + + + + + + + + From 41353b036f462d56397296b35e4286dfb0a023cf Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 14 Jun 2020 16:26:45 +0800 Subject: [PATCH 12/41] support img --- .gitignore | 2 + examples/pom.xml | 22 ++- .../io/github/wechaty/filebox/FileBox.kt | 184 +++++++++--------- .../main/kotlin/io/github/wechaty/Wechaty.kt | 5 +- .../kotlin/io/github/wechaty/user/Image.kt | 18 +- .../kotlin/io/github/wechaty/user/Message.kt | 19 ++ .../wechaty/user/manager/ImageManager.kt | 18 ++ 7 files changed, 157 insertions(+), 111 deletions(-) create mode 100644 wechaty/src/main/kotlin/io/github/wechaty/user/manager/ImageManager.kt diff --git a/.gitignore b/.gitignore index c9c3308..498f526 100644 --- a/.gitignore +++ b/.gitignore @@ -164,3 +164,5 @@ target/ token.txt Main2.java +Main3.java +aliyun/* diff --git a/examples/pom.xml b/examples/pom.xml index 933c802..10f17c4 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -72,6 +72,26 @@ 3.10 + + com.aliyun + aliyun-java-sdk-core + 4.5.2 + + + + + com.aliyun + aliyun-java-sdk-imagerecog + 1.0.7 + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.4.2 + + @@ -135,7 +155,7 @@ - io.github.wechaty.example.Main + io.github.wechaty.example.Main2 diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt index 9c5482c..80dec61 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt @@ -19,84 +19,88 @@ import java.util.concurrent.Future class FileBox(options: FileBoxOptions) { @JsonProperty - private var mimeType: String? = null + var mimeType: String? = null + @JsonProperty - private var base64 : String? = null + var base64: String? = null + @JsonProperty - private var remoteUrl : String? = null + var remoteUrl: String? = null + @JsonProperty - private var qrCode : String? = null + var qrCode: String? = null + @JsonProperty - private var buffer : ByteArray?=null - private var localPath : String? = null + var buffer: ByteArray? = null + var localPath: String? = null + @JsonProperty - private var headers : OutgoingHttpHeaders? = null + var headers: OutgoingHttpHeaders? = null + @JsonProperty - private var name :String? = null + var name: String? = null + @JsonProperty - private var metadata: Metadata? = null + var metadata: Metadata? = null + @JsonProperty - private lateinit var boxType:FileBoxType + var boxType: FileBoxType - private val client:OkHttpClient = OkHttpClient() + private val client: OkHttpClient = OkHttpClient() init { - when(options){ - is FileBoxOptionsBuffer ->{ + when (options) { + is FileBoxOptionsBuffer -> { this.name = options.name this.boxType = options.type this.buffer = options.buffer } - is FileBoxOptionsFile ->{ + is FileBoxOptionsFile -> { this.name = options.name this.boxType = options.type this.localPath = options.path } - is FileBoxOptionsUrl ->{ + is FileBoxOptionsUrl -> { this.name = options.name this.boxType = options.type this.remoteUrl = options.url this.headers = options.headers } - is FileBoxOptionsStream ->{ + is FileBoxOptionsStream -> { this.name = options.name this.boxType = options.type } - is FileBoxOptionsQRCode ->{ + is FileBoxOptionsQRCode -> { this.name = options.name this.boxType = options.type this.qrCode = options.qrCode } - is FileBoxOptionsBase64 ->{ + is FileBoxOptionsBase64 -> { this.name = options.name this.boxType = options.type this.base64 = options.base64 } - - - } - } - fun type():FileBoxType{ + fun type(): FileBoxType { return this.boxType } - fun ready():Future{ - if(this.boxType == FileBoxType.Url){ + fun ready(): Future { + if (this.boxType == FileBoxType.Url) { } return CompletableFuture.completedFuture(null); } - fun syncRemoteName():Future{ + fun syncRemoteName(): Future { val httpHeadHeader = httpHeadHeader(this.remoteUrl!!) @@ -121,29 +125,28 @@ class FileBox(options: FileBoxOptions) { } - private fun httpHeadHeader(url:String):Map>{ + private fun httpHeadHeader(url: String): Map> { val request: Request = Request.Builder() - .url(url) - .build() + .url(url) + .build() - client.newCall(request).execute().use { - response -> + client.newCall(request).execute().use { response -> val headers = response.headers return headers.toMultimap() } } - fun toJsonString():String { + fun toJsonString(): String { buffer = toByte(this) return JsonUtils.write(this) } - fun toByte(fileBox: FileBox):ByteArray?{ - when(fileBox.type()){ - FileBoxType.File ->{ + fun toByte(fileBox: FileBox): ByteArray? { + when (fileBox.type()) { + FileBoxType.File -> { val file = File(ClassLoader.getSystemResource("dong.jpg").path) @@ -151,24 +154,24 @@ class FileBox(options: FileBoxOptions) { } - FileBoxType.Url ->{ + FileBoxType.Url -> { return null; } - else ->{ + else -> { TODO() } } } - companion object{ + companion object { @JvmStatic - fun fromFile(path:String,name:String):FileBox{ + fun fromFile(path: String, name: String): FileBox { var localname = name - if(StringUtils.isEmpty(name)){ + if (StringUtils.isEmpty(name)) { localname = FilenameUtils.getBaseName(path) } @@ -178,70 +181,70 @@ class FileBox(options: FileBoxOptions) { } @JvmStatic - fun fromJson(obj:String):FileBox{ - - return JsonUtils.readValue(obj) - -// val jsonObject = JsonObject(obj) -// -// var fileBox:FileBox -// -// val type = jsonObject.getInteger("boxType") -// -// when(type){ -// -// FileBoxType.Base64.code ->{ -// fileBox = fromBase64( -// jsonObject.getString("base64"), -// jsonObject.getString("name") -// ) -// } -// -// FileBoxType.Url.code ->{ -// fileBox = fromUrl( -// jsonObject.getString("name"), -// jsonObject.getString("remoteUrl") -// ) -// } -// -// FileBoxType.QRcode.code ->{ -// fileBox = fromQRCode( -// jsonObject.getString("qrCode") -// ) -// } -// else ->{ -// throw Exception("unknown filebox json object{type} $jsonObject") -// } -// } -// -// fileBox.metadata = jsonObject.get("metadata") -// return fileBox; + fun fromJson(obj: String): FileBox { + +// return JsonUtils.readValue(obj) + + val jsonNode = JsonUtils.mapper.readTree(obj) + + var fileBox: FileBox + + val type = jsonNode.findValue("boxType").asInt() + + when (type) { + + FileBoxType.Base64.code -> { + fileBox = fromBase64( + jsonNode.findValue("base64").asText(), + jsonNode.findValue("name").asText() + ) + } + + FileBoxType.Url.code -> { + fileBox = fromUrl( + jsonNode.findValue("name").asText(), + jsonNode.findValue("remoteUrl").asText() + ) + } + + FileBoxType.QRcode.code -> { + fileBox = fromQRCode( + jsonNode.findValue("qrCode").asText() + ) + } + else -> { + throw Exception("unknown filebox json object{type} $jsonNode") + } + } + +// fileBox.metadata = jsonNode.get("metadata") + return fileBox; } @JvmStatic - fun fromBase64(base64: String,name:String):FileBox{ + fun fromBase64(base64: String, name: String): FileBox { val options = FileBoxOptionsBase64(base64 = base64, name = name) return FileBox(options) } @JvmStatic - fun fromDataUrl(dataUrl: String,name:String):FileBox{ + fun fromDataUrl(dataUrl: String, name: String): FileBox { val base64 = dataUrlToBase64(dataUrl); - return fromBase64(base64,name) + return fromBase64(base64, name) } @JvmStatic - fun fromQRCode(qrCode:String):FileBox{ + fun fromQRCode(qrCode: String): FileBox { val optionsQRCode = FileBoxOptionsQRCode(name = "qrcode.png", qrCode = qrCode) return FileBox(optionsQRCode) } @JvmStatic - fun fromUrl(url:String,name: String?,headers: OutgoingHttpHeaders? = null):FileBox{ + fun fromUrl(url: String, name: String?, headers: OutgoingHttpHeaders? = null): FileBox { - var localName :String? = name + var localName: String? = name - if(StringUtils.isEmpty(url)){ + if (StringUtils.isEmpty(url)) { val parsedUrl = URL(url) localName = parsedUrl.path } @@ -253,22 +256,13 @@ class FileBox(options: FileBoxOptions) { } - /** * ????? */ - fun dataUrlToBase64(dataUrl :String):String{ + fun dataUrlToBase64(dataUrl: String): String { val split = StringUtils.split(dataUrl, ",") return split[split.size - 1] } } - - - - - - - - } diff --git a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt index 2dd9310..4f0d6a5 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt @@ -37,7 +37,8 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : val contactManager = ContactManager(this) val messageManager = MessageManager(this) val roomManager = RoomManager(this) - val roomInvitationMessage = RoomInvitationManager(this) + val roomInvitationMessager = RoomInvitationManager(this) + val imageMessager = ImageManager(this) init { // this.memory = wechatyOptions.memory @@ -277,7 +278,7 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : EventEnum.ROOM_INVITE -> { puppet.on(it, object : PuppetRoomInviteListener { override fun handler(payload: EventRoomInvitePayload) { - val roomInvitation = roomInvitationMessage.load(payload.roomInvitationId) + val roomInvitation = roomInvitationMessager.load(payload.roomInvitationId) emit(EventEnum.ROOM_INVITE, roomInvitation) } }) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Image.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Image.kt index 302546d..0e55327 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Image.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Image.kt @@ -5,26 +5,18 @@ import io.github.wechaty.Wechaty import io.github.wechaty.filebox.FileBox import io.github.wechaty.schemas.ImageType -class Image(wechaty: Wechaty):Accessory(wechaty){ - - private var id:String?=null - - fun create(id:String):Image{ - val image = Image(wechaty) - image.id = id - return image - } +class Image(wechaty: Wechaty,val id:String):Accessory(wechaty){ fun thumbnail(): FileBox { - return wechaty.getPuppet().messageImage(id!!, ImageType.Thumbnail).get() + return wechaty.getPuppet().messageImage(id, ImageType.Thumbnail).get() } fun hd():FileBox{ - return wechaty.getPuppet().messageImage(id!!, ImageType.HD).get() + return wechaty.getPuppet().messageImage(id, ImageType.HD).get() } fun artwork():FileBox{ - return wechaty.getPuppet().messageImage(id!!, ImageType.Artwork).get() + return wechaty.getPuppet().messageImage(id, ImageType.Artwork).get() } -} \ No newline at end of file +} diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt index a8739e8..6e93039 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt @@ -283,6 +283,25 @@ open class Message(wechaty: Wechaty,val id: String) : Sayable, Accessory(wechaty } } + fun file():FileBox{ + return this.toFileBox() + } + + fun toImage():Image{ + if(this.type() != MessageType.Image){ + throw Exception("not a image type, type is "+ this.type()) + } + return wechaty.imageMessager.create(this.id); + + } + + fun toFileBox():FileBox{ + if(this.type() == MessageType.Text){ + throw Exception("text message no file") + } + return wechaty.getPuppet().messageFile(this.id).get() + } + override fun toString():String{ return "Message(payload=$payload,id=$id)" diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/ImageManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/ImageManager.kt new file mode 100644 index 0000000..da93025 --- /dev/null +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/ImageManager.kt @@ -0,0 +1,18 @@ +package io.github.wechaty.user.manager + +import io.github.wechaty.Accessory +import io.github.wechaty.Wechaty +import io.github.wechaty.user.Image +import org.slf4j.LoggerFactory + +class ImageManager (wechaty: Wechaty): Accessory(wechaty){ + + fun create(id:String):Image{ + return Image(wechaty,id) + } + + companion object { + private val log = LoggerFactory.getLogger(ImageManager::class.java) + } + +} From 3e99e9662f375894bb0a81d11365cfca4cba1e89 Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 14 Jun 2020 16:31:08 +0800 Subject: [PATCH 13/41] support image --- examples/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pom.xml b/examples/pom.xml index 10f17c4..c80f478 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -155,7 +155,7 @@ - io.github.wechaty.example.Main2 + io.github.wechaty.example.Main From d4f834b7e047cac3e81b6edb4bdb60b9c23c8b5c Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 14 Jun 2020 17:49:55 +0800 Subject: [PATCH 14/41] message support to Url,miniProgram --- .../kotlin/io/github/wechaty/user/Message.kt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt index 6e93039..5cdaf27 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt @@ -292,9 +292,44 @@ open class Message(wechaty: Wechaty,val id: String) : Sayable, Accessory(wechaty throw Exception("not a image type, type is "+ this.type()) } return wechaty.imageMessager.create(this.id); + } + + fun toContact():Contact{ + + if(this.type() != MessageType.Contact){ + throw Exception("message not a ShareCard") + } + + val contactId = wechaty.getPuppet().messageContact(this.id).get() + if(StringUtils.isEmpty(contactId)){ + throw Exception("can not get contact id by message ${this.id}") + } + + val contact = wechaty.contactManager.load(contactId) + contact.ready() + return contact + } + fun toUrlLink():UrlLink{ + if(this.type() != MessageType.Url){ + throw Exception("message not a Url Link") + } + + val urlPayload = wechaty.getPuppet().messageUrl(this.id).get() + return UrlLink(urlPayload) + } + + fun toMiniProgram():MiniProgram{ + + if(this.type() != MessageType.MiniProgram){ + throw Exception("message not a MiniProgram") + } + + val miniProgramPayload = wechaty.getPuppet().messageMiniProgram(this.id).get() + return MiniProgram(miniProgramPayload) } + fun toFileBox():FileBox{ if(this.type() == MessageType.Text){ throw Exception("text message no file") From e3cfe3db381e0c7c7afd162b71393e312ecb528a Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 14 Jun 2020 18:33:18 +0800 Subject: [PATCH 15/41] fix typo --- wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt | 6 +++--- wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt index 4f0d6a5..442c037 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt @@ -37,8 +37,8 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : val contactManager = ContactManager(this) val messageManager = MessageManager(this) val roomManager = RoomManager(this) - val roomInvitationMessager = RoomInvitationManager(this) - val imageMessager = ImageManager(this) + val roomInvitationManager = RoomInvitationManager(this) + val imageManager = ImageManager(this) init { // this.memory = wechatyOptions.memory @@ -278,7 +278,7 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : EventEnum.ROOM_INVITE -> { puppet.on(it, object : PuppetRoomInviteListener { override fun handler(payload: EventRoomInvitePayload) { - val roomInvitation = roomInvitationMessager.load(payload.roomInvitationId) + val roomInvitation = roomInvitationManager.load(payload.roomInvitationId) emit(EventEnum.ROOM_INVITE, roomInvitation) } }) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt index 5cdaf27..7dd15c9 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Message.kt @@ -291,7 +291,7 @@ open class Message(wechaty: Wechaty,val id: String) : Sayable, Accessory(wechaty if(this.type() != MessageType.Image){ throw Exception("not a image type, type is "+ this.type()) } - return wechaty.imageMessager.create(this.id); + return wechaty.imageManager.create(this.id); } fun toContact():Contact{ From bac471946d9e5c1f4139197789433ad6edf37598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20LI=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Thu, 18 Jun 2020 16:28:01 +0800 Subject: [PATCH 16/41] add hall of flame --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 361f90c..ec814c0 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,6 @@ We decided to use Kotlin to develop the Java Wechaty! - [Java Wechaty](https://github.com/wechaty/java-wechaty) - Java WeChaty Conversational AI Chatbot SDK for Wechat Individual Accounts (Java) - [Scala Wechaty](https://github.com/wechaty/scala-wechaty) - Scala WeChaty Conversational AI Chatbot SDK for WechatyIndividual Accounts (Scala) - ## Badge [![Wechaty in Kotlin](https://img.shields.io/badge/Wechaty-Kotlin-orange)](https://github.com/wechaty/java-wechaty) @@ -330,6 +329,17 @@ We decided to use Kotlin to develop the Java Wechaty! [![Wechaty in Kotlin](https://img.shields.io/badge/Wechaty-Kotlin-orange)](https://github.com/wechaty/java-wechaty) ``` +## Contributors + +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/0)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/0) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/1)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/1) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/2)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/2) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/3)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/3) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/4)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/4) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/5)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/5) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/6)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/6) +[![contributors](https://sourcerer.io/fame/huan/wechaty/java-wechaty/images/7)](https://sourcerer.io/fame/huan/wechaty/java-wechaty/links/7) + ## Committers - [@redmaple1](https://github.com/redmaple1) Xiaoya Ren From ceec37ae231af88d9055d3af0b67bca93a8d815c Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 21 Jun 2020 00:28:47 +0800 Subject: [PATCH 17/41] full impl --- .../main/kotlin/io/github/wechaty/Wechaty.kt | 41 ++++++++++--- .../kotlin/io/github/wechaty/user/Contact.kt | 60 ++++++++++++++++++- .../io/github/wechaty/user/Friendship.kt | 51 ++++++---------- .../wechaty/user/manager/FriendshipManager.kt | 56 +++++++++++++++++ 4 files changed, 166 insertions(+), 42 deletions(-) create mode 100644 wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt diff --git a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt index 442c037..10c9997 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt @@ -39,13 +39,13 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : val roomManager = RoomManager(this) val roomInvitationManager = RoomInvitationManager(this) val imageManager = ImageManager(this) + val friendshipManager = FriendshipManager(this) init { // this.memory = wechatyOptions.memory installGlobalPlugin() } - fun start(await: Boolean = false):Wechaty { initPuppet() @@ -72,6 +72,25 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : puppet.stop() } + fun logout(){ + log.debug("Wechaty logout()") + try { + puppet.logout() + } catch (e: Exception) { + log.error("logout error",e) + throw e + } + } + + fun logonoff():Boolean{ + return try { + puppet.logonoff() + } catch (e: Exception) { + false + } + } + + fun name(): String { return wechatyOptions.name } @@ -172,16 +191,10 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : } private fun initPuppet() { -// this.puppet = GrpcPuppet(puppetOptions) this.puppet = PuppetManager.resolveInstance(wechatyOptions).get() initPuppetEventBridge(puppet) } - fun friendship(): Friendship { - return Friendship(this); - } - - fun getPuppet(): Puppet { return puppet } @@ -192,6 +205,13 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : return user } + fun say(any: Any):Message?{ + return userSelf().say(any) + } + + fun ding(data:String?){ + this.puppet.ding(data) + } private fun initPuppetEventBridge(puppet: Puppet) { @@ -227,7 +247,7 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : EventEnum.FRIENDSHIP -> { puppet.on(it, object : PuppetFriendshipListener { override fun handler(payload: EventFriendshipPayload) { - val friendship = friendship().load(payload.friendshipId) + val friendship = friendshipManager.load(payload.friendshipId) friendship.ready() emit(EventEnum.FRIENDSHIP, friendship) } @@ -356,6 +376,11 @@ class Wechaty private constructor(private var wechatyOptions: WechatyOptions) : } } + + override fun toString():String{ + return "wechaty" + } + companion object Factory { @JvmStatic fun instance(token: String): Wechaty { diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Contact.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Contact.kt index e49fe43..8edd437 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Contact.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Contact.kt @@ -4,14 +4,17 @@ import io.github.wechaty.Accessory import io.github.wechaty.Puppet import io.github.wechaty.Wechaty import io.github.wechaty.filebox.FileBox +import io.github.wechaty.schemas.ContactGender import io.github.wechaty.schemas.ContactPayload import io.github.wechaty.schemas.ContactQueryFilter +import io.github.wechaty.schemas.ContactType import io.github.wechaty.type.Sayable import io.github.wechaty.utils.FutureUtils import org.apache.commons.lang3.StringUtils import org.slf4j.LoggerFactory import java.util.concurrent.CompletableFuture import java.util.concurrent.Future +import kotlin.math.E open class Contact(wechaty: Wechaty,val id:String) : Sayable, Accessory(wechaty) { @@ -114,8 +117,61 @@ open class Contact(wechaty: Wechaty,val id:String) : Sayable, Accessory(wechaty) return payload?.alias ?:null } - open fun avatar(): Future { - TODO() + fun stranger():Boolean?{ + return if(friend() == null){ + null + }else{ + !friend()!! + } + } + + fun friend():Boolean?{ + return payload?.friend + } + + fun type():ContactType{ + return payload?.type ?: throw Exception("no payload") + } + + fun gender():ContactGender{ + return payload?.gender ?: ContactGender.Unknown + } + + fun province():String?{ + return payload?.province + } + + fun city():String?{ + return payload?.city + } + + open fun avatar(): FileBox { + try { + return wechaty.getPuppet().getContactAvatar(this.id).get() + } catch (e: Exception) { + log.error("error",e) + TODO() + } + } + + fun tags():List{ + val tagIdList = wechaty.getPuppet().tagContactList(this.id).get() + return try { + tagIdList.map { + wechaty.tagManager.load(it) + } + } catch (e: Exception) { + log.error("error",e) + listOf() + } + } + + fun self():Boolean{ + val userId = puppet.selfId() + if(StringUtils.isEmpty(userId)){ + return false + } + return StringUtils.equals(id,userId) } diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Friendship.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Friendship.kt index 104e5f5..8afcb75 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Friendship.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Friendship.kt @@ -5,40 +5,15 @@ import io.github.wechaty.Wechaty import io.github.wechaty.schemas.FriendshipPayload import io.github.wechaty.schemas.FriendshipSearchCondition import io.github.wechaty.schemas.FriendshipType +import io.github.wechaty.utils.JsonUtils import org.apache.commons.lang3.StringUtils import org.slf4j.LoggerFactory -class Friendship (wechaty: Wechaty):Accessory(wechaty){ +class Friendship (wechaty: Wechaty,val id:String):Accessory(wechaty){ - constructor(wechaty: Wechaty,id: String):this(wechaty){ - this.id = id - } - - private var id:String? = null private var payload:FriendshipPayload? = null - fun load(id:String):Friendship{ - this.id = id - return this - } - - fun search(queryFilter: FriendshipSearchCondition):Contact?{ - val contactId = wechaty.getPuppet().friendshipSearch(queryFilter).get(); - if(StringUtils.isEmpty(contactId)){ - return null - } - val contact = wechaty.contactManager.load(contactId!!) - contact.ready() - return contact - } - - - fun add(contact: Contact, hello:String){ - log.debug("add contact: {} hello: {}",contact,hello) - wechaty.getPuppet().friendshipAdd(contact.id!!,hello).get() - } - fun isReady():Boolean{ return payload != null } @@ -67,17 +42,29 @@ class Friendship (wechaty: Wechaty):Accessory(wechaty){ if(payload!!.type != FriendshipType.Receive){ throw Exception("accept() need type to be FriendshipType.Receive, but it got a ${payload!!.type}") } - - wechaty.getPuppet().friendshipAccept(this.id!!).get() - + wechaty.getPuppet().friendshipAccept(this.id).get() val contact = contact() - contact.ready() - contact.sync() + } + fun hello():String{ + if(payload==null){ + throw Exception("ne payload") + } + return this.payload?.hello ?: ""; + } + + fun type():FriendshipType{ + return this.payload?.type ?:FriendshipType.Unknown } + fun toJson():String{ + if(payload==null){ + throw Exception("ne payload") + } + return JsonUtils.write(payload!!); + } companion object{ private val log = LoggerFactory.getLogger(Friendship::class.java) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt new file mode 100644 index 0000000..cb0b6d0 --- /dev/null +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt @@ -0,0 +1,56 @@ +package io.github.wechaty.user.manager + +import com.sun.xml.internal.ws.message.PayloadElementSniffer +import io.github.wechaty.Accessory +import io.github.wechaty.Wechaty +import io.github.wechaty.schemas.FriendshipPayload +import io.github.wechaty.schemas.FriendshipSearchCondition +import io.github.wechaty.user.Contact +import io.github.wechaty.user.Friendship +import io.github.wechaty.utils.JsonUtils +import org.apache.commons.lang3.StringUtils +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +class FriendshipManager (wechaty: Wechaty): Accessory(wechaty){ + + fun load(id:String): Friendship { + return Friendship(wechaty,id) + } + + fun search(queryFilter: FriendshipSearchCondition): Contact?{ + log.debug("query filter {}",queryFilter) + val contactId = wechaty.getPuppet().friendshipSearch(queryFilter).get(); + if(StringUtils.isEmpty(contactId)){ + return null + } + val contact = wechaty.contactManager.load(contactId!!) + contact.ready() + return contact + } + + fun add(contact: Contact,hello:String){ + log.debug("add {},{}",contact,hello) + wechaty.getPuppet().friendshipAdd(contact.id,hello).get() + } + + fun del(contact: Contact){ + log.debug("del {}",contact) + throw Exception("to be implemented") + } + + fun fromJSON(payload:String):Friendship{ + val readValue = JsonUtils.readValue(payload) + return fromJSON(readValue) + } + + fun fromJSON(friendshipPayload: FriendshipPayload):Friendship{ + wechaty.getPuppet().friendshipPayload(friendshipPayload.id!!,friendshipPayload).get() + return load(friendshipPayload.id!!) + } + + companion object{ + private val log: Logger = LoggerFactory.getLogger(FriendshipManager::class.java) + } + +} From 7cab2119a59292202a7e2053e1bc3f480bf46c14 Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 21 Jun 2020 11:24:44 +0800 Subject: [PATCH 18/41] full impl --- .../io/github/wechaty/user/ContactSelf.kt | 25 +++++++++++++------ .../kotlin/io/github/wechaty/user/Room.kt | 16 ++++++++++++ 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/ContactSelf.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/ContactSelf.kt index 8183c77..bfb5d22 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/ContactSelf.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/ContactSelf.kt @@ -5,18 +5,27 @@ import io.github.wechaty.filebox.FileBox import java.util.concurrent.CompletableFuture import java.util.concurrent.Future -class ContactSelf(wechaty: Wechaty,id: String) : Contact(wechaty,id){ +class ContactSelf(wechaty: Wechaty, id: String) : Contact(wechaty, id) { - override fun avatar(): Future { - return super.avatar() + fun avatar(fileBox: FileBox) { + puppet.setContactAvatar(super.id, fileBox) } - fun avatar(fileBox:FileBox):Future{ - return CompletableFuture.supplyAsync { - puppet.setContactAvatar(super.id, fileBox) - null + fun setName(name:String){ + puppet.contactSelfName(name).get() + sync() + } + + fun signature(signature:String){ + + var puppetId:String? = puppet.selfId() + + let{ + puppetId != null + }.run { + puppet.contactSelfSignature(signature).get() + sync() } } - } diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index 2b5bd87..6b82011 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt @@ -356,9 +356,25 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return payload != null } + fun owner():Contact?{ + val ownerId = payload?.ownerId + + return if(ownerId.isNullOrBlank()){ + null + }else{ + return wechaty.contactManager.load(ownerId) + } + } + + fun avatar():FileBox{ + log.debug("avatar:{}",avatar()) + return puppet.roomAvatar(this.id).get() + } + companion object { private val log = LoggerFactory.getLogger(Room::class.java) } + } val ROOM_EVENT_DICT = mapOf( From 1daa1f3c72e41b77ff1e8149aac2ba31282d0ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Tue, 30 Jun 2020 18:31:53 +0800 Subject: [PATCH 19/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec814c0..48300f8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # java-wechaty ![Java CI with Maven](https://github.com/wechaty/java-wechaty/workflows/Java%20CI%20with%20Maven/badge.svg) -[![Java Version](https://img.shields.io/maven-central/v/io.github.wechaty/wechaty?label=Java)](https://mvnrepository.com/artifact/io.github.wechaty/wechaty) +[![Java Version](https://img.shields.io/maven-central/v/io.github.wechaty/wechaty?label=Maven)](https://mvnrepository.com/artifact/io.github.wechaty/wechaty) ![Java Wechaty](https://wechaty.github.io/java-wechaty/images/java-wechaty.png) From 65b8099ced0dd5358fff062fdcbe44bfae02a5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Wed, 1 Jul 2020 14:17:05 +0800 Subject: [PATCH 20/41] v0.4 Beta Release --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 17e51c3..1d0ba9e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.1 +0.4.0 From 35426fde10b6e585e8a93944f3e0749f7d4dc4b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Wed, 1 Jul 2020 14:17:55 +0800 Subject: [PATCH 21/41] v0.4 for BETA release --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 48300f8..e2007ea 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,6 @@ Wechaty is a RPA SDK for Wechat **Individual** Account that can help you create a chatbot in 6 lines of Java. -## WORK IN PROGRESS - -Work in progress... - -Please come back after 4 weeks... - ## Voice of the Developers > "Wechaty is a great solution, I believe there would be much more users recognize it." [link](https://github.com/Wechaty/wechaty/pull/310#issuecomment-285574472) @@ -278,6 +272,14 @@ mvn install wechaty ### master +### v0.4 (Jun 19, 2020) + +Java(Kotlin) Wechaty **BETA** Released! + +Read more from our Multi-language Wechaty Beta Release event from our blog: + +- [Multi Language Wechaty Beta Release Announcement!](https://wechaty.github.io/2020/06/19/multi-language-wechaty-beta-release/) + ### v0.1.4 (June 13 2020) 1. use `PuppetManager` to manage multi puppet implementations. 2. add mock puppet. From c54d3d865be76dd09ff67ad6bef44f75e6e1eb50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2020 19:42:34 +0000 Subject: [PATCH 22/41] Bump log4j-core from 2.13.1 to 2.13.2 Bumps log4j-core from 2.13.1 to 2.13.2. Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e72301..cce3dab 100644 --- a/pom.xml +++ b/pom.xml @@ -79,7 +79,7 @@ org.apache.logging.log4j log4j-core - 2.13.1 + 2.13.2 test From 4db2003d191423472b2f5de05a3329061e653dc7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2020 19:44:39 +0000 Subject: [PATCH 23/41] Bump log4j-core from 2.13.1 to 2.13.2 in /examples Bumps log4j-core from 2.13.1 to 2.13.2. Signed-off-by: dependabot[bot] --- examples/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/pom.xml b/examples/pom.xml index c80f478..b613faf 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -41,7 +41,7 @@ org.apache.logging.log4j log4j-core - 2.13.1 + 2.13.2 org.apache.logging.log4j From 9dbfdb232b62a7162626ea1652eb6eea81aab15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Fri, 3 Jul 2020 02:42:37 +0800 Subject: [PATCH 24/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e2007ea..e8050b6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![Java CI with Maven](https://github.com/wechaty/java-wechaty/workflows/Java%20CI%20with%20Maven/badge.svg) [![Java Version](https://img.shields.io/maven-central/v/io.github.wechaty/wechaty?label=Maven)](https://mvnrepository.com/artifact/io.github.wechaty/wechaty) -![Java Wechaty](https://wechaty.github.io/java-wechaty/images/java-wechaty.png) +![Java Wechaty](docs/images/java-wechaty.png) [![Java Wechaty Getting Started](https://img.shields.io/badge/Java%20Wechaty-Getting%20Started-orange)](https://github.com/wechaty/java-wechaty-getting-started) [![Wechaty in Kotlin](https://img.shields.io/badge/Wechaty-Kotlin-orange)](https://github.com/wechaty/java-wechaty) From facb2528e4844c05718f650813dc11c7a8b1606c Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Fri, 3 Jul 2020 13:28:35 +0800 Subject: [PATCH 25/41] fix room.say to mentionText appending something --- wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index 2b5bd87..8b5307e 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt @@ -93,7 +93,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return@map "@$concatText" } val mentionText = mentionAlias.joinToString(separator = FOUR_PER_EM_SPACE) - text = mentionText + text = "$mentionText $something" } else { text = something } From 1d69d91f6bd9831703e34051fb9ee9f1d25e9da0 Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 5 Jul 2020 14:56:02 +0800 Subject: [PATCH 26/41] fix typo --- pom.xml | 1 + .../src/main/kotlin/io/github/wechaty/user/RoomInvitation.kt | 2 +- .../kotlin/io/github/wechaty/user/manager/RoomManager.kt | 5 ++--- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 2e72301..b775870 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@ wechaty wechaty-puppet wechaty-puppet-hostie + examples wechaty-puppet-mock diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/RoomInvitation.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/RoomInvitation.kt index 9859504..779ecb7 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/RoomInvitation.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/RoomInvitation.kt @@ -64,7 +64,7 @@ class RoomInvitation(wechaty: Wechaty,val id:String) : Accessory(wechaty){ fun topic():String { val payload = wechaty.getPuppet().roomInvitationPayload(this.id).get() - return payload.topic ?:""; + return payload.topic ?:"" } companion object{ diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/RoomManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/RoomManager.kt index 5c27a81..a08af52 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/RoomManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/RoomManager.kt @@ -9,11 +9,10 @@ import io.github.wechaty.user.Contact import io.github.wechaty.user.Room import org.apache.commons.collections4.CollectionUtils import org.slf4j.LoggerFactory -import java.util.* class RoomManager(wechaty: Wechaty) : Accessory(wechaty) { - private val roomaCache: Cache = Caffeine.newBuilder().build() + private val roomCache: Cache = Caffeine.newBuilder().build() fun create(contactList: List, topic: String?): Room { if (contactList.size < 2) { @@ -83,7 +82,7 @@ class RoomManager(wechaty: Wechaty) : Accessory(wechaty) { } fun load(id: String): Room { - return roomaCache.get(id) { + return roomCache.get(id) { Room(wechaty, id) }!! } From e79ac6d8ebb53f15a70d3c59b3297e6b5b2a5bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Sun, 5 Jul 2020 17:20:43 +0800 Subject: [PATCH 27/41] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e8050b6..aa4490b 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,7 @@ We decided to use Kotlin to develop the Java Wechaty! ## Committers - [@redmaple1](https://github.com/redmaple1) Xiaoya Ren +- [@huan](https://github.com/huan) - Huan LI (李卓桓) ## Author From bd48ab00e0404b761aa1440d44dc502105433eac Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Tue, 7 Jul 2020 23:03:53 +0800 Subject: [PATCH 28/41] add get set topic --- .../kotlin/io/github/wechaty/user/Room.kt | 90 ++++++++++++++----- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index 6b82011..df0f298 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt @@ -159,27 +159,27 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { } } - fun onInvite(listener: InviteListener):Room{ - return on(EventEnum.INVITE,listener) + fun onInvite(listener: InviteListener): Room { + return on(EventEnum.INVITE, listener) } - fun onLeave(listener: LeaveListener):Room{ - return on(EventEnum.LEAVE,listener) + fun onLeave(listener: LeaveListener): Room { + return on(EventEnum.LEAVE, listener) } - fun onInnerMessage(listener: RoomInnerMessageListener):Room{ - return on(EventEnum.MESSAGE,listener) + fun onInnerMessage(listener: RoomInnerMessageListener): Room { + return on(EventEnum.MESSAGE, listener) } - fun onJoin(listener: JoinListener):Room{ - return on(EventEnum.JOIN,listener); + fun onJoin(listener: JoinListener): Room { + return on(EventEnum.JOIN, listener); } - fun onTopic(listener: TopicListener):Room{ - return on(EventEnum.TOPIC,listener) + fun onTopic(listener: TopicListener): Room { + return on(EventEnum.TOPIC, listener) } - private fun on(eventName: Event, listener: InviteListener):Room { + private fun on(eventName: Event, listener: InviteListener): Room { super.on(eventName, object : Listener { override fun handler(vararg any: Any) { listener.handler(any[0] as Contact, any[1] as RoomInvitation) @@ -188,7 +188,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return this } - private fun on(eventName: Event, listener: LeaveListener):Room { + private fun on(eventName: Event, listener: LeaveListener): Room { super.on(eventName, object : Listener { override fun handler(vararg any: Any) { listener.handler(any[0] as List, any[1] as Contact, any[2] as Date) @@ -197,7 +197,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return this } - private fun on(eventName: Event, listenerRoomInner: RoomInnerMessageListener):Room { + private fun on(eventName: Event, listenerRoomInner: RoomInnerMessageListener): Room { super.on(eventName, object : Listener { override fun handler(vararg any: Any) { listenerRoomInner.handler(any[0] as Message, any[1] as Date) @@ -206,7 +206,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return this } - private fun on(eventName: Event, listener: JoinListener):Room { + private fun on(eventName: Event, listener: JoinListener): Room { super.on(eventName, object : Listener { override fun handler(vararg any: Any) { listener.handler(any[0] as List, any[1] as Contact, any[2] as Date) @@ -215,7 +215,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return this } - private fun on(eventName: Event, listener: TopicListener):Room { + private fun on(eventName: Event, listener: TopicListener): Room { super.on(eventName, object : Listener { override fun handler(vararg any: Any) { listener.handler(any[0] as String, any[1] as String, any[2] as Contact, any[3] as Date) @@ -245,6 +245,56 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { } } + fun getTopic(): Future { + + if (!isReady()) { + log.warn("Room topic() room not ready") + throw Exception("not ready") + } + + if (payload != null && payload!!.topic != null) { + return CompletableFuture.supplyAsync { + return@supplyAsync payload!!.topic + } + } else { + val memberIdList = puppet.roomMemberList(id).get() + val memberList = memberIdList.filter { it != puppet.selfId() } + .map { wechaty.contactManager.load(it) } + + var defaultTopic = "" + if (memberList.isNotEmpty()) { + defaultTopic = memberList[0].name() + } + + if (memberList.size >= 2) { + for (index in 1..2) { + defaultTopic += ",${memberList[index].name()}" + } + } + return CompletableFuture.supplyAsync { + return@supplyAsync defaultTopic + } + } + } + + fun setTopic(newTopic: String): Future { + if (!isReady()) { + log.warn("Room topic() room not ready") + throw Exception("not ready") + } + + return CompletableFuture.supplyAsync { + try { + return@supplyAsync puppet.roomTopic(id, newTopic).get() + } catch (e: Exception) { + log.warn("Room topic(newTopic=$newTopic) exception:$e") + throw Exception(e) + } + } + + } + + @Deprecated("this function is deprecated! see getTopic,setTopic") fun topic(newTopic: String?): Future { if (!isReady()) { log.warn("Room topic() room not ready") @@ -356,18 +406,18 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return payload != null } - fun owner():Contact?{ + fun owner(): Contact? { val ownerId = payload?.ownerId - return if(ownerId.isNullOrBlank()){ + return if (ownerId.isNullOrBlank()) { null - }else{ + } else { return wechaty.contactManager.load(ownerId) } } - fun avatar():FileBox{ - log.debug("avatar:{}",avatar()) + fun avatar(): FileBox { + log.debug("avatar:{}", avatar()) return puppet.roomAvatar(this.id).get() } From 6d443ddc634719c6c772ec6d792cb22f8b61b42d Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 19 Jul 2020 16:07:42 +0800 Subject: [PATCH 29/41] fix bug --- examples/pom.xml | 8 +++----- pom.xml | 2 +- .../src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt | 2 +- .../src/main/kotlin/io/github/wechaty/schemas/Event.kt | 3 ++- wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt | 1 + .../io/github/wechaty/user/manager/PuppetManager.kt | 9 +++++++-- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index c80f478..4f33855 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,14 +1,12 @@ - - io.github.wechaty - wechaty-parent - 1.0.0-SNAPSHOT - + 4.0.0 + io.github.wechaty wechaty-example jar + 1.0.0-SNAPSHOT 1.3.72 diff --git a/pom.xml b/pom.xml index b775870..2872eae 100644 --- a/pom.xml +++ b/pom.xml @@ -30,8 +30,8 @@ wechaty wechaty-puppet wechaty-puppet-hostie - examples wechaty-puppet-mock + examples diff --git a/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt b/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt index f7202d4..7e61a7a 100644 --- a/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt +++ b/wechaty-puppet-hostie/src/main/kotlin/io/github/wechaty/grpc/GrpcPuppet.kt @@ -946,7 +946,7 @@ class GrpcPuppet(puppetOptions: PuppetOptions) : Puppet(puppetOptions) { log.debug("PuppetHostie $type payload $payload") if (type != Event.EventType.EVENT_TYPE_HEARTBEAT) { - emit(EventEnum.HEART_BEAT, EventHeartbeatPayload("heartbeat")) + emit(EventEnum.HEART_BEAT, EventHeartbeatPayload("heartbeat",6000)) } when (type) { diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Event.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Event.kt index ae8f72b..dbdf9dd 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Event.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/schemas/Event.kt @@ -135,7 +135,8 @@ data class EventResetPayload( } data class EventHeartbeatPayload( - var data:String + var data:String, + var timeout:Long ) { override fun toString(): String { return "EventHeartbeatPayload(data='$data')" diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index df0f298..14162df 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt @@ -285,6 +285,7 @@ class Room(wechaty: Wechaty, val id: String) : Accessory(wechaty), Sayable { return CompletableFuture.supplyAsync { try { + val newTop = puppet.roomTopic(id, newTopic).get() return@supplyAsync puppet.roomTopic(id, newTopic).get() } catch (e: Exception) { log.warn("Room topic(newTopic=$newTopic) exception:$e") diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt index 1bb0ed9..4920220 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/PuppetManager.kt @@ -29,10 +29,15 @@ class PuppetManager { throw java.lang.RuntimeException("expect one puppet,but can not found any one.") } - if (subTypes.size > 1) { + val filterPuppet = subTypes.filter { + val clazz = it as Class<*> + clazz.name == wechatyOptions.puppet + } + + if (filterPuppet.size > 1) { throw RuntimeException("expect one puppet,but found ${subTypes.size}") } - val clazz = subTypes.first() as Class<*> + val clazz = filterPuppet.first() as Class<*> val declaredConstructor = clazz.getDeclaredConstructor(PuppetOptions::class.java) return CompletableFuture.completedFuture(declaredConstructor.newInstance(wechatyOptions.puppetOptions!!) as Puppet) } From f4e2129fa9911b4496895d83b5e9140841bf71ca Mon Sep 17 00:00:00 2001 From: Zhengxin Date: Sun, 19 Jul 2020 20:45:51 +0800 Subject: [PATCH 30/41] up date to 0.15 --- examples/pom.xml | 13 ++++++++++--- pom.xml | 4 ++-- wechaty-puppet-hostie/pom.xml | 2 +- wechaty-puppet-mock/pom.xml | 2 +- wechaty-puppet/pom.xml | 2 +- wechaty/pom.xml | 2 +- 6 files changed, 16 insertions(+), 9 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 2c676a9..7edcb7a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -2,9 +2,17 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + io.github.wechaty + wechaty-parent + 0.1.5-SNAPSHOT + + 4.0.0 - io.github.wechaty wechaty-example + + wechaty/example + jar 1.0.0-SNAPSHOT @@ -15,7 +23,7 @@ UTF-8 true 0.10.1 - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT @@ -67,7 +75,6 @@ org.apache.commons commons-lang3 - 3.10 diff --git a/pom.xml b/pom.xml index 731f2b9..59edf86 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.wechaty wechaty-parent pom - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT kotlin-wechaty @@ -31,7 +31,7 @@ wechaty-puppet wechaty-puppet-hostie wechaty-puppet-mock - examples + diff --git a/wechaty-puppet-hostie/pom.xml b/wechaty-puppet-hostie/pom.xml index c691c40..9742318 100644 --- a/wechaty-puppet-hostie/pom.xml +++ b/wechaty-puppet-hostie/pom.xml @@ -4,7 +4,7 @@ io.github.wechaty wechaty-parent - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT 4.0.0 wechaty-puppet-hostie diff --git a/wechaty-puppet-mock/pom.xml b/wechaty-puppet-mock/pom.xml index 5091b52..6d7c58a 100644 --- a/wechaty-puppet-mock/pom.xml +++ b/wechaty-puppet-mock/pom.xml @@ -5,7 +5,7 @@ wechaty-parent io.github.wechaty - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT 4.0.0 diff --git a/wechaty-puppet/pom.xml b/wechaty-puppet/pom.xml index c78acd0..b68cd47 100644 --- a/wechaty-puppet/pom.xml +++ b/wechaty-puppet/pom.xml @@ -4,7 +4,7 @@ io.github.wechaty wechaty-parent - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT 4.0.0 wechaty-puppet diff --git a/wechaty/pom.xml b/wechaty/pom.xml index 728e0d1..eb0d468 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -4,7 +4,7 @@ io.github.wechaty wechaty-parent - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT 4.0.0 wechaty From 1d8ea6a94841bd69a8301d800b64e4702ecd05ba Mon Sep 17 00:00:00 2001 From: renxiaoya Date: Sun, 19 Jul 2020 21:17:04 +0800 Subject: [PATCH 31/41] add hostie as default puppet implementation --- examples/pom.xml | 5 ----- wechaty/pom.xml | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index b613faf..c51fbc5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -27,11 +27,6 @@ wechaty ${wechaty.version} - - io.github.wechaty - wechaty-puppet-hostie - ${wechaty.version} - org.apache.logging.log4j log4j-api diff --git a/wechaty/pom.xml b/wechaty/pom.xml index 728e0d1..16ab3ed 100644 --- a/wechaty/pom.xml +++ b/wechaty/pom.xml @@ -23,6 +23,12 @@ ${project.version} + + io.github.wechaty + wechaty-puppet-hostie + ${project.version} + + io.github.wechaty wechaty-puppet-mock From 99c82afb4e1276a9ade088af881092d79b892330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Tue, 28 Jul 2020 01:39:02 +0800 Subject: [PATCH 32/41] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa4490b..61c064a 100644 --- a/README.md +++ b/README.md @@ -347,7 +347,7 @@ We decided to use Kotlin to develop the Java Wechaty! - [@redmaple1](https://github.com/redmaple1) Xiaoya Ren - [@huan](https://github.com/huan) - Huan LI (李卓桓) -## Author +## Creator - [@diaozxin007](https://github.com/diaozxin007) diaozxin@gmail.com - Website: [犀利豆的博客](https://xilidou.com/) From 74dd31f8323066654f4291b183ad85616f9951d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Mon, 10 Aug 2020 13:40:44 +0800 Subject: [PATCH 33/41] update friday bot qrcode --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61c064a..a6bc96b 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ See more at [Wiki:Voice Of Developer](https://github.com/Wechaty/wechaty/wiki/Vo Wechaty is used in many ChatBot projects by thousands of developers. If you want to talk with other developers, just scan the following QR Code in WeChat with secret code _java wechaty_, join our **Wechaty Java Developers' Home**. -![Wechaty Java Developers' Home](https://wechaty.github.io/wechaty/images/bot-qr-code.png) +![Wechaty Friday.BOT QR Code](https://wechaty.js.org/img/friday-qrcode.svg) Scan now, because other Wechaty Java developers want to talk with you too! (secret code: _java wechaty_) From 49bb67207cbe9ddf23f6f7e91609ad342ee1f2c6 Mon Sep 17 00:00:00 2001 From: Charles Wu Date: Sat, 26 Sep 2020 18:26:43 +1000 Subject: [PATCH 34/41] fix filebox load fromJson bug and add test case for the change --- wechaty-puppet/pom.xml | 15 ++++++++++++- .../io/github/wechaty/filebox/FileBox.kt | 4 ++-- .../io/github/wechaty/filebox/FileBoxTest.kt | 21 +++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 wechaty-puppet/src/test/kotlin/io/github/wechaty/filebox/FileBoxTest.kt diff --git a/wechaty-puppet/pom.xml b/wechaty-puppet/pom.xml index b68cd47..4279c40 100644 --- a/wechaty-puppet/pom.xml +++ b/wechaty-puppet/pom.xml @@ -104,7 +104,20 @@ com.squareup.okhttp3 okhttp - + + org.hamcrest + hamcrest-core + + + org.mockito + mockito-core + test + + + junit + junit + test + diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt index 80dec61..31f9857 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt @@ -202,8 +202,8 @@ class FileBox(options: FileBoxOptions) { FileBoxType.Url.code -> { fileBox = fromUrl( - jsonNode.findValue("name").asText(), - jsonNode.findValue("remoteUrl").asText() + jsonNode.findValue("remoteUrl").asText(), + jsonNode.findValue("name").asText() ) } diff --git a/wechaty-puppet/src/test/kotlin/io/github/wechaty/filebox/FileBoxTest.kt b/wechaty-puppet/src/test/kotlin/io/github/wechaty/filebox/FileBoxTest.kt new file mode 100644 index 0000000..43935f3 --- /dev/null +++ b/wechaty-puppet/src/test/kotlin/io/github/wechaty/filebox/FileBoxTest.kt @@ -0,0 +1,21 @@ +package io.github.wechaty.filebox + +import junit.framework.Assert.assertEquals +import org.junit.Test + +const val EXPECTED_FILEBOX_URL = "http://testurl" +const val EXPECTED_FILEBOX_NAME = "fileboxname" + +class FileBoxTest { + + @Test + fun testFileBoxFromURLShallHaveCorrectNameAndURL() { + + var filebox : FileBox = FileBox.fromJson("{\"remoteUrl\":\"" + EXPECTED_FILEBOX_URL + "\"," + + "\"name\":\"" + EXPECTED_FILEBOX_NAME + "\"," + + "\"boxType\":2}") + + assertEquals(EXPECTED_FILEBOX_URL, filebox.remoteUrl) + assertEquals(EXPECTED_FILEBOX_NAME, filebox.name) + } +} From 0d580d21a9b3a861fe3f386a0037ce154a3026a0 Mon Sep 17 00:00:00 2001 From: Charles Wu Date: Sun, 27 Sep 2020 23:40:19 +1000 Subject: [PATCH 35/41] remove unsed import --- .../kotlin/io/github/wechaty/user/manager/FriendshipManager.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt index cb0b6d0..889fa73 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt @@ -1,6 +1,5 @@ package io.github.wechaty.user.manager -import com.sun.xml.internal.ws.message.PayloadElementSniffer import io.github.wechaty.Accessory import io.github.wechaty.Wechaty import io.github.wechaty.schemas.FriendshipPayload From 51c3df9bc59b5c91c6cc5a14178e84c7ab0c5a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Fri, 30 Oct 2020 22:12:18 +0800 Subject: [PATCH 36/41] fix 404 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6bc96b..4485c88 100644 --- a/README.md +++ b/README.md @@ -228,7 +228,7 @@ If you are interested in the translation and want to look at how it works, it wi - [ ] Unit Tests - [ ] Documentation 1. [ ] Class WechatyPuppetHostie - - TS SLOC(909): + - TS SLOC(909): - [x] Code - [ ] Unit Tests - [ ] Documentation From 0aea5284781334f388ca40a53e14f279a17943a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Fri, 30 Oct 2020 22:14:44 +0800 Subject: [PATCH 37/41] fix announcement 404 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4485c88..910bdf6 100644 --- a/README.md +++ b/README.md @@ -278,7 +278,7 @@ Java(Kotlin) Wechaty **BETA** Released! Read more from our Multi-language Wechaty Beta Release event from our blog: -- [Multi Language Wechaty Beta Release Announcement!](https://wechaty.github.io/2020/06/19/multi-language-wechaty-beta-release/) +- [Multi Language Wechaty Beta Release Announcement!](https://wechaty.js.org/2020/06/19/multi-language-wechaty-beta-release/) ### v0.1.4 (June 13 2020) 1. use `PuppetManager` to manage multi puppet implementations. From 0c9242d429639bcfe208e15b9816426f5c1bc8e7 Mon Sep 17 00:00:00 2001 From: Charles Wu Date: Sun, 13 Dec 2020 23:32:25 +1100 Subject: [PATCH 38/41] add support of base64 in bufferbyte --- .../src/main/kotlin/io/github/wechaty/filebox/FileBox.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt index 80dec61..98236a7 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt @@ -138,13 +138,13 @@ class FileBox(options: FileBoxOptions) { } fun toJsonString(): String { - buffer = toByte(this) + buffer = getBufferByte(this) return JsonUtils.write(this) } - fun toByte(fileBox: FileBox): ByteArray? { + fun getBufferByte(fileBox: FileBox): ByteArray? { when (fileBox.type()) { FileBoxType.File -> { @@ -153,11 +153,12 @@ class FileBox(options: FileBoxOptions) { return FileUtils.readFileToByteArray(file) } - FileBoxType.Url -> { return null; } - + FileBoxType.Base64 -> { + return null; + } else -> { TODO() } From 63f5d8d22d0f2d8348148e2a627c669b145e0665 Mon Sep 17 00:00:00 2001 From: Charles Wu Date: Mon, 14 Dec 2020 21:01:05 +1100 Subject: [PATCH 39/41] change method to private --- .../src/main/kotlin/io/github/wechaty/filebox/FileBox.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt index 98236a7..5e3b9f4 100644 --- a/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt +++ b/wechaty-puppet/src/main/kotlin/io/github/wechaty/filebox/FileBox.kt @@ -144,7 +144,7 @@ class FileBox(options: FileBoxOptions) { } - fun getBufferByte(fileBox: FileBox): ByteArray? { + private fun getBufferByte(fileBox: FileBox): ByteArray? { when (fileBox.type()) { FileBoxType.File -> { From a0a374b8db2575f39306cbb0aa84b5950ff35a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Wed, 23 Dec 2020 15:11:56 +0800 Subject: [PATCH 40/41] add stars history badge --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 910bdf6..d2bd3b9 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,10 @@ We decided to use Kotlin to develop the Java Wechaty! - [Java Wechaty](https://github.com/wechaty/java-wechaty) - Java WeChaty Conversational AI Chatbot SDK for Wechat Individual Accounts (Java) - [Scala Wechaty](https://github.com/wechaty/scala-wechaty) - Scala WeChaty Conversational AI Chatbot SDK for WechatyIndividual Accounts (Scala) +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/wechaty/java-wechaty.svg)](https://starchart.cc/wechaty/java-wechaty) + ## Badge [![Wechaty in Kotlin](https://img.shields.io/badge/Wechaty-Kotlin-orange)](https://github.com/wechaty/java-wechaty) From 79817a2bf32b529befc45ec4b6b170a2f4c59e14 Mon Sep 17 00:00:00 2001 From: HeBo Date: Tue, 26 Jan 2021 11:34:27 +0800 Subject: [PATCH 41/41] Adding kotlin sources to built *-sources.jar Does not containing kotlin sources in built *-sources.jar currently, it's make using wechaty more diffcult. --- pom.xml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/pom.xml b/pom.xml index 59edf86..05f8401 100644 --- a/pom.xml +++ b/pom.xml @@ -180,6 +180,25 @@ + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + + generate-sources + + add-source + + + + src/main/kotlin + + + + +