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/README.md b/README.md index 361f90c..d2bd3b9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # 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) +![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) @@ -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) @@ -44,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_) @@ -234,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 @@ -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.js.org/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. @@ -321,6 +323,9 @@ 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 @@ -330,11 +335,23 @@ 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 +- [@huan](https://github.com/huan) - Huan LI (李卓桓) -## Author +## Creator - [@diaozxin007](https://github.com/diaozxin007) diaozxin@gmail.com - Website: [犀利豆的博客](https://xilidou.com/) diff --git a/VERSION b/VERSION index 17e51c3..1d0ba9e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.1 +0.4.0 diff --git a/examples/pom.xml b/examples/pom.xml index 933c802..f550c80 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -1,14 +1,20 @@ + io.github.wechaty wechaty-parent - 1.0.0-SNAPSHOT + 0.1.5-SNAPSHOT + 4.0.0 wechaty-example + + wechaty/example + jar + 1.0.0-SNAPSHOT 1.3.72 @@ -17,7 +23,7 @@ UTF-8 true 0.10.1 - 0.1.4-SNAPSHOT + 0.1.5-SNAPSHOT @@ -27,11 +33,6 @@ wechaty ${wechaty.version} - - io.github.wechaty - wechaty-puppet-hostie - ${wechaty.version} - org.apache.logging.log4j log4j-api @@ -41,7 +42,7 @@ org.apache.logging.log4j log4j-core - 2.13.1 + 2.13.2 org.apache.logging.log4j @@ -69,7 +70,26 @@ org.apache.commons commons-lang3 - 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 diff --git a/pom.xml b/pom.xml index 2e72301..05f8401 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,6 +31,7 @@ wechaty-puppet wechaty-puppet-hostie wechaty-puppet-mock + @@ -79,7 +80,7 @@ org.apache.logging.log4j log4j-core - 2.13.1 + 2.13.2 test @@ -179,6 +180,25 @@ + + org.codehaus.mojo + build-helper-maven-plugin + 3.0.0 + + + + generate-sources + + add-source + + + + src/main/kotlin + + + + + 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-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-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..4279c40 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 @@ -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 9c5482c..904e8ef 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,54 +125,54 @@ 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 { - buffer = toByte(this) + fun toJsonString(): String { + buffer = getBufferByte(this) return JsonUtils.write(this) } - fun toByte(fileBox: FileBox):ByteArray?{ - when(fileBox.type()){ - FileBoxType.File ->{ + private fun getBufferByte(fileBox: FileBox): ByteArray? { + when (fileBox.type()) { + FileBoxType.File -> { val file = File(ClassLoader.getSystemResource("dong.jpg").path) return FileUtils.readFileToByteArray(file) } - - FileBoxType.Url ->{ + FileBoxType.Url -> { return null; } - - else ->{ + FileBoxType.Base64 -> { + return null; + } + 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 +182,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("remoteUrl").asText(), + jsonNode.findValue("name").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 +257,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-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-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) + } +} diff --git a/wechaty/pom.xml b/wechaty/pom.xml index 728e0d1..10aa138 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 @@ -23,6 +23,12 @@ ${project.version} + + io.github.wechaty + wechaty-puppet-hostie + ${project.version} + + io.github.wechaty wechaty-puppet-mock diff --git a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt index 2dd9310..10c9997 100644 --- a/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt +++ b/wechaty/src/main/kotlin/io/github/wechaty/Wechaty.kt @@ -37,14 +37,15 @@ 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 roomInvitationManager = RoomInvitationManager(this) + val imageManager = ImageManager(this) + val friendshipManager = FriendshipManager(this) init { // this.memory = wechatyOptions.memory installGlobalPlugin() } - fun start(await: Boolean = false):Wechaty { initPuppet() @@ -71,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 } @@ -171,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 } @@ -191,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) { @@ -226,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) } @@ -277,7 +298,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 = roomInvitationManager.load(payload.roomInvitationId) emit(EventEnum.ROOM_INVITE, roomInvitation) } }) @@ -355,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/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/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/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..7dd15c9 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,60 @@ 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.imageManager.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") + } + 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/Room.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/Room.kt index 2b5bd87..9ed5058 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 } @@ -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,57 @@ 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 { + 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") + 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,9 +407,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( 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/FriendshipManager.kt b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt new file mode 100644 index 0000000..889fa73 --- /dev/null +++ b/wechaty/src/main/kotlin/io/github/wechaty/user/manager/FriendshipManager.kt @@ -0,0 +1,55 @@ +package io.github.wechaty.user.manager + +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) + } + +} 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) + } + +} 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) } 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) }!! }