util.kt 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright 2019-2020 Mamoe Technologies and contributors.
  3. *
  4. * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  5. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  6. *
  7. * https://github.com/mamoe/mirai/blob/master/LICENSE
  8. */
  9. @file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
  10. package net.mamoe.mirai.internal.contact
  11. import net.mamoe.mirai.contact.Contact
  12. import net.mamoe.mirai.contact.Friend
  13. import net.mamoe.mirai.contact.User
  14. import net.mamoe.mirai.event.broadcast
  15. import net.mamoe.mirai.event.events.*
  16. import net.mamoe.mirai.internal.asQQAndroidBot
  17. import net.mamoe.mirai.internal.message.MessageSourceToFriendImpl
  18. import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable
  19. import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
  20. import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToFriend
  21. import net.mamoe.mirai.message.*
  22. import net.mamoe.mirai.message.data.Message
  23. import net.mamoe.mirai.message.data.QuoteReply
  24. import net.mamoe.mirai.message.data.asMessageChain
  25. import net.mamoe.mirai.message.data.firstIsInstanceOrNull
  26. import net.mamoe.mirai.utils.verbose
  27. import kotlin.contracts.InvocationKind
  28. import kotlin.contracts.contract
  29. internal suspend fun <T : User> Friend.sendMessageImpl(
  30. message: Message,
  31. friendReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<Friend>,
  32. tReceiptConstructor: (MessageSourceToFriendImpl) -> MessageReceipt<T>
  33. ): MessageReceipt<T> {
  34. contract { callsInPlace(friendReceiptConstructor, InvocationKind.EXACTLY_ONCE) }
  35. val bot = bot.asQQAndroidBot()
  36. val chain = kotlin.runCatching {
  37. FriendMessagePreSendEvent(this, message).broadcast()
  38. }.onSuccess {
  39. check(!it.isCancelled) {
  40. throw EventCancelledException("cancelled by FriendMessagePreSendEvent")
  41. }
  42. }.getOrElse {
  43. throw EventCancelledException("exception thrown when broadcasting FriendMessagePreSendEvent", it)
  44. }.message.asMessageChain()
  45. chain.firstIsInstanceOrNull<QuoteReply>()?.source?.ensureSequenceIdAvailable()
  46. lateinit var source: MessageSourceToFriendImpl
  47. val result = bot.network.runCatching {
  48. MessageSvcPbSendMsg.createToFriend(
  49. bot.client,
  50. this@sendMessageImpl,
  51. chain
  52. ) {
  53. source = it
  54. }.sendAndExpect<MessageSvcPbSendMsg.Response>().let {
  55. check(it is MessageSvcPbSendMsg.Response.SUCCESS) {
  56. "Send friend message failed: $it"
  57. }
  58. }
  59. friendReceiptConstructor(source)
  60. }
  61. result.fold(
  62. onSuccess = {
  63. FriendMessagePostSendEvent(this, chain, null, it)
  64. },
  65. onFailure = {
  66. FriendMessagePostSendEvent(this, chain, it, null)
  67. }
  68. ).broadcast()
  69. result.getOrThrow()
  70. return tReceiptConstructor(source)
  71. }
  72. internal fun Contact.logMessageSent(message: Message) {
  73. @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
  74. if (message !is net.mamoe.mirai.message.data.LongMessage) {
  75. bot.logger.verbose("$this <- $message".replaceMagicCodes())
  76. }
  77. }
  78. internal fun MessageEvent.logMessageReceived() {
  79. when (this) {
  80. is GroupMessageEvent -> bot.logger.verbose {
  81. "[${group.name}(${group.id})] ${senderName}(${sender.id}) -> $message".replaceMagicCodes()
  82. }
  83. is TempMessageEvent -> bot.logger.verbose {
  84. "[${group.name}(${group.id})] $senderName(Temp ${sender.id}) -> $message".replaceMagicCodes()
  85. }
  86. is FriendMessageEvent -> bot.logger.verbose {
  87. "${sender.nick}(${sender.id}) -> $message".replaceMagicCodes()
  88. }
  89. }
  90. }
  91. internal val charMappings = mapOf(
  92. '\n' to """\n""",
  93. '\r' to "",
  94. '\u202E' to "<RTL>",
  95. '\u202D' to "<LTR>",
  96. )
  97. internal fun String.applyCharMapping() = buildString(capacity = this.length) {
  98. [email protected] { char ->
  99. append(charMappings[char] ?: char)
  100. }
  101. }
  102. internal fun String.replaceMagicCodes(): String = this
  103. .applyCharMapping()