Shamrock: fix: implement request type event

This commit is contained in:
ikechan8370 2023-11-23 19:33:50 +08:00
parent 5f91be547e
commit ee8dc75be3
12 changed files with 172 additions and 90 deletions

View File

@ -58,7 +58,7 @@ internal object FriendSvc: BaseSvc() {
) )
} }
suspend fun requestFriendSystemMsgNew(msgNum: Int, latestFriendSeq: Long, latestGroupSeq: Long): List<StructMsg>? { suspend fun requestFriendSystemMsgNew(msgNum: Int, latestFriendSeq: Long = 0, latestGroupSeq: Long = 0, retryCnt: Int = 3): List<StructMsg>? {
val req = `structmsg$ReqSystemMsgNew`() val req = `structmsg$ReqSystemMsgNew`()
req.msg_num.set(msgNum) req.msg_num.set(msgNum)
req.latest_friend_seq.set(latestFriendSeq) req.latest_friend_seq.set(latestFriendSeq)
@ -90,11 +90,16 @@ internal object FriendSvc: BaseSvc() {
req.uint32_req_msg_type.set(1) req.uint32_req_msg_type.set(1)
req.uint32_need_uid.set(1) req.uint32_need_uid.set(1)
val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgNew.Friend", true, req.toByteArray()) val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgNew.Friend", true, req.toByteArray())
?: return ArrayList() return if (respBuffer == null && retryCnt >= 0) {
requestFriendSystemMsgNew(msgNum, latestFriendSeq, latestGroupSeq, retryCnt - 1)
} else if (respBuffer == null) {
ArrayList()
} else {
val msg = `structmsg$RspSystemMsgNew`() val msg = `structmsg$RspSystemMsgNew`()
msg.mergeFrom(respBuffer.slice(4)) msg.mergeFrom(respBuffer.slice(4))
return msg.friendmsgs.get() return msg.friendmsgs.get()
} }
}
private suspend fun requestFriendList(runtime: AppRuntime, dataService: IFriendDataService): Boolean { private suspend fun requestFriendList(runtime: AppRuntime, dataService: IFriendDataService): Boolean {

View File

@ -677,7 +677,7 @@ internal object GroupSvc: BaseSvc() {
} }
} }
suspend fun requestGroupSystemMsgNew(msgNum: Int, latestFriendSeq: Long, latestGroupSeq: Long): List<StructMsg>? { suspend fun requestGroupSystemMsgNew(msgNum: Int, latestFriendSeq: Long = 0, latestGroupSeq: Long = 0, retryCnt: Int = 3): List<StructMsg>? {
val req = ReqSystemMsgNew() val req = ReqSystemMsgNew()
req.msg_num.set(msgNum) req.msg_num.set(msgNum)
req.latest_friend_seq.set(latestFriendSeq) req.latest_friend_seq.set(latestFriendSeq)
@ -709,9 +709,14 @@ internal object GroupSvc: BaseSvc() {
req.uint32_req_msg_type.set(1) req.uint32_req_msg_type.set(1)
req.uint32_need_uid.set(1) req.uint32_need_uid.set(1)
val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgNew.Group", true, req.toByteArray()) val respBuffer = sendBufferAW("ProfileService.Pb.ReqSystemMsgNew.Group", true, req.toByteArray())
?: return ArrayList() return if (respBuffer == null && retryCnt >= 0) {
requestGroupSystemMsgNew(msgNum, latestFriendSeq, latestGroupSeq, retryCnt - 1)
} else if (respBuffer == null) {
ArrayList()
} else {
val msg = RspSystemMsgNew() val msg = RspSystemMsgNew()
msg.mergeFrom(respBuffer.slice(4)) msg.mergeFrom(respBuffer.slice(4))
return msg.groupmsgs.get() return msg.groupmsgs.get()
} }
}
} }

View File

