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
eed9c8f1
Commit
eed9c8f1
authored
Oct 24, 2019
by
Him188
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Let BotNetworkHandler implements CoroutineScope
parent
b7628cd3
Changes
27
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
534 additions
and
374 deletions
+534
-374
build.gradle
build.gradle
+8
-10
dependencies.gradle
dependencies.gradle
+0
-44
gradle.properties
gradle.properties
+18
-0
mirai-console/build.gradle
mirai-console/build.gradle
+1
-13
mirai-core/build.gradle
mirai-core/build.gradle
+28
-30
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+1
-1
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
...core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
+7
-13
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
...rc/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
+72
-37
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt
.../net.mamoe.mirai/event/internal/InternalEventListeners.kt
+63
-11
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt
...nMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt
+21
-18
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt
...c/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt
+15
-6
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
....mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
+83
-37
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadFriendImage.kt
...oe.mirai/network/protocol/tim/packet/UploadFriendImage.kt
+8
-5
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadGroupImage.kt
...moe.mirai/network/protocol/tim/packet/UploadGroupImage.kt
+4
-4
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt
...n/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt
+2
-0
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BufferedImage.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/BufferedImage.kt
+17
-6
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt
.../commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt
+64
-20
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJvm.kt
.../src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJvm.kt
+30
-33
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt
...rc/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt
+14
-0
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventListeneresInternalJvm.kt
.../mamoe/mirai/event/internal/EventListeneresInternalJvm.kt
+5
-2
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BufferedImageJvm.kt
.../jvmMain/kotlin/net/mamoe/mirai/utils/BufferedImageJvm.kt
+29
-7
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt
.../jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt
+33
-49
mirai-debug/build.gradle
mirai-debug/build.gradle
+4
-5
mirai-debug/src/main/java/DownloadImgTest.kt
mirai-debug/src/main/java/DownloadImgTest.kt
+0
-12
mirai-demos/mirai-demo-1/build.gradle
mirai-demos/mirai-demo-1/build.gradle
+2
-2
mirai-demos/mirai-demo-1/build.gradle.kts
mirai-demos/mirai-demo-1/build.gradle.kts
+0
-0
mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
+5
-9
No files found.
build.gradle
View file @
eed9c8f1
...
@@ -2,12 +2,12 @@ buildscript {
...
@@ -2,12 +2,12 @@ buildscript {
ext
.
kotlin_version
=
'1.3.50'
ext
.
kotlin_version
=
'1.3.50'
repositories
{
repositories
{
google
()
mavenLocal
()
jcenter
()
mavenCentral
()
maven
{
url
"https://mirrors.huaweicloud.com/repository/maven/"
}
maven
{
url
"https://mirrors.huaweicloud.com/repository/maven/"
}
}
}
apply
from:
rootProject
.
file
(
'dependencies.gradle'
)
dependencies
{
dependencies
{
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath
"org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version"
classpath
"org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version"
...
@@ -16,14 +16,12 @@ buildscript {
...
@@ -16,14 +16,12 @@ buildscript {
allprojects
{
allprojects
{
group
=
"net.mamoe"
group
=
"net.mamoe"
version
=
"1.0"
version
=
getProperty
(
"mirai_version"
)
repositories
{
repositories
{
jcenter
()
//klock
mavenLocal
()
google
()
mavenCentral
()
jcenter
()
maven
{
url
"https://mirrors.huaweicloud.com/repository/maven/"
}
maven
{
url
"https://mirrors.huaweicloud.com/repository/maven/"
}
}
}
apply
from:
rootProject
.
file
(
'dependencies.gradle'
)
}
}
\ No newline at end of file
dependencies.gradle
deleted
100644 → 0
View file @
b7628cd3
ext
{
// dependencies
// kotlin
kotlinJvm
=
"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
kotlinCommon
=
"org.jetbrains.kotlin:kotlin-stdlib-common:$kotlin_version"
kotlinNative
=
"org.jetbrains.kotlin:kotlin-stdlib-native:$kotlin_version"
// kotlinx.coroutine
coroutine_version
=
"1.3.0"
coroutine
=
"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutine_version"
coroutineCommon
=
"org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$coroutine_version"
coroutineNative
=
"org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$coroutine_version"
coroutineAndroid
=
"org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutine_version"
coroutineJs
=
"org.jetbrains.kotlinx:kotlinx-coroutines-core-js:$coroutine_version"
coroutineIo
=
"org.jetbrains.kotlinx:kotlinx-coroutines-io:0.24.0"
// kotlin.reflect
reflect
=
"org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// kotlinx.atomicfu
atomicfu_version
=
"0.13.1"
atomicFUCommon
=
"org.jetbrains.kotlinx:atomicfu-common:$atomicfu_version"
// kotlinx.io
kotlinx_io_version
=
"0.1.15"
kotlinxIOJvm
=
"org.jetbrains.kotlinx:kotlinx-io-jvm:$kotlinx_io_version"
kotlinxIOCommon
=
"org.jetbrains.kotlinx:kotlinx-io:$kotlinx_io_version"
kotlinxIOJS
=
"org.jetbrains.kotlinx:kotlinx-io-js:$kotlinx_io_version"
kotlinxIONative
=
"org.jetbrains.kotlinx:kotlinx-io-native:$kotlinx_io_version"
// klock
klock
=
"com.soywiz.korlibs.klock:klock:1.7.0"
// ktor
ktor_version
=
"1.2.4"
ktorClientCore
=
"io.ktor:ktor-client-core:$ktor_version"
ktorClientCoreNative
=
"io.ktor:ktor-client-core-native:$ktor_version"
ktorClientCoreJvm
=
"io.ktor:ktor-client-core-jvm:$ktor_version"
ktorClientCio
=
"io.ktor:ktor-client-cio:$ktor_version"
ktorHttp
=
"io.ktor:ktor-http:$ktor_version"
ktorHttpCio
=
"io.ktor:ktor-http-cio:$ktor_version"
}
gradle.properties
0 → 100644
View file @
eed9c8f1
# style guide
kotlin.code.style
=
official
# config
mirai_version
=
1.0.0
kotlin.incremental.multiplatform
=
true
kotlin.parallel.tasks.in.project
=
true
# kotlin
kotlin_version
=
1.3.50
# kotlin libraries
serialization_version
=
0.13.0
coroutines_version
=
1.3.2
atomicfu_version
=
0.13.0
ktor_version
=
1.2.4
ktorio_version
=
1.3.0-beta-1
klock_version
=
1.7.0
kotlinxio_version
=
0.1.15
coroutinesio_version
=
0.24.0
# utility
mirai-console/build.gradle
View file @
eed9c8f1
apply
plugin:
"kotlin"
apply
plugin:
"kotlin"
apply
plugin:
"application"
apply
plugin:
"java"
apply
plugin:
"java"
dependencies
{
dependencies
{
compile
project
(
':mirai-core'
)
implementation
project
(
':mirai-core'
)
compile
rootProject
.
ext
.
kotlinCommon
compile
rootProject
.
ext
.
kotlinJvm
compile
rootProject
.
ext
.
reflect
compile
rootProject
.
ext
.
coroutine
}
sourceCompatibility
=
"11"
tasks
.
withType
(
JavaCompile
)
{
options
.
encoding
=
"UTF-8"
}
}
mirai-core/build.gradle
View file @
eed9c8f1
...
@@ -23,24 +23,21 @@ kotlin {
...
@@ -23,24 +23,21 @@ kotlin {
sourceSets
{
sourceSets
{
commonMain
{
commonMain
{
dependencies
{
dependencies
{
// https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-reflect
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-common'
,
version:
kotlin_version
implementation
rootProject
.
ext
.
kotlinCommon
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-reflect'
,
version:
kotlin_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-core-common'
,
version:
coroutines_version
implementation
rootProject
.
ext
.
reflect
api
group:
'org.jetbrains.kotlinx'
,
name:
'atomicfu-common'
,
version:
atomicfu_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-io'
,
version:
kotlinxio_version
//implementation rootProject.ext.coroutine
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-io'
,
version:
coroutinesio_version
implementation
rootProject
.
ext
.
coroutineCommon
implementation
rootProject
.
ext
.
coroutineIo
implementation
"com.soywiz.korlibs.klock:klock:$klock_version"
implementation
rootProject
.
ext
.
atomicFUCommon
api
group:
'io.ktor'
,
name:
'ktor-client-core'
,
version:
ktor_version
//api group: 'io.ktor', name: 'ktor-client-cio', version: ktor_version
implementation
rootProject
.
ext
.
kotlinxIOCommon
//api group: 'io.ktor', name: 'ktor-client', version: ktor_version
implementation
rootProject
.
ext
.
klock
api
group:
'io.ktor'
,
name:
'ktor-http'
,
version:
ktor_version
//api group: 'io.ktor', name: 'ktor-utils', version: ktor_version
implementation
rootProject
.
ext
.
ktorClientCore
//api group: 'io.ktor', name: 'ktor-io', version: ktorio_version
implementation
rootProject
.
ext
.
ktorClientCio
implementation
rootProject
.
ext
.
ktorHttp
implementation
rootProject
.
ext
.
ktorHttpCio
}
}
}
}
...
@@ -48,22 +45,23 @@ kotlin {
...
@@ -48,22 +45,23 @@ kotlin {
apply
plugin:
'java'
apply
plugin:
'java'
dependencies
{
dependencies
{
implementation
rootProject
.
ext
.
kotlinJvm
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib'
,
version:
kotlin_version
implementation
rootProject
.
ext
.
reflect
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-jdk8'
,
version:
kotlin_version
implementation
rootProject
.
ext
.
coroutine
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-reflect'
,
version:
kotlin_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-core'
,
version:
coroutines_version
implementation
rootProject
.
ext
.
kotlinxIOJvm
api
group:
'org.jetbrains.kotlinx'
,
name:
'atomicfu'
,
version:
atomicfu_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-io'
,
version:
kotlinxio_version
// api group: 'org.jetbrains.kotlinx', name: 'kotlinx-io-jvm', version: kotlinxio_version
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-io'
,
version:
coroutinesio_version
api
group:
'io.ktor'
,
name:
'ktor-http-cio'
,
version:
ktor_version
api
group:
'io.ktor'
,
name:
'ktor-http'
,
version:
ktor_version
api
group:
'io.ktor'
,
name:
'ktor-client-core-jvm'
,
version:
ktor_version
api
group:
'io.ktor'
,
name:
'ktor-client-cio'
,
version:
ktor_version
implementation
'org.yaml:snakeyaml:1.18'
implementation
'org.yaml:snakeyaml:1.18'
implementation
'org.jsoup:jsoup:1.12.1'
implementation
'org.jsoup:jsoup:1.12.1'
implementation
'org.ini4j:ini4j:0.5.2'
implementation
'org.ini4j:ini4j:0.5.2'
implementation
rootProject
.
ext
.
klock
implementation
rootProject
.
ext
.
ktorClientCore
implementation
rootProject
.
ext
.
ktorClientCoreJvm
implementation
rootProject
.
ext
.
ktorClientCio
implementation
rootProject
.
ext
.
ktorHttp
implementation
rootProject
.
ext
.
ktorHttpCio
}
}
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
View file @
eed9c8f1
...
@@ -110,7 +110,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
...
@@ -110,7 +110,7 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
}
}
}
}
fun
close
()
{
suspend
fun
close
()
{
this
.
network
.
close
()
this
.
network
.
close
()
this
.
contacts
.
groups
.
clear
()
this
.
contacts
.
groups
.
clear
()
this
.
contacts
.
qqs
.
clear
()
this
.
contacts
.
qqs
.
clear
()
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Event.kt
View file @
eed9c8f1
...
@@ -4,13 +4,14 @@ package net.mamoe.mirai.event
...
@@ -4,13 +4,14 @@ package net.mamoe.mirai.event
import
kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineExceptionHandler
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.
Dispatchers
import
kotlinx.coroutines.
newCoroutineContext
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withContext
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.contact.Contact
import
net.mamoe.mirai.event.internal.broadcastInternal
import
net.mamoe.mirai.event.internal.broadcastInternal
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.network.BotNetworkHandler
import
net.mamoe.mirai.utils.log
import
net.mamoe.mirai.utils.log
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.CoroutineContext
import
kotlin.coroutines.EmptyCoroutineContext
import
kotlin.jvm.JvmOverloads
import
kotlin.jvm.JvmOverloads
/**
/**
...
@@ -57,17 +58,8 @@ interface Cancellable {
...
@@ -57,17 +58,8 @@ interface Cancellable {
*/
*/
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
@JvmOverloads
@JvmOverloads
suspend
fun
<
E
:
Event
>
E
.
broadcast
(
context
:
CoroutineContext
?
=
CoroutineExceptionHandler
{
_
,
e
->
e
.
log
()
}):
E
{
suspend
fun
<
E
:
Event
>
E
.
broadcast
(
context
:
CoroutineContext
=
EmptyCoroutineContext
):
E
{
var
ctx
=
EventScope
.
coroutineContext
return
withContext
(
EventScope
.
newCoroutineContext
(
context
))
{
this
@
broadcast
.
broadcastInternal
()
}
if
(
context
==
null
)
{
ctx
+=
CoroutineExceptionHandler
{
_
,
e
->
e
.
log
()
}
}
else
{
ctx
+=
context
if
(
context
[
CoroutineExceptionHandler
]
==
null
)
{
ctx
+=
CoroutineExceptionHandler
{
_
,
e
->
e
.
log
()
}
}
}
return
withContext
(
ctx
)
{
this
@
broadcast
.
broadcastInternal
()
}
}
}
/**
/**
...
@@ -77,4 +69,6 @@ suspend fun <E : Event> E.broadcast(context: CoroutineContext? = CoroutineExcept
...
@@ -77,4 +69,6 @@ suspend fun <E : Event> E.broadcast(context: CoroutineContext? = CoroutineExcept
* 然而, 若在事件处理过程中使用到 [Contact.sendMessage] 等会 [发送数据包][BotNetworkHandler.sendPacket] 的方法,
* 然而, 若在事件处理过程中使用到 [Contact.sendMessage] 等会 [发送数据包][BotNetworkHandler.sendPacket] 的方法,
* 发送过程将会通过 [withContext] 将协程切换到 [BotNetworkHandler.NetworkScope]
* 发送过程将会通过 [withContext] 将协程切换到 [BotNetworkHandler.NetworkScope]
*/
*/
object
EventScope
:
CoroutineScope
by
CoroutineScope
(
Dispatchers
.
Default
)
//todo may change
object
EventScope
:
CoroutineScope
{
\ No newline at end of file
override
val
coroutineContext
:
CoroutineContext
=
EmptyCoroutineContext
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt
View file @
eed9c8f1
...
@@ -21,44 +21,72 @@ enum class ListeningStatus {
...
@@ -21,44 +21,72 @@ enum class ListeningStatus {
// region 顶层方法
// region 顶层方法
inline
fun
<
reified
E
:
Event
>
subscribe
(
noinline
handler
:
suspend
(
E
)
->
ListeningStatus
)
=
E
::
class
.
subscribe
(
handler
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribe
(
noinline
handler
:
suspend
(
E
)
->
ListeningStatus
)
=
E
::
class
.
subscribe
(
handler
)
inline
fun
<
reified
E
:
Event
>
subscribeAlways
(
noinline
listener
:
suspend
(
E
)
->
Unit
)
=
E
::
class
.
subscribeAlways
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeAlways
(
noinline
listener
:
suspend
(
E
)
->
Unit
)
=
E
::
class
.
subscribeAlways
(
listener
)
inline
fun
<
reified
E
:
Event
>
subscribeOnce
(
noinline
listener
:
suspend
(
E
)
->
Unit
)
=
E
::
class
.
subscribeOnce
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeOnce
(
noinline
listener
:
suspend
(
E
)
->
Unit
)
=
E
::
class
.
subscribeOnce
(
listener
)
inline
fun
<
reified
E
:
Event
,
T
>
subscribeUntil
(
valueIfStop
:
T
,
noinline
listener
:
suspend
(
E
)
->
T
)
=
E
::
class
.
subscribeUntil
(
valueIfStop
,
listener
)
suspend
inline
fun
<
reified
E
:
Event
,
T
>
subscribeUntil
(
valueIfStop
:
T
,
noinline
listener
:
suspend
(
E
)
->
T
)
=
inline
fun
<
reified
E
:
Event
>
subscribeUntilFalse
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeUntilFalse
(
listener
)
E
::
class
.
subscribeUntil
(
valueIfStop
,
listener
)
inline
fun
<
reified
E
:
Event
>
subscribeUntilTrue
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeUntilTrue
(
listener
)
inline
fun
<
reified
E
:
Event
>
subscribeUntilNull
(
noinline
listener
:
suspend
(
E
)
->
Any
?)
=
E
::
class
.
subscribeUntilNull
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeUntilFalse
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeUntilFalse
(
listener
)
inline
fun
<
reified
E
:
Event
,
T
>
subscribeWhile
(
valueIfContinue
:
T
,
noinline
listener
:
suspend
(
E
)
->
T
)
=
E
::
class
.
subscribeWhile
(
valueIfContinue
,
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeUntilTrue
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
inline
fun
<
reified
E
:
Event
>
subscribeWhileFalse
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeWhileFalse
(
listener
)
E
::
class
.
subscribeUntilTrue
(
listener
)
inline
fun
<
reified
E
:
Event
>
subscribeWhileTrue
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeWhileTrue
(
listener
)
inline
fun
<
reified
E
:
Event
>
subscribeWhileNull
(
noinline
listener
:
suspend
(
E
)
->
Any
?)
=
E
::
class
.
subscribeWhileNull
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeUntilNull
(
noinline
listener
:
suspend
(
E
)
->
Any
?)
=
E
::
class
.
subscribeUntilNull
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
,
T
>
subscribeWhile
(
valueIfContinue
:
T
,
noinline
listener
:
suspend
(
E
)
->
T
)
=
E
::
class
.
subscribeWhile
(
valueIfContinue
,
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeWhileFalse
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeWhileFalse
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeWhileTrue
(
noinline
listener
:
suspend
(
E
)
->
Boolean
)
=
E
::
class
.
subscribeWhileTrue
(
listener
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeWhileNull
(
noinline
listener
:
suspend
(
E
)
->
Any
?)
=
E
::
class
.
subscribeWhileNull
(
listener
)
// endregion
// endregion
// region KClass 的扩展方法 (不推荐)
// region KClass 的扩展方法 (不推荐)
fun
<
E
:
Event
>
KClass
<
E
>.
subscribe
(
handler
:
suspend
(
E
)
->
ListeningStatus
)
=
this
.
subscribeInternal
(
Handler
(
handler
))
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribe
(
handler
:
suspend
(
E
)
->
ListeningStatus
)
=
this
.
subscribeInternal
(
Handler
(
handler
))
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeAlways
(
listener
:
suspend
(
E
)
->
Unit
)
=
this
.
subscribeInternal
(
Handler
{
listener
(
it
);
ListeningStatus
.
LISTENING
})
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeAlways
(
listener
:
suspend
(
E
)
->
Unit
)
=
this
.
subscribeInternal
(
Handler
{
listener
(
it
);
ListeningStatus
.
LISTENING
})
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeOnce
(
listener
:
suspend
(
E
)
->
Unit
)
=
this
.
subscribeInternal
(
Handler
{
listener
(
it
);
ListeningStatus
.
STOPPED
})
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeOnce
(
listener
:
suspend
(
E
)
->
Unit
)
=
this
.
subscribeInternal
(
Handler
{
listener
(
it
);
ListeningStatus
.
STOPPED
})
suspend
fun
<
E
:
Event
,
T
>
KClass
<
E
>.
subscribeUntil
(
valueIfStop
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
subscribeInternal
(
Handler
{
if
(
listener
(
it
)
===
valueIfStop
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
fun
<
E
:
Event
,
T
>
KClass
<
E
>.
subscribeUntil
(
valueIfStop
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
subscribeInternal
(
Handler
{
if
(
listener
(
it
)
===
valueIfStop
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeUntilFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeUntilFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeUntil
(
false
,
listener
)
subscribeUntil
(
false
,
listener
)
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeUntilTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeUntil
(
true
,
listener
)
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeUntilNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
subscribeUntil
(
null
,
listener
)
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeUntilTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeUntil
(
true
,
listener
)
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeUntilNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
subscribeUntil
(
null
,
listener
)
fun
<
E
:
Event
,
T
>
KClass
<
E
>.
subscribeWhile
(
valueIfContinue
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
subscribeInternal
(
Handler
{
if
(
listener
(
it
)
!==
valueIfContinue
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeWhileFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeWhile
(
false
,
listener
)
suspend
fun
<
E
:
Event
,
T
>
KClass
<
E
>.
subscribeWhile
(
valueIfContinue
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeWhileTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeWhile
(
true
,
listener
)
subscribeInternal
(
Handler
{
if
(
listener
(
it
)
!==
valueIfContinue
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
})
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeWhileNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
subscribeWhile
(
null
,
listener
)
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeWhileFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeWhile
(
false
,
listener
)
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeWhileTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
subscribeWhile
(
true
,
listener
)
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeWhileNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
subscribeWhile
(
null
,
listener
)
// endregion
// endregion
...
@@ -68,15 +96,18 @@ fun <E : Event> KClass<E>.subscribeWhileNull(listener: suspend (E) -> Any?) = su
...
@@ -68,15 +96,18 @@ fun <E : Event> KClass<E>.subscribeWhileNull(listener: suspend (E) -> Any?) = su
* 监听一个事件. 可同时进行多种方式的监听
* 监听一个事件. 可同时进行多种方式的监听
* @see ListenerBuilder
* @see ListenerBuilder
*/
*/
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeAll
(
listeners
:
ListenerBuilder
<
E
>.()
->
Unit
)
{
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeAll
(
listeners
:
suspend
ListenerBuilder
<
E
>.()
->
Unit
)
{
ListenerBuilder
<
E
>
{
this
.
subscribeInternal
(
it
)
}.
apply
(
listeners
)
with
(
ListenerBuilder
<
E
>
{
this
.
subscribeInternal
(
it
)
})
{
listeners
()
}
}
}
/**
/**
* 监听一个事件. 可同时进行多种方式的监听
* 监听一个事件. 可同时进行多种方式的监听
* @see ListenerBuilder
* @see ListenerBuilder
*/
*/
inline
fun
<
reified
E
:
Event
>
subscribeAll
(
noinline
listeners
:
ListenerBuilder
<
E
>.()
->
Unit
)
=
E
::
class
.
subscribeAll
(
listeners
)
suspend
inline
fun
<
reified
E
:
Event
>
subscribeAll
(
noinline
listeners
:
suspend
ListenerBuilder
<
E
>.()
->
Unit
)
=
E
::
class
.
subscribeAll
(
listeners
)
/**
/**
* 监听构建器. 可同时进行多种方式的监听
* 监听构建器. 可同时进行多种方式的监听
...
@@ -96,27 +127,31 @@ inline fun <reified E : Event> subscribeAll(noinline listeners: ListenerBuilder<
...
@@ -96,27 +127,31 @@ inline fun <reified E : Event> subscribeAll(noinline listeners: ListenerBuilder<
*/
*/
@Suppress
(
"MemberVisibilityCanBePrivate"
,
"unused"
)
@Suppress
(
"MemberVisibilityCanBePrivate"
,
"unused"
)
inline
class
ListenerBuilder
<
out
E
:
Event
>(
inline
class
ListenerBuilder
<
out
E
:
Event
>(
private
val
handlerConsumer
:
(
Handler
<
in
E
>)
->
Unit
private
val
handlerConsumer
:
suspend
(
Handler
<
in
E
>)
->
Unit
)
{
)
{
fun
handler
(
listener
:
suspend
(
E
)
->
ListeningStatus
)
{
suspend
fun
handler
(
listener
:
suspend
(
E
)
->
ListeningStatus
)
{
handlerConsumer
(
Handler
(
listener
))
handlerConsumer
(
Handler
(
listener
))
}
}
fun
always
(
listener
:
suspend
(
E
)
->
Unit
)
=
handler
{
listener
(
it
);
ListeningStatus
.
LISTENING
}
suspend
fun
always
(
listener
:
suspend
(
E
)
->
Unit
)
=
handler
{
listener
(
it
);
ListeningStatus
.
LISTENING
}
suspend
fun
<
T
>
until
(
until
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
handler
{
if
(
listener
(
it
)
===
until
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
}
suspend
fun
untilFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
until
(
false
,
listener
)
suspend
fun
untilTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
until
(
true
,
listener
)
suspend
fun
untilNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
until
(
null
,
listener
)
fun
<
T
>
until
(
until
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
handler
{
if
(
listener
(
it
)
===
until
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
}
fun
untilFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
until
(
false
,
listener
)
fun
untilTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
until
(
true
,
listener
)
fun
untilNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
until
(
null
,
listener
)
suspend
fun
<
T
>
`while`
(
until
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
handler
{
if
(
listener
(
it
)
!==
until
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
}
fun
<
T
>
`while`
(
until
:
T
,
listener
:
suspend
(
E
)
->
T
)
=
handler
{
if
(
listener
(
it
)
!==
until
)
ListeningStatus
.
STOPPED
else
ListeningStatus
.
LISTENING
}
suspend
fun
whileFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
`while`
(
false
,
listener
)
fun
whileFalse
(
listener
:
suspend
(
E
)
->
Boolean
)
=
`while`
(
false
,
listener
)
suspend
fun
whileTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
`while`
(
true
,
listener
)
fun
whileTrue
(
listener
:
suspend
(
E
)
->
Boolean
)
=
`while`
(
true
,
listener
)
suspend
fun
whileNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
`while`
(
null
,
listener
)
fun
whileNull
(
listener
:
suspend
(
E
)
->
Any
?)
=
`while`
(
null
,
listener
)
fun
once
(
block
:
suspend
(
E
)
->
Unit
)
=
handler
{
block
(
it
);
ListeningStatus
.
STOPPED
}
suspend
fun
once
(
block
:
suspend
(
E
)
->
Unit
)
=
handler
{
block
(
it
);
ListeningStatus
.
STOPPED
}
}
}
// endregion
// endregion
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt
View file @
eed9c8f1
package
net.mamoe.mirai.event.internal
package
net.mamoe.mirai.event.internal
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.withLock
import
kotlinx.coroutines.sync.withLock
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.event.Event
import
net.mamoe.mirai.event.EventScope
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.utils.inlinedRemoveIf
import
net.mamoe.mirai.utils.inlinedRemoveIf
import
kotlin.reflect.KClass
import
kotlin.reflect.KClass
/**
/**
* 监听和广播实现
* 监听和广播实现.
* 它会首先检查这个事件是否正在被广播
* - 如果是, 则将新的监听者放入缓存中. 在当前广播结束后转移到主列表 (通过一个协程完成)
* - 如果不是, 则直接将新的监听者放入主列表
*
*
* @author Him188moe
* @author Him188moe
*/
*/
internal
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeInternal
(
listener
:
Listener
<
E
>)
=
this
.
listeners
.
add
(
listener
)
//TODO lock or sth else
internal
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
subscribeInternal
(
listener
:
Listener
<
E
>):
Unit
=
with
(
this
.
listeners
())
{
if
(
mainMutex
.
tryLock
())
{
//能锁则代表这个事件目前没有正在广播.
try
{
add
(
listener
)
//直接修改主监听者列表
}
finally
{
mainMutex
.
unlock
()
}
return
}
//不能锁住, 则这个事件正在广播, 那么要将新的监听者放入缓存
cacheMutex
.
withLock
{
cache
.
add
(
listener
)
}
EventScope
.
launch
{
//启动协程并等待正在进行的广播结束, 然后将缓存转移到主监听者列表
//启动后的协程马上就会因为锁而被挂起
mainMutex
.
withLock
{
if
(
cache
.
size
!=
0
)
{
addAll
(
cache
)
cache
.
clear
()
}
}
}
}
/**
/**
* 事件监听器
* 事件监听器
...
@@ -31,18 +61,37 @@ class Handler<E : Event>(val handler: suspend (E) -> ListeningStatus) : Listener
...
@@ -31,18 +61,37 @@ class Handler<E : Event>(val handler: suspend (E) -> ListeningStatus) : Listener
override
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
=
handler
.
invoke
(
event
)
override
suspend
fun
onEvent
(
event
:
E
):
ListeningStatus
=
handler
.
invoke
(
event
)
}
}
internal
val
<
E
:
Event
>
KClass
<
E
>.
listeners
:
EventListeners
<
E
>
get
()
=
EventListenerManger
.
get
(
this
)
/**
* 这个事件类的监听器 list
*/
internal
suspend
fun
<
E
:
Event
>
KClass
<
E
>.
listeners
():
EventListeners
<
E
>
=
EventListenerManger
.
get
(
this
)
internal
class
EventListeners
<
E
:
Event
>
:
MutableList
<
Listener
<
E
>>
by
mutableListOf
()
{
internal
class
EventListeners
<
E
:
Event
>
:
MutableList
<
Listener
<
E
>>
by
mutableListOf
()
{
val
lock
=
Mutex
()
/**
* 主监听者列表.
* 广播事件时使用这个锁.
*/
val
mainMutex
=
Mutex
()
/**
* 缓存(监听)事件时使用的锁
*/
val
cacheMutex
=
Mutex
()
/**
* 等待加入到主 list 的监听者. 务必使用 [cacheMutex]
*/
val
cache
:
MutableList
<
Listener
<
E
>>
=
mutableListOf
()
}
}
/**
* 管理每个事件 class 的 [EventListeners].
* [EventListeners] 是 lazy 的: 它们只会在被需要的时候才创建和存储.
*/
internal
object
EventListenerManger
{
internal
object
EventListenerManger
{
private
val
registries
:
MutableMap
<
KClass
<
out
Event
>,
EventListeners
<
out
Event
>>
=
mutableMapOf
()
private
val
registries
:
MutableMap
<
KClass
<
out
Event
>,
EventListeners
<
out
Event
>>
=
mutableMapOf
()
private
val
registriesMutex
=
Mutex
()
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
internal
fun
<
E
:
Event
>
get
(
clazz
:
KClass
<
E
>):
EventListeners
<
E
>
{
internal
suspend
fun
<
E
:
Event
>
get
(
clazz
:
KClass
<
E
>):
EventListeners
<
E
>
=
registriesMutex
.
withLock
{
//synchronized(clazz) {
if
(
registries
.
containsKey
(
clazz
))
{
if
(
registries
.
containsKey
(
clazz
))
{
return
registries
[
clazz
]
as
EventListeners
<
E
>
return
registries
[
clazz
]
as
EventListeners
<
E
>
}
else
{
}
else
{
...
@@ -51,21 +100,24 @@ internal object EventListenerManger {
...
@@ -51,21 +100,24 @@ internal object EventListenerManger {
return
it
return
it
}
}
}
}
//}
}
}
}
}
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
internal
suspend
fun
<
E
:
Event
>
E
.
broadcastInternal
():
E
{
internal
suspend
fun
<
E
:
Event
>
E
.
broadcastInternal
():
E
{
suspend
fun
callListeners
(
listeners
:
EventListeners
<
in
E
>)
=
listeners
.
lock
.
withLock
{
//FIXME 若一个 listener 阻塞, 则这个事件全部阻塞.
//fixme 这个锁会导致在事件处理时再监听这个事件死锁
suspend
fun
callListeners
(
listeners
:
EventListeners
<
in
E
>)
=
listeners
.
mainMutex
.
withLock
{
listeners
.
inlinedRemoveIf
{
it
.
onEvent
(
this
)
==
ListeningStatus
.
STOPPED
}
listeners
.
inlinedRemoveIf
{
it
.
onEvent
(
this
)
==
ListeningStatus
.
STOPPED
}
}
}
callListeners
(
this
::
class
.
listeners
as
EventListeners
<
in
E
>)
callListeners
(
this
::
class
.
listeners
()
as
EventListeners
<
in
E
>)
//FIXME 这可能不支持所有的平台. 可能需要修改.
loopAllListeners
(
this
::
class
)
{
callListeners
(
it
as
EventListeners
<
in
E
>)
}
loopAllListeners
(
this
::
class
)
{
callListeners
(
it
as
EventListeners
<
in
E
>)
}
return
this
return
this
}
}
internal
expect
inline
fun
<
E
:
Event
>
loopAllListeners
(
clazz
:
KClass
<
E
>,
consumer
:
(
EventListeners
<
in
E
>)
->
Unit
)
internal
expect
suspend
inline
fun
<
E
:
Event
>
loopAllListeners
(
\ No newline at end of file
clazz
:
KClass
<
E
>,
consumer
:
(
EventListeners
<
in
E
>)
->
Unit
)
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt
View file @
eed9c8f1
...
@@ -28,27 +28,25 @@ import kotlin.coroutines.ContinuationInterceptor
...
@@ -28,27 +28,25 @@ import kotlin.coroutines.ContinuationInterceptor
* - [EventPacketHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket])
* - [EventPacketHandler] 处理消息相关(群消息/好友消息)([ServerEventPacket])
* - [ActionPacketHandler] 处理动作相关(踢人/加入群/好友列表等)
* - [ActionPacketHandler] 处理动作相关(踢人/加入群/好友列表等)
*
*
* A BotNetworkHandler is used to connect with Tencent servers.
*
*/
* NetworkHandler 实现接口 [CoroutineScope]
@Suppress
(
"PropertyName"
)
* 即 [BotNetworkHandler] 自己就是作用域.
interface
BotNetworkHandler
<
Socket
:
DataPacketSocketAdapter
>
{
/**
* [BotNetworkHandler] 的协程作用域.
* 所有 [BotNetworkHandler] 的协程均启动在此作用域下.
* 所有 [BotNetworkHandler] 的协程均启动在此作用域下.
*
*
* [BotNetworkHandler] 的协程包含:
* [BotNetworkHandler] 的协程包含:
* - UDP 包接收: [PlatformDatagramChannel.read]
* - UDP 包接收: [PlatformDatagramChannel.read]
* - 心跳 Job [HeartbeatPacket]
* - 心跳 Job [HeartbeatPacket]
* - SKey 刷新 [RefreshSKeyRequestPa
cket]
* - SKey 刷新 [ReuestSKeyP
cket]
* - 所有数据包处理和发送
* - 所有数据包处理和发送
*
*
* [BotNetworkHandler.close] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程
* [BotNetworkHandler.close] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程
*
* A BotNetworkHandler is used to connect with Tencent servers.
*/
*/
val
NetworkScope
:
CoroutineScope
@Suppress
(
"PropertyName"
)
interface
BotNetworkHandler
<
Socket
:
DataPacketSocketAdapter
>
:
CoroutineScope
{
val
socket
:
Socket
val
socket
:
Socket
/**
/**
* 得到 [PacketHandler].
* 得到 [PacketHandler].
* `get(EventPacketHandler)` 返回 [EventPacketHandler]
* `get(EventPacketHandler)` 返回 [EventPacketHandler]
...
@@ -76,8 +74,13 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> {
...
@@ -76,8 +74,13 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> {
*/
*/
suspend
fun
sendPacket
(
packet
:
OutgoingPacket
)
suspend
fun
sendPacket
(
packet
:
OutgoingPacket
)
fun
close
(
cause
:
Throwable
?
=
null
)
{
/**
* 等待直到与服务器断开连接. 若未连接则立即返回
*/
suspend
fun
awaitDisconnection
()
suspend
fun
close
(
cause
:
Throwable
?
=
null
)
{
//todo check??
//todo check??
NetworkScope
.
coroutineContext
[
ContinuationInterceptor
]
!!
.
cancelChildren
(
CancellationException
(
"handler closed"
,
cause
))
coroutineContext
[
ContinuationInterceptor
]
!!
.
cancelChildren
(
CancellationException
(
"handler closed"
,
cause
))
}
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotSession.kt
View file @
eed9c8f1
...
@@ -6,6 +6,7 @@ import kotlinx.coroutines.CompletableDeferred
...
@@ -6,6 +6,7 @@ import kotlinx.coroutines.CompletableDeferred
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.CoroutineScope
import
kotlinx.coroutines.Job
import
kotlinx.coroutines.Job
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import
net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler
import
net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler
import
net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
import
net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
import
net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
import
net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
...
@@ -14,6 +15,12 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
...
@@ -14,6 +15,12 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import
net.mamoe.mirai.utils.getGTK
import
net.mamoe.mirai.utils.getGTK
import
kotlin.coroutines.coroutineContext
import
kotlin.coroutines.coroutineContext
internal
fun
TIMBotNetworkHandler
.
BotSession
(
bot
:
Bot
,
sessionKey
:
ByteArray
,
socket
:
DataPacketSocketAdapter
)
=
BotSession
(
bot
,
sessionKey
,
socket
,
this
)
/**
/**
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
* 此时建立 session, 然后开始处理事务.
* 此时建立 session, 然后开始处理事务.
...
@@ -66,7 +73,8 @@ class BotSession(
...
@@ -66,7 +73,8 @@ class BotSession(
* @param handler 处理期待的包
* @param handler 处理期待的包
*/
*/
suspend
inline
fun
<
reified
P
:
ServerPacket
,
R
>
OutgoingPacket
.
sendAndExpect
(
noinline
handler
:
suspend
(
P
)
->
R
):
CompletableDeferred
<
R
>
{
suspend
inline
fun
<
reified
P
:
ServerPacket
,
R
>
OutgoingPacket
.
sendAndExpect
(
noinline
handler
:
suspend
(
P
)
->
R
):
CompletableDeferred
<
R
>
{
val
deferred
:
CompletableDeferred
<
R
>
=
coroutineContext
[
Job
].
takeIf
{
it
!=
null
}
?.
let
{
CompletableDeferred
<
R
>(
it
)
}
?:
CompletableDeferred
()
val
deferred
:
CompletableDeferred
<
R
>
=
coroutineContext
[
Job
].
takeIf
{
it
!=
null
}
?.
let
{
CompletableDeferred
<
R
>(
it
)
}
?:
CompletableDeferred
()
bot
.
network
.
addHandler
(
TemporaryPacketHandler
(
P
::
class
,
deferred
,
this
@BotSession
).
also
{
bot
.
network
.
addHandler
(
TemporaryPacketHandler
(
P
::
class
,
deferred
,
this
@BotSession
).
also
{
it
.
toSend
(
this
)
it
.
toSend
(
this
)
it
.
onExpect
(
handler
)
it
.
onExpect
(
handler
)
...
@@ -74,7 +82,8 @@ class BotSession(
...
@@ -74,7 +82,8 @@ class BotSession(
return
deferred
return
deferred
}
}
suspend
inline
fun
<
reified
P
:
ServerPacket
>
OutgoingPacket
.
sendAndExpect
():
CompletableDeferred
<
Unit
>
=
sendAndExpect
<
P
,
Unit
>
{}
suspend
inline
fun
<
reified
P
:
ServerPacket
>
OutgoingPacket
.
sendAndExpect
():
CompletableDeferred
<
Unit
>
=
sendAndExpect
<
P
,
Unit
>
{}
suspend
inline
fun
OutgoingPacket
.
send
()
=
socket
.
sendPacket
(
this
)
suspend
inline
fun
OutgoingPacket
.
send
()
=
socket
.
sendPacket
(
this
)
}
}
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/TIMBotNetworkHandler.kt
View file @
eed9c8f1
...
@@ -5,7 +5,6 @@ import kotlinx.coroutines.sync.Mutex
...
@@ -5,7 +5,6 @@ import kotlinx.coroutines.sync.Mutex
import
kotlinx.coroutines.sync.withLock
import
kotlinx.coroutines.sync.withLock
import
kotlinx.io.core.*
import
kotlinx.io.core.*
import
net.mamoe.mirai.*
import
net.mamoe.mirai.*
import
net.mamoe.mirai.event.EventScope
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.event.ListeningStatus
import
net.mamoe.mirai.event.broadcast
import
net.mamoe.mirai.event.broadcast
import
net.mamoe.mirai.event.events.BeforePacketSendEvent
import
net.mamoe.mirai.event.events.BeforePacketSendEvent
...
@@ -26,14 +25,18 @@ import net.mamoe.mirai.network.session
...
@@ -26,14 +25,18 @@ import net.mamoe.mirai.network.session
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.*
import
net.mamoe.mirai.utils.io.parseServerPacket
import
net.mamoe.mirai.utils.io.parseServerPacket
import
net.mamoe.mirai.utils.io.toUHexString
import
net.mamoe.mirai.utils.io.toUHexString
import
kotlin.coroutines.CoroutineContext
/**
/**
* [BotNetworkHandler] 的 TIM PC 协议实现
* [BotNetworkHandler] 的 TIM PC 协议实现
*
*
* @see BotNetworkHandler
* @see BotNetworkHandler
*/
*/
internal
class
TIMBotNetworkHandler
internal
constructor
(
private
val
bot
:
Bot
)
:
BotNetworkHandler
<
TIMBotNetworkHandler
.
BotSocketAdapter
>,
PacketHandlerList
()
{
internal
class
TIMBotNetworkHandler
internal
constructor
(
private
val
bot
:
Bot
)
:
override
val
NetworkScope
:
CoroutineScope
=
CoroutineScope
(
Dispatchers
.
Default
)
BotNetworkHandler
<
TIMBotNetworkHandler
.
BotSocketAdapter
>,
PacketHandlerList
()
{
override
val
coroutineContext
:
CoroutineContext
=
Dispatchers
.
Default
+
CoroutineExceptionHandler
{
_
,
e
->
bot
.
logger
.
log
(
e
)
}
override
lateinit
var
socket
:
BotSocketAdapter
override
lateinit
var
socket
:
BotSocketAdapter
private
set
private
set
...
@@ -76,7 +79,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -76,7 +79,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
//private | internal
//private | internal
private
fun
onLoggedIn
(
sessionKey
:
ByteArray
)
{
private
fun
onLoggedIn
(
sessionKey
:
ByteArray
)
{
require
(
size
==
0
)
{
"Already logged in"
}
require
(
size
==
0
)
{
"Already logged in"
}
val
session
=
BotSession
(
bot
,
sessionKey
,
socket
,
NetworkScope
)
val
session
=
BotSession
(
bot
,
sessionKey
,
socket
)
add
(
EventPacketHandler
(
session
).
asNode
(
EventPacketHandler
))
add
(
EventPacketHandler
(
session
).
asNode
(
EventPacketHandler
))
add
(
ActionPacketHandler
(
session
).
asNode
(
ActionPacketHandler
))
add
(
ActionPacketHandler
(
session
).
asNode
(
ActionPacketHandler
))
...
@@ -85,14 +88,20 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -85,14 +88,20 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
private
lateinit
var
sessionKey
:
ByteArray
private
lateinit
var
sessionKey
:
ByteArray
override
fun
close
(
cause
:
Throwable
?)
{
override
suspend
fun
awaitDisconnection
()
{
heartbeatJob
?.
join
()
}
override
suspend
fun
close
(
cause
:
Throwable
?)
{
super
.
close
(
cause
)
super
.
close
(
cause
)
this
.
heartbeatJob
?.
cancel
(
CancellationException
(
"handler closed"
))
this
.
heartbeatJob
?.
cancel
(
CancellationException
(
"handler closed"
))
this
.
heartbeatJob
?.
join
()
//等待 cancel 完成
this
.
heartbeatJob
=
null
this
.
heartbeatJob
=
null
if
(!
this
.
loginResult
.
isCompleted
&&
!
this
.
loginResult
.
isCancelled
)
{
if
(!
this
.
loginResult
.
isCompleted
&&
!
this
.
loginResult
.
isCancelled
)
{
this
.
loginResult
.
cancel
(
CancellationException
(
"socket closed"
))
this
.
loginResult
.
cancel
(
CancellationException
(
"socket closed"
))
this
.
loginResult
.
join
()
}
}
this
.
forEach
{
this
.
forEach
{
...
@@ -104,7 +113,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -104,7 +113,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
override
suspend
fun
sendPacket
(
packet
:
OutgoingPacket
)
=
socket
.
sendPacket
(
packet
)
override
suspend
fun
sendPacket
(
packet
:
OutgoingPacket
)
=
socket
.
sendPacket
(
packet
)
internal
inner
class
BotSocketAdapter
(
override
val
serverIp
:
String
,
val
configuration
:
BotNetworkConfiguration
)
:
DataPacketSocketAdapter
{
internal
inner
class
BotSocketAdapter
(
override
val
serverIp
:
String
,
val
configuration
:
BotNetworkConfiguration
)
:
DataPacketSocketAdapter
{
override
val
channel
:
PlatformDatagramChannel
=
PlatformDatagramChannel
(
serverIp
,
8000
)
override
val
channel
:
PlatformDatagramChannel
=
PlatformDatagramChannel
(
serverIp
,
8000
)
override
val
isOpen
:
Boolean
get
()
=
channel
.
isOpen
override
val
isOpen
:
Boolean
get
()
=
channel
.
isOpen
...
@@ -130,15 +140,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -130,15 +140,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
continue
continue
}
}
NetworkScope
.
launch
{
launch
{
try
{
//`.use`: Ensure that the packet is consumed totally so that all the buffers are released
//`.use`: Ensure that the packet is consumed totally so that all the buffers are released
ByteReadPacket
(
buffer
,
IoBuffer
.
Pool
).
use
{
ByteReadPacket
(
buffer
,
IoBuffer
.
Pool
).
use
{
distributePacket
(
it
.
parseServerPacket
(
buffer
.
readRemaining
))
distributePacket
(
it
.
parseServerPacket
(
buffer
.
readRemaining
))
}
}
}
catch
(
e
:
Throwable
)
{
e
.
log
()
}
}
}
}
}
}
}
...
@@ -150,8 +156,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -150,8 +156,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
val
expect
=
expectPacket
<
ServerTouchResponsePacket
>()
val
expect
=
expectPacket
<
ServerTouchResponsePacket
>()
NetworkScope
.
launch
{
processReceive
()
}
launch
{
processReceive
()
}
NetworkScope
.
launch
{
launch
{
if
(
withTimeoutOrNull
(
configuration
.
touchTimeout
.
millisecondsLong
)
{
expect
.
join
()
}
==
null
)
{
if
(
withTimeoutOrNull
(
configuration
.
touchTimeout
.
millisecondsLong
)
{
expect
.
join
()
}
==
null
)
{
loginResult
.
complete
(
LoginResult
.
TIMEOUT
)
loginResult
.
complete
(
LoginResult
.
TIMEOUT
)
}
}
...
@@ -161,7 +167,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -161,7 +167,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
return
loginResult
.
await
()
return
loginResult
.
await
()
}
}
private
inline
fun
<
reified
P
:
ServerPacket
>
expectPacket
():
CompletableDeferred
<
P
>
{
private
suspend
inline
fun
<
reified
P
:
ServerPacket
>
expectPacket
():
CompletableDeferred
<
P
>
{
val
receiving
=
CompletableDeferred
<
P
>()
val
receiving
=
CompletableDeferred
<
P
>()
subscribe
<
ServerPacketReceivedEvent
>
{
subscribe
<
ServerPacketReceivedEvent
>
{
if
(
it
.
packet
is
P
&&
it
.
bot
===
bot
)
{
if
(
it
.
packet
is
P
&&
it
.
bot
===
bot
)
{
...
@@ -173,7 +179,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -173,7 +179,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
return
receiving
return
receiving
}
}
override
suspend
fun
distributePacket
(
packet
:
ServerPacket
)
{
override
suspend
fun
distributePacket
(
packet
:
ServerPacket
)
=
coroutineScope
{
try
{
try
{
packet
.
decode
()
packet
.
decode
()
}
catch
(
e
:
Exception
)
{
}
catch
(
e
:
Exception
)
{
...
@@ -197,13 +203,13 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -197,13 +203,13 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
if
(
packet
is
ServerEventPacket
)
{
if
(
packet
is
ServerEventPacket
)
{
//no need to sync acknowledgement packets
//no need to sync acknowledgement packets
NetworkScope
.
launch
{
launch
{
sendPacket
(
packet
.
ResponsePacket
(
bot
.
qqAccount
,
sessionKey
))
sendPacket
(
packet
.
ResponsePacket
(
bot
.
qqAccount
,
sessionKey
))
}
}
}
}
if
(
ServerPacketReceivedEvent
(
bot
,
packet
).
broadcast
().
cancelled
)
{
if
(
ServerPacketReceivedEvent
(
bot
,
packet
).
broadcast
().
cancelled
)
{
return
return
@
coroutineScope
}
}
loginHandler
.
onPacketReceived
(
packet
)
loginHandler
.
onPacketReceived
(
packet
)
...
@@ -231,11 +237,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -231,11 +237,11 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
}
}
}*/
}*/
override
suspend
fun
sendPacket
(
packet
:
OutgoingPacket
)
=
withContext
(
NetworkScope
.
coroutineContext
)
{
override
suspend
fun
sendPacket
(
packet
:
OutgoingPacket
)
:
Unit
=
coroutineScope
{
check
(
channel
.
isOpen
)
{
"channel is not open"
}
check
(
channel
.
isOpen
)
{
"channel is not open"
}
if
(
BeforePacketSendEvent
(
bot
,
packet
).
broadcast
().
cancelled
)
{
if
(
BeforePacketSendEvent
(
bot
,
packet
).
broadcast
().
cancelled
)
{
return
@
withContext
return
@
coroutineScope
}
}
packet
.
packet
.
use
{
build
->
packet
.
packet
.
use
{
build
->
...
@@ -246,7 +252,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -246,7 +252,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
}
catch
(
e
:
SendPacketInternalException
)
{
}
catch
(
e
:
SendPacketInternalException
)
{
bot
.
logger
.
logError
(
"Caught SendPacketInternalException: ${e.cause?.message}"
)
bot
.
logger
.
logError
(
"Caught SendPacketInternalException: ${e.cause?.message}"
)
bot
.
reinitializeNetworkHandler
(
configuration
,
e
)
bot
.
reinitializeNetworkHandler
(
configuration
,
e
)
return
@
withContext
return
@
coroutineScope
}
finally
{
}
finally
{
buffer
.
release
(
IoBuffer
.
Pool
)
buffer
.
release
(
IoBuffer
.
Pool
)
}
}
...
@@ -254,7 +260,9 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -254,7 +260,9 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
bot
.
logGreen
(
"Packet sent: $packet"
)
bot
.
logGreen
(
"Packet sent: $packet"
)
EventScope
.
launch
{
PacketSentEvent
(
bot
,
packet
).
broadcast
()
}
PacketSentEvent
(
bot
,
packet
).
broadcast
()
Unit
}
}
override
val
owner
:
Bot
get
()
=
this
@TIMBotNetworkHandler
.
bot
override
val
owner
:
Bot
get
()
=
this
@TIMBotNetworkHandler
.
bot
...
@@ -307,7 +315,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -307,7 +315,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this
.
loginTime
=
packet
.
loginTime
this
.
loginTime
=
packet
.
loginTime
this
.
token0825
=
packet
.
token0825
this
.
token0825
=
packet
.
token0825
socket
.
sendPacket
(
OutgoingPasswordSubmissionPacket
(
socket
.
sendPacket
(
OutgoingPasswordSubmissionPacket
(
bot
=
bot
.
qqAccount
,
bot
=
bot
.
qqAccount
,
password
=
bot
.
account
.
password
,
password
=
bot
.
account
.
password
,
loginTime
=
loginTime
,
loginTime
=
loginTime
,
...
@@ -316,7 +325,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -316,7 +325,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
token0825
=
token0825
,
token0825
=
token0825
,
token00BA
=
null
,
token00BA
=
null
,
randomDeviceName
=
socket
.
configuration
.
randomDeviceName
randomDeviceName
=
socket
.
configuration
.
randomDeviceName
))
)
)
}
}
}
}
...
@@ -329,7 +339,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -329,7 +339,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
this
.
privateKey
=
getRandomByteArray
(
16
)
//似乎是必须的
this
.
privateKey
=
getRandomByteArray
(
16
)
//似乎是必须的
this
.
token00BA
=
packet
.
token00BA
this
.
token00BA
=
packet
.
token00BA
socket
.
sendPacket
(
OutgoingPasswordSubmissionPacket
(
socket
.
sendPacket
(
OutgoingPasswordSubmissionPacket
(
bot
=
bot
.
qqAccount
,
bot
=
bot
.
qqAccount
,
password
=
bot
.
account
.
password
,
password
=
bot
.
account
.
password
,
loginTime
=
loginTime
,
loginTime
=
loginTime
,
...
@@ -338,7 +349,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -338,7 +349,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
token0825
=
token0825
,
token0825
=
token0825
,
token00BA
=
packet
.
token00BA
,
token00BA
=
packet
.
token00BA
,
randomDeviceName
=
socket
.
configuration
.
randomDeviceName
randomDeviceName
=
socket
.
configuration
.
randomDeviceName
))
)
)
}
}
is
ServerLoginResponseCaptchaInitPacket
->
{
is
ServerLoginResponseCaptchaInitPacket
->
{
...
@@ -348,7 +360,14 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -348,7 +360,14 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
if
(
packet
.
unknownBoolean
)
{
if
(
packet
.
unknownBoolean
)
{
this
.
captchaSectionId
=
1
this
.
captchaSectionId
=
1
socket
.
sendPacket
(
OutgoingCaptchaTransmissionRequestPacket
(
bot
.
qqAccount
,
this
.
token0825
,
this
.
captchaSectionId
++,
packet
.
token00BA
))
socket
.
sendPacket
(
OutgoingCaptchaTransmissionRequestPacket
(
bot
.
qqAccount
,
this
.
token0825
,
this
.
captchaSectionId
++,
packet
.
token00BA
)
)
}
}
}
}
...
@@ -372,23 +391,46 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -372,23 +391,46 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
socket
.
sendPacket
(
OutgoingCaptchaRefreshPacket
(
bot
.
qqAccount
,
token0825
))
socket
.
sendPacket
(
OutgoingCaptchaRefreshPacket
(
bot
.
qqAccount
,
token0825
))
}
else
{
}
else
{
this
.
captchaSectionId
=
0
//意味着已经提交验证码
this
.
captchaSectionId
=
0
//意味着已经提交验证码
socket
.
sendPacket
(
OutgoingCaptchaSubmitPacket
(
bot
.
qqAccount
,
token0825
,
code
,
packet
.
verificationToken
))
socket
.
sendPacket
(
OutgoingCaptchaSubmitPacket
(
bot
.
qqAccount
,
token0825
,
code
,
packet
.
verificationToken
)
)
}
}
}
else
{
}
else
{
socket
.
sendPacket
(
OutgoingCaptchaTransmissionRequestPacket
(
bot
.
qqAccount
,
token0825
,
captchaSectionId
++,
packet
.
token00BA
))
socket
.
sendPacket
(
OutgoingCaptchaTransmissionRequestPacket
(
bot
.
qqAccount
,
token0825
,
captchaSectionId
++,
packet
.
token00BA
)
)
}
}
}
}
is
ServerLoginResponseSuccessPacket
->
{
is
ServerLoginResponseSuccessPacket
->
{
this
.
sessionResponseDecryptionKey
=
packet
.
sessionResponseDecryptionKey
this
.
sessionResponseDecryptionKey
=
packet
.
sessionResponseDecryptionKey
socket
.
sendPacket
(
OutgoingSessionRequestPacket
(
bot
.
qqAccount
,
socket
.
serverIp
,
packet
.
token38
,
packet
.
token88
,
packet
.
encryptionKey
))
socket
.
sendPacket
(
OutgoingSessionRequestPacket
(
bot
.
qqAccount
,
socket
.
serverIp
,
packet
.
token38
,
packet
.
token88
,
packet
.
encryptionKey
)
)
}
}
//是ClientPasswordSubmissionPacket之后服务器回复的可能之一
//是ClientPasswordSubmissionPacket之后服务器回复的可能之一
is
ServerLoginResponseKeyExchangePacket
->
{
is
ServerLoginResponseKeyExchangePacket
->
{
this
.
privateKey
=
packet
.
privateKeyUpdate
this
.
privateKey
=
packet
.
privateKeyUpdate
socket
.
sendPacket
(
OutgoingPasswordSubmissionPacket
(
socket
.
sendPacket
(
OutgoingPasswordSubmissionPacket
(
bot
=
bot
.
qqAccount
,
bot
=
bot
.
qqAccount
,
password
=
bot
.
account
.
password
,
password
=
bot
.
account
.
password
,
loginTime
=
loginTime
,
loginTime
=
loginTime
,
...
@@ -398,21 +440,25 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
...
@@ -398,21 +440,25 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
token00BA
=
packet
.
tokenUnknown
?:
token00BA
,
token00BA
=
packet
.
tokenUnknown
?:
token00BA
,
randomDeviceName
=
socket
.
configuration
.
randomDeviceName
,
randomDeviceName
=
socket
.
configuration
.
randomDeviceName
,
tlv0006
=
packet
.
tlv0006
tlv0006
=
packet
.
tlv0006
))
)
)
}
}
is
ServerSessionKeyResponsePacket
->
{
is
ServerSessionKeyResponsePacket
->
{
sessionKey
=
packet
.
sessionKey
sessionKey
=
packet
.
sessionKey
bot
.
logger
.
logPurple
(
"sessionKey = ${sessionKey.toUHexString()}"
)
bot
.
logger
.
logPurple
(
"sessionKey = ${sessionKey.toUHexString()}"
)
heartbeatJob
=
NetworkScope
.
launch
{
heartbeatJob
=
launch
{
while
(
socket
.
isOpen
)
{
while
(
socket
.
isOpen
)
{
delay
(
configuration
.
heartbeatPeriod
.
millisecondsLong
)
delay
(
configuration
.
heartbeatPeriod
.
millisecondsLong
)
with
(
session
)
{
with
(
session
)
{
class
HeartbeatTimeoutException
:
CancellationException
(
"heartbeat timeout"
)
class
HeartbeatTimeoutException
:
CancellationException
(
"heartbeat timeout"
)
if
(
withTimeoutOrNull
(
configuration
.
heartbeatTimeout
.
millisecondsLong
)
{
if
(
withTimeoutOrNull
(
configuration
.
heartbeatTimeout
.
millisecondsLong
)
{
HeartbeatPacket
(
bot
.
qqAccount
,
sessionKey
).
sendAndExpect
<
HeartbeatPacket
.
Response
>().
join
()
HeartbeatPacket
(
bot
.
qqAccount
,
sessionKey
).
sendAndExpect
<
HeartbeatPacket
.
Response
>().
join
()
}
==
null
)
{
}
==
null
)
{
bot
.
logPurple
(
"Heartbeat timed out"
)
bot
.
logPurple
(
"Heartbeat timed out"
)
bot
.
reinitializeNetworkHandler
(
configuration
,
HeartbeatTimeoutException
())
bot
.
reinitializeNetworkHandler
(
configuration
,
HeartbeatTimeoutException
())
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadFriendImage.kt
View file @
eed9c8f1
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
package
net.mamoe.mirai.network.protocol.tim.packet
package
net.mamoe.mirai.network.protocol.tim.packet
import
kotlinx.coroutines.GlobalScope
import
kotlinx.coroutines.launch
import
kotlinx.io.core.*
import
kotlinx.io.core.*
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.contact.QQ
import
net.mamoe.mirai.message.ImageId
import
net.mamoe.mirai.message.ImageId
...
@@ -21,11 +23,10 @@ suspend fun QQ.uploadImage(image: BufferedImage): ImageId = with(bot.network.ses
...
@@ -21,11 +23,10 @@ suspend fun QQ.uploadImage(image: BufferedImage): ImageId = with(bot.network.ses
return
FriendImageIdRequestPacket
(
this
.
qqAccount
,
sessionKey
,
this
.
qqAccount
,
image
).
sendAndExpect
<
FriendImageIdRequestPacket
.
Response
,
ImageId
>
{
return
FriendImageIdRequestPacket
(
this
.
qqAccount
,
sessionKey
,
this
.
qqAccount
,
image
).
sendAndExpect
<
FriendImageIdRequestPacket
.
Response
,
ImageId
>
{
if
(
it
.
uKey
!=
null
)
if
(
it
.
uKey
!=
null
)
require
(
httpPostFriendImage
(
require
(
httpPostFriendImage
(
botAccount
=
bot
.
qqAccount
,
uKeyHex
=
it
.
uKey
!!
.
toUHexString
(
""
),
uKeyHex
=
it
.
uKey
!!
.
toUHexString
(
""
),
botNumber
=
bot
.
qqAccount
,
imageInput
=
image
.
input
,
imageData
=
image
.
data
,
inputSize
=
image
.
inputSize
fileSize
=
image
.
fileSize
,
qq
=
this
.
qqAccount
))
))
it
.
imageId
!!
it
.
imageId
!!
}.
await
()
}.
await
()
...
@@ -217,8 +218,10 @@ class FriendImageIdRequestPacket(
...
@@ -217,8 +218,10 @@ class FriendImageIdRequestPacket(
writeFully
(
image
.
md5
)
writeFully
(
image
.
md5
)
writeUByte
(
0
x28u
)
writeUByte
(
0
x28u
)
writeUVarInt
(
image
.
file
Size
.
toUInt
())
writeUVarInt
(
image
.
input
Size
.
toUInt
())
GlobalScope
.
launch
{
}
writeUByte
(
0
x32u
)
writeUByte
(
0
x32u
)
//长度应为1A
//长度应为1A
writeUVarintLVPacket
{
writeUVarintLVPacket
{
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/protocol/tim/packet/UploadGroupImage.kt
View file @
eed9c8f1
...
@@ -18,10 +18,10 @@ suspend fun Group.uploadImage(
...
@@ -18,10 +18,10 @@ suspend fun Group.uploadImage(
.
sendAndExpect
<
GroupImageIdRequestPacket
.
Response
,
Unit
>
{
.
sendAndExpect
<
GroupImageIdRequestPacket
.
Response
,
Unit
>
{
if
(
it
.
uKey
!=
null
)
{
if
(
it
.
uKey
!=
null
)
{
httpPostGroupImage
(
httpPostGroupImage
(
bo
t
=
bot
.
qqAccount
,
botAccoun
t
=
bot
.
qqAccount
,
groupNumber
=
groupId
,
groupNumber
=
groupId
,
imageData
=
image
.
data
,
imageInput
=
image
.
input
,
fileSize
=
image
.
file
Size
,
inputSize
=
image
.
input
Size
,
uKeyHex
=
it
.
uKey
!!
.
toUHexString
(
""
)
uKeyHex
=
it
.
uKey
!!
.
toUHexString
(
""
)
)
)
}
}
...
@@ -154,7 +154,7 @@ class GroupImageIdRequestPacket(
...
@@ -154,7 +154,7 @@ class GroupImageIdRequestPacket(
writeUByte
(
0
x10u
)
writeUByte
(
0
x10u
)
writeFully
(
image
.
md5
)
writeFully
(
image
.
md5
)
writeTUVarint
(
0
x28u
,
image
.
file
Size
.
toUInt
())
writeTUVarint
(
0
x28u
,
image
.
input
Size
.
toUInt
())
writeUVarintLVPacket
(
tag
=
0
x32u
)
{
writeUVarintLVPacket
(
tag
=
0
x32u
)
{
writeTV
(
0
x5B_00u
)
writeTV
(
0
x5B_00u
)
writeTV
(
0
x40_00u
)
writeTV
(
0
x40_00u
)
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotNetworkConfiguration.kt
View file @
eed9c8f1
...
@@ -3,6 +3,7 @@ package net.mamoe.mirai.utils
...
@@ -3,6 +3,7 @@ package net.mamoe.mirai.utils
import
com.soywiz.klock.TimeSpan
import
com.soywiz.klock.TimeSpan
import
com.soywiz.klock.seconds
import
com.soywiz.klock.seconds
import
net.mamoe.mirai.network.protocol.tim.packet.login.ServerTouchResponsePacket
import
net.mamoe.mirai.network.protocol.tim.packet.login.ServerTouchResponsePacket
import
kotlin.jvm.JvmField
/**
/**
* 网络配置
* 网络配置
...
@@ -32,6 +33,7 @@ class BotNetworkConfiguration {
...
@@ -32,6 +33,7 @@ class BotNetworkConfiguration {
var
heartbeatTimeout
:
TimeSpan
=
2
.
seconds
var
heartbeatTimeout
:
TimeSpan
=
2
.
seconds
companion
object
{
companion
object
{
@JvmField
val
Default
=
BotNetworkConfiguration
()
val
Default
=
BotNetworkConfiguration
()
}
}
}
}
\ No newline at end of file
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BufferedImage.kt
View file @
eed9c8f1
@
file
:
Suppress
(
"EXPERIMENTAL_API_USAGE"
)
package
net.mamoe.mirai.utils
package
net.mamoe.mirai.utils
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.Input
import
net.mamoe.mirai.message.ImageId
import
net.mamoe.mirai.message.ImageId
fun
BufferedImage
(
width
:
Int
,
height
:
Int
,
md5
:
ByteArray
,
format
:
String
,
data
:
ByteReadPacket
)
=
BufferedImage
(
width
,
height
,
md5
,
format
,
data
,
data
.
remaining
)
class
BufferedImage
(
class
BufferedImage
(
val
width
:
Int
,
val
width
:
Int
,
val
height
:
Int
,
val
height
:
Int
,
val
md5
:
ByteArray
,
val
md5
:
ByteArray
,
val
format
:
String
,
val
format
:
String
,
val
data
:
ByteReadPacket
val
input
:
Input
,
val
inputSize
:
Long
)
{
)
{
val
fileSize
:
Long
=
data
.
remaining
/**
/**
* 用于发送消息的 [ImageId]
* 用于发送消息的 [ImageId]
...
...
mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt
View file @
eed9c8f1
...
@@ -3,8 +3,13 @@
...
@@ -3,8 +3,13 @@
package
net.mamoe.mirai.utils
package
net.mamoe.mirai.utils
import
com.soywiz.klock.DateTime
import
com.soywiz.klock.DateTime
import
kotlinx.io.core.ByteReadPacket
import
io.ktor.client.HttpClient
import
net.mamoe.mirai.utils.io.printStringFromHex
import
io.ktor.client.request.HttpRequestBuilder
import
io.ktor.client.request.post
import
io.ktor.http.HttpStatusCode
import
io.ktor.http.URLProtocol
import
io.ktor.http.userAgent
import
kotlinx.io.core.Input
/**
/**
* 时间戳
* 时间戳
...
@@ -39,28 +44,67 @@ expect fun solveIpAddress(hostname: String): String
...
@@ -39,28 +44,67 @@ expect fun solveIpAddress(hostname: String): String
*/
*/
expect
fun
localIpAddress
():
String
expect
fun
localIpAddress
():
String
/**
* Provided by Ktor Http
*/
internal
expect
val
httpClient
:
HttpClient
/**
/**
* 上传好友图片
* 上传好友图片
*/
*/
expect
suspend
fun
httpPostFriendImage
(
@Suppress
(
"DuplicatedCode"
)
suspend
fun
httpPostFriendImage
(
botAccount
:
UInt
,
uKeyHex
:
String
,
uKeyHex
:
String
,
fileSize
:
Long
,
imageInput
:
Input
,
botNumber
:
UInt
,
inputSize
:
Long
qq
:
UInt
,
):
Boolean
=
(
httpClient
.
postImage
(
imageInput
,
inputSize
,
uKeyHex
)
{
imageData
:
ByteReadPacket
url
{
):
Boolean
parameters
[
"htcmd"
]
=
"0x6ff0070"
parameters
[
"uin"
]
=
botAccount
.
toLong
().
toString
()
}
}
as
HttpStatusCode
).
value
.
also
{
println
(
it
)
}
==
200
/**
/**
* 上传群图片
* 上传群图片
*/
*/
expect
suspend
fun
httpPostGroupImage
(
@Suppress
(
"DuplicatedCode"
)
bot
:
UInt
,
suspend
fun
httpPostGroupImage
(
botAccount
:
UInt
,
groupNumber
:
UInt
,
groupNumber
:
UInt
,
uKeyHex
:
String
,
uKeyHex
:
String
,
fileSize
:
Long
,
imageInput
:
Input
,
imageData
:
ByteReadPacket
inputSize
:
Long
):
Boolean
):
Boolean
=
(
httpClient
.
postImage
(
imageInput
,
inputSize
,
uKeyHex
)
{
url
{
parameters
[
"htcmd"
]
=
"0x6ff0071"
parameters
[
"uin"
]
=
botAccount
.
toLong
().
toString
()
parameters
[
"groupcode"
]
=
groupNumber
.
toLong
().
toString
()
}
}
as
HttpStatusCode
).
value
.
also
{
println
(
it
)
}
==
200
fun
main
()
{
private
suspend
inline
fun
<
reified
T
>
HttpClient
.
postImage
(
"46 52 25 46 60 30 59 4F 4A 5A 51"
.
printStringFromHex
()
imageInput
:
Input
,
inputSize
:
Long
,
uKeyHex
:
String
,
block
:
HttpRequestBuilder
.()
->
Unit
=
{}
):
T
=
post
{
url
{
protocol
=
URLProtocol
.
HTTP
host
=
"htdata2.qq.com"
path
(
"cgi-bin/httpconn"
)
parameters
[
"ver"
]
=
"5603"
parameters
[
"filezise"
]
=
inputSize
.
toString
()
parameters
[
"range"
]
=
0
.
toString
()
parameters
[
"ukey"
]
=
uKeyHex
userAgent
(
"QQClient"
)
}
block
()
configureBody
(
inputSize
,
imageInput
)
}
}
internal
expect
fun
HttpRequestBuilder
.
configureBody
(
inputSize
:
Long
,
input
:
Input
)
\ No newline at end of file
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/contact/ContactJvm.kt
View file @
eed9c8f1
...
@@ -2,10 +2,7 @@
...
@@ -2,10 +2,7 @@
package
net.mamoe.mirai.contact
package
net.mamoe.mirai.contact
import
kotlinx.coroutines.launch
import
kotlinx.coroutines.runBlocking
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.message.Message
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.message.MessageChain
import
net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import
net.mamoe.mirai.network.protocol.tim.handler.EventPacketHandler
import
net.mamoe.mirai.utils.ContactList
import
net.mamoe.mirai.utils.ContactList
...
@@ -26,36 +23,36 @@ actual sealed class Contact actual constructor(bot: Bot, number: UInt) : Platfor
...
@@ -26,36 +23,36 @@ actual sealed class Contact actual constructor(bot: Bot, number: UInt) : Platfor
abstract
override
suspend
fun
sendXMLMessage
(
message
:
String
)
abstract
override
suspend
fun
sendXMLMessage
(
message
:
String
)
//
/**
//
/**
* 阻塞发送一个消息. 仅应在 Java 使用
//
* 阻塞发送一个消息. 仅应在 Java 使用
*/
//
*/
fun
blockingSendMessage
(
chain
:
MessageChain
)
=
runBlocking
{
sendMessage
(
chain
)
}
//
fun blockingSendMessage(chain: MessageChain) = runBlocking { sendMessage(chain) }
//
/**
//
/**
* 阻塞发送一个消息. 仅应在 Java 使用
//
* 阻塞发送一个消息. 仅应在 Java 使用
*/
//
*/
fun
blockingSendMessage
(
message
:
Message
)
=
runBlocking
{
sendMessage
(
message
)
}
//
fun blockingSendMessage(message: Message) = runBlocking { sendMessage(message) }
//
/**
//
/**
* 阻塞发送一个消息. 仅应在 Java 使用
//
* 阻塞发送一个消息. 仅应在 Java 使用
*/
//
*/
fun
blockingSendMessage
(
plain
:
String
)
=
runBlocking
{
sendMessage
(
plain
)
}
//
fun blockingSendMessage(plain: String) = runBlocking { sendMessage(plain) }
//
/**
//
/**
* 异步发送一个消息. 仅应在 Java 使用
//
* 异步发送一个消息. 仅应在 Java 使用
*/
//
*/
fun
asyncSendMessage
(
chain
:
MessageChain
)
=
bot
.
network
.
NetworkScope
.
launch
{
sendMessage
(
chain
)
}
// fun asyncSendMessage(chain: MessageChain) = bot.network
.launch { sendMessage(chain) }
//
/**
//
/**
* 异步发送一个消息. 仅应在 Java 使用
//
* 异步发送一个消息. 仅应在 Java 使用
*/
//
*/
fun
asyncSendMessage
(
message
:
Message
)
=
bot
.
network
.
NetworkScope
.
launch
{
sendMessage
(
message
)
}
// fun asyncSendMessage(message: Message) = bot.network
.launch { sendMessage(message) }
//
/**
//
/**
* 异步发送一个消息. 仅应在 Java 使用
//
* 异步发送一个消息. 仅应在 Java 使用
*/
//
*/
fun
asyncSendMessage
(
plain
:
String
)
=
bot
.
network
.
NetworkScope
.
launch
{
sendMessage
(
plain
)
}
// fun asyncSendMessage(plain: String) = bot.network
.launch { sendMessage(plain) }
}
}
/**
/**
...
...
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt
0 → 100644
View file @
eed9c8f1
package
net.mamoe.mirai.event
import
kotlinx.coroutines.runBlocking
// TODO 添加更多
/**
* Jvm 调用实现(阻塞)
*/
object
Events
{
@JvmStatic
fun
<
E
:
Event
>
subscribe
(
type
:
Class
<
E
>,
handler
:
suspend
(
E
)
->
ListeningStatus
)
=
runBlocking
{
type
.
kotlin
.
subscribe
(
handler
)
}
}
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventListeneresInternalJvm.kt
View file @
eed9c8f1
...
@@ -6,10 +6,13 @@ import kotlin.reflect.full.allSuperclasses
...
@@ -6,10 +6,13 @@ import kotlin.reflect.full.allSuperclasses
import
kotlin.reflect.full.isSuperclassOf
import
kotlin.reflect.full.isSuperclassOf
@Suppress
(
"UNCHECKED_CAST"
)
@Suppress
(
"UNCHECKED_CAST"
)
internal
actual
inline
fun
<
E
:
Event
>
loopAllListeners
(
clazz
:
KClass
<
E
>,
consumer
:
(
EventListeners
<
in
E
>)
->
Unit
)
{
internal
actual
suspend
inline
fun
<
E
:
Event
>
loopAllListeners
(
clazz
:
KClass
<
E
>,
consumer
:
(
EventListeners
<
in
E
>)
->
Unit
)
{
clazz
.
allSuperclasses
.
forEach
{
clazz
.
allSuperclasses
.
forEach
{
if
(
Event
::
class
.
isSuperclassOf
(
it
))
{
if
(
Event
::
class
.
isSuperclassOf
(
it
))
{
consumer
((
it
as
KClass
<
out
Event
>).
listeners
as
EventListeners
<
in
E
>)
consumer
((
it
as
KClass
<
out
Event
>).
listeners
()
as
EventListeners
<
in
E
>)
}
}
}
}
}
}
\ No newline at end of file
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BufferedImageJvm.kt
View file @
eed9c8f1
...
@@ -2,8 +2,11 @@
...
@@ -2,8 +2,11 @@
package
net.mamoe.mirai.utils
package
net.mamoe.mirai.utils
import
kotlinx.io.core.IoBuffer
import
kotlinx.io.core.buildPacket
import
kotlinx.io.core.buildPacket
import
kotlinx.io.streams.writePacket
import
kotlinx.io.streams.asInput
import
java.io.File
import
java.io.FileInputStream
import
java.io.InputStream
import
java.io.InputStream
import
java.io.OutputStream
import
java.io.OutputStream
import
java.security.MessageDigest
import
java.security.MessageDigest
...
@@ -29,14 +32,33 @@ fun JavaBufferedImage.toMiraiImage(formatName: String = "gif"): BufferedImage {
...
@@ -29,14 +32,33 @@ fun JavaBufferedImage.toMiraiImage(formatName: String = "gif"): BufferedImage {
}
}
fun
BufferedImage
.
toJavaImage
():
JavaBufferedImage
=
ImageIO
.
read
(
object
:
InputStream
()
{
fun
BufferedImage
.
toJavaImage
():
JavaBufferedImage
=
ImageIO
.
read
(
object
:
InputStream
()
{
override
fun
read
():
Int
=
with
(
this
@
toJavaImage
.
data
)
{
override
fun
read
():
Int
=
with
(
this
@
toJavaImage
.
input
)
{
if
(
remaining
!=
0L
)
if
(
!
endOfInput
)
readByte
().
toInt
()
readByte
().
toInt
()
else
-
1
else
-
1
}
}
})
})
/**
fun
File
.
toMiraiImage
():
BufferedImage
{
* 将缓存的图片写入流. 注意, 写入后缓存将会被清空.
val
image
=
ImageIO
.
getImageReaders
(
this
.
inputStream
()).
asSequence
().
first
()
*/
fun
OutputStream
.
writeImage
(
image
:
BufferedImage
)
=
this
.
writePacket
(
image
.
data
)
val
digest
=
MessageDigest
.
getInstance
(
"md5"
)
\ No newline at end of file
digest
.
reset
()
FileInputStream
(
this
).
transferTo
(
object
:
OutputStream
()
{
override
fun
write
(
b
:
Int
)
{
b
.
toByte
().
let
{
digest
.
update
(
it
)
}
}
})
val
dimension
=
image
.
defaultReadParam
.
sourceRenderSize
return
BufferedImage
(
width
=
dimension
.
width
,
height
=
dimension
.
height
,
md5
=
digest
.
digest
(),
format
=
image
.
formatName
,
input
=
this
.
inputStream
().
asInput
(
IoBuffer
.
Pool
),
inputSize
=
this
.
length
()
)
}
\ No newline at end of file
mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsJvm.kt
View file @
eed9c8f1
...
@@ -4,15 +4,17 @@ package net.mamoe.mirai.utils
...
@@ -4,15 +4,17 @@ package net.mamoe.mirai.utils
import
io.ktor.client.HttpClient
import
io.ktor.client.HttpClient
import
io.ktor.client.engine.cio.CIO
import
io.ktor.client.engine.cio.CIO
import
io.ktor.client.request.post
import
io.ktor.client.request.HttpRequestBuilder
import
io.ktor.content.ByteArrayContent
import
io.ktor.http.ContentType
import
io.ktor.http.ContentType
import
io.ktor.http.HttpStatusCode
import
io.ktor.http.content.OutgoingContent
import
io.ktor.http.URLProtocol
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.io.ByteWriteChannel
import
kotlinx.coroutines.io.writeFully
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withContext
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.ByteReadPacket
import
kotlinx.io.core.Input
import
kotlinx.io.core.readBytes
import
kotlinx.io.core.readBytes
import
kotlinx.io.core.readFully
import
org.jsoup.Connection
import
org.jsoup.Connection
import
org.jsoup.Jsoup
import
org.jsoup.Jsoup
import
java.net.InetAddress
import
java.net.InetAddress
...
@@ -22,7 +24,7 @@ import java.util.zip.CRC32
...
@@ -22,7 +24,7 @@ import java.util.zip.CRC32
actual
val
deviceName
:
String
=
InetAddress
.
getLocalHost
().
hostName
actual
val
deviceName
:
String
=
InetAddress
.
getLocalHost
().
hostName
/*
/*
* TODO we may use libraries that provide these functions
* TODO
:
we may use libraries that provide these functions
*/
*/
actual
fun
crc32
(
key
:
ByteArray
):
Int
=
CRC32
().
let
{
it
.
update
(
key
);
it
.
value
.
toInt
()
}
actual
fun
crc32
(
key
:
ByteArray
):
Int
=
CRC32
().
let
{
it
.
update
(
key
);
it
.
value
.
toInt
()
}
...
@@ -33,56 +35,18 @@ actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(host
...
@@ -33,56 +35,18 @@ actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(host
actual
fun
localIpAddress
():
String
=
InetAddress
.
getLocalHost
().
hostAddress
actual
fun
localIpAddress
():
String
=
InetAddress
.
getLocalHost
().
hostAddress
/**
suspend
fun
httpPostFriendImageOld
(
* Provided by Ktor Http
*/
private
val
httpClient
:
HttpClient
=
HttpClient
{
engine
{
CIO
}
}
actual
suspend
fun
httpPostFriendImage
(
uKeyHex
:
String
,
uKeyHex
:
String
,
fileSize
:
Long
,
botNumber
:
UInt
,
botNumber
:
UInt
,
qq
:
UInt
,
imageData
:
ByteReadPacket
):
Boolean
=
(
httpClient
.
post
{
url
{
protocol
=
URLProtocol
.
HTTP
host
=
"htdata2.qq.com"
path
(
"cgi-bin/httpconn"
)
parameters
[
"htcmd"
]
=
"0x6ff0070"
parameters
[
"ver"
]
=
"5603"
parameters
[
"ukey"
]
=
uKeyHex
parameters
[
"filezise"
]
=
imageData
.
remaining
.
toString
()
parameters
[
"range"
]
=
0
.
toString
()
parameters
[
"uin"
]
=
qq
.
toString
()
}
body
=
ByteArrayContent
(
imageData
.
readBytes
(),
ContentType
.
Image
.
Any
)
}
as
HttpStatusCode
).
value
==
200
//.postImage(imageData)
/**
* 上传群图片
*/
actual
suspend
fun
httpPostGroupImage
(
bot
:
UInt
,
groupNumber
:
UInt
,
uKeyHex
:
String
,
fileSize
:
Long
,
imageData
:
ByteReadPacket
imageData
:
ByteReadPacket
):
Boolean
=
Jsoup
.
connect
(
"http://htdata2.qq.com/cgi-bin/httpconn"
+
):
Boolean
=
Jsoup
.
connect
(
"http://htdata2.qq.com/cgi-bin/httpconn"
+
"?htcmd=0x6ff0071"
+
"?htcmd=0x6ff0070"
+
"&term=pc"
+
"&ver=5603"
+
"&ver=5603"
+
"&filesize=${imageData.remaining}"
+
"&ukey=${uKeyHex}"
+
"&uin=$bot"
+
"&filezise=${imageData.remaining}"
+
"&groupcode=$groupNumber"
+
"&range=0"
+
"&range=0"
+
"&ukey="
+
uKeyHex
)
"&uin=$botNumber"
)
.
postImage
(
imageData
)
.
postImage
(
imageData
)
...
@@ -100,3 +64,23 @@ private suspend fun Connection.postImage(image: ByteReadPacket): Boolean = this
...
@@ -100,3 +64,23 @@ private suspend fun Connection.postImage(image: ByteReadPacket): Boolean = this
private
suspend
fun
Connection
.
suspendExecute
():
Connection
.
Response
=
withContext
(
Dispatchers
.
IO
)
{
private
suspend
fun
Connection
.
suspendExecute
():
Connection
.
Response
=
withContext
(
Dispatchers
.
IO
)
{
execute
()
execute
()
}
}
internal
actual
val
httpClient
:
HttpClient
=
HttpClient
(
CIO
)
internal
actual
fun
HttpRequestBuilder
.
configureBody
(
inputSize
:
Long
,
input
:
Input
)
{
body
=
object
:
OutgoingContent
.
WriteChannelContent
()
{
override
val
contentType
:
ContentType
=
ContentType
.
Image
.
GIF
override
val
contentLength
:
Long
=
inputSize
override
suspend
fun
writeTo
(
channel
:
ByteWriteChannel
)
{
val
buffer
=
byteArrayOf
(
1
)
while
(!
input
.
endOfInput
)
{
input
.
readFully
(
buffer
)
channel
.
writeFully
(
buffer
)
}
}
}
}
\ No newline at end of file
mirai-debug/build.gradle
View file @
eed9c8f1
...
@@ -5,11 +5,10 @@ dependencies {
...
@@ -5,11 +5,10 @@ dependencies {
implementation
project
(
':mirai-core'
)
implementation
project
(
':mirai-core'
)
compile
files
(
'./lib/jpcap.jar'
)
compile
files
(
'./lib/jpcap.jar'
)
implementation
rootProject
.
ext
.
coroutineCommon
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-jdk8'
,
version:
kotlin_version
implementation
rootProject
.
ext
.
kotlinJvm
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-io'
,
version:
kotlinxio_version
implementation
rootProject
.
ext
.
kotlinxIOJvm
compile
"org.jetbrains.kotlin:kotlin-reflect:1.3.50"
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-reflect'
,
version:
kotlin_version
implementation
'org.jsoup:jsoup:1.12.1'
}
}
tasks
.
withType
(
JavaCompile
)
{
tasks
.
withType
(
JavaCompile
)
{
...
...
mirai-debug/src/main/java/DownloadImgTest.kt
deleted
100644 → 0
View file @
b7628cd3
import
net.mamoe.mirai.utils.io.toUHexString
import
org.jsoup.Connection
import
org.jsoup.Jsoup
fun
main
()
{
println
(
Jsoup
.
connect
(
"http://61.183.164.34/gchatpic_new/B814D8D6A55D6DB423469E38D2A17AAA23836D74E7A656A4A8288C6078950A33B4A49E854E59B6D2314EFC47D6475902EDE8CADAFAF7F2A7670CAC05EA8314A1241128102F0A3AAF9C07284B1AE35E52F6D0A265235AFA6B/0?vuin=1040400290&term=255&srvver=26933&rf=n"
)
.
cookie
(
"ST"
,
"00015DAA9C030040F3B82971FCBC718AA35573100B9CDBA2CB0DE38AF8710CA22E2986246345FC96B82BA0C211FDA700C397DF99FCC0989D67FD75F00B2FFB9CE0D032C3DCAC5A77"
)
.
method
(
Connection
.
Method
.
GET
)
.
ignoreContentType
(
true
)
.
execute
()
.
bodyAsBytes
().
toUHexString
())
}
\ No newline at end of file
mirai-demos/mirai-demo-1/build.gradle
View file @
eed9c8f1
...
@@ -3,6 +3,6 @@ apply plugin: "java"
...
@@ -3,6 +3,6 @@ apply plugin: "java"
dependencies
{
dependencies
{
compile
project
(
":mirai-core"
)
compile
project
(
":mirai-core"
)
compile
rootProject
.
ext
.
coroutine
api
group:
'org.jetbrains.kotlin'
,
name:
'kotlin-stdlib-jdk8'
,
version:
kotlin_version
compile
rootProject
.
ext
.
kotlinJvm
api
group:
'org.jetbrains.kotlinx'
,
name:
'kotlinx-coroutines-core'
,
version:
coroutines_version
}
}
mirai-demos/mirai-demo-1/build.gradle.kts
0 → 100644
View file @
eed9c8f1
mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
View file @
eed9c8f1
...
@@ -2,10 +2,7 @@
...
@@ -2,10 +2,7 @@
package
demo1
package
demo1
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.*
import
kotlinx.coroutines.delay
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.withTimeoutOrNull
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.Bot
import
net.mamoe.mirai.BotAccount
import
net.mamoe.mirai.BotAccount
import
net.mamoe.mirai.contact.Group
import
net.mamoe.mirai.contact.Group
...
@@ -44,14 +41,14 @@ private fun readTestAccount(): BotAccount? {
...
@@ -44,14 +41,14 @@ private fun readTestAccount(): BotAccount? {
}
}
@Suppress
(
"UNUSED_VARIABLE"
)
@Suppress
(
"UNUSED_VARIABLE"
)
suspend
fun
main
()
{
suspend
fun
main
()
=
coroutineScope
{
val
bot
=
Bot
(
readTestAccount
()
?:
BotAccount
(
//填写你的账号
val
bot
=
Bot
(
readTestAccount
()
?:
BotAccount
(
//填写你的账号
account
=
1994701121
u
,
account
=
1994701121
u
,
password
=
"123456"
password
=
"123456"
),
PlatformLogger
())
),
PlatformLogger
())
bot
.
login
{
bot
.
login
{
randomDeviceName
=
tru
e
randomDeviceName
=
fals
e
}.
let
{
}.
let
{
if
(
it
!=
LoginResult
.
SUCCESS
)
{
if
(
it
!=
LoginResult
.
SUCCESS
)
{
MiraiLogger
.
logError
(
"Login failed: "
+
it
.
name
)
MiraiLogger
.
logError
(
"Login failed: "
+
it
.
name
)
...
@@ -143,8 +140,7 @@ suspend fun main() {
...
@@ -143,8 +140,7 @@ suspend fun main() {
demo2
()
demo2
()
//由于使用的是协程, main函数执行完后就会结束程序.
bot
.
network
.
awaitDisconnection
()
//等到直到断开连接
delay
(
Long
.
MAX_VALUE
)
//永远等待, 以测试事件
}
}
...
@@ -153,7 +149,7 @@ suspend fun main() {
...
@@ -153,7 +149,7 @@ suspend fun main() {
* 对机器人说 "记笔记", 机器人记录之后的所有消息.
* 对机器人说 "记笔记", 机器人记录之后的所有消息.
* 对机器人说 "停止", 机器人停止
* 对机器人说 "停止", 机器人停止
*/
*/
fun
demo2
()
{
suspend
fun
demo2
()
{
subscribeAlways
<
FriendMessageEvent
>
{
event
->
subscribeAlways
<
FriendMessageEvent
>
{
event
->
if
(
event
.
message
eq
"记笔记"
)
{
if
(
event
.
message
eq
"记笔记"
)
{
subscribeUntilFalse
<
FriendMessageEvent
>
{
subscribeUntilFalse
<
FriendMessageEvent
>
{
...
...
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