mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 05:12:17 +00:00
Compare commits
4 Commits
88beaf8b6f
...
c28c9981c4
Author | SHA1 | Date | |
---|---|---|---|
c28c9981c4 | |||
8fadd0016a | |||
77504d68fd | |||
1490450178 |
@ -176,9 +176,6 @@ internal object MsgSvc: BaseSvc() {
|
|||||||
fromId: String = peedId,
|
fromId: String = peedId,
|
||||||
retryCnt: Int = 3
|
retryCnt: Int = 3
|
||||||
): Result<Pair<Long, Int>> {
|
): Result<Pair<Long, Int>> {
|
||||||
//LogCenter.log(message.toString(), Level.ERROR)
|
|
||||||
//callback.msgHash = result.second 什么垃圾代码,万一cb比你快,你不就寄了?
|
|
||||||
|
|
||||||
// 主动临时消息
|
// 主动临时消息
|
||||||
when (chatType) {
|
when (chatType) {
|
||||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> {
|
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> {
|
||||||
@ -188,13 +185,7 @@ internal object MsgSvc: BaseSvc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val result = MessageHelper.sendMessageWithoutMsgId(
|
val result = MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, fromId, MessageCallback(peedId, 0))
|
||||||
chatType,
|
|
||||||
peedId,
|
|
||||||
message,
|
|
||||||
fromId,
|
|
||||||
MessageCallback(peedId, 0)
|
|
||||||
)
|
|
||||||
return if (result.isFailure
|
return if (result.isFailure
|
||||||
&& result.exceptionOrNull()?.javaClass == SendMsgException::class.java
|
&& result.exceptionOrNull()?.javaClass == SendMsgException::class.java
|
||||||
&& retryCnt > 0) {
|
&& retryCnt > 0) {
|
||||||
|
@ -51,6 +51,47 @@ internal object QFavSvc: BaseSvc() {
|
|||||||
private const val MINOR_VERSION = 9
|
private const val MINOR_VERSION = 9
|
||||||
private var seq = 1
|
private var seq = 1
|
||||||
|
|
||||||
|
suspend fun getItemList(
|
||||||
|
category: Int,
|
||||||
|
startPos: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
): Result<NetResp> {
|
||||||
|
val data = protobufMapOf {
|
||||||
|
it[1] = mapOf(
|
||||||
|
20000 to mapOf(
|
||||||
|
/**
|
||||||
|
* "type", "bid", "category", "start_time", "order_type", "start_pos", "page_size", "sync_policy", "req_source"
|
||||||
|
*/
|
||||||
|
1 to 0,
|
||||||
|
2 to 0,
|
||||||
|
3 to category,
|
||||||
|
//4 to System.currentTimeMillis() - 1000 * 60,
|
||||||
|
//4 to System.currentTimeMillis(),
|
||||||
|
4 to 0,
|
||||||
|
5 to 0,
|
||||||
|
6 to startPos,
|
||||||
|
7 to pageSize,
|
||||||
|
8 to 0,
|
||||||
|
9 to 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.toByteArray()
|
||||||
|
return sendWeiyunReq(20000, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getItemContent(
|
||||||
|
id: String
|
||||||
|
): Result<NetResp> {
|
||||||
|
val data = protobufMapOf {
|
||||||
|
it[1] = mapOf(
|
||||||
|
20001 to mapOf(
|
||||||
|
1 to id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.toByteArray()
|
||||||
|
return sendWeiyunReq(20001, data)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun addImageMsg(
|
suspend fun addImageMsg(
|
||||||
uin: Long,
|
uin: Long,
|
||||||
name: String,
|
name: String,
|
||||||
@ -215,7 +256,7 @@ internal object QFavSvc: BaseSvc() {
|
|||||||
* 4 => pic_list
|
* 4 => pic_list
|
||||||
* 5 => file_list
|
* 5 => file_list
|
||||||
*/
|
*/
|
||||||
2 to content
|
2 to content.textToHtml()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -223,6 +264,10 @@ internal object QFavSvc: BaseSvc() {
|
|||||||
return sendWeiyunReq(20009, data)
|
return sendWeiyunReq(20009, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.textToHtml(): String {
|
||||||
|
return replace("\n", "<div><br/></div>")
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun sendPicUpBlock(
|
suspend fun sendPicUpBlock(
|
||||||
fileSize: Long,
|
fileSize: Long,
|
||||||
offset: Long,
|
offset: Long,
|
||||||
@ -300,7 +345,6 @@ internal object QFavSvc: BaseSvc() {
|
|||||||
override fun onUpdateProgeress(netReq: NetReq, curr: Long, final: Long) {}
|
override fun onUpdateProgeress(netReq: NetReq, curr: Long, final: Long) {}
|
||||||
}
|
}
|
||||||
val pSKey = getWeiYunPSKey()
|
val pSKey = getWeiYunPSKey()
|
||||||
//LogCenter.log(pSKey)
|
|
||||||
httpNetReq.mHttpMethod = HttpNetReq.HTTP_POST
|
httpNetReq.mHttpMethod = HttpNetReq.HTTP_POST
|
||||||
httpNetReq.mSendData = DeflateTools.gzip(packData(packHead(cmd, pSKey), body))
|
httpNetReq.mSendData = DeflateTools.gzip(packData(packHead(cmd, pSKey), body))
|
||||||
httpNetReq.mOutStream = outputStream
|
httpNetReq.mOutStream = outputStream
|
||||||
|
@ -9,6 +9,7 @@ import com.tencent.qqnt.msg.api.IMsgService
|
|||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import kotlinx.serialization.json.JsonArray
|
import kotlinx.serialization.json.JsonArray
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
@ -38,7 +39,11 @@ internal object MessageHelper {
|
|||||||
): Pair<Long, Int> {
|
): Pair<Long, Int> {
|
||||||
val uniseq = generateMsgId(chatType)
|
val uniseq = generateMsgId(chatType)
|
||||||
val msg = messageArrayToMessageElements(chatType, uniseq.second, peerId, decodeCQCode(message)).also {
|
val msg = messageArrayToMessageElements(chatType, uniseq.second, peerId, decodeCQCode(message)).also {
|
||||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
if (it.second.isEmpty() && !it.first) {
|
||||||
|
error("消息合成失败,请查看日志或者检查输入。")
|
||||||
|
} else if (it.second.isEmpty()) {
|
||||||
|
return System.currentTimeMillis() to 0
|
||||||
|
}
|
||||||
}.second.filter {
|
}.second.filter {
|
||||||
it.elementType != -1
|
it.elementType != -1
|
||||||
} as ArrayList<MsgElement>
|
} as ArrayList<MsgElement>
|
||||||
@ -59,6 +64,12 @@ internal object MessageHelper {
|
|||||||
}.second.filter {
|
}.second.filter {
|
||||||
it.elementType != -1
|
it.elementType != -1
|
||||||
} as ArrayList<MsgElement>
|
} as ArrayList<MsgElement>
|
||||||
|
|
||||||
|
// ActionMsg No Care
|
||||||
|
if (msg.isEmpty()) {
|
||||||
|
return Result.success(System.currentTimeMillis() to 0)
|
||||||
|
}
|
||||||
|
|
||||||
val totalSize = msg.filter {
|
val totalSize = msg.filter {
|
||||||
it.elementType == MsgConstant.KELEMTYPEPIC ||
|
it.elementType == MsgConstant.KELEMTYPEPIC ||
|
||||||
it.elementType == MsgConstant.KELEMTYPEPTT ||
|
it.elementType == MsgConstant.KELEMTYPEPTT ||
|
||||||
@ -67,11 +78,11 @@ internal object MessageHelper {
|
|||||||
(it.picElement?.fileSize ?: 0) + (it.pttElement?.fileSize
|
(it.picElement?.fileSize ?: 0) + (it.pttElement?.fileSize
|
||||||
?: 0) + (it.videoElement?.fileSize ?: 0)
|
?: 0) + (it.videoElement?.fileSize ?: 0)
|
||||||
}.reduceOrNull { a, b -> a + b } ?: 0
|
}.reduceOrNull { a, b -> a + b } ?: 0
|
||||||
|
val estimateTime = (totalSize / (300 * 1024)) * 1000 + 2000
|
||||||
|
|
||||||
val estimateTime = (totalSize / (300 * 1024)) * 1000 + 5000
|
|
||||||
lateinit var sendResultPair: Pair<Long, Int>
|
lateinit var sendResultPair: Pair<Long, Int>
|
||||||
val sendRet = withTimeoutOrNull<Pair<Int, String>>(estimateTime) {
|
val sendRet = withTimeoutOrNull<Pair<Int, String>>(estimateTime) {
|
||||||
suspendCoroutine {
|
suspendCancellableCoroutine {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
sendResultPair = sendMessageWithoutMsgId(
|
sendResultPair = sendMessageWithoutMsgId(
|
||||||
chatType,
|
chatType,
|
||||||
|
@ -52,7 +52,7 @@ internal object ActionManager {
|
|||||||
GetWeatherCityCode, GetWeather,
|
GetWeatherCityCode, GetWeather,
|
||||||
|
|
||||||
// FAV
|
// FAV
|
||||||
FavAddRichMediaMsg, FavAddImageMsg,
|
FavAddTextMsg, FavAddImageMsg, FavGetItemContent, FavGetItemList,
|
||||||
|
|
||||||
// OTHER
|
// OTHER
|
||||||
GetDeviceBattery, DownloadFile
|
GetDeviceBattery, DownloadFile
|
||||||
|
@ -3,6 +3,8 @@ package moe.fuqiuluo.shamrock.remote.action.handlers
|
|||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import kotlinx.io.core.discardExact
|
import kotlinx.io.core.discardExact
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
import moe.fuqiuluo.proto.ProtoUtils
|
import moe.fuqiuluo.proto.ProtoUtils
|
||||||
import moe.fuqiuluo.proto.asUtf8String
|
import moe.fuqiuluo.proto.asUtf8String
|
||||||
@ -40,8 +42,14 @@ internal object FavAddImageMsg: IActionHandler() {
|
|||||||
FileUtils.parseAndSave(it)
|
FileUtils.parseAndSave(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val options = BitmapFactory.Options()
|
val options = BitmapFactory.Options()
|
||||||
BitmapFactory.decodeFile(image.absolutePath, options)
|
BitmapFactory.decodeFile(image.absolutePath, options)
|
||||||
|
lateinit var picUrl: String
|
||||||
|
lateinit var picId: String
|
||||||
|
lateinit var itemId: String
|
||||||
|
lateinit var md5: String
|
||||||
|
|
||||||
QFavSvc.applyUpImageMsg(uin, nickName,
|
QFavSvc.applyUpImageMsg(uin, nickName,
|
||||||
image = image,
|
image = image,
|
||||||
groupName = groupName,
|
groupName = groupName,
|
||||||
@ -49,14 +57,12 @@ internal object FavAddImageMsg: IActionHandler() {
|
|||||||
width = options.outWidth,
|
width = options.outWidth,
|
||||||
height = options.outHeight
|
height = options.outHeight
|
||||||
).onSuccess {
|
).onSuccess {
|
||||||
return if (it.mHttpCode == 200 && it.mResult == 0) {
|
if (it.mHttpCode == 200 && it.mResult == 0) {
|
||||||
val readPacket = ByteReadPacket(DeflateTools.ungzip(it.mRespData))
|
val readPacket = ByteReadPacket(DeflateTools.ungzip(it.mRespData))
|
||||||
readPacket.discardExact(6)
|
readPacket.discardExact(6)
|
||||||
val allLength = readPacket.readInt()
|
val allLength = readPacket.readInt()
|
||||||
val dataLength = readPacket.readInt()
|
val dataLength = readPacket.readInt()
|
||||||
val headLength = allLength - dataLength - 16
|
val headLength = allLength - dataLength - 16
|
||||||
//LogCenter.log("上传图片请求成功: ${DeflateTools.ungzip(it.mRespData).toHexString()}")
|
|
||||||
//LogCenter.log("图片上传响应: allLength=$allLength, dataLength=$dataLength, headLength=$headLength")
|
|
||||||
readPacket.discardExact(2)
|
readPacket.discardExact(2)
|
||||||
ByteArray(headLength).also {
|
ByteArray(headLength).also {
|
||||||
readPacket.readFully(it, 0, it.size)
|
readPacket.readFully(it, 0, it.size)
|
||||||
@ -66,55 +72,82 @@ internal object FavAddImageMsg: IActionHandler() {
|
|||||||
}
|
}
|
||||||
val pb = ProtoUtils.decodeFromByteArray(data)
|
val pb = ProtoUtils.decodeFromByteArray(data)
|
||||||
val resp = pb[2, 20010, 1, 2]
|
val resp = pb[2, 20010, 1, 2]
|
||||||
val picUrl = resp[1].asUtf8String
|
picUrl = resp[1].asUtf8String
|
||||||
val picId = resp[11].asUtf8String
|
picId = resp[11].asUtf8String
|
||||||
val md5 = resp[4].asUtf8String
|
md5 = resp[4].asUtf8String
|
||||||
|
|
||||||
val sha = CryptTools
|
|
||||||
.getSHA1("/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/QQ_Collection/pic/" + md5.uppercase() + "_0")
|
|
||||||
|
|
||||||
image.inputStream().use {
|
|
||||||
var offset = 0L
|
|
||||||
val block = ByteArray(131072)
|
|
||||||
var rest = image.length()
|
|
||||||
do {
|
|
||||||
val length = if (rest <= 131072) rest else 131072L
|
|
||||||
if(it.read(block, 0, length.toInt()) != -1) {
|
|
||||||
QFavSvc.sendPicUpBlock(
|
|
||||||
fileSize = image.length(),
|
|
||||||
offset = offset,
|
|
||||||
block = block,
|
|
||||||
blockSize = length,
|
|
||||||
pid = picId,
|
|
||||||
sha = sha
|
|
||||||
).onFailure {
|
|
||||||
return error(it.message ?: it.toString(), echo)
|
|
||||||
}
|
|
||||||
offset += length
|
|
||||||
rest -= length
|
|
||||||
} else {
|
|
||||||
rest = -1
|
|
||||||
}
|
|
||||||
} while (rest > 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
QFavSvc.addImageMsg(
|
|
||||||
uin, nickName, groupId, groupName, picUrl, picId, options.outWidth, options.outHeight, image.length(), md5.uppercase()
|
|
||||||
).onFailure {
|
|
||||||
return error(it.message ?: it.toString(), echo)
|
|
||||||
}
|
|
||||||
|
|
||||||
ok(picUrl, echo)
|
|
||||||
} else {
|
} else {
|
||||||
logic(it.mErrDesc, echo)
|
return logic(it.mErrDesc, echo)
|
||||||
}
|
}
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
return error(it.message ?: it.toString(), echo)
|
return error(it.message ?: it.toString(), echo)
|
||||||
}
|
}
|
||||||
return ok("请求已提交", echo)
|
|
||||||
|
val sha = CryptTools
|
||||||
|
.getSHA1("/storage/emulated/0/Android/data/com.tencent.mobileqq/Tencent/QQ_Collection/pic/" + md5.uppercase() + "_0")
|
||||||
|
|
||||||
|
image.inputStream().use {
|
||||||
|
var offset = 0L
|
||||||
|
val block = ByteArray(131072)
|
||||||
|
var rest = image.length()
|
||||||
|
do {
|
||||||
|
val length = if (rest <= 131072) rest else 131072L
|
||||||
|
if(it.read(block, 0, length.toInt()) != -1) {
|
||||||
|
QFavSvc.sendPicUpBlock(
|
||||||
|
fileSize = image.length(),
|
||||||
|
offset = offset,
|
||||||
|
block = block,
|
||||||
|
blockSize = length,
|
||||||
|
pid = picId,
|
||||||
|
sha = sha
|
||||||
|
).onFailure {
|
||||||
|
return error(it.message ?: it.toString(), echo)
|
||||||
|
}
|
||||||
|
offset += length
|
||||||
|
rest -= length
|
||||||
|
} else {
|
||||||
|
rest = -1
|
||||||
|
}
|
||||||
|
} while (rest > 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
QFavSvc.addImageMsg(
|
||||||
|
uin, nickName, groupId, groupName, picUrl, picId, options.outWidth, options.outHeight, image.length(), md5.uppercase()
|
||||||
|
).onFailure {
|
||||||
|
return error(it.message ?: it.toString(), echo)
|
||||||
|
}.onSuccess {
|
||||||
|
if (it.mHttpCode == 200 && it.mResult == 0) {
|
||||||
|
val readPacket = ByteReadPacket(DeflateTools.ungzip(it.mRespData))
|
||||||
|
readPacket.discardExact(6)
|
||||||
|
val allLength = readPacket.readInt()
|
||||||
|
val dataLength = readPacket.readInt()
|
||||||
|
val headLength = allLength - dataLength - 16
|
||||||
|
readPacket.discardExact(2)
|
||||||
|
ByteArray(headLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val data = ByteArray(dataLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val pb = ProtoUtils.decodeFromByteArray(data)
|
||||||
|
itemId = pb[2, 20009, 1].asUtf8String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok(PicInfo(
|
||||||
|
picUrl = picUrl,
|
||||||
|
picId = picId,
|
||||||
|
id = itemId
|
||||||
|
), echo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun path(): String = "fav.add_image_msg"
|
override fun path(): String = "fav.add_image_msg"
|
||||||
|
|
||||||
override val requiredParams: Array<String> = arrayOf("user_id", "nick", "file")
|
override val requiredParams: Array<String> = arrayOf("user_id", "nick", "file")
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class PicInfo(
|
||||||
|
@SerialName("pic_url") val picUrl: String,
|
||||||
|
@SerialName("pic_id") val picId: String,
|
||||||
|
@SerialName("id") val id: String
|
||||||
|
)
|
||||||
}
|
}
|
@ -1,12 +1,21 @@
|
|||||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||||
|
|
||||||
|
import kotlinx.io.core.ByteReadPacket
|
||||||
|
import kotlinx.io.core.discardExact
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.JsonElement
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import moe.fuqiuluo.proto.ProtoUtils
|
||||||
|
import moe.fuqiuluo.proto.asUtf8String
|
||||||
import moe.fuqiuluo.qqinterface.servlet.QFavSvc
|
import moe.fuqiuluo.qqinterface.servlet.QFavSvc
|
||||||
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
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.tools.EmptyJsonString
|
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||||
|
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||||
|
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||||
|
|
||||||
internal object FavAddRichMediaMsg: IActionHandler() {
|
internal object FavAddTextMsg: IActionHandler() {
|
||||||
override suspend fun internalHandle(session: ActionSession): String {
|
override suspend fun internalHandle(session: ActionSession): String {
|
||||||
val uin = session.getLong("user_id")
|
val uin = session.getLong("user_id")
|
||||||
val nickName = session.getString("nick")
|
val nickName = session.getString("nick")
|
||||||
@ -33,7 +42,23 @@ internal object FavAddRichMediaMsg: IActionHandler() {
|
|||||||
groupId = groupId
|
groupId = groupId
|
||||||
).onSuccess {
|
).onSuccess {
|
||||||
return if (it.mHttpCode == 200 && it.mResult == 0) {
|
return if (it.mHttpCode == 200 && it.mResult == 0) {
|
||||||
ok("成功", echo)
|
val readPacket = ByteReadPacket(DeflateTools.ungzip(it.mRespData))
|
||||||
|
readPacket.discardExact(6)
|
||||||
|
val allLength = readPacket.readInt()
|
||||||
|
val dataLength = readPacket.readInt()
|
||||||
|
val headLength = allLength - dataLength - 16
|
||||||
|
readPacket.discardExact(2)
|
||||||
|
ByteArray(headLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val data = ByteArray(dataLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val pb = ProtoUtils.decodeFromByteArray(data)
|
||||||
|
|
||||||
|
ok(data = QFavItem(
|
||||||
|
pb[2, 20009, 1].asUtf8String
|
||||||
|
), echo)
|
||||||
} else {
|
} else {
|
||||||
logic(it.mErrDesc, echo)
|
logic(it.mErrDesc, echo)
|
||||||
}
|
}
|
||||||
@ -41,7 +66,12 @@ internal object FavAddRichMediaMsg: IActionHandler() {
|
|||||||
return ok("请求已提交", echo)
|
return ok("请求已提交", echo)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun path(): String = "fav.add_rich_media_msg"
|
override fun path(): String = "fav.add_text_msg"
|
||||||
|
|
||||||
override val requiredParams: Array<String> = arrayOf("user_id", "nick", "content")
|
override val requiredParams: Array<String> = arrayOf("user_id", "nick", "content")
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class QFavItem(
|
||||||
|
@SerialName("id") val id: String
|
||||||
|
)
|
||||||
}
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||||
|
|
||||||
|
import kotlinx.io.core.ByteReadPacket
|
||||||
|
import kotlinx.io.core.discardExact
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import moe.fuqiuluo.proto.ProtoUtils
|
||||||
|
import moe.fuqiuluo.proto.asUtf8String
|
||||||
|
import moe.fuqiuluo.qqinterface.servlet.QFavSvc
|
||||||
|
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||||
|
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||||
|
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||||
|
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||||
|
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||||
|
|
||||||
|
internal object FavGetItemContent: IActionHandler() {
|
||||||
|
override suspend fun internalHandle(session: ActionSession): String {
|
||||||
|
val id = session.getString("id")
|
||||||
|
return invoke(id, session.echo)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend operator fun invoke(
|
||||||
|
id: String,
|
||||||
|
echo: JsonElement = EmptyJsonString
|
||||||
|
): String {
|
||||||
|
val respData = DeflateTools.ungzip(QFavSvc.getItemContent(id).onSuccess {
|
||||||
|
if (it.mHttpCode != 200 || it.mResult != 0) {
|
||||||
|
return logic(it.mErrDesc, echo)
|
||||||
|
}
|
||||||
|
}.getOrThrow().mRespData)
|
||||||
|
val readPacket = ByteReadPacket(respData)
|
||||||
|
readPacket.discardExact(6)
|
||||||
|
val allLength = readPacket.readInt()
|
||||||
|
val dataLength = readPacket.readInt()
|
||||||
|
val headLength = allLength - dataLength - 16
|
||||||
|
readPacket.discardExact(2)
|
||||||
|
ByteArray(headLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val data = ByteArray(dataLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val pb = ProtoUtils.decodeFromByteArray(data)
|
||||||
|
|
||||||
|
return ok(ItemContent(pb[2, 20001, 1, 8, 2].asUtf8String))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun path(): String = "fav.get_item_content"
|
||||||
|
|
||||||
|
override val requiredParams: Array<String> = arrayOf("id")
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class ItemContent(
|
||||||
|
@SerialName("content") val content: String
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||||
|
|
||||||
|
import kotlinx.io.core.ByteReadPacket
|
||||||
|
import kotlinx.io.core.discardExact
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import moe.fuqiuluo.proto.ProtoUtils
|
||||||
|
import moe.fuqiuluo.proto.asInt
|
||||||
|
import moe.fuqiuluo.proto.asList
|
||||||
|
import moe.fuqiuluo.proto.asLong
|
||||||
|
import moe.fuqiuluo.proto.asMap
|
||||||
|
import moe.fuqiuluo.proto.asULong
|
||||||
|
import moe.fuqiuluo.proto.asUtf8String
|
||||||
|
import moe.fuqiuluo.qqinterface.servlet.QFavSvc
|
||||||
|
import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||||
|
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||||
|
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||||
|
import moe.fuqiuluo.shamrock.tools.toHexString
|
||||||
|
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||||
|
|
||||||
|
internal object FavGetItemList: IActionHandler() {
|
||||||
|
override suspend fun internalHandle(session: ActionSession): String {
|
||||||
|
val category = session.getInt("category")
|
||||||
|
val startPos = session.getInt("start_pos")
|
||||||
|
val pageSize = session.getInt("page_size")
|
||||||
|
return invoke(category, startPos, pageSize, session.echo)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend operator fun invoke(
|
||||||
|
category: Int,
|
||||||
|
startPos: Int,
|
||||||
|
pageSize: Int,
|
||||||
|
echo: JsonElement = EmptyJsonString
|
||||||
|
): String {
|
||||||
|
if (pageSize <= 1) {
|
||||||
|
return logic("page_size must be greater than 1", echo)
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = DeflateTools.ungzip(QFavSvc.getItemList(
|
||||||
|
category = category,
|
||||||
|
startPos = startPos,
|
||||||
|
pageSize = pageSize
|
||||||
|
).onSuccess {
|
||||||
|
if (it.mHttpCode != 200 || it.mResult != 0) {
|
||||||
|
return logic("fav.get_item_list failed", echo)
|
||||||
|
}
|
||||||
|
}.getOrThrow().mRespData)
|
||||||
|
val readPacket = ByteReadPacket(result)
|
||||||
|
readPacket.discardExact(6)
|
||||||
|
val allLength = readPacket.readInt()
|
||||||
|
val dataLength = readPacket.readInt()
|
||||||
|
val headLength = allLength - dataLength - 16
|
||||||
|
readPacket.discardExact(2)
|
||||||
|
ByteArray(headLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val data = ByteArray(dataLength).also {
|
||||||
|
readPacket.readFully(it, 0, it.size)
|
||||||
|
}
|
||||||
|
val pb = ProtoUtils.decodeFromByteArray(data)
|
||||||
|
|
||||||
|
val itemList = arrayListOf<Item>()
|
||||||
|
val rawItemList = pb[2, 20000, 1].asList
|
||||||
|
rawItemList.value.forEach {
|
||||||
|
val item = it.asMap
|
||||||
|
val itemId = item[1].asUtf8String
|
||||||
|
val authorType = item[4, 1].asInt
|
||||||
|
val author = item[4, 2].asULong
|
||||||
|
val authorName = item[4, 3].asUtf8String
|
||||||
|
val groupName: String
|
||||||
|
val groupId: Long
|
||||||
|
if (authorType == 2) {
|
||||||
|
groupName = item[4, 5].asUtf8String
|
||||||
|
groupId = item[4, 4].asULong
|
||||||
|
} else {
|
||||||
|
groupName = ""
|
||||||
|
groupId = 0L
|
||||||
|
}
|
||||||
|
val clientVersion = item[7].asUtf8String
|
||||||
|
val time = item[9].asLong
|
||||||
|
itemList.add(Item(
|
||||||
|
id = itemId,
|
||||||
|
authorType = authorType,
|
||||||
|
author = author,
|
||||||
|
authorName = authorName,
|
||||||
|
groupName = groupName,
|
||||||
|
groupId = groupId,
|
||||||
|
clientVersion = clientVersion,
|
||||||
|
time = time
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok(ItemList(itemList), echo)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val requiredParams: Array<String> = arrayOf("category", "start_pos", "page_size")
|
||||||
|
|
||||||
|
override fun path(): String = "fav.get_item_list"
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class ItemList(
|
||||||
|
val items: List<Item>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
private data class Item(
|
||||||
|
@SerialName("id") val id: String,
|
||||||
|
@SerialName("author_type") val authorType: Int,
|
||||||
|
@SerialName("author") val author: Long,
|
||||||
|
@SerialName("author_name") val authorName: String,
|
||||||
|
@SerialName("group_name") val groupName: String,
|
||||||
|
@SerialName("group_id") val groupId: Long,
|
||||||
|
@SerialName("client_version") val clientVersion: String,
|
||||||
|
@SerialName("time") val time: Long
|
||||||
|
)
|
||||||
|
}
|
@ -5,11 +5,9 @@ import io.ktor.server.application.call
|
|||||||
import io.ktor.server.response.respondText
|
import io.ktor.server.response.respondText
|
||||||
import io.ktor.server.routing.Routing
|
import io.ktor.server.routing.Routing
|
||||||
import moe.fuqiuluo.shamrock.remote.action.handlers.FavAddImageMsg
|
import moe.fuqiuluo.shamrock.remote.action.handlers.FavAddImageMsg
|
||||||
import moe.fuqiuluo.shamrock.remote.action.handlers.FavAddRichMediaMsg
|
import moe.fuqiuluo.shamrock.remote.action.handlers.FavAddTextMsg
|
||||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetFriendList
|
import moe.fuqiuluo.shamrock.remote.action.handlers.FavGetItemContent
|
||||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetFriendSystemMsg
|
import moe.fuqiuluo.shamrock.remote.action.handlers.FavGetItemList
|
||||||
import moe.fuqiuluo.shamrock.remote.action.handlers.GetStrangerInfo
|
|
||||||
import moe.fuqiuluo.shamrock.remote.action.handlers.IsBlackListUin
|
|
||||||
import moe.fuqiuluo.shamrock.tools.fetchOrNull
|
import moe.fuqiuluo.shamrock.tools.fetchOrNull
|
||||||
import moe.fuqiuluo.shamrock.tools.fetchOrThrow
|
import moe.fuqiuluo.shamrock.tools.fetchOrThrow
|
||||||
import moe.fuqiuluo.shamrock.tools.getOrPost
|
import moe.fuqiuluo.shamrock.tools.getOrPost
|
||||||
@ -24,7 +22,7 @@ fun Routing.fav() {
|
|||||||
val content = call.fetchOrThrow("content")
|
val content = call.fetchOrThrow("content")
|
||||||
val groupName = call.fetchOrNull("group_name") ?: ""
|
val groupName = call.fetchOrNull("group_name") ?: ""
|
||||||
val groupId = call.fetchOrNull("group_id")?.toLong() ?: 0L
|
val groupId = call.fetchOrNull("group_id")?.toLong() ?: 0L
|
||||||
call.respondText(FavAddRichMediaMsg(uin, nickName, time, content, groupName, groupId), ContentType.Application.Json)
|
call.respondText(FavAddTextMsg(uin, nickName, time, content, groupName, groupId), ContentType.Application.Json)
|
||||||
}
|
}
|
||||||
|
|
||||||
getOrPost("/fav/add_image_msg") {
|
getOrPost("/fav/add_image_msg") {
|
||||||
@ -35,4 +33,16 @@ fun Routing.fav() {
|
|||||||
val groupId = call.fetchOrNull("group_id")?.toLong() ?: 0L
|
val groupId = call.fetchOrNull("group_id")?.toLong() ?: 0L
|
||||||
call.respondText(FavAddImageMsg(uin, nickName, file, groupName, groupId), ContentType.Application.Json)
|
call.respondText(FavAddImageMsg(uin, nickName, file, groupName, groupId), ContentType.Application.Json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getOrPost("/fav/get_item_content") {
|
||||||
|
val id = call.fetchOrThrow("id")
|
||||||
|
call.respondText(FavGetItemContent(id), ContentType.Application.Json)
|
||||||
|
}
|
||||||
|
|
||||||
|
getOrPost("/fav/get_item_list") {
|
||||||
|
val category = call.fetchOrThrow("category").toInt()
|
||||||
|
val startPos = call.fetchOrThrow("start_pos").toInt()
|
||||||
|
val pageSize = call.fetchOrThrow("page_size").toInt()
|
||||||
|
call.respondText(FavGetItemList(category, startPos, pageSize), ContentType.Application.Json)
|
||||||
|
}
|
||||||
}
|
}
|
@ -16,6 +16,7 @@ import mqq.app.MobileQQ
|
|||||||
|
|
||||||
internal class HookForDebug: IAction {
|
internal class HookForDebug: IAction {
|
||||||
override fun invoke(ctx: Context) {
|
override fun invoke(ctx: Context) {
|
||||||
|
/*
|
||||||
val httpEngineService = AppRuntimeFetcher.appRuntime
|
val httpEngineService = AppRuntimeFetcher.appRuntime
|
||||||
.getRuntimeService(IHttpEngineService::class.java, "all")
|
.getRuntimeService(IHttpEngineService::class.java, "all")
|
||||||
httpEngineService.javaClass.hookMethod("sendReq").before {
|
httpEngineService.javaClass.hookMethod("sendReq").before {
|
||||||
@ -28,7 +29,7 @@ internal class HookForDebug: IAction {
|
|||||||
LogCenter.log("请求地址: ${req.mReqUrl}")
|
LogCenter.log("请求地址: ${req.mReqUrl}")
|
||||||
LogCenter.log("请求: ${req.toInnerValuesString(NetReq::class.java)}")
|
LogCenter.log("请求: ${req.toInnerValuesString(NetReq::class.java)}")
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user