@ -2,6 +2,7 @@ package moe.fuqiuluo.shamrock.remote.action.handlers
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.GroupSvc import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
import moe.fuqiuluo.shamrock.remote.action.ActionSession import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.IActionHandler import moe.fuqiuluo.shamrock.remote.action.IActionHandler
import moe.fuqiuluo.shamrock.remote.service.data.GroupRequest import moe.fuqiuluo.shamrock.remote.service.data.GroupRequest
@ -10,11 +11,11 @@ import moe.fuqiuluo.shamrock.tools.EmptyJsonString
internal object GetGroupSystemMsg: IActionHandler() { internal object GetGroupSystemMsg: IActionHandler() {
override suspend fun internalHandle(session: ActionSession): String { override suspend fun internalHandle(session: ActionSession): String {
return invoke(session.echo) return invoke(echo = session.echo)
} }
suspend operator fun invoke(echo: JsonElement = EmptyJsonString): String { suspend operator fun invoke(echo: JsonElement = EmptyJsonString): String {
val list = GroupSvc.requestGroupSystemMsgNew(20, 0, 0) val list = GroupSvc.requestGroupSystemMsgNew(20)
val msgs = GroupSystemMessage( val msgs = GroupSystemMessage(
invited = mutableListOf(), invited = mutableListOf(),
join = mutableListOf() join = mutableListOf()

View File

@ -16,12 +16,21 @@ internal object SetFriendAddRequest: IActionHandler() {
return invoke(flag, approve, remark, notSeen, session.echo) return invoke(flag, approve, remark, notSeen, session.echo)
} }
operator fun invoke(flag: String, approve: Boolean? = true, remark: String? = "", notSeen: Boolean? = false, echo: JsonElement = EmptyJsonString): String { suspend operator fun invoke(flag: String, approve: Boolean? = true, remark: String? = "", notSeen: Boolean? = false, echo: JsonElement = EmptyJsonString): String {
val flags = flag.split(";") val flags = flag.split(";")
val ts = flags[0].toLong() var ts = flags[0].toLong()
// val src = flags[1].toInt() // val src = flags[1].toInt()
// val subSrc = flags[2].toInt() // val subSrc = flags[2].toInt()
val applier = flags[3].toLong() val applier = flags[3].toLong()
if (ts.toString().length < 13) {
// time but not seq, query seq again
val reqs = FriendSvc.requestFriendSystemMsgNew(20, 0, 0, 1)
val req = reqs?.first {
it.msg_time.get() == ts
}
// 好友请求seq貌似就是time*1000查不到直接*1000
ts = req?.msg_seq?.get() ?: (ts * 1000)
}
return try { return try {
FriendSvc.requestFriendRequest(ts, applier, remark ?: "", approve, notSeen) FriendSvc.requestFriendRequest(ts, applier, remark ?: "", approve, notSeen)
ok("成功", echo) ok("成功", echo)

View File

@ -1,6 +1,7 @@
package moe.fuqiuluo.shamrock.remote.action.handlers package moe.fuqiuluo.shamrock.remote.action.handlers
import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.qqinterface.servlet.FriendSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.shamrock.remote.action.ActionSession import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.IActionHandler import moe.fuqiuluo.shamrock.remote.action.IActionHandler
@ -18,7 +19,15 @@ internal object SetGroupAddRequest: IActionHandler() {
suspend operator fun invoke(flag: String, approve: Boolean? = true, subType: String, remark: String? = "", notSeen: Boolean? = false, echo: JsonElement = EmptyJsonString): String { suspend operator fun invoke(flag: String, approve: Boolean? = true, subType: String, remark: String? = "", notSeen: Boolean? = false, echo: JsonElement = EmptyJsonString): String {
val flags = flag.split(";") val flags = flag.split(";")
val ts = flags[0].toLong() var ts = flags[0].toLong()
if (ts.toString().length < 13) {
// time but not seq, query seq again
val reqs = GroupSvc.requestGroupSystemMsgNew(20)
val req = reqs?.first {
it.msg_time.get() == ts
}
ts = req?.msg_seq?.get() ?: return error("失败:未找到该请求", echo)
}
val groupCode = flags[1].toLong() val groupCode = flags[1].toLong()
val uin = flags[2].toLong() val uin = flags[2].toLong()
return try { return try {
@ -32,7 +41,6 @@ internal object SetGroupAddRequest: IActionHandler() {
err.printStackTrace() err.printStackTrace()
error("失败:${err.message}", echo) error("失败:${err.message}", echo)
} }
} }
override fun path(): String = "set_group_add_request" override fun path(): String = "set_group_add_request"

View File

@ -54,6 +54,12 @@ internal object HttpService: HttpTransmitServlet() {
GlobalEventTransmitter.onNoticeEvent { event -> GlobalEventTransmitter.onNoticeEvent { event ->
pushTo(event) pushTo(event)
} }
})
submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onRequestEvent {
pushTo(it)
}
}) })
LogCenter.log("HttpService: 初始化服务", Level.WARN) LogCenter.log("HttpService: 初始化服务", Level.WARN)
} }

View File

@ -33,6 +33,11 @@ internal class WebSocketClientService(
pushTo(event) pushTo(event)
} }
}) })
submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onRequestEvent() { event ->
pushTo(event)
}
})
LogCenter.log("WebSocketClientService: 初始化服务", Level.WARN) LogCenter.log("WebSocketClientService: 初始化服务", Level.WARN)
} }

