diff --git a/mirai-core/pom.xml b/mirai-core/pom.xml index 7f61f476c..fac520c0f 100644 --- a/mirai-core/pom.xml +++ b/mirai-core/pom.xml @@ -9,10 +9,6 @@ jar - - 1.3.41 - - net.mamoe mirai @@ -21,7 +17,6 @@ - org.jetbrains.kotlinx kotlinx-coroutines-core @@ -31,42 +26,36 @@ io.netty netty-all + net.java.dev.jna jna + org.jetbrains.kotlin kotlin-stdlib - ${kotlin.version} - + org.apache.logging.log4j log4j-core - 2.12.1 + org.yaml snakeyaml - 1.18 - - - org.yaml - snakeyaml - 1.18 + org.jetbrains.kotlin kotlin-reflect - 1.3.41 compile - /src/main/resources @@ -94,63 +83,16 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.3 - - - package - - shade - - - - - true - shaded - + + + org.projectlombok + lombok-maven-plugin + + org.jetbrains.kotlin kotlin-maven-plugin - ${kotlin.version} - - - compile - process-sources - - compile - - - - test-compile - test-compile - - test-compile - - - - - 1.8 - - - - org.apache.maven.plugins - maven-compiler-plugin - - - compile - compile - - compile - - - - testCompile - test-compile - - testCompile - - - diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt index ab33c4d10..251786779 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt @@ -2,6 +2,7 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Robot import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.message.defaults.PlainText /** @@ -15,7 +16,14 @@ abstract class Contact(val robot: Robot, val number: Long) { /** * Async */ - abstract fun sendMessage(message: Message) + abstract fun sendMessage(message: MessageChain) + + fun sendMessage(message: Message) { + if (message is MessageChain) { + return sendMessage(message) + } + return sendMessage(message.toChain()) + } fun sendMessage(message: String) { this.sendMessage(PlainText(message)) diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt index 1f2e82040..8573e6cd1 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt @@ -1,15 +1,26 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Robot -import net.mamoe.mirai.message.Message +import net.mamoe.mirai.contact.Group.Companion.groupNumberToId +import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.utils.ContactList import java.io.Closeable +/** + * 群 + * + * Java 获取 groupNumber: `group.getNumber()` + * Java 获取所属 robot: `group.getRobot()` + * Java 获取群成员列表: `group.getMembers()` + * Java 获取 groupId: `group.getGroupId()` + * + * Java 调用 [groupNumberToId] : `Group.groupNumberToId(number)` + */ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable { val groupId = groupNumberToId(number) val members = ContactList() - override fun sendMessage(message: Message) { + override fun sendMessage(message: MessageChain) { robot.network.messageHandler.sendGroupMessage(this, message) } @@ -23,7 +34,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable { companion object { @JvmStatic - fun groupNumberToId(number: Long): Long { + fun groupNumberToId(number: Long): Long {//求你别出错 val left: Long = number.toString().let { if (it.length < 6) { return@groupNumberToId number @@ -61,7 +72,7 @@ class Group(robot: Robot, number: Long) : Contact(robot, number), Closeable { } @JvmStatic - fun groupIdToNumber(id: Long): Long { + fun groupIdToNumber(id: Long): Long {//求你别出错 var left: Long = id.toString().let { if (it.length < 6) { return@groupIdToNumber id diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt index af009045e..eebcd728f 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt @@ -3,18 +3,22 @@ package net.mamoe.mirai.contact import net.mamoe.mirai.Robot import net.mamoe.mirai.message.Message import net.mamoe.mirai.message.defaults.At +import net.mamoe.mirai.message.defaults.MessageChain /** * QQ 账号. * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Robot]. * + * Java 获取 qq 号: `qq.getNumber()` + * Java 获取所属 robot: `qq.getRobot()` + * * A QQ instance helps you to receive message from or send message to. * Notice that, one QQ instance belong to one [Robot], that is, QQ instances from different [Robot] are NOT the same. * * @author Him188moe */ class QQ(robot: Robot, number: Long) : Contact(robot, number) { - override fun sendMessage(message: Message) { + override fun sendMessage(message: MessageChain) { robot.network.messageHandler.sendFriendMessage(this, message) } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java b/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java index 38d18b5a4..400f0c0ac 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java +++ b/mirai-core/src/main/java/net/mamoe/mirai/event/events/qq/FriendMessageEvent.java @@ -12,19 +12,14 @@ import java.util.Objects; */ public final class FriendMessageEvent extends FriendEvent { private final MessageChain messageChain; - private final String messageString; public FriendMessageEvent(@NotNull Robot robot, @NotNull QQ sender, @NotNull MessageChain messageChain) { super(robot, sender); this.messageChain = Objects.requireNonNull(messageChain); - this.messageString = messageChain.toString(); } - public String getMessageString() { - return messageString; - } - - public MessageChain getMessageChain() { + @NotNull + public MessageChain message() { return messageChain; } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java deleted file mode 100644 index 81c41ce2a..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.mamoe.mirai.message; - -import net.mamoe.mirai.contact.Contact; -import net.mamoe.mirai.contact.QQ; -import net.mamoe.mirai.message.defaults.At; -import net.mamoe.mirai.message.defaults.Image; -import net.mamoe.mirai.message.defaults.MessageChain; -import net.mamoe.mirai.message.defaults.PlainText; -import org.jetbrains.annotations.NotNull; - -import java.awt.image.BufferedImage; -import java.io.File; -import java.util.Objects; - -/** - * 可发送的或从服务器接收的消息. - * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 {@linkplain PlainText 纯文本}, {@linkplain Image 图片} 等. - * - * @author Him188moe - * @see Contact#sendMessage(Message) 发送这个消息 - * @see MessageKt 若你使用 kotlin, 请查看针对 kotlin 的优化实现 - */ -public abstract class Message { - @Override - public abstract String toString(); - - public String toDebugString() { - return this.getClass().getSimpleName() + String.format("(%s)", this.toString()); - } - - /** - * 把这个消息连接到另一个消息的头部. 相当于字符串相加 - *

- * Connects this Message to the head of another Message. - * That is, another message becomes the tail of this message. - * This method does similar to {@link String#concat(String)} - *

- * E.g.: - * PlainText a = new PlainText("Hello "); - * PlainText b = new PlainText("world"); - * PlainText c = a.concat(b); - *

- * the text of c is "Hello world" - * - * @param tail tail - * @return message connected - */ - public Message concat(@NotNull Message tail) { - return new MessageChain(this, Objects.requireNonNull(tail)); - } - - public final Message concat(String tail) { - return concat(new PlainText(tail)); - } - - - public Message withImage(String imageId) { - - // TODO: 2019/9/1 - return this; - } - - public Message withImage(BufferedImage image) { - // TODO: 2019/9/1 - return this; - - } - - public Message withImage(File image) { - // TODO: 2019/9/1 - return this; - } - - public Message withAt(@NotNull QQ target) { - this.concat(target.at()); - return this; - } - - public Message withAt(int target) { - this.concat(new At(target)); - return this; - } - -} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt new file mode 100644 index 000000000..15cfc30a9 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt @@ -0,0 +1,174 @@ +package net.mamoe.mirai.message + +import net.mamoe.mirai.contact.Contact +import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.message.defaults.At +import net.mamoe.mirai.message.defaults.Image +import net.mamoe.mirai.message.defaults.MessageChain +import net.mamoe.mirai.message.defaults.PlainText +import java.awt.image.BufferedImage +import java.io.File +import java.util.* + + +/** + * 可发送的或从服务器接收的消息. + * 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等. + * + * 在 Kotlin, 使用 [Message] 与使用 [String] 几乎没有什么用法上的区别. + * + * @author Him188moe + * @see Contact.sendMessage + */ +abstract class Message { + internal abstract val type: Int + + private var toStringCache: String? = null + private val cacheLock = object : Any() {} + + internal abstract fun toStringImpl(): String + + /** + * 得到用户层的文本消息. 如: + * - [PlainText] 得到 消息内容 + * - [Image] 得到 "{ID}.png" + * - [At] 得到 "[@qq]" + */ + final override fun toString(): String { + synchronized(cacheLock) { + if (toStringCache != null) { + return toStringCache!! + } + + this.toStringCache = toStringImpl() + return toStringCache!! + } + } + + internal fun clearToStringCache() { + synchronized(cacheLock) { + toStringCache = null + } + } + + /** + * 得到类似 "PlainText(内容)", "Image(ID)" + */ + open fun toObjectString(): String { + return this.javaClass.simpleName + String.format("(%s)", this.toString()) + } + + /** + * 转换为数据包使用的 byte array + */ + abstract fun toByteArray(): ByteArray + + + /** + * 比较两个 Message 的内容是否相等. 如: + * - [PlainText] 比较 [PlainText.text] + * - [Image] 比较 [Image.imageID] + */ + abstract infix fun valueEquals(another: Message): Boolean + + /** + * 将这个消息的 [toString] 与 [another] 比较 + */ + infix fun valueEquals(another: String): Boolean = this.toString() == another + + /** + * 把这个消息连接到另一个消息的头部. 相当于字符串相加 + * + * + * Connects this Message to the head of another Message. + * That is, another message becomes the tail of this message. + * This method does similar to [String.concat] + * + * + * E.g.: + * PlainText a = new PlainText("Hello "); + * PlainText b = new PlainText("world"); + * PlainText c = a.concat(b); + * + * + * the text of c is "Hello world" + * + * @param tail tail + * @return message connected + */ + open fun concat(tail: Message): Message { + return MessageChain(this, Objects.requireNonNull(tail)) + } + + fun concat(tail: String): Message { + return concat(PlainText(tail)) + } + + + fun withImage(imageId: String): Message { + + // TODO: 2019/9/1 + return this + } + + fun withImage(image: BufferedImage): Message { + // TODO: 2019/9/1 + return this + + } + + fun withImage(image: File): Message { + // TODO: 2019/9/1 + return this + } + + fun withAt(target: QQ): Message { + this.concat(target.at()) + return this + } + + fun withAt(target: Int): Message { + this.concat(At(target.toLong())) + return this + } + + open fun toChain(): MessageChain { + return MessageChain(this) + } + + + /* For Kotlin */ + + /** + * 实现使用 '+' 操作符连接 [Message] 与 [Message] + */ + infix operator fun plus(another: Message): Message = this.concat(another) + + /** + * 实现使用 '+' 操作符连接 [Message] 与 [String] + */ + infix operator fun plus(another: String): Message = this.concat(another) + + /** + * 实现使用 '+' 操作符连接 [Message] 与 [Number] + */ + infix operator fun plus(another: Number): Message = this.concat(another.toString()) + + /** + * 连接 [String] 与 [Message] + */ + fun String.concat(another: Message): Message = PlainText(this).concat(another) + + override fun hashCode(): Int { + return javaClass.hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Message) return false + + if (type != other.type) return false + + return this.toString() == other.toString() + } +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageId.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageId.kt new file mode 100644 index 000000000..4e4f3dcad --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageId.kt @@ -0,0 +1,22 @@ +package net.mamoe.mirai.message + +/** + * [Message] 在数据包中的 id([UByte]) + * + * Java 调用方式: + * MessageId.at + * + * @author Him188moe + */ +object MessageId { + + const val AT: Int = 0x00//todo 不知道是多少 + + const val FACE: Int = 0x00//todo 不知道是多少 + + const val TEXT: Int = 0x01 + + const val IMAGE: Int = 0x06 + + const val CHAIN: Int = 0xff//仅用于 equals. Packet 中不存在 Chain 概念 +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt deleted file mode 100644 index 0257cbf57..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKt.kt +++ /dev/null @@ -1,20 +0,0 @@ -@file:JvmName("MessageKt") - -package net.mamoe.mirai.message - -import net.mamoe.mirai.message.defaults.PlainText - -/** - * 实现使用 '+' 操作符连接 [Message] 与 [Message] - */ -infix operator fun Message.plus(another: Message): Message = this.concat(another) - -/** - * 实现使用 '+' 操作符连接 [Message] 与 [String] - */ -infix operator fun Message.plus(another: String): Message = this.concat(another) - -/** - * 连接 [String] 与 [Message] - */ -infix fun String.concat(another: Message): Message = PlainText(this).concat(another) \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java deleted file mode 100644 index dbae4f45a..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.mamoe.mirai.message.defaults; - -import net.mamoe.mirai.contact.QQ; -import net.mamoe.mirai.message.Message; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; - -/** - * At 一个人的消息. - * - * @author Him188moe - */ -public final class At extends Message { - private final long target; - - public At(@NotNull QQ target) { - this(Objects.requireNonNull(target).getNumber()); - } - - public At(long target) { - this.target = target; - } - - public long getTarget() { - return target; - } - - @Override - public String toString() { - // TODO: 2019/9/4 At.toString - throw new UnsupportedOperationException(); - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt new file mode 100644 index 000000000..904e474cf --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt @@ -0,0 +1,30 @@ +package net.mamoe.mirai.message.defaults + +import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.MessageId + +/** + * At 一个人 + * + * @author Him188moe + */ +class At(val target: Long) : Message() { + override val type: Int = MessageId.AT + + constructor(target: QQ) : this(target.number) + + override fun toStringImpl(): String = "[@$target]" + + override fun toByteArray(): ByteArray { + TODO() + } + + override fun valueEquals(another: Message): Boolean { + if (another !is At) { + return false + } + + return another.target == this.target + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java deleted file mode 100644 index 0f5f2cd6b..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.mamoe.mirai.message.defaults; - -import net.mamoe.mirai.message.FaceID; -import net.mamoe.mirai.message.Message; - -/** - * QQ 自带表情 - * - * @author Him188moe - */ -public final class Face extends Message { - private final FaceID id; - - public Face(FaceID id) { - this.id = id; - } - - public FaceID getId() { - return id; - } - - @Override - public String toString() { - if (id == null) { - return "[face?]"; - - } - return String.format("[face%d]", id.getId()); - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt new file mode 100644 index 000000000..56a5fba4d --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt @@ -0,0 +1,33 @@ +package net.mamoe.mirai.message.defaults + +import net.mamoe.mirai.message.FaceID +import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.MessageId + +/** + * QQ 自带表情 + * + * @author Him188moe + */ +class Face(val id: FaceID?) : Message() { + override val type: Int = MessageId.FACE + + override fun toStringImpl(): String { + return if (id == null) { + "[face?]" + + } else String.format("[face%d]", id.id) + } + + override fun toByteArray(): ByteArray { + TODO() + } + + override fun valueEquals(another: Message): Boolean { + if (another !is Face) { + return false + } + return this.id == another.id + } +} + diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.java deleted file mode 100644 index 565be2fe3..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.java +++ /dev/null @@ -1,45 +0,0 @@ -package net.mamoe.mirai.message.defaults; - -import net.mamoe.mirai.message.Message; - -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.*; -import java.net.URL; - -/** - * @author Him188moe - */ -public final class Image extends Message { - private String imageID; - - public Image(InputStream inputStream) { - - } - - public Image(BufferedImage image) { - - } - - public Image(File imageFile) throws FileNotFoundException { - this(new FileInputStream(imageFile)); - } - - public Image(URL url) throws IOException { - this(ImageIO.read(url)); - } - - /** - * {xxxxx}.jpg - * - * @param imageID - */ - public Image(String imageID) { - this.imageID = imageID; - } - - @Override - public String toString() { - return imageID; - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt new file mode 100644 index 000000000..b168c250c --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt @@ -0,0 +1,57 @@ +package net.mamoe.mirai.message.defaults + +import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.MessageId +import java.awt.image.BufferedImage +import java.io.* +import java.net.URL +import javax.imageio.ImageIO + +/** + * @author Him188moe + */ +class Image : Message { + override val type: Int = MessageId.IMAGE + + private var imageID: String? = null + + constructor(inputStream: InputStream) { + + } + + constructor(image: BufferedImage) { + + } + + @Throws(FileNotFoundException::class) + constructor(imageFile: File) : this(FileInputStream(imageFile)) { + } + + @Throws(IOException::class) + constructor(url: URL) : this(ImageIO.read(url)) { + } + + /** + * {xxxxx}.jpg + * + * @param imageID + */ + constructor(imageID: String) { + this.imageID = imageID + } + + override fun toStringImpl(): String { + return imageID!! + } + + override fun toByteArray(): ByteArray { + TODO() + } + + override fun valueEquals(another: Message): Boolean { + if (another !is Image) { + return false + } + return this.imageID == another.imageID + } +} \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java deleted file mode 100644 index 00fb54944..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.mamoe.mirai.message.defaults; - -import net.mamoe.mirai.message.Message; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - * @author Him188moe - */ -public final class MessageChain extends Message { - private LinkedList list = new LinkedList<>(); - - public MessageChain(@NotNull Message head, @NotNull Message tail) { - Objects.requireNonNull(head); - Objects.requireNonNull(tail); - - list.add(head); - list.add(tail); - } - - public MessageChain(@NotNull Message message) { - Objects.requireNonNull(message); - list.add(message); - } - - public MessageChain() { - } - - - /** - * @return An unmodifiable list - */ - public List toList() { - return List.copyOf(list); - } - - public Stream stream() { - return new ArrayList<>(list).stream(); - } - - @Override - public synchronized String toString() { - return this.list.stream().map(Message::toString).collect(Collectors.joining("")); - } - - public synchronized String toDebugString() { - return String.format("MessageChain(%s)", this.list.stream().map(Message::toDebugString).collect(Collectors.joining(", "))); - } - - @Override - public synchronized Message concat(@NotNull Message tail) { - this.list.add(tail); - return this; - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt new file mode 100644 index 000000000..18dd74ad4 --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt @@ -0,0 +1,71 @@ +package net.mamoe.mirai.message.defaults + +import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.MessageId +import net.mamoe.mirai.utils.lazyEncode +import java.util.* +import java.util.stream.Collectors +import java.util.stream.Stream + +class MessageChain : Message { + override val type: Int = MessageId.CHAIN + + internal val list = LinkedList() + + constructor(head: Message, tail: Message) { + Objects.requireNonNull(head) + Objects.requireNonNull(tail) + + list.add(head) + list.add(tail) + } + + constructor(message: Message) { + Objects.requireNonNull(message) + list.add(message) + } + + constructor() + + fun toList(): List { + return list.toList() + } + + fun stream(): Stream { + return ArrayList(list).stream() + } + + @Synchronized + override fun toStringImpl(): String { + return this.list.stream().map { it.toString() }.collect(Collectors.joining("")) + } + + @Synchronized + override fun toObjectString(): String { + return String.format("MessageChain(%s)", this.list.stream().map { it.toObjectString() }.collect(Collectors.joining(", "))) + } + + @Synchronized + override fun concat(tail: Message): Message { + this.list.add(tail) + clearToStringCache() + return this + } + + override fun toChain(): MessageChain { + return this + } + + override fun toByteArray(): ByteArray = lazyEncode { + stream().forEach { message -> + it.write(message.toByteArray()) + } + } + + override fun valueEquals(another: Message): Boolean { + if (another !is MessageChain) { + return false + } + return this.list == another.list + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.java deleted file mode 100644 index c60e0bd83..000000000 --- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.mamoe.mirai.message.defaults; - -import net.mamoe.mirai.message.Message; - -/** - * @author Him188moe - */ -public final class PlainText extends Message { - private final String text; - - public PlainText(String text) { - this.text = text; - } - - @Override - public String toString() { - return text; - } -} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt new file mode 100644 index 000000000..56506f6fc --- /dev/null +++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt @@ -0,0 +1,34 @@ +package net.mamoe.mirai.message.defaults + +import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.MessageId +import net.mamoe.mirai.network.packet.writeVarByteArray +import net.mamoe.mirai.network.packet.writeVarString +import net.mamoe.mirai.utils.lazyEncode + +/** + * @author Him188moe + */ +class PlainText(private val text: String) : Message() { + override val type: Int = MessageId.TEXT + + override fun toStringImpl(): String { + return text + } + + override fun toByteArray(): ByteArray = lazyEncode { section -> + section.writeByte(this.type) + + section.writeVarByteArray(lazyEncode { child -> + child.writeByte(0x01) + child.writeVarString(this.text) + }) + } + + override fun valueEquals(another: Message): Boolean { + if (another !is PlainText) { + return false + } + return this.text == another.text + } +} diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt index c1811de31..4a47a5e7e 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt @@ -14,8 +14,10 @@ import net.mamoe.mirai.event.events.qq.FriendMessageEvent import net.mamoe.mirai.event.events.robot.RobotLoginSucceedEvent import net.mamoe.mirai.event.hookWhile import net.mamoe.mirai.message.Message +import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.network.RobotNetworkHandler.* import net.mamoe.mirai.network.packet.* +import net.mamoe.mirai.network.packet.action.ClientSendFriendMessagePacket import net.mamoe.mirai.network.packet.action.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.packet.login.* @@ -85,16 +87,14 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { //private | internal - internal fun tryLogin(): CompletableFuture = this.tryLogin(200)//登录回复非常快, 没必要等太久. - - /** * 仅当 [LoginState] 非 [LoginState.UNKNOWN] 且非 [LoginState.TIMEOUT] 才会调用 [loginHook]. * 如果要输入验证码, 那么会以参数 [LoginState.VERIFICATION_CODE] 调用 [loginHandler], 登录完成后再以 [LoginState.SUCCESS] 调用 [loginHandler] * * @param touchingTimeoutMillis 连接每个服务器的 timeout */ - internal fun tryLogin(touchingTimeoutMillis: Long): CompletableFuture { + @JvmOverloads + internal fun tryLogin(touchingTimeoutMillis: Long = 200): CompletableFuture { val ipQueue: LinkedList = LinkedList(Protocol.SERVER_IP) val future = CompletableFuture() @@ -199,10 +199,10 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { return this.loginFuture!! } - @Synchronized /** * Not async */ + @Synchronized @ExperimentalUnsignedTypes internal fun sendPacket(packet: ClientPacket) { checkNotNull(socket) { "network closed" } @@ -329,7 +329,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { this.loginIP = packet.loginIP this.loginTime = packet.loginTime this.token0825 = packet.token0825 - sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, this.tgtgtKey!!, packet.token0825)) + sendPacket(ClientPasswordSubmissionPacket(robot.account.qqNumber, robot.account.password, packet.loginTime, packet.loginIP, this.tgtgtKey, packet.token0825)) } } @@ -341,7 +341,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { is ServerVerificationCodeCorrectPacket -> { this.tgtgtKey = getRandomByteArray(16) this.token00BA = packet.token00BA - sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA)) + sendPacket(ClientLoginResendPacket3105(robot.account.qqNumber, robot.account.password, this.loginTime, this.loginIP, this.tgtgtKey, this.token0825, this.token00BA)) } is ServerLoginResponseVerificationCodeInitPacket -> { @@ -419,7 +419,7 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { //登录成功后会收到大量上次的消息, 忽略掉 MiraiThreadPool.getInstance().schedule({ - (packetHandlers[MessageHandler::class] as MessageHandler).ignoreMessage = false + messageHandler.ignoreMessage = false }, 2, TimeUnit.SECONDS) this.tlv0105 = packet.tlv0105 @@ -432,7 +432,6 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { } is ServerSKeyResponsePacket -> { - val actionHandler = packetHandlers[ActionHandler::class] as ActionHandler actionHandler.sKey = packet.sKey actionHandler.cookies = "uin=o" + robot.account.qqNumber + ";skey=" + actionHandler.sKey + ";" @@ -496,7 +495,12 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { return } - FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message) + val friendMessageEvent = FriendMessageEvent(robot, robot.contacts.getQQ(packet.qq), packet.message) + friendMessageEvent.broadcast() + + if (friendMessageEvent.message() valueEquals "你好") { + friendMessageEvent.qq.sendMessage("你好") + } } is ServerGroupMessageEventPacket -> { @@ -515,9 +519,8 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { } } - fun sendFriendMessage(qq: QQ, message: Message) { - TODO() - //sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message)) + fun sendFriendMessage(qq: QQ, message: MessageChain) { + sendPacket(ClientSendFriendMessagePacket(robot.account.qqNumber, qq.number, sessionKey, message)) } fun sendGroupMessage(group: Group, message: Message): Unit { @@ -532,7 +535,11 @@ class RobotNetworkHandler(private val robot: Robot) : Closeable { */ inner class ActionHandler : PacketHandler() { internal lateinit var cookies: String - internal lateinit var sKey: String + internal var sKey: String = "" + set(value) { + field = value + gtk = getGTK(value) + } internal var gtk: Int = 0 override fun onPacketReceived(packet: ServerPacket) { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt index c9e3f501a..bea51f94c 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt @@ -230,7 +230,7 @@ fun DataOutputStream.writeZero(count: Int) { @Throws(IOException::class) fun DataOutputStream.writeRandom(length: Int) { repeat(length) { - this.writeByte((Math.random() * 255).toInt().toByte().toInt()) + this.writeByte((Math.random() * 255).toInt()) } } @@ -244,4 +244,13 @@ fun DataOutputStream.writeQQ(qq: Long) { @Throws(IOException::class) fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) { this.write(groupIdOrGroupNumber.toUInt().toByteArray()) +} + +fun DataOutputStream.writeVarByteArray(byteArray: ByteArray) { + this.writeShort(byteArray.size) + this.write(byteArray) +} + +fun DataOutputStream.writeVarString(str: String) { + this.writeVarByteArray(str.toByteArray()) } \ No newline at end of file diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt index 2a5c489c9..7bb280023 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt @@ -199,11 +199,10 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray val l1 = input.readShortAt(22) input.goto(93 + l1) - val l2 = input.readShort() - input.readNBytes(l2)//font + input.readVarByteArray()//font input.skip(2)//2个0x00 message = input.readSections() - println(message.toDebugString()) + println(message.toObjectString()) /* val offset = unknownLength0 + fontLength//57 @@ -218,14 +217,14 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray val sectionLength = this.readShort().toLong()//sectionLength: short this.skip(1)//message和face是 0x01, image是0x06 return when (messageType) { - 0x01 -> PlainText(readShortVarString()) + 0x01 -> PlainText(readVarString()) 0x02 -> { //00 01 AF 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 F0 //00 01 0C 0B 00 08 00 01 00 04 52 CC F5 D0 FF 00 02 14 4D - val id1 = FaceID.ofId(readShortVarNumber().toInt())//可能这个是id, 也可能下面那个 + val id1 = FaceID.ofId(readVarNumber().toInt())//可能这个是id, 也可能下面那个 this.skip(this.readByte().toLong()) - this.readShortVarNumber()//某id? + this.readVarNumber()//某id? return Face(id1) } 0x06 -> { diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt index e3051f09a..f1811c4c1 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt @@ -176,8 +176,12 @@ fun DataInputStream.readIP(): String { return buff } -fun DataInputStream.readShortVarString(): String { - return String(this.readNBytes(this.readShort().toInt())) +fun DataInputStream.readVarString(): String { + return String(this.readVarByteArray()) +} + +fun DataInputStream.readVarByteArray(): ByteArray { + return this.readNBytes(this.readShort().toInt()) } fun DataInputStream.readString(length: Int): String { @@ -206,7 +210,7 @@ fun DataInputStream.readNBytes(length: N): ByteArray { } -fun DataInputStream.readShortVarNumber(): Number { +fun DataInputStream.readVarNumber(): Number { return when (this.readShort().toInt()) { 1 -> this.readByte() 2 -> this.readShort() diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt index 768993e77..1ac425868 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/action/ClientSendFriendMessagePacket.kt @@ -1,5 +1,6 @@ package net.mamoe.mirai.network.packet.action +import net.mamoe.mirai.message.defaults.MessageChain import net.mamoe.mirai.network.Protocol import net.mamoe.mirai.network.packet.* import net.mamoe.mirai.utils.lazyEncode @@ -14,7 +15,7 @@ class ClientSendFriendMessagePacket( private val robotQQ: Long, private val targetQQ: Long, private val sessionKey: ByteArray, - private val message: String + private val message: MessageChain ) : ClientPacket() { override fun encode() { this.writeRandom(2)//part of packet id @@ -36,24 +37,20 @@ class ClientSendFriendMessagePacket( it.writeTime() it.writeRandom(4) it.writeHex("00 00 00 00 09 00 86") - it.writeHex(Protocol.friendMessageConst1) + it.writeHex(Protocol.friendMessageConst1)//... 85 E9 BB 91 it.writeZero(2) - if ("[face" in message - || ".gif]" in message - || ".jpg]" in message - || ".png]" in message - ) { - TODO("复合消息构建") - } else { + + it.write(message.toByteArray()) + + /* //Plain text val bytes = message.toByteArray() it.writeByte(0x01) it.writeShort(bytes.size + 3) it.writeByte(0x01) it.writeShort(bytes.size) - it.write(bytes) - } + it.write(bytes)*/ } } } diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt index 118012401..1a4ed2f70 100644 --- a/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt +++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/MiraiLogger.kt @@ -29,6 +29,7 @@ object MiraiLogger { this.print(e.cause.toString())*/ } + @Synchronized private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) { val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date()) kotlin.io.println("$color[Mirai] $s : $value") @@ -52,12 +53,14 @@ infix fun Robot.success(o: Any?) = print(this, o.toString(), LoggerTextFormat.GR infix fun Robot.debug(o: Any?) = print(this, o.toString(), LoggerTextFormat.YELLOW) +@Synchronized private fun print(robot: Robot, value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) { val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date()) kotlin.io.println("$color[Mirai] $s #R${robot.id}: $value") } +@Synchronized private fun print(value: String?, color: LoggerTextFormat = LoggerTextFormat.WHITE) { val s = SimpleDateFormat("MM-dd HH:mm:ss").format(Date()) kotlin.io.println("$color[Mirai] $s : $value") diff --git a/mirai-ui/pom.xml b/mirai-ui/pom.xml new file mode 100644 index 000000000..146dd507e --- /dev/null +++ b/mirai-ui/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + mirai-ui + 1.0 + + jar + + + net.mamoe + mirai + 1.0 + ../pom.xml + + + + + + + + + + /src/main/resources + + + **/*.* + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 28d665c86..7c26ba49b 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ mirai-core mirai-native + mirai-ui @@ -27,41 +28,14 @@ pom + + 1.3.41 11 11 UTF-8 - - package - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - - org.ow2.asm - asm - 7.1 - - - - UTF-8 - - - - - org.projectlombok - lombok-maven-plugin - 1.18.6.0 - - - - - @@ -121,7 +95,114 @@ 0.5.2 + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + + + org.apache.logging.log4j + log4j-core + 2.12.1 + + + + org.yaml + snakeyaml + 1.18 + + + + org.jetbrains.kotlin + kotlin-reflect + 1.3.41 + compile + + + + package + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + org.ow2.asm + asm + 7.1 + + + + UTF-8 + + + + + org.projectlombok + lombok-maven-plugin + 1.18.6.0 + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.3 + + + package + + shade + + + + + true + shaded + + + + + org.projectlombok + lombok-maven-plugin + 1.18.6.0 + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + process-sources + + compile + + + + test-compile + test-compile + + test-compile + + + + + 1.8 + + + + + + \ No newline at end of file