mirror of
https://github.com/Mrs4s/MiraiGo.git
synced 2025-05-04 19:17:38 +08:00
* 重构:netLoop下移到Listener * 格式:修正NewClient中注释段缩进 * 格式:更名&将代码移动到对应位置 * 格式:TCPListener去锁化 * 修正:netLoop中的错误调用 * 修正:使其可用 * 修正:使功能一致 * 修正:现在可正常运行 * 优化:更早的释放锁(? * 修正:未写完的部分 * 修正:潜在的断线时仍然认为在线这件事&删除空重复文件 * 文档:添加部分注释 * 修正:CoverError可能引起死锁 * 修正:永远不会被触发的DisconnectEvent * 文档:将注释移动至对应位置
91 lines
2.2 KiB
Go
91 lines
2.2 KiB
Go
package network
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/Mrs4s/MiraiGo/binary"
|
|
)
|
|
|
|
type Response struct {
|
|
SequenceID int32
|
|
CommandName string
|
|
Body []byte
|
|
|
|
Params Params
|
|
// Request is the original request that obtained this response.
|
|
// Request *Request
|
|
}
|
|
|
|
var (
|
|
ErrSessionExpired = errors.New("session expired")
|
|
ErrPacketDropped = errors.New("packet dropped")
|
|
ErrInvalidPacketType = errors.New("invalid packet type")
|
|
ErrConnectionBroken = errors.New("connection broken")
|
|
)
|
|
|
|
func (t *Transport) ReadRequest(head []byte) (*Request, error) {
|
|
req := new(Request)
|
|
r := binary.NewReader(head)
|
|
req.Type = RequestType(r.ReadInt32())
|
|
if req.Type != RequestTypeLogin && req.Type != RequestTypeSimple {
|
|
return req, ErrInvalidPacketType
|
|
}
|
|
req.EncryptType = EncryptType(r.ReadByte())
|
|
_ = r.ReadByte() // 0x00?
|
|
|
|
req.Uin, _ = strconv.ParseInt(r.ReadString(), 10, 64)
|
|
body := r.ReadAvailable()
|
|
switch req.EncryptType {
|
|
case EncryptTypeNoEncrypt:
|
|
// nothing to do
|
|
case EncryptTypeD2Key:
|
|
body = binary.NewTeaCipher(t.Sig.D2Key).Decrypt(body)
|
|
case EncryptTypeEmptyKey:
|
|
body = binary.NewTeaCipher(emptyKey).Decrypt(body)
|
|
}
|
|
err := t.readSSOFrame(req, body)
|
|
return req, err
|
|
}
|
|
|
|
func (t *Transport) readSSOFrame(req *Request, payload []byte) error {
|
|
reader := binary.NewReader(payload)
|
|
headLen := reader.ReadInt32()
|
|
if headLen-4 > int32(reader.Len()) {
|
|
return errors.WithStack(ErrPacketDropped)
|
|
}
|
|
|
|
head := binary.NewReader(reader.ReadBytes(int(headLen) - 4))
|
|
req.SequenceID = head.ReadInt32()
|
|
retCode := head.ReadInt32()
|
|
message := head.ReadString()
|
|
switch retCode {
|
|
case 0:
|
|
// ok
|
|
case -10008:
|
|
return errors.WithMessage(ErrSessionExpired, message)
|
|
default:
|
|
return errors.Errorf("return code unsuccessful: %d message: %s", retCode, message)
|
|
}
|
|
req.CommandName = head.ReadString()
|
|
if req.CommandName == "Heartbeat.Alive" {
|
|
return nil
|
|
}
|
|
_ = head.ReadInt32Bytes() // session id
|
|
compressedFlag := head.ReadInt32()
|
|
|
|
bodyLen := reader.ReadInt32() - 4
|
|
body := reader.ReadAvailable()
|
|
if bodyLen > 0 && bodyLen < int32(len(body)) {
|
|
body = body[:bodyLen]
|
|
}
|
|
switch compressedFlag {
|
|
case 0, 8:
|
|
case 1:
|
|
body = binary.ZlibUncompress(body)
|
|
}
|
|
req.Body = body
|
|
return nil
|
|
}
|