View File

@ -39,6 +39,11 @@ internal class WebSocketService(host: String, port: Int): WebSocketTransmitServl
pushTo(event) pushTo(event)
} }
}) })
submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onRequestEvent { event ->
pushTo(event)
}
})
LogCenter.log("WebSocketService: 初始化服务", Level.WARN) LogCenter.log("WebSocketService: 初始化服务", Level.WARN)
} }

View File

@ -20,6 +20,9 @@ import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeEvent
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.remote.service.data.push.PrivateFileMsg import moe.fuqiuluo.shamrock.remote.service.data.push.PrivateFileMsg
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestEvent
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestType
import moe.fuqiuluo.shamrock.remote.service.data.push.Sender import moe.fuqiuluo.shamrock.remote.service.data.push.Sender
import moe.fuqiuluo.shamrock.tools.ShamrockDsl import moe.fuqiuluo.shamrock.tools.ShamrockDsl
import moe.fuqiuluo.shamrock.tools.json import moe.fuqiuluo.shamrock.tools.json
@ -32,9 +35,14 @@ internal object GlobalEventTransmitter: BaseSvc() {
private val noticeEventFlow by lazy { private val noticeEventFlow by lazy {
MutableSharedFlow<NoticeEvent>() MutableSharedFlow<NoticeEvent>()
} }
private val requestEventFlow by lazy {
MutableSharedFlow<RequestEvent>()
}
private suspend fun pushNotice(noticeEvent: NoticeEvent) = noticeEventFlow.emit(noticeEvent) private suspend fun pushNotice(noticeEvent: NoticeEvent) = noticeEventFlow.emit(noticeEvent)
private suspend fun pushRequest(requestEvent: RequestEvent) = requestEventFlow.emit(requestEvent)
private suspend fun transMessageEvent(record: MsgRecord, message: MessageEvent) = messageEventFlow.emit(record to message) private suspend fun transMessageEvent(record: MsgRecord, message: MessageEvent) = messageEventFlow.emit(record to message)
/** /**
@ -314,30 +322,6 @@ internal object GlobalEventTransmitter: BaseSvc() {
)) ))
return true return true
} }
suspend fun transGroupApply(
time: Long,
operator: Long,
reason: String,
groupCode: Long,
flag: String,
subType: NoticeSubType
): Boolean {
pushNotice(NoticeEvent(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.GroupApply,
operatorId = operator,
userId = operator,
tip = reason,
groupId = groupCode,
subType = subType,
flag = flag
))
return true
}
} }
/** /**
@ -373,15 +357,42 @@ internal object GlobalEventTransmitter: BaseSvc() {
return true return true
} }
suspend fun transFriendApply(time: Long, operation: Long, tipText: String, flag: String): Boolean { }
pushNotice(NoticeEvent(
/**
* 请求 通知器
*/
object RequestTransmitter {
suspend fun transFriendApp(time: Long, operation: Long, tipText: String, flag: String): Boolean {
pushRequest(RequestEvent(
time = time, time = time,
selfId = app.longAccountUin, selfId = app.longAccountUin,
postType = PostType.Notice, postType = PostType.Request,
type = NoticeType.FriendApply, type = RequestType.Friend,
operatorId = operation,
userId = operation, userId = operation,
tip = tipText, comment = tipText,
flag = flag
))
return true
}
suspend fun transGroupApply(
time: Long,
operator: Long,
reason: String,
groupCode: Long,
flag: String,
subType: RequestSubType
): Boolean {
pushRequest(RequestEvent(
time = time,
selfId = app.longAccountUin,
postType = PostType.Request,
type = RequestType.Group,
userId = operator,
comment = reason,
groupId = groupCode,
subType = subType,
flag = flag flag = flag
)) ))
return true return true
@ -398,6 +409,12 @@ internal object GlobalEventTransmitter: BaseSvc() {
noticeEventFlow noticeEventFlow
.collect(collector) .collect(collector)
} }
@ShamrockDsl
suspend inline fun onRequestEvent(collector: FlowCollector<RequestEvent>) {
requestEventFlow
.collect(collector)
}
} }

View File

