Test Failed
Push — master ( d4cdd3...569253 )
by Vyacheslav
03:17 queued 01:50
created

interface.go (1 issue)

Severity
1
package goagi
2
3
import (
4
	"bufio"
5
	"fmt"
6
	"strings"
7
)
8
9
// AGI interface structure
10
type AGI struct {
11
	env    map[string]string
12
	arg    []string
13
	hangup bool
14
	io     *bufio.ReadWriter
15
}
16
17
var (
18
	// error returned when AGI environment header is not valid
0 ignored issues
show
comment on exported var EInvalEnv should be of the form "EInvalEnv ..."
Loading history...
19
	EInvalEnv = errorNew("Invalid AGI env variable")
20
)
21
22
func newInterface(iodev *bufio.ReadWriter) (*AGI, error) {
23
	agi := &AGI{
24
		env:    make(map[string]string),
25
		arg:    make([]string, 0),
26
		hangup: false,
27
		io:     iodev,
28
	}
29
	scanner := bufio.NewScanner(iodev)
30
	for scanner.Scan() {
31
		line := scanner.Text()
32
		if line == "" {
33
			break
34
		}
35
		if err := agi.setEnv(line); err != nil {
36
			return nil, err
37
		}
38
	}
39
	if err := scanner.Err(); err != nil {
40
		return nil, err
41
	}
42
	return agi, nil
43
}
44
45
// Env returns AGI environment variable by key
46
func (agi *AGI) Env(key string) string {
47
	val, ok := agi.env[key]
48
	if ok {
49
		return val
50
	}
51
	return ""
52
}
53
54
// EnvArgs returns list of environment arguments
55
func (agi *AGI) EnvArgs() []string {
56
	return agi.arg
57
}
58
59
func (agi *AGI) setEnv(line string) error {
60
	if !strings.HasPrefix(line, "agi_") {
61
		return EInvalEnv.withInfo(line)
62
	}
63
	idx := strings.Index(line, ": ")
64
	if idx == -1 {
65
		return EInvalEnv.withInfo(line)
66
	}
67
	if strings.HasPrefix(line, "agi_arg_") {
68
		agi.arg = append(agi.arg, line[idx+2:])
69
	} else {
70
		agi.env[line[4:idx]] = line[idx+2:]
71
	}
72
	return nil
73
}
74
75
func (agi *AGI) execute(cmd string, args ...interface{}) (*agiResp, error) {
76
	_, err := agi.io.WriteString(compileCmd(cmd, args...))
77
	if err != nil {
78
		return nil, err
79
	}
80
	agi.io.Flush()
81
82
	chStr, chErr := agi.read()
83
	select {
84
	case str := <-chStr:
85
		return parseResponse(str)
86
	case err := <-chErr:
87
		return nil, err
88
	}
89
}
90
91
func (agi *AGI) read() (chan string, chan error) {
92
	chStr := make(chan string)
93
	chErr := make(chan error)
94
	go func() {
95
		defer close(chStr)
96
		defer close(chErr)
97
98
		str, err := agi.io.ReadString('\n')
99
		if err != nil {
100
			chErr <- err
101
			return
102
		}
103
		// TODO: read ignore HANGUP or set agi var
104
		if strings.HasPrefix(str, "HANGUP") {
105
			str, err := agi.io.ReadString('\n')
106
			agi.hangup = true // set AGI Hangup flag
107
			if err != nil {
108
				chErr <- err
109
				return
110
			}
111
			chStr <- str
112
		}
113
		if !strings.HasPrefix(str, "520-") {
114
			chStr <- str
115
			return
116
		}
117
		for {
118
			s, err := agi.io.ReadString('\n')
119
			if err != nil {
120
				chErr <- err
121
				return
122
			}
123
			str += s
124
			if strings.HasPrefix(s, "520 End") {
125
				chStr <- str
126
				return
127
			}
128
		}
129
	}()
130
	return chStr, chErr
131
}
132
133
func compileCmd(cmd string, args ...interface{}) string {
134
	for _, arg := range args {
135
		val := fmt.Sprintf("%v", arg)
136
		if len(val) > 0 {
137
			cmd = fmt.Sprintf("%s %s", cmd, val)
138
		} else {
139
			cmd = fmt.Sprintf("%s \"\"", cmd)
140
		}
141
	}
142
143
	return fmt.Sprintf("%s\n", cmd)
144
}
145