mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: Reusable and restrictive coroutine context
Signed-off-by: 白池 <whitechi73@outlook.com>
This commit is contained in:
parent
18126b1fda
commit
c940aea153
@ -11,9 +11,10 @@ import io.ktor.utils.io.core.BytePacketBuilder
|
|||||||
import io.ktor.utils.io.core.readBytes
|
import io.ktor.utils.io.core.readBytes
|
||||||
import io.ktor.utils.io.core.writeFully
|
import io.ktor.utils.io.core.writeFully
|
||||||
import io.ktor.utils.io.core.writeInt
|
import io.ktor.utils.io.core.writeInt
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
@ -28,10 +29,11 @@ import moe.fuqiuluo.shamrock.xposed.helper.internal.IPCRequest
|
|||||||
import protobuf.oidb.TrpcOidb
|
import protobuf.oidb.TrpcOidb
|
||||||
import mqq.app.MobileQQ
|
import mqq.app.MobileQQ
|
||||||
import tencent.im.oidb.oidb_sso
|
import tencent.im.oidb.oidb_sso
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
|
||||||
internal abstract class BaseSvc {
|
internal abstract class BaseSvc {
|
||||||
companion object {
|
companion object Default: CoroutineScope {
|
||||||
val currentUin: String
|
val currentUin: String
|
||||||
get() = app.currentAccountUin
|
get() = app.currentAccountUin
|
||||||
|
|
||||||
@ -46,7 +48,7 @@ internal abstract class BaseSvc {
|
|||||||
val seq = MsfCore.getNextSeq()
|
val seq = MsfCore.getNextSeq()
|
||||||
val buffer = withTimeoutOrNull(timeout) {
|
val buffer = withTimeoutOrNull(timeout) {
|
||||||
suspendCancellableCoroutine { continuation ->
|
suspendCancellableCoroutine { continuation ->
|
||||||
GlobalScope.launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||||
val buffer = it.getByteArrayExtra("buffer")!!
|
val buffer = it.getByteArrayExtra("buffer")!!
|
||||||
continuation.resume(buffer)
|
continuation.resume(buffer)
|
||||||
@ -75,7 +77,7 @@ internal abstract class BaseSvc {
|
|||||||
val seq = MsfCore.getNextSeq()
|
val seq = MsfCore.getNextSeq()
|
||||||
val buffer = withTimeoutOrNull<ByteArray?>(timeout) {
|
val buffer = withTimeoutOrNull<ByteArray?>(timeout) {
|
||||||
suspendCancellableCoroutine { continuation ->
|
suspendCancellableCoroutine { continuation ->
|
||||||
GlobalScope.launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
DynamicReceiver.register(IPCRequest(cmd, seq) {
|
||||||
val buffer = it.getByteArrayExtra("buffer")!!
|
val buffer = it.getByteArrayExtra("buffer")!!
|
||||||
continuation.resume(buffer)
|
continuation.resume(buffer)
|
||||||
@ -143,6 +145,11 @@ internal abstract class BaseSvc {
|
|||||||
toServiceMsg.addAttribute("shamrock_seq", seq)
|
toServiceMsg.addAttribute("shamrock_seq", seq)
|
||||||
app.sendToService(toServiceMsg)
|
app.sendToService(toServiceMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
override val coroutineContext: CoroutineContext by lazy {
|
||||||
|
Dispatchers.IO.limitedParallelism(12)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun send(toServiceMsg: ToServiceMsg) {
|
protected fun send(toServiceMsg: ToServiceMsg) {
|
||||||
@ -153,7 +160,7 @@ internal abstract class BaseSvc {
|
|||||||
val seq = MsfCore.getNextSeq()
|
val seq = MsfCore.getNextSeq()
|
||||||
val buffer = withTimeoutOrNull<ByteArray?>(timeout) {
|
val buffer = withTimeoutOrNull<ByteArray?>(timeout) {
|
||||||
suspendCancellableCoroutine { continuation ->
|
suspendCancellableCoroutine { continuation ->
|
||||||
GlobalScope.launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
DynamicReceiver.register(IPCRequest(toServiceMsg.serviceCmd, seq) {
|
DynamicReceiver.register(IPCRequest(toServiceMsg.serviceCmd, seq) {
|
||||||
val buffer = it.getByteArrayExtra("buffer")!!
|
val buffer = it.getByteArrayExtra("buffer")!!
|
||||||
continuation.resume(buffer)
|
continuation.resume(buffer)
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
@file:OptIn(DelicateCoroutinesApi::class)
|
|
||||||
|
|
||||||
package moe.fuqiuluo.shamrock.remote.service
|
package moe.fuqiuluo.shamrock.remote.service
|
||||||
|
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketClientServlet
|
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketClientServlet
|
||||||
import moe.fuqiuluo.shamrock.helper.Level
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter.onMessageEvent
|
||||||
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter.onNoticeEvent
|
||||||
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter.onRequestEvent
|
||||||
|
|
||||||
internal class WebSocketClientService(
|
internal class WebSocketClientService(
|
||||||
override val address: String,
|
override val address: String,
|
||||||
@ -27,18 +26,18 @@ internal class WebSocketClientService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
subscribe(GlobalScope.launch {
|
subscribe(launch {
|
||||||
GlobalEventTransmitter.onMessageEvent { (_, event) ->
|
onMessageEvent { (_, event) ->
|
||||||
pushTo(event)
|
pushTo(event)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
subscribe(GlobalScope.launch {
|
subscribe(launch {
|
||||||
GlobalEventTransmitter.onNoticeEvent { event ->
|
onNoticeEvent { event ->
|
||||||
pushTo(event)
|
pushTo(event)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
subscribe(GlobalScope.launch {
|
subscribe(launch {
|
||||||
GlobalEventTransmitter.onRequestEvent { event ->
|
onRequestEvent { event ->
|
||||||
pushTo(event)
|
pushTo(event)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
package moe.fuqiuluo.shamrock.remote.service
|
package moe.fuqiuluo.shamrock.remote.service
|
||||||
|
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.fuqiuluo.shamrock.helper.ErrorTokenException
|
import moe.fuqiuluo.shamrock.helper.ErrorTokenException
|
||||||
@ -15,7 +14,9 @@ import moe.fuqiuluo.shamrock.remote.service.data.push.*
|
|||||||
import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty
|
import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty
|
||||||
import moe.fuqiuluo.shamrock.helper.Level
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter.onMessageEvent
|
||||||
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter.onNoticeEvent
|
||||||
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter.onRequestEvent
|
||||||
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
|
||||||
import org.java_websocket.WebSocket
|
import org.java_websocket.WebSocket
|
||||||
import org.java_websocket.handshake.ClientHandshake
|
import org.java_websocket.handshake.ClientHandshake
|
||||||
@ -33,20 +34,14 @@ internal class WebSocketService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun init() {
|
override fun init() {
|
||||||
subscribe(GlobalScope.launch {
|
subscribe(launch {
|
||||||
GlobalEventTransmitter.onMessageEvent { (_, event) ->
|
onMessageEvent { (_, event) -> pushTo(event) }
|
||||||
pushTo(event)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
subscribe(GlobalScope.launch {
|
subscribe(launch {
|
||||||
GlobalEventTransmitter.onNoticeEvent { event ->
|
onNoticeEvent { event -> pushTo(event) }
|
||||||
pushTo(event)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
subscribe(GlobalScope.launch {
|
subscribe(launch {
|
||||||
GlobalEventTransmitter.onRequestEvent { event ->
|
onRequestEvent { event -> pushTo(event) }
|
||||||
pushTo(event)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
LogCenter.log("WebSocketService: 初始化服务", Level.WARN)
|
LogCenter.log("WebSocketService: 初始化服务", Level.WARN)
|
||||||
}
|
}
|
||||||
@ -86,7 +81,7 @@ internal class WebSocketService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun pushMetaLifecycle() {
|
private fun pushMetaLifecycle() {
|
||||||
GlobalScope.launch {
|
launch {
|
||||||
val runtime = AppRuntimeFetcher.appRuntime
|
val runtime = AppRuntimeFetcher.appRuntime
|
||||||
pushTo(PushMetaEvent(
|
pushTo(PushMetaEvent(
|
||||||
time = System.currentTimeMillis() / 1000,
|
time = System.currentTimeMillis() / 1000,
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
package moe.fuqiuluo.shamrock.remote.service.api
|
package moe.fuqiuluo.shamrock.remote.service.api
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import moe.fuqiuluo.shamrock.remote.action.ActionManager
|
import moe.fuqiuluo.shamrock.remote.action.ActionManager
|
||||||
@ -30,12 +31,13 @@ import org.java_websocket.handshake.ServerHandshake
|
|||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
internal abstract class WebSocketClientServlet(
|
internal abstract class WebSocketClientServlet(
|
||||||
private val url: String,
|
private val url: String,
|
||||||
private val heartbeatInterval: Long,
|
private val heartbeatInterval: Long,
|
||||||
private val wsHeaders: Map<String, String>
|
private val wsHeaders: Map<String, String>
|
||||||
) : BaseTransmitServlet, WebSocketClient(URI(url), wsHeaders) {
|
) : BaseTransmitServlet, WebSocketClient(URI(url), wsHeaders), CoroutineScope {
|
||||||
init {
|
init {
|
||||||
if (connectedClients.containsKey(url)) {
|
if (connectedClients.containsKey(url)) {
|
||||||
throw RuntimeException("WebSocketClient已存在: $url")
|
throw RuntimeException("WebSocketClient已存在: $url")
|
||||||
@ -43,14 +45,13 @@ internal abstract class WebSocketClientServlet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var firstOpen = true
|
private var firstOpen = true
|
||||||
private val sendLock = Mutex()
|
|
||||||
|
|
||||||
override fun transmitAccess(): Boolean {
|
override fun transmitAccess(): Boolean {
|
||||||
return ShamrockConfig.openWebSocketClient()
|
return ShamrockConfig.openWebSocketClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMessage(message: String) {
|
override fun onMessage(message: String) {
|
||||||
GlobalScope.launch {
|
launch {
|
||||||
handleMessage(message)
|
handleMessage(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +86,6 @@ internal abstract class WebSocketClientServlet(
|
|||||||
|
|
||||||
connectedClients[url] = this
|
connectedClients[url] = this
|
||||||
|
|
||||||
//startHeartbeatTimer()
|
|
||||||
pushMetaLifecycle()
|
pushMetaLifecycle()
|
||||||
if (firstOpen) {
|
if (firstOpen) {
|
||||||
firstOpen = false
|
firstOpen = false
|
||||||
@ -106,21 +106,21 @@ internal abstract class WebSocketClientServlet(
|
|||||||
}
|
}
|
||||||
LogCenter.log("WebSocketClient onClose: $code, $reason, $remote")
|
LogCenter.log("WebSocketClient onClose: $code, $reason, $remote")
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
coroutineContext.cancel()
|
||||||
connectedClients.remove(url)
|
connectedClients.remove(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onError(ex: Exception?) {
|
override fun onError(ex: Exception?) {
|
||||||
LogCenter.log("WebSocketClient onError: ${ex?.message}")
|
LogCenter.log("WebSocketClient onError: ${ex?.message}")
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
coroutineContext.cancel()
|
||||||
connectedClients.remove(url)
|
connectedClients.remove(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected suspend inline fun <reified T> pushTo(body: T) {
|
protected suspend inline fun <reified T> pushTo(body: T) {
|
||||||
if (!transmitAccess() || isClosed || isClosing) return
|
if (!transmitAccess() || isClosed || isClosing) return
|
||||||
try {
|
try {
|
||||||
sendLock.withLock {
|
send(GlobalJson.encodeToString(body))
|
||||||
send(GlobalJson.encodeToString(body))
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
LogCenter.log("被动WS推送失败: ${e.stackTraceToString()}", Level.ERROR)
|
LogCenter.log("被动WS推送失败: ${e.stackTraceToString()}", Level.ERROR)
|
||||||
}
|
}
|
||||||
@ -142,8 +142,7 @@ internal abstract class WebSocketClientServlet(
|
|||||||
}
|
}
|
||||||
val runtime = AppRuntimeFetcher.appRuntime
|
val runtime = AppRuntimeFetcher.appRuntime
|
||||||
LogCenter.log("WebSocketClient心跳: ${app.longAccountUin}", Level.DEBUG)
|
LogCenter.log("WebSocketClient心跳: ${app.longAccountUin}", Level.DEBUG)
|
||||||
send(
|
send(GlobalJson.encodeToString(
|
||||||
GlobalJson.encodeToString(
|
|
||||||
PushMetaEvent(
|
PushMetaEvent(
|
||||||
time = System.currentTimeMillis() / 1000,
|
time = System.currentTimeMillis() / 1000,
|
||||||
selfId = app.longAccountUin,
|
selfId = app.longAccountUin,
|
||||||
@ -164,7 +163,7 @@ internal abstract class WebSocketClientServlet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun pushMetaLifecycle() {
|
private fun pushMetaLifecycle() {
|
||||||
GlobalScope.launch {
|
launch {
|
||||||
val runtime = AppRuntimeFetcher.appRuntime
|
val runtime = AppRuntimeFetcher.appRuntime
|
||||||
val curUin = runtime.currentAccountUin
|
val curUin = runtime.currentAccountUin
|
||||||
pushTo(
|
pushTo(
|
||||||
@ -183,6 +182,10 @@ internal abstract class WebSocketClientServlet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
override val coroutineContext: CoroutineContext =
|
||||||
|
Dispatchers.IO.limitedParallelism(20)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val connectedClients = mutableMapOf<String, WebSocketClientServlet>()
|
private val connectedClients = mutableMapOf<String, WebSocketClientServlet>()
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
@file:OptIn(DelicateCoroutinesApi::class)
|
@file:OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
|
||||||
|
|
||||||
package moe.fuqiuluo.shamrock.remote.service.api
|
package moe.fuqiuluo.shamrock.remote.service.api
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
|
||||||
import kotlinx.coroutines.sync.withLock
|
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import moe.fuqiuluo.shamrock.remote.action.ActionManager
|
import moe.fuqiuluo.shamrock.remote.action.ActionManager
|
||||||
@ -31,22 +32,23 @@ import org.java_websocket.server.WebSocketServer
|
|||||||
import java.net.InetSocketAddress
|
import java.net.InetSocketAddress
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
import java.util.Timer
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
internal abstract class WebSocketTransmitServlet(
|
internal abstract class WebSocketTransmitServlet(
|
||||||
host:String,
|
host:String,
|
||||||
port: Int,
|
port: Int,
|
||||||
protected val heartbeatInterval: Long,
|
protected val heartbeatInterval: Long,
|
||||||
) : BaseTransmitServlet, WebSocketServer(InetSocketAddress(host, port)) {
|
) : BaseTransmitServlet, WebSocketServer(InetSocketAddress(host, port)), CoroutineScope {
|
||||||
private val sendLock = Mutex()
|
private lateinit var heartbeatTask: Timer
|
||||||
protected val eventReceivers: MutableList<WebSocket> = Collections.synchronizedList(mutableListOf<WebSocket>())
|
protected val eventReceivers: MutableList<WebSocket> = Collections.synchronizedList(mutableListOf<WebSocket>())
|
||||||
|
|
||||||
init {
|
init {
|
||||||
connectionLostTimeout = 0
|
connectionLostTimeout = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
override val address: String
|
override val address: String = "-"
|
||||||
get() = "-"
|
|
||||||
|
|
||||||
override fun transmitAccess(): Boolean {
|
override fun transmitAccess(): Boolean {
|
||||||
return ShamrockConfig.openWebSocket()
|
return ShamrockConfig.openWebSocket()
|
||||||
@ -62,7 +64,7 @@ internal abstract class WebSocketTransmitServlet(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
if (heartbeatInterval > 0) {
|
if (heartbeatInterval > 0) {
|
||||||
timer("heartbeat", true, 0, heartbeatInterval) {
|
heartbeatTask = timer("heartbeat", true, 0, heartbeatInterval) {
|
||||||
val runtime = AppRuntimeFetcher.appRuntime
|
val runtime = AppRuntimeFetcher.appRuntime
|
||||||
val curUin = runtime.currentAccountUin
|
val curUin = runtime.currentAccountUin
|
||||||
LogCenter.log("WebSocket心跳: $curUin", Level.DEBUG)
|
LogCenter.log("WebSocket心跳: $curUin", Level.DEBUG)
|
||||||
@ -104,7 +106,7 @@ internal abstract class WebSocketTransmitServlet(
|
|||||||
|
|
||||||
override fun onMessage(conn: WebSocket, message: String) {
|
override fun onMessage(conn: WebSocket, message: String) {
|
||||||
val path = URI.create(conn.resourceDescriptor).path
|
val path = URI.create(conn.resourceDescriptor).path
|
||||||
GlobalScope.launch {
|
launch {
|
||||||
onHandleAction(conn, message, path)
|
onHandleAction(conn, message, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +132,10 @@ internal abstract class WebSocketTransmitServlet(
|
|||||||
override fun onError(conn: WebSocket, ex: Exception?) {
|
override fun onError(conn: WebSocket, ex: Exception?) {
|
||||||
LogCenter.log("WSServer Error: " + ex?.stackTraceToString(), Level.ERROR)
|
LogCenter.log("WSServer Error: " + ex?.stackTraceToString(), Level.ERROR)
|
||||||
unsubscribe()
|
unsubscribe()
|
||||||
|
coroutineContext.cancel()
|
||||||
|
if (::heartbeatTask.isInitialized) {
|
||||||
|
heartbeatTask.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
@ -137,14 +143,15 @@ internal abstract class WebSocketTransmitServlet(
|
|||||||
init()
|
init()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected suspend inline fun <reified T> pushTo(body: T) {
|
protected inline fun <reified T> pushTo(body: T) {
|
||||||
if(!transmitAccess()) return
|
if(!transmitAccess()) return
|
||||||
try {
|
try {
|
||||||
sendLock.withLock {
|
broadcastTextEvent(GlobalJson.encodeToString(body))
|
||||||
broadcastTextEvent(GlobalJson.encodeToString(body))
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
LogCenter.log("WS推送失败: ${e.stackTraceToString()}", Level.ERROR)
|
LogCenter.log("WS推送失败: ${e.stackTraceToString()}", Level.ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext =
|
||||||
|
Dispatchers.IO.limitedParallelism(40)
|
||||||
}
|
}
|
@ -22,6 +22,7 @@ import java.io.RandomAccessFile
|
|||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
|
||||||
object DownloadUtils {
|
object DownloadUtils {
|
||||||
private const val MAX_THREAD = 4
|
private const val MAX_THREAD = 4
|
||||||
@ -71,7 +72,7 @@ object DownloadUtils {
|
|||||||
}
|
}
|
||||||
processed += blockSize
|
processed += blockSize
|
||||||
}
|
}
|
||||||
withTimeoutOrNull(60000L) {
|
withTimeoutOrNull(1.minutes) {
|
||||||
while (progress.value < contentLength) {
|
while (progress.value < contentLength) {
|
||||||
if(progress.addAndGet(channel.receive()) >= contentLength) {
|
if(progress.addAndGet(channel.receive()) >= contentLength) {
|
||||||
break
|
break
|
||||||
|
@ -5,6 +5,7 @@ package moe.fuqiuluo.shamrock.xposed.hooks
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.fuqiuluo.shamrock.remote.service.WebSocketClientService
|
import moe.fuqiuluo.shamrock.remote.service.WebSocketClientService
|
||||||
import moe.fuqiuluo.shamrock.remote.service.WebSocketService
|
import moe.fuqiuluo.shamrock.remote.service.WebSocketService
|
||||||
@ -20,12 +21,12 @@ import moe.fuqiuluo.symbols.Process
|
|||||||
import moe.fuqiuluo.symbols.XposedHook
|
import moe.fuqiuluo.symbols.XposedHook
|
||||||
import mqq.app.MobileQQ
|
import mqq.app.MobileQQ
|
||||||
import kotlin.concurrent.timer
|
import kotlin.concurrent.timer
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@XposedHook(Process.MAIN, priority = 10)
|
@XposedHook(Process.MAIN, priority = 10)
|
||||||
internal class InitRemoteService : IAction {
|
internal class InitRemoteService : IAction {
|
||||||
override fun invoke(ctx: Context) {
|
override fun invoke(ctx: Context) {
|
||||||
//if (!PlatformUtils.isMainProcess()) return
|
|
||||||
|
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
try {
|
try {
|
||||||
HTTPServer.start(ShamrockConfig.getPort())
|
HTTPServer.start(ShamrockConfig.getPort())
|
||||||
@ -109,9 +110,12 @@ internal class InitRemoteService : IAction {
|
|||||||
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
if (url.startsWith("ws://") || url.startsWith("wss://")) {
|
||||||
val wsClient = WebSocketClientService(url, interval, wsHeaders)
|
val wsClient = WebSocketClientService(url, interval, wsHeaders)
|
||||||
wsClient.connect()
|
wsClient.connect()
|
||||||
timer(initialDelay = 5000L, period = 5000L) {
|
wsClient.launch {
|
||||||
if (wsClient.isClosed || wsClient.isClosing) {
|
while (true) {
|
||||||
wsClient.reconnect()
|
delay(5.seconds)
|
||||||
|
if (wsClient.isClosed || wsClient.isClosing) {
|
||||||
|
wsClient.reconnect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user