@ -33,6 +33,7 @@ internal enum class MsgType {
internal enum class PostType { internal enum class PostType {
@SerialName("meta_event") Meta, @SerialName("meta_event") Meta,
@SerialName("notice") Notice, @SerialName("notice") Notice,
@SerialName("request") Request,
@SerialName("message") Msg, @SerialName("message") Msg,
@SerialName("message_sent") MsgSent, @SerialName("message_sent") MsgSent,
} }

View File

@ -10,14 +10,18 @@ internal enum class NoticeType {
@SerialName("group_decrease") GroupMemDecrease, @SerialName("group_decrease") GroupMemDecrease,
@SerialName("group_increase") GroupMemIncrease, @SerialName("group_increase") GroupMemIncrease,
@SerialName("group_recall") GroupRecall, @SerialName("group_recall") GroupRecall,
@SerialName("group_apply") GroupApply,
@SerialName("friend_recall") FriendRecall, @SerialName("friend_recall") FriendRecall,
@SerialName("friend_add") FriendApply,
@SerialName("notify") Notify, @SerialName("notify") Notify,
@SerialName("group_upload") GroupUpload, @SerialName("group_upload") GroupUpload,
@SerialName("private_upload") PrivateUpload @SerialName("private_upload") PrivateUpload
} }
@Serializable
internal enum class RequestType {
@SerialName("friend ") Friend,
@SerialName("group") Group,
}
@Serializable @Serializable
internal enum class NoticeSubType { internal enum class NoticeSubType {
@SerialName("none") None, @SerialName("none") None,
@ -38,6 +42,13 @@ internal enum class NoticeSubType {
@SerialName("poke") Poke, @SerialName("poke") Poke,
} }
@Serializable
internal enum class RequestSubType {
@SerialName("none") None,
@SerialName("add") Add,
@SerialName("invite") Invite,
}
/** /**
* 不要使用继承的方式实现通用字段那样会很难维护 * 不要使用继承的方式实现通用字段那样会很难维护
*/ */
@ -61,6 +72,23 @@ internal data class NoticeEvent(
@SerialName("flag") val flag: String? = null, @SerialName("flag") val flag: String? = null,
) )
/**
* 不要使用继承的方式实现通用字段那样会很难维护
*/
@Serializable
internal data class RequestEvent(
@SerialName("time") val time: Long,
@SerialName("self_id") val selfId: Long,
@SerialName("post_type") val postType: PostType,
@SerialName("request_type ") val type: RequestType,
@SerialName("sub_type") val subType: RequestSubType = RequestSubType.None,
@SerialName("group_id") val groupId: Long = 0,
@SerialName("user_id") val userId: Long = 0,
@SerialName("comment") val comment: String = "",
@SerialName("flag") val flag: String? = null,
)
@Serializable @Serializable
internal data class GroupFileMsg( internal data class GroupFileMsg(
val id: String, val id: String,

View File

@ -29,6 +29,7 @@ import moe.fuqiuluo.shamrock.tools.slice
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
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestSubType
import moe.fuqiuluo.shamrock.tools.readBuf32Long import moe.fuqiuluo.shamrock.tools.readBuf32Long
import moe.fuqiuluo.shamrock.tools.toHexString import moe.fuqiuluo.shamrock.tools.toHexString
import moe.fuqiuluo.shamrock.xposed.helper.PacketHandler import moe.fuqiuluo.shamrock.xposed.helper.PacketHandler
@ -118,19 +119,21 @@ internal object PrimitiveListener {
if (applier == 0L) { if (applier == 0L) {
applier = pb[4, 3, 8].asLong applier = pb[4, 3, 8].asLong
} }
val msg_time = pb[1, 3, 2, 1, 9].asLong
val src = pb[1, 3, 2, 1, 7].asInt val src = pb[1, 3, 2, 1, 7].asInt
val subSrc = pb[1, 3, 2, 1, 8].asInt val subSrc = pb[1, 3, 2, 1, 8].asInt
val flag: String = try {
val reqs = requestFriendSystemMsgNew(20, 0, 0) val reqs = requestFriendSystemMsgNew(20, 0, 0)
val req = reqs?.first { val req = reqs?.first {
it.msg_time.get() == msg_time it.msg_time.get() == msgTime
} }
val seq = req?.msg_seq?.get() val seq = req?.msg_seq?.get()
val flag = "$seq;$src;$subSrc;$applier" "$seq;$src;$subSrc;$applier"
} catch (err: Throwable) {
"$msgTime;$src;$subSrc;$applier"
}
LogCenter.log("来自$applier 的好友申请:$msg ($source)") LogCenter.log("来自$applier 的好友申请:$msg ($source)")
if(!GlobalEventTransmitter.PrivateNoticeTransmitter if(!GlobalEventTransmitter.RequestTransmitter
.transFriendApply(msgTime, applier, msg, flag)) { .transFriendApp(msgTime, applier, msg, flag)) {
LogCenter.log("好友申请推送失败!", Level.WARN) LogCenter.log("好友申请推送失败!", Level.WARN)
} }
} }
@ -340,24 +343,20 @@ internal object PrimitiveListener {
val applier = ContactHelper.getUinByUidAsync(applierUid).toLong() val applier = ContactHelper.getUinByUidAsync(applierUid).toLong()
LogCenter.log("入群申请($groupCode) $applier: \"$reason\"") LogCenter.log("入群申请($groupCode) $applier: \"$reason\"")
try { val flag = try {
val reqs = requestGroupSystemMsgNew(20, 0, 0) val reqs = requestGroupSystemMsgNew(10, 0, 0)
val req = reqs?.first { val req = reqs?.first {
it.msg_time.get() == time it.msg_time.get() == time
} }
val seq = req?.msg_seq?.get() val seq = req?.msg_seq?.get()
val flag = "$seq;$groupCode;$applierUid" "$seq;$groupCode;$applierUid"
if(!seq?.let {
GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupApply(it, applier, reason, groupCode, flag, NoticeSubType.Add)
}!!) {
LogCenter.log("入群申请推送失败!", Level.WARN)
}
} catch (err: Throwable) { } catch (err: Throwable) {
LogCenter.log("入群申请推送失败!", Level.WARN) "$time;$groupCode;$applierUid"
LogCenter.log(err.stackTraceToString(), Level.ERROR) }
if(!GlobalEventTransmitter.RequestTransmitter
.transGroupApply(time, applier, reason, groupCode, flag, RequestSubType.Add)) {
LogCenter.log("入群申请推送失败!", Level.WARN)
} }
} }
528 -> { 528 -> {
val groupCode = pb[1, 3, 2, 2, 3].asULong val groupCode = pb[1, 3, 2, 2, 3].asULong
@ -368,23 +367,19 @@ internal object PrimitiveListener {
return return
} }
LogCenter.log("邀请入群申请($groupCode): $applier") LogCenter.log("邀请入群申请($groupCode): $applier")
try { val flag = try {
val reqs = requestGroupSystemMsgNew(20, 0, 0) val reqs = requestGroupSystemMsgNew(10, 0, 0)
val req = reqs?.first { val req = reqs?.first {
it.msg_time.get() == time it.msg_time.get() == time
} }
val seq = req?.msg_seq?.get() val seq = req?.msg_seq?.get()
val flag = "$seq;$groupCode;$applier" "$seq;$groupCode;$applier"
if(!seq?.let {
GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupApply(it, applier, "", groupCode, flag, NoticeSubType.Add)
}!!) {
LogCenter.log("邀请入群申请推送失败!", Level.WARN)
}
} catch (err: Throwable) { } catch (err: Throwable) {
"$time;$groupCode;$applierUid"
}
if(GlobalEventTransmitter.RequestTransmitter
.transGroupApply(time, applier, "", groupCode, flag, RequestSubType.Add)) {
LogCenter.log("邀请入群申请推送失败!", Level.WARN) LogCenter.log("邀请入群申请推送失败!", Level.WARN)
LogCenter.log(err.stackTraceToString(), Level.ERROR)
} }
} }
} }
@ -395,22 +390,19 @@ internal object PrimitiveListener {
val invitor = ContactHelper.getUinByUidAsync(invitorUid).toLong() val invitor = ContactHelper.getUinByUidAsync(invitorUid).toLong()
val uin = pb[1, 1, 5].asLong val uin = pb[1, 1, 5].asLong
LogCenter.log("邀请入群$groupCode 邀请者: \"$invitor\"") LogCenter.log("邀请入群$groupCode 邀请者: \"$invitor\"")
try { val flag = try {
val reqs = requestGroupSystemMsgNew(20, 0, 0) val reqs = requestGroupSystemMsgNew(10, 0, 0)
val req = reqs?.first { val req = reqs?.first {
it.msg_time.get() == time it.msg_time.get() == time
} }
val seq = req?.msg_seq?.get() val seq = req?.msg_seq?.get()
val flag = "$seq;$groupCode;$uin" "$seq;$groupCode;$uin"
if(!seq?.let {
GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupApply(it, invitor, "", groupCode, flag, NoticeSubType.Invite)
}!!) {
LogCenter.log("邀请入群推送失败!", Level.WARN)
}
} catch (err: Throwable) { } catch (err: Throwable) {
"$time;$groupCode;$uin"
}
if(GlobalEventTransmitter.RequestTransmitter
.transGroupApply(time, invitor, "", groupCode, flag, RequestSubType.Invite)) {
LogCenter.log("邀请入群推送失败!", Level.WARN) LogCenter.log("邀请入群推送失败!", Level.WARN)
LogCenter.log(err.stackTraceToString(), Level.ERROR)
} }
} }