You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.3 KiB
Go
115 lines
2.3 KiB
Go
1 year ago
|
package gtp
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"git.noahlan.cn/noahlan/ntool/nbyte"
|
||
|
"git.noahlan.cn/noahlan/ntool/nstr"
|
||
|
"regexp"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
TabRegex = regexp.MustCompile(`\t`)
|
||
|
IdRegex = regexp.MustCompile(`\s`)
|
||
|
)
|
||
|
|
||
|
type GTPSerializer struct {
|
||
|
contentBuf strings.Builder
|
||
|
firstLine bool
|
||
|
//
|
||
|
lastResp *GTPResponse
|
||
|
}
|
||
|
|
||
|
func NewGTPSerializer() *GTPSerializer {
|
||
|
ret := >PSerializer{
|
||
|
contentBuf: strings.Builder{},
|
||
|
}
|
||
|
ret.reset()
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
func (s *GTPSerializer) Marshal(v any) ([]byte, error) {
|
||
|
ret, ok := v.(*GTPCommand)
|
||
|
if !ok {
|
||
|
return nil, errors.New(fmt.Sprintf("参数类型必须为 %T", GTPCommand{}))
|
||
|
}
|
||
|
// ret arg0 arg1 arg2 ...
|
||
|
// Cmd arg0 arg1 arg2 ...
|
||
|
sb := strings.Builder{}
|
||
|
if ret.ID != "" {
|
||
|
sb.WriteString(ret.ID)
|
||
|
sb.WriteString(" ")
|
||
|
}
|
||
|
sb.WriteString(ret.Cmd)
|
||
|
sb.WriteString(" ")
|
||
|
sb.WriteString(strings.Join(ret.Args, " "))
|
||
|
return []byte(sb.String()), nil
|
||
|
}
|
||
|
|
||
|
func (s *GTPSerializer) reset() {
|
||
|
s.contentBuf.Reset()
|
||
|
s.firstLine = true
|
||
|
s.lastResp = nil
|
||
|
}
|
||
|
|
||
|
func (s *GTPSerializer) Unmarshal(line string) (*GTPResponse, bool) {
|
||
|
// replace \t and trimSpace
|
||
|
line = strings.TrimSpace(TabRegex.ReplaceAllString(line, " "))
|
||
|
// 是否第一行
|
||
|
s.firstLine = nstr.ContainsOne(line, []string{"=", "?"})
|
||
|
|
||
|
if len(line) == 0 {
|
||
|
defer s.reset()
|
||
|
|
||
|
if s.firstLine {
|
||
|
s.lastResp = >PResponse{
|
||
|
ID: "",
|
||
|
Content: s.contentBuf.String(),
|
||
|
Err: errors.New("unknown"),
|
||
|
}
|
||
|
return s.lastResp, true
|
||
|
} else {
|
||
|
// end line
|
||
|
content := s.contentBuf.String()
|
||
|
|
||
|
// remove last '\n'
|
||
|
cLen := len(content)
|
||
|
if cLen > 0 && content[cLen-1] == '\n' {
|
||
|
content = content[:cLen-1]
|
||
|
}
|
||
|
|
||
|
if s.lastResp.Err == nil {
|
||
|
s.lastResp.Content = content
|
||
|
} else {
|
||
|
s.lastResp.Err = errors.New(content)
|
||
|
}
|
||
|
|
||
|
return s.lastResp, true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if s.firstLine {
|
||
|
s.lastResp = >PResponse{}
|
||
|
|
||
|
// 第一行,处理 err, id 等内容
|
||
|
hasErr := line[0] == '?'
|
||
|
hasId := len(line) >= 2 && nbyte.IsDigit(line[1])
|
||
|
line = line[1:]
|
||
|
|
||
|
if hasId {
|
||
|
s.lastResp.ID = IdRegex.Split(line, -1)[0]
|
||
|
line = line[len(s.lastResp.ID):]
|
||
|
}
|
||
|
if hasErr {
|
||
|
s.lastResp.Err = errors.New("接收GTP错误消息")
|
||
|
}
|
||
|
}
|
||
|
// 填充内容直至末尾行
|
||
|
s.contentBuf.WriteString(strings.TrimSpace(line))
|
||
|
s.contentBuf.WriteByte('\n')
|
||
|
|
||
|
return nil, false
|
||
|
}
|