-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresp.go
133 lines (113 loc) · 2.82 KB
/
resp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package resp
import (
"fmt"
"github.com/arianxx/camellia-io"
"log"
)
// Command represents a command parsed from the input bytes.
type Command struct {
// Raw is the original data received from the client.
Raw []byte
// Args is the a series of arguments that make up the command.
Args [][]byte
Type string
}
func NewCommand(t string) *Command {
return &Command{[]byte{}, [][]byte{}, t}
}
// Parser tries to parse the input bytes to a series of Command.
type Parser struct {
raw []byte
// nowConverter represents the converter that is now used to process the input stream
nowConverter *Converter
// end indicates whether it should continue parsing.
end bool
}
func NewParser() *Parser {
return &Parser{raw: []byte{}}
}
// AppendRawData appends a raw data to the parser.
func (p *Parser) AppendRawData(in []byte) {
p.raw = append(p.raw, in...)
}
/* Parse parses the received data.
* Return a Command pointers if there are some completed parsings, otherwise it remains nil.
* Return a errProtocol if the error data has been detected.
* If a err was be returned, then the parser will be unusable and should be replaced by a new Parser.
*/
func (p *Parser) Parse() (cmd *Command, err error) {
if p.end {
return nil, fmt.Errorf("unusable ended parser")
}
if p.nowConverter != nil {
cmd, err, p.raw = (*p.nowConverter).Parse(p.raw)
if err != nil {
p.end = true
cmd = nil
return
}
if cmd != nil {
p.nowConverter = nil
return
}
} else if len(p.raw) != 0 {
for s, f := range converters {
if s == p.raw[0] {
c := f()
p.nowConverter = &c
break
}
}
if p.nowConverter == nil {
p.end = true
return nil, fmt.Errorf("unknown type symbol")
}
return p.Parse()
}
return
}
type Server struct {
*camellia.Server
proc CommandProc
Event *camellia.Event
}
func NewServer(net, addr string, f CommandProc) (*Server, error) {
s := &Server{camellia.NewServer(), f, nil}
lis, err := camellia.NewListener(net, addr, s.El)
if err != nil {
return nil, err
}
s.AddListener(lis)
s.Event = &camellia.Event{Data: s.loopProc}
s.AddEvent(s.Event)
return s, nil
}
func (s *Server) StartServe() error {
if s.proc == nil {
log.Fatal("empty proc")
}
return s.Server.StartServe()
}
func (s *Server) loopProc(el *camellia.EventLoop, connPtr *interface{}) {
conn := (*connPtr).(*camellia.Conn)
parserInterface := conn.GetContext()
if parserInterface == nil {
parserInterface = NewParser()
conn.SetContext(parserInterface)
}
parser := parserInterface.(*Parser)
parser.AppendRawData(conn.Read())
cmd, err := parser.Parse()
if err != nil {
conn.SetContext(NewParser())
conn.Write(AppendError([]byte{}, []byte(err.Error())))
return
}
if cmd != nil {
res := &[]byte{}
s.proc(cmd, conn, res)
conn.Write(*res)
return
}
}
type CommandProc func(cmd *Command, conn *camellia.Conn, res *[]byte)