Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
M
Mirai
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Mirai
Commits
579b8da7
Commit
579b8da7
authored
Jul 09, 2020
by
Him188
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'dev'
parents
9892af59
181f4a53
Changes
33
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
33 changed files
with
484 additions
and
211 deletions
+484
-211
CHANGELOG.md
CHANGELOG.md
+31
-2
buildSrc/src/main/kotlin/Versions.kt
buildSrc/src/main/kotlin/Versions.kt
+1
-1
buildSrc/src/main/kotlin/upload/GitHub.kt
buildSrc/src/main/kotlin/upload/GitHub.kt
+3
-3
gradle/publish.gradle
gradle/publish.gradle
+1
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt
...rc/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt
+10
-3
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
...n/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
+16
-5
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt
...in/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt
+1
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt
...in/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt
+1
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
...moe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+6
-3
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt
...oe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt
+5
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/NewContact.kt
...irai/qqandroid/network/protocol/packet/chat/NewContact.kt
+14
-15
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt
...twork/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt
+15
-0
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt
...etwork/protocol/packet/chat/receive/OnlinePush.ReqPush.kt
+4
-1
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/ConfigPushSvc.kt
.../qqandroid/network/protocol/packet/login/ConfigPushSvc.kt
+15
-16
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt
.../mirai/qqandroid/network/protocol/packet/login/StatSvc.kt
+4
-4
mirai-core/build.gradle.kts
mirai-core/build.gradle.kts
+3
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+4
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupActiveData.kt
...commonMain/kotlin/net.mamoe.mirai/data/GroupActiveData.kt
+26
-26
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt
...src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt
+24
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/group.kt
...c/commonMain/kotlin/net.mamoe.mirai/event/events/group.kt
+4
-3
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt
...core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt
+25
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
...c/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
+4
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt
...rc/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.common.kt
...n/kotlin/net.mamoe.mirai/utils/BotConfiguration.common.kt
+26
-25
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
+19
-2
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt
...rc/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/internal/ChunkedFlowSession.kt
...tlin/net.mamoe.mirai/utils/internal/ChunkedFlowSession.kt
+28
-38
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/JvmMethodListeners.kt
...vmMain/kotlin/net/mamoe/mirai/event/JvmMethodListeners.kt
+45
-7
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfiguration.kt
.../jvmMain/kotlin/net/mamoe/mirai/utils/BotConfiguration.kt
+22
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformLogger.jvm.kt
...vmMain/kotlin/net/mamoe/mirai/utils/PlatformLogger.jvm.kt
+31
-14
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/asReusableInput.jvm.kt
...lin/net/mamoe/mirai/utils/internal/asReusableInput.jvm.kt
+7
-3
mirai-core/src/jvmTest/java/net/mamoe/mirai/event/JvmMethodEventsTestJava.java
...t/java/net/mamoe/mirai/event/JvmMethodEventsTestJava.java
+61
-0
mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/JvmMethodEventsTest.kt
...mTest/kotlin/net/mamoe/mirai/event/JvmMethodEventsTest.kt
+26
-19
No files found.
CHANGELOG.md
View file @
579b8da7
# Version 1.x
## `1.1.0` 2020/7/9
-
支持 Android 手表协议 (
`BotConfiguration.MiraiProtocol.ANDROID_PAD`
)
-
`EventHandler`
现在支持
`Nothing`
类型.
-
修复无需同意直接进群时,在加载新群信息完成前收到消息过早处理的问题 (#370)
-
修复在某些情况下,管理员邀请群Bot加群会被误判为群成员申请加群的问题 (#402 by
[
@kenvix
](
https://github.com/kenvix
)
)
-
修复从其他客户端加群时未同步的问题 (#404, #410)
-
修复
`ConfigPushSvc.PushReq`
解析失败的问题 (#417)
-
修复
`_lowLevelGetGroupActiveData`
-
修复
`SimpleListenerHost.coroutineScope`
潜在的 Job 被覆盖的问题
## `1.0.4` 2020/7/2
-
修复上传图片失败时内存泄露的问题 (#385)
-
修复大量图片同时上传时出错的问题 (#387)
-
修复在一些情况下 BotOfflineEvent 没有正常处理而无法继续接收消息的问题 (#376)
-
修复 Bot 在某个群 T 出某个人导致 Bot 终止的问题 (#372)
-
修复
`@PlannedRemoval`
的文档
## `1.1-EA2` 2020/7/2
-
添加
`BotConfiguration.json`
, 作为序列化时使用的 Json format, 修复潜在的因 kotlinx.serialization 进行不兼容更新而导致的不兼容.
**不兼容变更**
:
-
Image.imageId 后缀由
`.mirai`
变为图片文件实际类型, 如
`.png`
,
`.jpg`
. 兼容原
`.mirai`
后缀.
**修复**
:
-
(
[
1.0.4
](
https://github.com/mamoe/mirai/releases/tag/1.0.4
)
中修复的问题)
-
(
[
1.0.3
](
https://github.com/mamoe/mirai/releases/tag/1.0.3
)
中修复的问题)
## `1.0.3` 2020/6/29
-
修复 friendlist.GetTroopListReqV2:java.lang.IllegalStateException: type mismatch 10 (#405)
## `1.1-EA` 2020/6/16
**1.1.0 Early Access**
/
**1.1.0 预览版**
**此版本新增的 API 可能不稳定, 且可能在下一个版本中删除.**
**主要**
:
-
添加实验性
`CodableMessage`
作为支持 mirai 码的
`Message`
的接口.
...
...
buildSrc/src/main/kotlin/Versions.kt
View file @
579b8da7
...
...
@@ -9,7 +9,7 @@
object
Versions
{
object
Mirai
{
const
val
version
=
"1.1
-EA
"
const
val
version
=
"1.1
.0
"
}
object
Kotlin
{
...
...
buildSrc/src/main/kotlin/upload/GitHub.kt
View file @
579b8da7
...
...
@@ -74,7 +74,7 @@ object GitHub {
fun
upload
(
file
:
File
,
project
:
Project
,
repo
:
String
,
targetFilePath
:
String
)
=
runBlocking
{
val
token
=
getGithubToken
(
project
)
println
(
"token.length=${token.length}"
)
val
url
=
"https://api.github.com/repos/
mamoe
/$repo/contents/$targetFilePath"
val
url
=
"https://api.github.com/repos/
project-mirai
/$repo/contents/$targetFilePath"
retryCatching
(
100
,
onFailure
=
{
delay
(
30
_000
)
})
{
// 403 forbidden?
Http
.
put
<
String
>(
"$url?access_token=$token"
)
{
val
sha
=
retryCatching
(
3
,
onFailure
=
{
delay
(
30
_000
)
})
{
...
...
@@ -121,7 +121,7 @@ object GitHub {
return
withContext
(
Dispatchers
.
IO
)
{
val
response
=
Jsoup
.
connect
(
"https://api.github.com/repos/
mamoe
/$repo/contents/$filePath?access_token="
+
getGithubToken
(
"https://api.github.com/repos/
project-mirai
/$repo/contents/$filePath?access_token="
+
getGithubToken
(
project
)
)
...
...
@@ -150,7 +150,7 @@ object GitHub {
val
resp
=
withContext
(
Dispatchers
.
IO
)
{
Jsoup
.
connect
(
"https://api.github.com/repos/
mamoe
/$repo/git/ref/heads/$branch?access_token="
+
getGithubToken
(
"https://api.github.com/repos/
project-mirai
/$repo/git/ref/heads/$branch?access_token="
+
getGithubToken
(
project
)
)
...
...
gradle/publish.gradle
View file @
579b8da7
...
...
@@ -24,7 +24,7 @@ bintray {
pkg
{
repo
=
'mirai'
name
=
project
.
name
name
=
"mirai-core"
licenses
=
[
'AGPL'
]
vcsUrl
=
miraiGitHubUrl
websiteUrl
=
miraiGitHubUrl
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/BotImpl.kt
View file @
579b8da7
...
...
@@ -74,11 +74,13 @@ internal abstract class BotImpl<N : BotNetworkHandler> constructor(
// bot 还未登录就被 close
return
@
subscribeAlways
}
if
(
network
.
areYouOk
()
&&
event
!
is
BotOfflineEvent
.
Force
)
{
/*
if (network.areYouOk() && event !is BotOfflineEvent.Force && event !is BotOfflineEvent.MsfOffline) {
// network 运行正常
return@subscribeAlways
}
}
*/
when
(
event
)
{
is
BotOfflineEvent
.
MsfOffline
,
is
BotOfflineEvent
.
Dropped
,
is
BotOfflineEvent
.
RequireReconnect
->
{
...
...
@@ -105,7 +107,12 @@ internal abstract class BotImpl<N : BotNetworkHandler> constructor(
@OptIn
(
ThisApiMustBeUsedInWithConnectionLockBlock
::
class
)
relogin
((
event
as
?
BotOfflineEvent
.
Dropped
)
?.
cause
)
}
launch
{
BotReloginEvent
(
bot
,
(
event
as
?
BotOfflineEvent
.
Dropped
)
?.
cause
).
broadcast
()
}
launch
{
BotReloginEvent
(
bot
,
(
event
as
?
BotOfflineEvent
.
CauseAware
)
?.
cause
).
broadcast
()
}
return
}.
getOrElse
{
if
(
it
is
LoginFailedException
&&
!
it
.
killBot
)
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.common.kt
View file @
579b8da7
...
...
@@ -144,6 +144,12 @@ internal class QQAndroidBot constructor(
@Suppress
(
"DuplicatedCode"
)
@OptIn
(
LowLevelAPI
::
class
)
override
suspend
fun
rejectMemberJoinRequest
(
event
:
MemberJoinRequestEvent
,
blackList
:
Boolean
)
{
rejectMemberJoinRequest
(
event
,
blackList
,
""
)
}
@Suppress
(
"DuplicatedCode"
)
@OptIn
(
LowLevelAPI
::
class
)
override
suspend
fun
rejectMemberJoinRequest
(
event
:
MemberJoinRequestEvent
,
blackList
:
Boolean
,
message
:
String
)
{
checkGroupPermission
(
event
.
bot
,
event
.
group
)
{
event
::
class
.
simpleName
?:
"<anonymous class>"
}
check
(
event
.
responded
.
compareAndSet
(
false
,
true
))
{
"the request $this has already been responded"
...
...
@@ -159,7 +165,8 @@ internal class QQAndroidBot constructor(
fromNick
=
event
.
fromNick
,
groupId
=
event
.
groupId
,
accept
=
false
,
blackList
=
blackList
blackList
=
blackList
,
message
=
message
)
}
...
...
@@ -578,13 +585,15 @@ internal abstract class QQAndroidBotBase constructor(
@LowLevelAPI
@MiraiExperimentalAPI
override
suspend
fun
_lowLevelGetGroupActiveData
(
groupId
:
Long
):
GroupActiveData
{
override
suspend
fun
_lowLevelGetGroupActiveData
(
groupId
:
Long
,
page
:
Int
):
GroupActiveData
{
val
data
=
network
.
async
{
HttpClient
().
get
<
String
>
{
url
(
"https://qqweb.qq.com/c/activedata/get_mygroup_data"
)
parameter
(
"bkn"
,
bkn
)
parameter
(
"gc"
,
groupId
)
if
(
page
!=
-
1
)
{
parameter
(
"page"
,
page
)
}
headers
{
append
(
"cookie"
,
...
...
@@ -755,7 +764,8 @@ internal abstract class QQAndroidBotBase constructor(
fromNick
:
String
,
groupId
:
Long
,
accept
:
Boolean
?,
blackList
:
Boolean
blackList
:
Boolean
,
message
:
String
)
{
network
.
apply
{
NewContact
.
SystemMsgNewGroup
.
Action
(
...
...
@@ -765,7 +775,8 @@ internal abstract class QQAndroidBotBase constructor(
groupId
=
groupId
,
isInvited
=
false
,
accept
=
accept
,
blackList
=
blackList
blackList
=
blackList
,
message
=
message
).
sendWithoutExpect
()
if
(
accept
?:
return
)
groups
[
groupId
].
apply
{
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/FriendImpl.kt
View file @
579b8da7
...
...
@@ -114,7 +114,7 @@ internal class FriendImpl(
fileId
=
0
,
fileMd5
=
image
.
md5
,
fileSize
=
image
.
input
.
size
.
toInt
(),
fileName
=
image
.
md5
.
toUHexString
(
""
)
+
"."
+
ExternalImage
.
defaultF
ormatName
,
fileName
=
image
.
md5
.
toUHexString
(
""
)
+
"."
+
image
.
f
ormatName
,
imgOriginal
=
1
)
).
sendAndExpect
<
LongConn
.
OffPicUp
.
Response
>()
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/contact/MemberImpl.kt
View file @
579b8da7
...
...
@@ -237,7 +237,7 @@ internal class MemberImpl constructor(
@Suppress
(
"INVISIBLE_MEMBER"
,
"INVISIBLE_REFERENCE"
)
group
.
members
.
delegate
.
removeIf
{
it
.
id
==
this
@MemberImpl
.
id
}
this
.
cancel
(
CancellationException
(
"Kicked by bot"
))
this
@MemberImpl
.
cancel
(
CancellationException
(
"Kicked by bot"
))
MemberLeaveEvent
.
Kick
(
this
@MemberImpl
,
null
).
broadcast
()
}
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
View file @
579b8da7
...
...
@@ -96,14 +96,17 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
private
fun
startHeartbeatJobOrKill
(
cancelCause
:
CancellationException
?
=
null
):
Job
{
heartbeatJob
?.
cancel
(
cancelCause
)
return
this
@QQAndroidBotNetworkHandler
.
launch
(
CoroutineName
(
"Heartbeat"
))
{
return
this
@QQAndroidBotNetworkHandler
.
launch
(
CoroutineName
(
"Heartbeat"
))
heartBeatJob
@
{
while
(
this
.
isActive
)
{
delay
(
bot
.
configuration
.
heartbeatPeriodMillis
)
val
failException
=
doHeartBeat
()
if
(
failException
!=
null
)
{
delay
(
bot
.
configuration
.
firstReconnectDelayMillis
)
bot
.
launch
{
BotOfflineEvent
.
Dropped
(
bot
,
failException
).
broadcast
()
}
return
@
launch
bot
.
launch
{
BotOfflineEvent
.
Dropped
(
bot
,
failException
).
broadcast
()
}
return
@
heartBeatJob
}
}
}.
also
{
heartbeatJob
=
it
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt
View file @
579b8da7
...
...
@@ -99,9 +99,13 @@ internal class StGroupRankInfo(
@JceId
(
4
)
@JvmField
val
dwGroupRankSeq
:
Long
?
=
null
,
@JceId
(
5
)
@JvmField
val
ownerName
:
String
?
=
""
,
@JceId
(
6
)
@JvmField
val
adminName
:
String
?
=
""
,
@JceId
(
7
)
@JvmField
val
dwOfficeMode
:
Long
?
=
null
@JceId
(
7
)
@JvmField
val
dwOfficeMode
:
Long
?
=
null
,
@JceId
(
9
)
@JvmField
val
fuckIssue405
:
List
<
FuckIssue405
?
>?
=
null
// fake
)
:
JceStruct
@Serializable
internal
class
FuckIssue405
@Serializable
internal
class
StFavoriteGroup
(
@JceId
(
0
)
@JvmField
val
dwGroupCode
:
Long
,
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/NewContact.kt
View file @
579b8da7
...
...
@@ -148,22 +148,22 @@ internal class NewContact {
return
struct
?.
msg
?.
run
{
//this.soutv("SystemMsg")
when
(
subType
)
{
1
->
{
//
管理员邀
请
when
(
c2cInviteJoinGroupFlag
)
{
1
->
{
//
处理被邀请入群 或 处理成员入群申
请
when
(
groupMsgType
)
{
1
->
{
// 被邀请入群
BotInvitedJoinGroupRequestEvent
(
bot
,
struct
.
msgSeq
,
actionUin
,
groupCode
,
groupName
,
actionUinNick
)
}
0
->
{
// 成员申请入群
MemberJoinRequestEvent
(
bot
,
struct
.
msgSeq
,
msgAdditional
,
struct
.
reqUin
,
groupCode
,
groupName
,
reqUinNick
)
}
2
->
{
// 被邀请入群
BotInvitedJoinGroupRequestEvent
(
bot
,
struct
.
msgSeq
,
actionUin
,
groupCode
,
groupName
,
actionUinNick
)
}
else
->
throw
contextualBugReportException
(
"parse SystemMsgNewGroup, subType=1"
,
this
.
_miraiContentToString
(),
...
...
@@ -171,16 +171,14 @@ internal class NewContact {
)
}
}
2
->
{
// 被邀请入群, 自动同意
2
->
{
// 被邀请入群, 自动同意, 不需处理
val
group
=
bot
.
getNewGroup
(
groupCode
)
?:
return
null
val
invitor
=
group
[
actionUin
]
BotJoinGroupEvent
.
Invite
(
invitor
)
}
3
->
{
// 已被请他管理员处理
3
->
{
// 已被请他管理员处理
null
}
5
->
{
...
...
@@ -223,7 +221,8 @@ internal class NewContact {
groupId
:
Long
,
isInvited
:
Boolean
,
accept
:
Boolean
?,
blackList
:
Boolean
=
false
blackList
:
Boolean
=
false
,
message
:
String
=
""
)
=
buildOutgoingUniPacket
(
client
)
{
writeProtoBuf
(
...
...
@@ -236,7 +235,7 @@ internal class NewContact {
false
->
12
// reject
},
groupCode
=
groupId
,
msg
=
""
,
msg
=
message
,
remark
=
""
,
blacklist
=
blackList
),
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.PbGetMsg.kt
View file @
579b8da7
...
...
@@ -44,6 +44,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.GroupInfoImpl
import
net.mamoe.mirai.qqandroid.network.protocol.packet.chat.NewContact
import
net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
import
net.mamoe.mirai.qqandroid.utils._miraiContentToString
import
net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
import
net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
import
net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
...
...
@@ -190,6 +191,20 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
34
->
{
// 与 33 重复
return
@
mapNotNull
null
}
85
->
bot
.
groupListModifyLock
.
withLock
{
// 其他客户端入群
val
group
=
bot
.
getGroupByUinOrNull
(
msg
.
msgHead
.
fromUin
)
if
(
msg
.
msgHead
.
toUin
==
bot
.
id
&&
group
==
null
)
{
val
newGroup
=
bot
.
getNewGroup
(
Group
.
calculateGroupCodeByGroupUin
(
msg
.
msgHead
.
fromUin
))
?:
return
@
mapNotNull
null
bot
.
groups
.
delegate
.
addLast
(
newGroup
)
return
@
mapNotNull
BotJoinGroupEvent
.
Active
(
newGroup
)
}
else
{
// unknown
return
@
mapNotNull
null
}
}
/*
34 -> { // 主动入群
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt
View file @
579b8da7
...
...
@@ -81,7 +81,9 @@ internal object OnlinePushReqPush : IncomingPacketFactory<OnlinePushReqPush.ReqP
val
packets
:
Sequence
<
Packet
>
=
reqPushMsg
.
vMsgInfos
.
deco
(
bot
.
client
)
{
msgInfo
->
when
(
msgInfo
.
shMsgType
.
toInt
())
{
732
->
{
val
group
=
bot
.
getGroup
(
readUInt
().
toLong
())
val
group
=
bot
.
getGroupOrNull
(
readUInt
().
toLong
())
?:
return
@
deco
emptySequence
()
// group has not been initialized
GroupImpl
.
checkIsInstance
(
group
)
val
internalType
=
readByte
().
toInt
()
...
...
@@ -257,6 +259,7 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
}
}
@Suppress
(
"DEPRECATION"
)
if
(
group
.
settings
.
isConfessTalkEnabled
==
new
)
{
return
@
lambda732
emptySequence
()
}
...
...
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/ConfigPushSvc.kt
View file @
579b8da7
This diff is collapsed.
Click to expand it.
mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/StatSvc.kt
View file @
579b8da7
...
...
@@ -182,7 +182,7 @@ internal class StatSvc {
}
internal
object
ReqMSFOffline
:
IncomingPacketFactory
<
BotOfflineEvent
.
Dropped
>(
"StatSvc.ReqMSFOffline"
,
"StatSvc.RspMSFForceOffline"
)
{
IncomingPacketFactory
<
BotOfflineEvent
.
MsfOffline
>(
"StatSvc.ReqMSFOffline"
,
"StatSvc.RspMSFForceOffline"
)
{
internal
data class
MsfOfflineToken
(
val
uin
:
Long
,
...
...
@@ -190,13 +190,13 @@ internal class StatSvc {
val
const
:
Byte
)
:
Packet
,
RuntimeException
(
"dropped by StatSvc.ReqMSFOffline"
)
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
,
sequenceId
:
Int
):
BotOfflineEvent
.
Dropped
{
override
suspend
fun
ByteReadPacket
.
decode
(
bot
:
QQAndroidBot
,
sequenceId
:
Int
):
BotOfflineEvent
.
MsfOffline
{
val
decodeUniPacket
=
readUniPacket
(
RequestMSFForceOffline
.
serializer
())
@Suppress
(
"INVISIBLE_MEMBER"
)
return
BotOfflineEvent
.
Dropped
(
bot
,
MsfOfflineToken
(
decodeUniPacket
.
uin
,
decodeUniPacket
.
iSeqno
,
0
))
return
BotOfflineEvent
.
MsfOffline
(
bot
,
MsfOfflineToken
(
decodeUniPacket
.
uin
,
decodeUniPacket
.
iSeqno
,
0
))
}
override
suspend
fun
QQAndroidBot
.
handle
(
packet
:
BotOfflineEvent
.
Dropped
,
sequenceId
:
Int
):
OutgoingPacket
?
{
override
suspend
fun
QQAndroidBot
.
handle
(
packet
:
BotOfflineEvent
.
MsfOffline
,
sequenceId
:
Int
):
OutgoingPacket
?
{
val
cause
=
packet
.
cause
check
(
cause
is
MsfOfflineToken
)
{
"internal error: handling $packet in StatSvc.ReqMSFOffline"
}
return
buildResponseUniPacket
(
client
)
{
...
...
mirai-core/build.gradle.kts
View file @
579b8da7
...
...
@@ -34,7 +34,9 @@ kotlin {
)
}
jvm
()
jvm
()
{
// withJava() // https://youtrack.jetbrains.com/issue/KT-39991
}
sourceSets
{
all
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
View file @
579b8da7
...
...
@@ -291,11 +291,13 @@ abstract class Bot internal constructor(
@Deprecated
(
"use member function."
,
replaceWith
=
ReplaceWith
(
"event.reject(blackList)"
),
level
=
DeprecationLevel
.
ERROR
level
=
DeprecationLevel
.
HIDDEN
)
@JvmSynthetic
abstract
suspend
fun
rejectMemberJoinRequest
(
event
:
MemberJoinRequestEvent
,
blackList
:
Boolean
=
false
)
@JvmSynthetic
abstract
suspend
fun
rejectMemberJoinRequest
(
event
:
MemberJoinRequestEvent
,
blackList
:
Boolean
=
false
,
message
:
String
=
""
)
/**
* 忽略加群验证(需管理员权限)
*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/GroupActiveData.kt
View file @
579b8da7
...
...
@@ -26,109 +26,109 @@ data class GroupActiveData(
val
info
:
GInfo
?
=
null
,
@SerialName
(
"role"
)
val
role
:
Int
?
val
role
:
Int
?
=
0
)
{
@Serializable
data class
GInfo
(
@SerialName
(
"g_act_num"
)
val
actNum
:
List
<
GActNum
?
>?,
//发言人数列表
val
actNum
:
List
<
GActNum
?
>?
=
null
,
//发言人数列表
@SerialName
(
"g_createtime"
)
val
createTime
:
Int
?,
val
createTime
:
Int
?
=
0
,
@SerialName
(
"g_exit_num"
)
val
exitNum
:
List
<
GExitNum
?
>?,
//退群人数列表
val
exitNum
:
List
<
GExitNum
?
>?
=
null
,
//退群人数列表
@SerialName
(
"g_join_num"
)
val
joinNum
:
List
<
GJoinNum
?
>?,
val
joinNum
:
List
<
GJoinNum
?
>?
=
null
,
@SerialName
(
"g_mem_num"
)
val
memNum
:
List
<
GMemNum
?
>?,
//人数变化
val
memNum
:
List
<
GMemNum
?
>?
=
null
,
//人数变化
@SerialName
(
"g_most_act"
)
val
mostAct
:
List
<
GMostAct
?
>?,
//发言排行
val
mostAct
:
List
<
GMostAct
?
>?
=
null
,
//发言排行
@SerialName
(
"g_sentences"
)
val
sentences
:
List
<
GSentence
?
>?,
val
sentences
:
List
<
GSentence
?
>?
=
null
,
@SerialName
(
"gc"
)
val
gc
:
Int
?,
val
gc
:
Int
?
=
null
,
@SerialName
(
"gn"
)
val
gn
:
String
?,
val
gn
:
String
?
=
null
,
@SerialName
(
"gowner"
)
val
gowner
:
String
?,
val
gowner
:
String
?
=
null
,
@SerialName
(
"isEnd"
)
val
isEnd
:
Int
?
val
isEnd
:
Int
?
=
null
)
{
@Serializable
data class
GActNum
(
@SerialName
(
"date"
)
val
date
:
String
?,
val
date
:
String
?
=
null
,
@SerialName
(
"num"
)
val
num
:
Int
?
val
num
:
Int
?
=
0
)
@Serializable
data class
GExitNum
(
@SerialName
(
"date"
)
val
date
:
String
?,
val
date
:
String
?
=
null
,
@SerialName
(
"num"
)
val
num
:
Int
?
val
num
:
Int
?
=
0
)
@Serializable
data class
GJoinNum
(
@SerialName
(
"date"
)
val
date
:
String
?,
val
date
:
String
?
=
null
,
@SerialName
(
"num"
)
val
num
:
Int
?
val
num
:
Int
?
=
0
)
@Serializable
data class
GMemNum
(
@SerialName
(
"date"
)
val
date
:
String
?,
val
date
:
String
?
=
null
,
@SerialName
(
"num"
)
val
num
:
Int
?
val
num
:
Int
?
=
0
)
@Serializable
data class
GMostAct
(
@SerialName
(
"name"
)
val
name
:
String
?,
// 名称 不完整
val
name
:
String
?
=
null
,
// 名称 不完整
@SerialName
(
"sentences_num"
)
val
sentencesNum
:
Int
?,
// 发言数
val
sentencesNum
:
Int
?
=
0
,
// 发言数
@SerialName
(
"sta"
)
val
sta
:
Int
?,
val
sta
:
Int
?
=
0
,
@SerialName
(
"uin"
)
val
uin
:
Long
?
val
uin
:
Long
?
=
0
)
@Serializable
data class
GSentence
(
@SerialName
(
"date"
)
val
date
:
String
?,
val
date
:
String
?
=
null
,
@SerialName
(
"num"
)
val
num
:
Int
?
val
num
:
Int
?
=
0
)
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/bot.kt
View file @
579b8da7
...
...
@@ -16,6 +16,9 @@ package net.mamoe.mirai.event.events
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.event.AbstractEvent
import
net.mamoe.mirai.qqandroid.network.Packet
import
net.mamoe.mirai.utils.MiraiExperimentalAPI
import
net.mamoe.mirai.utils.MiraiInternalAPI
import
net.mamoe.mirai.utils.SinceMirai
import
kotlin.jvm.JvmMultifileClass
import
kotlin.jvm.JvmName
...
...
@@ -35,7 +38,8 @@ sealed class BotOfflineEvent : BotEvent, AbstractEvent() {
/**
* 主动离线. 主动广播这个事件也可以让 [Bot] 关闭.
*/
data class
Active
(
override
val
bot
:
Bot
,
val
cause
:
Throwable
?)
:
BotOfflineEvent
(),
BotActiveEvent
data class
Active
(
override
val
bot
:
Bot
,
override
val
cause
:
Throwable
?)
:
BotOfflineEvent
(),
BotActiveEvent
,
CauseAware
/**
* 被挤下线
...
...
@@ -45,15 +49,31 @@ sealed class BotOfflineEvent : BotEvent, AbstractEvent() {
BotPassiveEvent
/**
* 被服务器断开
或因网络问题而掉线
* 被服务器断开
*/
data class
Dropped
internal
constructor
(
override
val
bot
:
Bot
,
val
cause
:
Throwable
?)
:
BotOfflineEvent
(),
Packet
,
BotPassiveEvent
@SinceMirai
(
"1.1.0"
)
@MiraiInternalAPI
(
"This is very experimental and might be changed"
)
data class
MsfOffline
internal
constructor
(
override
val
bot
:
Bot
,
override
val
cause
:
Throwable
?)
:
BotOfflineEvent
(),
Packet
,
BotPassiveEvent
,
CauseAware
/**
* 因网络问题而掉线
*/
data class
Dropped
internal
constructor
(
override
val
bot
:
Bot
,
override
val
cause
:
Throwable
?)
:
BotOfflineEvent
(),
Packet
,
BotPassiveEvent
,
CauseAware
/**
* 服务器主动要求更换另一个服务器
*/
@MiraiInternalAPI
data class
RequireReconnect
internal
constructor
(
override
val
bot
:
Bot
)
:
BotOfflineEvent
(),
Packet
,
BotPassiveEvent
@MiraiExperimentalAPI
interface
CauseAware
{
val
cause
:
Throwable
?
}
}
/**
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/group.kt
View file @
579b8da7
...
...
@@ -355,7 +355,8 @@ data class MemberJoinRequestEvent internal constructor(
suspend
fun
accept
()
=
bot
.
acceptMemberJoinRequest
(
this
)
@JvmSynthetic
suspend
fun
reject
(
blackList
:
Boolean
=
false
)
=
bot
.
rejectMemberJoinRequest
(
this
,
blackList
)
@JvmOverloads
suspend
fun
reject
(
blackList
:
Boolean
=
false
,
message
:
String
=
""
)
=
bot
.
rejectMemberJoinRequest
(
this
,
blackList
,
message
)
@JvmSynthetic
suspend
fun
ignore
(
blackList
:
Boolean
=
false
)
=
bot
.
ignoreMemberJoinRequest
(
this
,
blackList
)
...
...
@@ -368,8 +369,8 @@ data class MemberJoinRequestEvent internal constructor(
@JavaFriendlyAPI
@JvmOverloads
@JvmName
(
"reject"
)
fun
__rejectBlockingForJava__
(
blackList
:
Boolean
=
false
)
=
runBlocking
{
bot
.
rejectMemberJoinRequest
(
this
@MemberJoinRequestEvent
,
blackList
)
}
fun
__rejectBlockingForJava__
(
blackList
:
Boolean
=
false
,
message
:
String
=
""
)
=
runBlocking
{
bot
.
rejectMemberJoinRequest
(
this
@MemberJoinRequestEvent
,
blackList
,
message
)
}
@JavaFriendlyAPI
@JvmOverloads
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/lowLevelApi.kt
View file @
579b8da7
...
...
@@ -112,10 +112,12 @@ interface LowLevelBotAPIAccessor {
/**
* 获取群活跃信息
* 不传page可得到趋势图
* page从0开始传入可以得到发言列表
*/
@LowLevelAPI
@MiraiExperimentalAPI
suspend
fun
_lowLevelGetGroupActiveData
(
groupId
:
Long
):
GroupActiveData
suspend
fun
_lowLevelGetGroupActiveData
(
groupId
:
Long
,
page
:
Int
=
-
1
):
GroupActiveData
/**
...
...
@@ -123,19 +125,38 @@ interface LowLevelBotAPIAccessor {
*/
@LowLevelAPI
@MiraiExperimentalAPI
suspend
fun
_lowLevelSolveNewFriendRequestEvent
(
eventId
:
Long
,
fromId
:
Long
,
fromNick
:
String
,
accept
:
Boolean
,
blackList
:
Boolean
)
suspend
fun
_lowLevelSolveNewFriendRequestEvent
(
eventId
:
Long
,
fromId
:
Long
,
fromNick
:
String
,
accept
:
Boolean
,
blackList
:
Boolean
)
/**
* 处理被邀请加入一个群请求事件
*/
@LowLevelAPI
@MiraiExperimentalAPI
suspend
fun
_lowLevelSolveBotInvitedJoinGroupRequestEvent
(
eventId
:
Long
,
invitorId
:
Long
,
groupId
:
Long
,
accept
:
Boolean
)
suspend
fun
_lowLevelSolveBotInvitedJoinGroupRequestEvent
(
eventId
:
Long
,
invitorId
:
Long
,
groupId
:
Long
,
accept
:
Boolean
)
/**
* 处理账号请求加入群事件
*/
@LowLevelAPI
@MiraiExperimentalAPI
suspend
fun
_lowLevelSolveMemberJoinRequestEvent
(
eventId
:
Long
,
fromId
:
Long
,
fromNick
:
String
,
groupId
:
Long
,
accept
:
Boolean
?,
blackList
:
Boolean
)
suspend
fun
_lowLevelSolveMemberJoinRequestEvent
(
eventId
:
Long
,
fromId
:
Long
,
fromNick
:
String
,
groupId
:
Long
,
accept
:
Boolean
?,
blackList
:
Boolean
,
message
:
String
=
""
)
}
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt
View file @
579b8da7
...
...
@@ -73,7 +73,7 @@ expect interface Image : Message, MessageContent, CodableMessage {
*
* ### 格式
* 群图片:
* - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.
mirai` (后缀一定为 `".mirai"`
)
* - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.
ext` (ext系扩展名
)
*
* 好友图片:
* - [FRIEND_IMAGE_ID_REGEX_1], 示例: `/f8f1ab55-bf8e-4236-b55e-955848d7069f`
...
...
@@ -125,7 +125,7 @@ abstract class FriendImage internal constructor() : AbstractImage() { // change
/**
* 群图片.
*
* @property imageId 形如 `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.
mirai` (后缀一定为 `".mirai"`
)
* @property imageId 形如 `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.
ext` (ext系扩展名
)
* @see Image 查看更多说明
*/
// CustomFace
...
...
@@ -156,11 +156,11 @@ val FRIEND_IMAGE_ID_REGEX_2 = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""")
/**
* 群图片 ID 正则表达式
*
* `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.
mirai
`
* `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.
ext
`
*/
@Suppress
(
"RegExpRedundantEscape"
)
// This is required on Android
// Java: MessageUtils.GROUP_IMAGE_ID_REGEX
val
GROUP_IMAGE_ID_REGEX
=
Regex
(
"""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\.
mirai
"""
)
val
GROUP_IMAGE_ID_REGEX
=
Regex
(
"""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\.
.{3,5}
"""
)
/**
* 通过 [Image.imageId] 构造一个 [Image] 以便发送.
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt
View file @
579b8da7
...
...
@@ -51,7 +51,7 @@ annotation class MiraiExperimentalAPI(
annotation
class
SinceMirai
(
val
version
:
String
)
/**
* 标记一个正计划在 [version] 版本时删除的 API.
* 标记一个正计划在 [version] 版本时删除
(对外隐藏)
的 API.
*/
@Target
(
CLASS
,
PROPERTY
,
FIELD
,
CONSTRUCTOR
,
FUNCTION
,
PROPERTY_GETTER
,
PROPERTY_SETTER
,
TYPEALIAS
)
@Retention
(
AnnotationRetention
.
SOURCE
)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.common.kt
View file @
579b8da7
...
...
@@ -16,10 +16,10 @@ import kotlinx.serialization.UnstableDefault
import
kotlinx.serialization.json.Json
import
kotlinx.serialization.json.JsonConfiguration
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.coroutines.coroutineContext
import
kotlin.jvm.JvmField
import
kotlin.jvm.JvmStatic
import
kotlin.jvm.JvmSynthetic
...
...
@@ -52,6 +52,30 @@ expect open class BotConfiguration() : BotConfigurationBase {
@ConfigurationDsl
fun
randomDeviceInfo
()
/**
* 协议类型, 服务器仅允许使用不同协议同时登录.
*/
enum
class
MiraiProtocol
{
/**
* Android 手机.
*/
ANDROID_PHONE
,
/**
* Android 平板.
*/
ANDROID_PAD
,
/**
* Android 手表.
* */
@SinceMirai
(
"1.1.0"
)
ANDROID_WATCH
;
internal
val
id
:
Long
}
companion
object
{
/** 默认的配置实例. 可以进行修改 */
@JvmStatic
...
...
@@ -61,10 +85,8 @@ expect open class BotConfiguration() : BotConfigurationBase {
fun
copy
():
BotConfiguration
}
@MiraiInternalAPI
@Suppress
(
"PropertyName"
)
@SinceMirai
(
"1.1.0"
)
internal
open
class
BotConfigurationBase
internal
constructor
()
{
open
class
BotConfigurationBase
internal
constructor
()
{
/**
* 日志记录器
*
...
...
@@ -131,27 +153,6 @@ internal open class BotConfigurationBase internal constructor() {
Json
(
JsonConfiguration
(
isLenient
=
true
,
ignoreUnknownKeys
=
true
))
}.
getOrElse
{
Json
(
JsonConfiguration
.
Stable
)
}
enum
class
MiraiProtocol
(
/** 协议模块使用的 ID */
@JvmField
internal
val
id
:
Long
)
{
/**
* Android 手机.
*
* - 与手机冲突
* - 与平板和电脑不冲突
*/
ANDROID_PHONE
(
537062845
),
/**
* Android 平板.
*
* - 与平板冲突
* - 与手机和电脑不冲突
*/
ANDROID_PAD
(
537062409
)
}
/**
* 不显示网络日志. 不推荐.
* @see networkLoggerSupplier 更多日志处理方式
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt
View file @
579b8da7
...
...
@@ -11,15 +11,18 @@
package
net.mamoe.mirai.utils
import
kotlinx.io.core.readBytes
import
kotlinx.io.core.use
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.User
import
net.mamoe.mirai.message.MessageReceipt
import
net.mamoe.mirai.message.data.*
import
net.mamoe.mirai.message.data.Image
import
net.mamoe.mirai.message.data.sendTo
import
net.mamoe.mirai.message.data.toUHexString
import
net.mamoe.mirai.utils.internal.DeferredReusableInput
import
net.mamoe.mirai.utils.internal.ReusableInput
import
kotlin.jvm.JvmField
import
kotlin.jvm.JvmName
import
kotlin.jvm.JvmSynthetic
/**
...
...
@@ -35,6 +38,12 @@ class ExternalImage internal constructor(
internal
val
input
:
ReusableInput
)
{
internal
val
md5
:
ByteArray
get
()
=
this
.
input
.
md5
val
formatName
:
String
by
lazy
{
val
hex
=
input
.
asInput
().
use
{
it
.
readBytes
(
8
).
toUHexString
(
""
)
}
return
@
lazy
hex
.
detectFormatName
()
}
init
{
if
(
input
!
is
DeferredReusableInput
)
{
...
...
@@ -67,6 +76,14 @@ class ExternalImage internal constructor(
}
internal
fun
calculateImageResourceId
():
String
=
generateImageId
(
md5
)
private
fun
String
.
detectFormatName
():
String
=
when
{
startsWith
(
"FFD8"
)
->
"jpg"
startsWith
(
"89504E47"
)
->
"png"
startsWith
(
"47494638"
)
->
"gif"
startsWith
(
"424D"
)
->
"bmp"
else
->
defaultFormatName
}
}
/*
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt
View file @
579b8da7
...
...
@@ -262,7 +262,7 @@ open class SimpleLogger(
enum
class
LogPriority
(
@MiraiExperimentalAPI
val
nameAligned
:
String
,
@MiraiExperimentalAPI
val
simpleName
:
String
,
val
simpleName
:
String
,
@MiraiExperimentalAPI
val
correspondingFunction
:
MiraiLogger
.(
message
:
String
?,
e
:
Throwable
?)
->
Unit
)
{
VERBOSE
(
"VERBOSE"
,
"V"
,
MiraiLogger
::
verbose
),
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/internal/ChunkedFlowSession.kt
View file @
579b8da7
...
...
@@ -64,10 +64,9 @@ internal class ChunkedInput(
*
* 若 [ByteReadPacket.remaining] 小于 [sizePerPacket], 将会返回唯一元素 [this] 的 [Sequence]
*/
internal
fun
ByteReadPacket
.
chunkedFlow
(
sizePerPacket
:
Int
):
Flow
<
ChunkedInput
>
{
internal
fun
ByteReadPacket
.
chunkedFlow
(
sizePerPacket
:
Int
,
buffer
:
ByteArray
):
Flow
<
ChunkedInput
>
{
ByteArrayPool
.
checkBufferSize
(
sizePerPacket
)
if
(
this
.
remaining
<=
sizePerPacket
.
toLong
())
{
ByteArrayPool
.
useInstance
{
buffer
->
return
flowOf
(
ChunkedInput
(
buffer
,
...
...
@@ -75,16 +74,13 @@ internal fun ByteReadPacket.chunkedFlow(sizePerPacket: Int): Flow<ChunkedInput>
)
)
}
}
return
flow
{
ByteArrayPool
.
useInstance
{
buffer
->
val
chunkedInput
=
ChunkedInput
(
buffer
,
0
)
do
{
chunkedInput
.
size
=
this
@
chunkedFlow
.
readAvailable
(
buffer
,
0
,
sizePerPacket
)
emit
(
chunkedInput
)
}
while
(
this
@
chunkedFlow
.
isNotEmpty
)
}
}
}
/**
...
...
@@ -93,20 +89,18 @@ internal fun ByteReadPacket.chunkedFlow(sizePerPacket: Int): Flow<ChunkedInput>
* 对于一个 1000 长度的 [ByteReadChannel] 和参数 [sizePerPacket] = 300, 将会产生含四个元素的 [Sequence],
* 其长度分别为: 300, 300, 300, 100.
*/
internal
fun
ByteReadChannel
.
chunkedFlow
(
sizePerPacket
:
Int
):
Flow
<
ChunkedInput
>
{
internal
fun
ByteReadChannel
.
chunkedFlow
(
sizePerPacket
:
Int
,
buffer
:
ByteArray
):
Flow
<
ChunkedInput
>
{
ByteArrayPool
.
checkBufferSize
(
sizePerPacket
)
if
(
this
.
isClosedForRead
)
{
return
flowOf
()
}
return
flow
{
ByteArrayPool
.
useInstance
{
buffer
->
val
chunkedInput
=
ChunkedInput
(
buffer
,
0
)
do
{
chunkedInput
.
size
=
this
@
chunkedFlow
.
readAvailable
(
buffer
,
0
,
sizePerPacket
)
emit
(
chunkedInput
)
}
while
(!
this
@
chunkedFlow
.
isClosedForRead
)
}
}
}
...
...
@@ -117,7 +111,7 @@ internal fun ByteReadChannel.chunkedFlow(sizePerPacket: Int): Flow<ChunkedInput>
* 其长度分别为: 300, 300, 300, 100.
*/
@OptIn
(
ExperimentalCoroutinesApi
::
class
)
internal
fun
Input
.
chunkedFlow
(
sizePerPacket
:
Int
):
Flow
<
ChunkedInput
>
{
internal
fun
Input
.
chunkedFlow
(
sizePerPacket
:
Int
,
buffer
:
ByteArray
):
Flow
<
ChunkedInput
>
{
ByteArrayPool
.
checkBufferSize
(
sizePerPacket
)
if
(
this
.
endOfInput
)
{
...
...
@@ -125,14 +119,12 @@ internal fun Input.chunkedFlow(sizePerPacket: Int): Flow<ChunkedInput> {
}
return
flow
{
ByteArrayPool
.
useInstance
{
buffer
->
val
chunkedInput
=
ChunkedInput
(
buffer
,
0
)
while
(!
this
@
chunkedFlow
.
endOfInput
)
{
chunkedInput
.
size
=
this
@
chunkedFlow
.
readAvailable
(
buffer
,
0
,
sizePerPacket
)
emit
(
chunkedInput
)
}
}
}
}
/**
...
...
@@ -144,16 +136,14 @@ internal fun Input.chunkedFlow(sizePerPacket: Int): Flow<ChunkedInput> {
* 若 [ByteReadPacket.remaining] 小于 [sizePerPacket], 将会返回唯一元素 [this] 的 [Sequence]
*/
@OptIn
(
ExperimentalCoroutinesApi
::
class
,
InternalSerializationApi
::
class
)
internal
fun
InputStream
.
chunkedFlow
(
sizePerPacket
:
Int
):
Flow
<
ChunkedInput
>
{
ByteArrayPool
.
checkBufferSize
(
sizePerPacket
)
internal
fun
InputStream
.
chunkedFlow
(
sizePerPacket
:
Int
,
buffer
:
ByteArray
):
Flow
<
ChunkedInput
>
{
require
(
sizePerPacket
<=
buffer
.
size
)
{
"sizePerPacket is too large. Maximum buffer size=buffer.size=${buffer.size}"
}
return
flow
{
ByteArrayPool
.
useInstance
{
buffer
->
val
chunkedInput
=
ChunkedInput
(
buffer
,
0
)
while
(
this
@
chunkedFlow
.
available
()
!=
0
)
{
chunkedInput
.
size
=
this
@
chunkedFlow
.
read
(
buffer
,
0
,
sizePerPacket
)
emit
(
chunkedInput
)
}
}
}
}
\ No newline at end of file
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/JvmMethodListeners.kt
View file @
579b8da7
...
...
@@ -7,6 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@
file
:
JvmMultifileClass
@
file
:
JvmName
(
"Events"
)
@
file
:
Suppress
(
"unused"
,
"INVISIBLE_MEMBER"
,
"INVISIBLE_REFERENCE"
,
"NOTHING_TO_INLINE"
)
...
...
@@ -37,18 +38,26 @@ import kotlin.reflect.jvm.kotlinFunction
*
* 支持的函数类型:
* ```
* // 所有函数参数, 函数返回值都不允许标记为可空 (带有 '?' 符号)
* // T 表示任何 Event 类型.
* suspend fun T.onEvent(T)
* suspend fun T.onEvent(T): ListeningStatus
* suspend fun T.onEvent(T): Nothing
* suspend fun onEvent(T)
* suspend fun onEvent(T): ListeningStatus
* suspend fun onEvent(T): Nothing
* suspend fun T.onEvent()
* suspend fun T.onEvent(): ListeningStatus
* suspend fun T.onEvent(): Nothing
* fun T.onEvent(T)
* fun T.onEvent(T): ListeningStatus
* fun T.onEvent(T): Nothing
* fun onEvent(T)
* fun onEvent(T): ListeningStatus
* fun onEvent(T): Nothing
* fun T.onEvent()
* fun T.onEvent(): ListeningStatus
* fun T.onEvent(): Nothing
* ```
*
* Kotlin 使用示例:
...
...
@@ -57,6 +66,8 @@ import kotlin.reflect.jvm.kotlinFunction
* object MyEvents : ListenerHost {
* override val coroutineContext = SupervisorJob()
*
*
* // 可以抛出任何异常, 将在 this.coroutineContext 或 registerEvents 时提供的 CoroutineScope.coroutineContext 中的 CoroutineExceptionHandler 处理.
* @EventHandler
* suspend fun MessageEvent.onMessage() {
* reply("received")
...
...
@@ -76,8 +87,17 @@ import kotlin.reflect.jvm.kotlinFunction
*
}
*
*
@EventHandler
*
suspend
fun
MessageEvent
.
onMessage
()
{
*
suspend
fun
MessageEvent
.
onMessage
()
{
// 可以抛出任何异常, 将在 handleException 处理
*
reply
(
"received"
)
*
// 无返回值 (或者返回 Unit), 表示一直监听事件.
*
}
*
*
@EventHandler
*
suspend
fun
MessageEvent
.
onMessage
():
ListeningStatus
{
// 可以抛出任何异常, 将在 handleException 处理
*
reply
(
"received"
)
*
*
return
ListeningStatus
.
LISTENING
// 表示继续监听事件
*
// return ListeningStatus.STOPPED // 表示停止监听事件
*
}
*
}
*
...
...
@@ -90,8 +110,10 @@ import kotlin.reflect.jvm.kotlinFunction
*
*
支持的方法类型
*
```
*
// T 表示任何 Event 类型.
*
void
onEvent
(
T
)
*
ListeningStatus
onEvent
(
T
)
*
Void
onEvent
(
T
)
*
@NotNull
ListeningStatus
onEvent
(
T
)
// 返回 null 时将抛出异常
*
```
*
*
...
...
@@ -99,13 +121,23 @@ import kotlin.reflect.jvm.kotlinFunction
*
```
*
public
class
MyEventHandlers
extends
SimpleListenerHost
{
*
@Override
*
public
void
handleException
(
CoroutineContext
context
,
Throwable
exception
){
*
public
void
handleException
(
@NotNull
CoroutineContext
context
,
@NotNull
Throwable
exception
){
*
// 处理事件处理时抛出的异常
*
}
*
*
@EventHandler
*
public
void
onMessage
(
MessageEvent
event
)
throws
Exception
{
*
event
.
subject
.
sendMessage
(
"received"
)
*
public
void
onMessage
(
@NotNull
MessageEvent
event
)
throws
Exception
{
// 可以抛出任何异常, 将在 handleException 处理
*
event
.
subject
.
sendMessage
(
"received"
);
*
// 无返回值, 表示一直监听事件.
*
}
*
*
@NotNull
*
@EventHandler
*
public
ListeningStatus
onMessage
(
@NotNull
MessageEvent
event
)
throws
Exception
{
// 可以抛出任何异常, 将在 handleException 处理
*
event
.
subject
.
sendMessage
(
"received"
);
*
*
return
ListeningStatus
.
LISTENING
;
// 表示继续监听事件
*
// return ListeningStatus.STOPPED; // 表示停止监听事件
*
}
*
}
*
...
...
@@ -152,7 +184,7 @@ abstract class SimpleListenerHost
@JvmOverloads
constructor
(
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
)
:
ListenerHost
,
CoroutineScope
{
final
override
val
coroutineContext
:
CoroutineContext
=
SupervisorJob
(
coroutineContext
[
Job
])
+
CoroutineExceptionHandler
(
::
handleException
)
+
coroutineContext
CoroutineExceptionHandler
(
::
handleException
)
+
coroutineContext
+
SupervisorJob
(
coroutineContext
[
Job
])
/**
* 处理事件处理中未捕获的异常. 在构造器中的 [coroutineContext] 未提供 [CoroutineExceptionHandler] 情况下必须继承此函数.
...
...
@@ -260,6 +292,12 @@ private fun Method.registerEvent(
return
ListeningStatus
.
STOPPED
}
}
require
(!
kotlinFunction
.
returnType
.
isMarkedNullable
)
{
"Kotlin event handlers cannot have nullable return type."
}
require
(
kotlinFunction
.
parameters
.
any
{
it
.
type
.
isMarkedNullable
})
{
"Kotlin event handlers cannot have nullable parameter type."
}
when
(
kotlinFunction
.
returnType
.
classifier
)
{
Unit
::
class
,
Nothing
::
class
-> {
scope.subscribe
Always
(
...
...
@@ -299,7 +337,7 @@ private fun Method.registerEvent(
"Illegal method parameter. Required one exact Event subclass. found $paramType"
}
when
(
this
.
returnType
)
{
Void
::
class
.
java
,
Void
.
TYPE
->
{
Void
::
class
.
java
,
Void
.
TYPE
,
Nothing
::
class
.
java
->
{
scope
.
subscribeAlways
(
paramType
.
kotlin
as
KClass
<
out
Event
>,
priority
=
annotation
.
priority
,
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfiguration.kt
View file @
579b8da7
...
...
@@ -127,6 +127,28 @@ actual open class BotConfiguration : BotConfigurationBase() { // open for Java
botLoggerSupplier
=
{
SingleFileLogger
(
identity
(
it
),
file
)
}
}
@Suppress
(
"ACTUAL_WITHOUT_EXPECT"
)
actual
enum
class
MiraiProtocol
actual
constructor
(
/** 协议模块使用的 ID */
@JvmField
actual
internal
val
id
:
Long
)
{
/**
* Android 手机.
*/
ANDROID_PHONE
(
537062845
),
/**
* Android 平板.
*/
ANDROID_PAD
(
537062409
),
/**
* Android 手表.
* */
@SinceMirai
(
"1.1.0"
)
ANDROID_WATCH
(
537061176
)
}
actual
companion
object
{
/** 默认的配置实例. 可以进行修改 */
@JvmStatic
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformLogger.jvm.kt
View file @
579b8da7
...
...
@@ -53,50 +53,67 @@ actual open class PlatformLogger @JvmOverloads constructor(
)
:
MiraiLoggerPlatformBase
()
{
actual
constructor
(
identity
:
String
?)
:
this
(
identity
,
::
println
)
private
fun
out
(
message
:
String
?,
priority
:
String
,
color
:
Color
)
{
if
(
isColored
)
output
(
"$color$currentTimeFormatted $priority/$identity: $message"
)
else
output
(
"$currentTimeFormatted $priority/$identity: $message"
)
/**
* 输出一条日志. [message] 末尾可能不带换行符.
*/
@SinceMirai
(
"1.1.0"
)
protected
open
fun
printLog
(
message
:
String
?,
priority
:
SimpleLogger
.
LogPriority
)
{
if
(
isColored
)
output
(
"${priority.color}$currentTimeFormatted ${priority.simpleName}/$identity: $message"
)
else
output
(
"$currentTimeFormatted ${priority.simpleName}/$identity: $message"
)
}
override
fun
verbose0
(
message
:
String
?)
=
out
(
message
,
"V"
,
Color
.
RESET
)
/**
* 获取指定 [SimpleLogger.LogPriority] 的颜色
*/
@SinceMirai
(
"1.1.0"
)
protected
open
val
SimpleLogger
.
LogPriority
.
color
:
Color
get
()
=
when
(
this
)
{
SimpleLogger
.
LogPriority
.
VERBOSE
->
Color
.
RESET
SimpleLogger
.
LogPriority
.
INFO
->
Color
.
LIGHT_GREEN
SimpleLogger
.
LogPriority
.
WARNING
->
Color
.
LIGHT_RED
SimpleLogger
.
LogPriority
.
ERROR
->
Color
.
RED
SimpleLogger
.
LogPriority
.
DEBUG
->
Color
.
LIGHT_CYAN
}
override
fun
verbose0
(
message
:
String
?)
=
printLog
(
message
,
SimpleLogger
.
LogPriority
.
VERBOSE
)
override
fun
verbose0
(
message
:
String
?,
e
:
Throwable
?)
{
if
(
e
!=
null
)
verbose
((
message
?:
e
.
toString
())
+
"\n${e.stackTraceString}"
)
else
verbose
(
message
.
toString
())
}
override
fun
info0
(
message
:
String
?)
=
out
(
message
,
"I"
,
Color
.
LIGHT_GREEN
)
override
fun
info0
(
message
:
String
?)
=
printLog
(
message
,
SimpleLogger
.
LogPriority
.
INFO
)
override
fun
info0
(
message
:
String
?,
e
:
Throwable
?)
{
if
(
e
!=
null
)
info
((
message
?:
e
.
toString
())
+
"\n${e.stackTraceString}"
)
else
info
(
message
.
toString
())
}
override
fun
warning0
(
message
:
String
?)
=
out
(
message
,
"W"
,
Color
.
LIGHT_RED
)
override
fun
warning0
(
message
:
String
?)
=
printLog
(
message
,
SimpleLogger
.
LogPriority
.
WARNING
)
override
fun
warning0
(
message
:
String
?,
e
:
Throwable
?)
{
if
(
e
!=
null
)
warning
((
message
?:
e
.
toString
())
+
"\n${e.stackTraceString}"
)
else
warning
(
message
.
toString
())
}
override
fun
error0
(
message
:
String
?)
=
out
(
message
,
"E"
,
Color
.
RED
)
override
fun
error0
(
message
:
String
?)
=
printLog
(
message
,
SimpleLogger
.
LogPriority
.
ERROR
)
override
fun
error0
(
message
:
String
?,
e
:
Throwable
?)
{
if
(
e
!=
null
)
error
((
message
?:
e
.
toString
())
+
"\n${e.stackTraceString}"
)
else
error
(
message
.
toString
())
}
override
fun
debug0
(
message
:
String
?)
=
out
(
message
,
"D"
,
Color
.
LIGHT_CYAN
)
override
fun
debug0
(
message
:
String
?)
=
printLog
(
message
,
SimpleLogger
.
LogPriority
.
DEBUG
)
override
fun
debug0
(
message
:
String
?,
e
:
Throwable
?)
{
if
(
e
!=
null
)
debug
((
message
?:
e
.
toString
())
+
"\n${e.stackTraceString}"
)
else
debug
(
message
.
toString
())
}
private
val
timeFormat
=
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss"
,
Locale
.
SIMPLIFIED_CHINESE
)
@SinceMirai
(
"1.1.0"
)
protected
open
val
timeFormat
=
SimpleDateFormat
(
"yyyy-MM-dd HH:mm:ss"
,
Locale
.
SIMPLIFIED_CHINESE
)
private
val
currentTimeFormatted
get
()
=
timeFormat
.
format
(
Date
())
/**
* @author NaturalHG
*/
@Suppress
(
"unused"
)
private
enum
class
Color
(
private
val
format
:
String
)
{
@MiraiExperimentalAPI
(
"This is subject to change."
)
@SinceMirai
(
"1.1.0"
)
protected
enum
class
Color
(
private
val
format
:
String
)
{
RESET
(
"\u001b[0m"
),
WHITE
(
"\u001b[30m"
),
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/internal/asReusableInput.jvm.kt
View file @
579b8da7
...
...
@@ -11,6 +11,8 @@ import net.mamoe.mirai.message.data.toLongUnsigned
import
java.io.File
import
java.io.InputStream
internal
const
val
DEFAULT_REUSABLE_INPUT_BUFFER_SIZE
=
8192
internal
actual
fun
ByteArray
.
asReusableInput
():
ReusableInput
{
return
object
:
ReusableInput
{
override
val
md5
:
ByteArray
=
md5
()
...
...
@@ -18,9 +20,11 @@ internal actual fun ByteArray.asReusableInput(): ReusableInput {
override
fun
chunkedFlow
(
sizePerPacket
:
Int
):
ChunkedFlowSession
<
ChunkedInput
>
{
return
object
:
ChunkedFlowSession
<
ChunkedInput
>
{
override
val
flow
:
Flow
<
ChunkedInput
>
=
inputStream
().
chunkedFlow
(
sizePerPacket
)
private
val
stream
=
inputStream
()
override
val
flow
:
Flow
<
ChunkedInput
>
=
stream
.
chunkedFlow
(
sizePerPacket
,
ByteArray
(
DEFAULT_REUSABLE_INPUT_BUFFER_SIZE
.
coerceAtLeast
(
sizePerPacket
)))
override
fun
close
()
{
stream
.
close
()
// nothing to do
}
}
...
...
@@ -46,7 +50,7 @@ internal fun File.asReusableInput(deleteOnClose: Boolean): ReusableInput {
override
fun
chunkedFlow
(
sizePerPacket
:
Int
):
ChunkedFlowSession
<
ChunkedInput
>
{
val
stream
=
inputStream
()
return
object
:
ChunkedFlowSession
<
ChunkedInput
>
{
override
val
flow
:
Flow
<
ChunkedInput
>
=
stream
.
chunkedFlow
(
sizePerPacket
)
override
val
flow
:
Flow
<
ChunkedInput
>
=
stream
.
chunkedFlow
(
sizePerPacket
,
ByteArray
(
DEFAULT_REUSABLE_INPUT_BUFFER_SIZE
.
coerceAtLeast
(
sizePerPacket
))
)
override
fun
close
()
{
stream
.
close
()
if
(
deleteOnClose
)
this
@
asReusableInput
.
delete
()
...
...
@@ -72,7 +76,7 @@ internal fun File.asReusableInput(deleteOnClose: Boolean, md5: ByteArray): Reusa
override
fun
chunkedFlow
(
sizePerPacket
:
Int
):
ChunkedFlowSession
<
ChunkedInput
>
{
val
stream
=
inputStream
()
return
object
:
ChunkedFlowSession
<
ChunkedInput
>
{
override
val
flow
:
Flow
<
ChunkedInput
>
=
stream
.
chunkedFlow
(
sizePerPacket
)
override
val
flow
:
Flow
<
ChunkedInput
>
=
stream
.
chunkedFlow
(
sizePerPacket
,
ByteArray
(
DEFAULT_REUSABLE_INPUT_BUFFER_SIZE
.
coerceAtLeast
(
sizePerPacket
))
)
override
fun
close
()
{
stream
.
close
()
if
(
deleteOnClose
)
this
@
asReusableInput
.
delete
()
...
...
mirai-core/src/jvmTest/java/net/mamoe/mirai/event/JvmMethodEventsTestJava.java
0 → 100644
View file @
579b8da7
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package
net.mamoe.mirai.event
;
import
org.junit.Test
;
import
java.util.concurrent.atomic.AtomicInteger
;
import
static
kotlin
.
test
.
AssertionsKt
.
assertEquals
;
public
class
JvmMethodEventsTestJava
extends
SimpleListenerHost
{
private
final
AtomicInteger
called
=
new
AtomicInteger
(
0
);
@EventHandler
public
void
ev
(
TestEvent
event
)
{
called
.
incrementAndGet
();
}
@EventHandler
public
Void
ev2
(
TestEvent
event
)
{
called
.
incrementAndGet
();
return
null
;
}
@EventHandler
public
ListeningStatus
ev3
(
TestEvent
event
)
{
called
.
incrementAndGet
();
return
ListeningStatus
.
LISTENING
;
}
@EventHandler
public
void
ev
(
TestEvent
event
,
TestEvent
event2
)
{
called
.
incrementAndGet
();
}
@EventHandler
public
Void
ev2
(
TestEvent
event
,
TestEvent
event2
)
{
called
.
incrementAndGet
();
return
null
;
}
@EventHandler
public
ListeningStatus
ev3
(
TestEvent
event
,
TestEvent
event2
)
{
called
.
incrementAndGet
();
return
ListeningStatus
.
LISTENING
;
}
@Test
public
void
test
()
{
Events
.
registerEvents
(
this
);
EventKt
.
broadcast
(
new
TestEvent
());
assertEquals
(
6
,
called
.
get
(),
null
);
}
}
\ No newline at end of file
mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/event/JvmMethodEventsTest.kt
View file @
579b8da7
...
...
@@ -11,12 +11,12 @@
package
net.mamoe.mirai.event
import
junit.framework.TestCase.assertEquals
import
kotlinx.coroutines.CoroutineScope
import
net.mamoe.mirai.utils.internal.runBlocking
import
org.junit.Test
import
java.util.concurrent.atomic.AtomicInteger
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.test.assertEquals
internal
class
JvmMethodEventsTest
{
...
...
@@ -46,6 +46,13 @@ internal class JvmMethodEventsTest {
called
.
getAndIncrement
()
}
@Suppress
(
"unused"
)
@EventHandler
suspend
fun
`suspend
param
Void`
(
event
:
TestEvent
):
Void
?
{
called
.
getAndIncrement
()
return
null
}
@EventHandler
@Suppress
(
"unused"
)
fun
TestEvent
.
`receiver
param
Unit`
(
event
:
TestEvent
)
{
...
...
@@ -81,15 +88,15 @@ internal class JvmMethodEventsTest {
}
}
TestClass
().
run
{
this
.
registerEvents
()
runBlocking
{
TestEvent
().
broadcast
()
}
assertEquals
(
8
,
this
.
getCalled
())
}
//
TestClass().run {
//
this.registerEvents()
//
//
runBlocking {
//
TestEvent().broadcast()
//
}
//
// assertEquals(9
, this.getCalled())
//
}
}
@Test
...
...
@@ -114,14 +121,14 @@ internal class JvmMethodEventsTest {
}
}
TestClass
().
run
{
this
.
registerEvents
()
runBlocking
{
TestEvent
().
broadcast
()
}
assertEquals
(
1
,
this
.
getCalled
())
}
//
TestClass().run {
//
this.registerEvents()
//
//
runBlocking {
//
TestEvent().broadcast()
//
}
//
//
assertEquals(1, this.getCalled())
//
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment