Test Failed
Push — master ( 569253...ad9af8 )
by Vyacheslav
01:38
created

response.go (1 issue)

Severity
1
package goagi
2
3
import (
4
	"strconv"
5
	"strings"
6
)
7
8
type Response interface {
0 ignored issues
show
exported type Response should have comment or be unexported
Loading history...
9
	Code() int
10
	RawResponse() string
11
	Result() int
12
	Value() string
13
	Data() string
14
	EndPos() int64
15
	Digit() string
16
	SResults() int
17
}
18
19
type response struct {
20
	code   int
21
	result int
22
	raw    string
23
	data   string
24
}
25
26
func (r *response) Code() int           { return r.code }
27
func (r *response) RawResponse() string { return r.raw }
28
func (r *response) Result() int         { return r.result }
29
func (r *response) Value() string       { return r.data }
30
func (r *response) Data() string        { return r.data }
31
func (r *response) EndPos() int64       { return 0 }
32
func (r *response) Digit() string       { return "" }
33
func (r *response) SResults() int       { return 0 }
34
35
type responseSuccess struct {
36
	response
37
	value    string
38
	endpos   int64
39
	digit    string
40
	sresults int
41
}
42
43
func (r *responseSuccess) Value() string { return r.value }
44
func (r *responseSuccess) EndPos() int64 { return r.endpos }
45
func (r *responseSuccess) Digit() string { return r.digit }
46
func (r *responseSuccess) SResults() int { return r.sresults }
47
48
func (agi *AGI) sessionSetup(data []string) {
49
	agi.dbg("[>] sessionSetup")
50
	agi.env = make(map[string]string)
51
	agi.arg = make([]string, 0)
52
53
	for _, line := range data {
54
		idx := strings.Index(line, ": ")
55
		if idx == -1 || line[:4] != "agi_" {
56
			agi.dbg(" [!] ignore invalid line: %q", line)
57
			continue
58
		}
59
		if line[:8] == "agi_arg_" {
60
			arg := line[idx+2:]
61
			agi.arg = append(agi.arg, arg)
62
			agi.dbg(" [v] add arg: %q", arg)
63
			continue
64
		}
65
		key, val := line[4:idx], line[idx+2:]
66
		agi.dbg(" [v] add env: %s => %s", key, val)
67
		agi.env[key] = val
68
	}
69
}
70
71
// read and parse response
72
func (agi *AGI) parseResponse(data string, code int) (Response, error) {
73
	agi.dbg("[>] parseResponse")
74
75
	if len(data) < 4 {
76
		agi.dbg(" [!] response is invalid: %q", data)
77
		return nil, ErrAGI.Msg("Recieved response is invalid: %q", data)
78
	}
79
80
	if code == codeEarly {
81
		return agi.parseEarlyResponse(data, code)
82
	}
83
84
	if code == codeSucc {
85
		return agi.parseSuccessResponse(data)
86
	}
87
88
	if code > 500 && code < 600 {
89
		return agi.parseErrorResponse(data, code)
90
	}
91
	return nil, ErrAGI.Msg("Can not recognize the response: %q", data)
92
}
93
94
func (agi *AGI) parseSuccessResponse(data string) (Response, error) {
95
	agi.dbg("[>] parseSuccessResponse: %q", data)
96
	resp := &responseSuccess{}
97
	resp.code = codeSucc
98
	resp.raw = data
99
100
	data = data[4:]
101
	data = trimLastNL(data)
102
	data, result := scanResult(data)
103
	resp.result = result
104
105
	if len(data) == 0 {
106
		return resp, nil
107
	}
108
109
	// parse value
110
	data, value := parseValue(data)
111
	resp.value = value
112
	tokens := strings.Fields(data)
113
	resp.endpos = parseEndpos(tokens)
114
	resp.digit = parseDigit(tokens)
115
	resp.sresults = parseSResults(tokens)
116
	return resp, nil
117
}
118
119
func parseSResults(tokens []string) int {
120
	for _, tok := range tokens {
121
		if len(tok) < 9 || tok[:8] != "results=" {
122
			continue
123
		}
124
		if num, err := strconv.Atoi(tok[8:]); err == nil {
125
			return num
126
		}
127
		return 0
128
	}
129
	return 0
130
}
131
132
func parseDigit(tokens []string) string {
133
	for _, tok := range tokens {
134
		if len(tok) < 7 || tok[:6] != "digit=" {
135
			continue
136
		}
137
		return tok[6:]
138
	}
139
	return ""
140
}
141
142
func parseEndpos(tokens []string) int64 {
143
	for _, tok := range tokens {
144
		if len(tok) < 8 || tok[:7] != "endpos=" {
145
			continue
146
		}
147
		if pos, err := strconv.ParseInt(tok[7:], 10, 64); err == nil {
148
			return pos
149
		}
150
		return 0
151
	}
152
	return 0
153
}
154
155
func parseValue(data string) (string, string) {
156
	if data[0] != '(' {
157
		return data, ""
158
	}
159
	if idx := strings.IndexByte(data, ')'); idx > 0 {
160
		return data[idx+1:], data[1:idx]
161
	}
162
	return data, ""
163
}
164
165
func (agi *AGI) parseEarlyResponse(data string, code int) (Response, error) {
166
	agi.dbg("[>] parseEarlyResponse %d: %q", code, data)
167
	resp := &response{}
168
	resp.code = code
169
	resp.raw = data
170
171
	data = data[4:]
172
	data = trimLastNL(data)
173
174
	data, result := scanResult(data)
175
	resp.result = result
176
	resp.data = data
177
178
	return resp, nil
179
}
180
181
func (agi *AGI) parseErrorResponse(data string, code int) (Response, error) {
182
	agi.dbg("[>] parseErrorResponse %d: %q", code, data)
183
	resp := &response{}
184
	resp.code = code
185
	resp.raw = data
186
187
	if code == codeE520 && data[:4] == "520-" {
188
		resp.data = scanE520Usage(data)
189
		return resp, nil
190
	}
191
192
	data = data[4:]
193
	data = trimLastNL(data)
194
195
	data, result := scanResult(data)
196
	resp.result = result
197
	resp.data = data
198
199
	return resp, nil
200
}
201
202
func trimLastNL(data string) string {
203
	l := len(data)
204
	if l > 0 && data[l-1:] == "\n" {
205
		return data[:l-1]
206
	}
207
	return data
208
}
209
210
func scanResult(data string) (string, int) {
211
	if len(data) < 7 || data[:7] != "result=" {
212
		return data, 0
213
	}
214
	token := strings.SplitN(data, " ", 2)
215
	resultTok := strings.SplitN(token[0], "=", 2)
216
217
	if len(resultTok) > 1 {
218
		if num, err := strconv.Atoi(resultTok[1]); err == nil {
219
			return strings.Join(token[1:], " "), num
220
		}
221
	}
222
	return strings.Join(token[1:], " "), 0
223
}
224
225
func scanResultStrFromRaw(data string) string {
226
	raw := data[4:]
227
	raw = trimLastNL(raw)
228
	tokens := strings.Fields(raw)
229
	if strings.Compare(tokens[0], "result=") <= 0 {
230
		return ""
231
	}
232
	return tokens[0][7:]
233
}
234
235
func scanE520Usage(data string) string {
236
	token := strings.Split(data, "\n")
237
238
	return strings.Join(token[1:len(token)-2], "\n")
239
}
240