├── codecov.yml
├── agi
├── README.md
├── agi_demo_test.go
├── agi_test.go
├── agimodels
│ ├── command_test.go
│ ├── iface.go
│ └── commands.go
├── agi_bin.go
└── agi.go
├── pkg
└── tools
│ └── xmlgen
│ ├── template
│ ├── field.tmpl
│ ├── ami
│ │ ├── events.tmpl
│ │ ├── actions.tmpl
│ │ ├── event.tmpl
│ │ └── action.tmpl
│ └── agi
│ │ ├── commands.tmpl
│ │ └── command.tmpl
│ ├── parse.go
│ ├── _ami_parse_test.go
│ ├── _doc_test.go
│ ├── gen_model_build.go
│ ├── gen_model.go
│ ├── build.go
│ ├── tmpl.go
│ ├── doc_model.go
│ └── model.go
├── ami
├── amimodels
│ ├── evt.go
│ └── iface.go
├── conn.go
├── connect_demo_test.go
├── handler.go
├── subscribe.go
├── msg_test.go
├── request.go
├── conn_internal.go
├── msg.go
└── connect.go
├── .editorconfig
├── Makefile
├── .github
└── workflows
│ └── ci.yml
├── go.mod
├── astdb
├── ps_model.go
├── model.go
├── _enum_gen_test.go
└── enums.go
├── .golangci.yml
├── .gitignore
├── README.md
├── LICENSE
└── go.sum
/codecov.yml:
--------------------------------------------------------------------------------
1 | ignore:
2 | - pkg/tools
3 | - astdb # not ready yet
4 | # generated
5 | - ami/amimodels
6 | - agi/agimodels
7 |
--------------------------------------------------------------------------------
/agi/README.md:
--------------------------------------------------------------------------------
1 | # AGI
2 | - [handle_connection](https://github.com/asterisk/asterisk/blob/master/res/res_agi.c#L2012)
3 | - FastAGI defaults port 4573
4 | # See also
5 |
6 | - [CyCoreSystems/agi](https://github.com/CyCoreSystems/agi)
7 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/field.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.Field */}}
2 | {{- define "field"}}
3 | {{- with .Doc}}
4 | {{template "comment" . | nindent 2}}
5 | {{- end}}
6 | {{.Name}} {{.Type}}
7 | {{- end}}
8 |
--------------------------------------------------------------------------------
/ami/amimodels/evt.go:
--------------------------------------------------------------------------------
1 | package amimodels
2 |
3 | import "github.com/pkg/errors"
4 |
5 | func (evt OriginateResponseEvent) Err() error {
6 | if evt.Response == "Failure" {
7 | return errors.Errorf("Originate failed: exten %v reason %v", evt.Exten, evt.Reason)
8 | }
9 | return nil
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [Makefile]
12 | indent_style = tab
13 | indent_size = 4
14 |
15 | [*.go]
16 | indent_style = tab
17 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/ami/events.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.Model */}}
2 | {{- define "ami/events"}}
3 | // Code generated by xmlgen. DO NOT EDIT.
4 |
5 | package amimodels
6 |
7 | {{range $_,$v := $.Events}}
8 | {{template "ami/event" $v}}
9 | {{end}}
10 | {{- end}}
11 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/ami/actions.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.Model */}}
2 | {{- define "ami/actions"}}
3 | // Code generated by xmlgen. DO NOT EDIT.
4 |
5 | package amimodels
6 |
7 | {{range $_,$v := $.Actions}}
8 | {{template "ami/action" $v}}
9 | {{end}}
10 | {{- end}}
11 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/agi/commands.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.Model*/}}
2 |
3 | {{- define "agi/commands"}}
4 | // Code generated by xmlgen. DO NOT EDIT.
5 |
6 | package agimodels
7 |
8 | {{range $_,$v := $.AGICommands}}
9 | {{template "agi/command" $v}}
10 | {{end}}
11 | {{- end}}
12 |
--------------------------------------------------------------------------------
/agi/agi_demo_test.go:
--------------------------------------------------------------------------------
1 | package agi_test
2 |
3 | import "github.com/wenerme/astgo/agi"
4 |
5 | func ExampleRun() {
6 | agi.Run(func(session *agi.Session) {
7 | client := session.Client()
8 | client.Answer()
9 | client.StreamFile("activated", "#")
10 | client.SetVariable("AGISTATUS", "SUCCESS")
11 | client.Hangup()
12 | })
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/ami/event.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.ManagerEvent*/}}
2 | {{- define "ami/event"}}
3 | {{with .Synopsis}} {{template "comment" (printf "%v %v" $.StructName .)}} {{end}}
4 | type {{.StructName}} struct {
5 | {{- template "ami/fields" .}}
6 | }
7 | func({{.StructName}})EventTypeName() string{
8 | return "{{.Name}}"
9 | }
10 | {{- end}}
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | love:
3 |
4 | fmt:
5 | gofmt -w `find . -type f -name '*.go' -not -path "./vendor/*"`
6 | goimports -w `find . -type f -name '*.go' -not -path "./vendor/*"`
7 |
8 | lint:
9 | golangci-lint run
10 |
11 | ci: cover
12 | [ -z "$(CODECOV_TOKEN)" ] || bash -c 'bash <(curl -s https://codecov.io/bash)'
13 |
14 | .PHONY: cover
15 | cover:
16 | go test -race -coverprofile=cover.out -coverpkg=./... ./...
17 | go tool cover -html=cover.out -o cover.html
18 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Test and coverage
2 |
3 | on: [ push, pull_request ]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | with:
11 | fetch-depth: 2
12 | - uses: actions/setup-go@v2
13 | with:
14 | go-version: '1.16'
15 | - name: Run CI
16 | run: make ci
17 | - name: Upload coverage to codecov.io
18 | uses: codecov/codecov-action@v1
19 |
--------------------------------------------------------------------------------
/agi/agi_test.go:
--------------------------------------------------------------------------------
1 | package agi
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestParseResponse(t *testing.T) {
10 | for _, test := range []struct {
11 | L string
12 | R Response
13 | }{
14 | {L: "200 result=1", R: Response{Status: 200, Result: 1, ResultString: "1"}},
15 | {L: "200 result=0 endpos=8640", R: Response{Status: 200, Result: 0, ResultString: "0", Value: "endpos=8640"}},
16 | } {
17 | assert.Equal(t, &test.R, ParseResponse(test.L))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/parse.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | type Type struct {
4 | Name string
5 | Doc string
6 | Fields []*Field
7 | }
8 | type Field struct {
9 | Name string
10 | Doc string
11 | Default string
12 | Required bool
13 | Type *TypeInfo
14 | StructTag string
15 | Annotations interface{}
16 | }
17 | type Annotation interface {
18 | Name() string
19 | }
20 | type TypeInfo struct {
21 | Type string
22 | }
23 |
24 | func (ti *TypeInfo) String() string {
25 | return ti.Type
26 | }
27 |
--------------------------------------------------------------------------------
/ami/conn.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import (
4 | "bufio"
5 | "context"
6 | "net"
7 | "sync"
8 |
9 | "go.uber.org/zap"
10 | "golang.org/x/sync/errgroup"
11 | )
12 |
13 | type Conn struct {
14 | g *errgroup.Group
15 | conn net.Conn
16 | reader *bufio.Reader
17 | nextID func() string
18 | pending chan *asyncMsg
19 | recv chan *Message
20 | ctx context.Context
21 | closer context.CancelFunc
22 | closed bool
23 |
24 | version string
25 | logger *zap.Logger
26 | conf *ConnectOptions
27 | subs []*subscribe
28 | subLoc sync.Mutex
29 | }
30 |
--------------------------------------------------------------------------------
/agi/agimodels/command_test.go:
--------------------------------------------------------------------------------
1 | package agimodels
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 | )
8 |
9 | func TestBuild(t *testing.T) {
10 | for _, test := range []struct {
11 | S string
12 | C Command
13 | }{
14 | {S: "HANGUP 16", C: HangupCommand{}.SetChannelName("16")},
15 | {S: "CONTROL STREAM FILE fn #", C: ControlStreamFileCommand{FileName: "fn", EscapeDigits: "#"}},
16 | {S: "CONTROL STREAM FILE fn #", C: ControlStreamFileCommand{FileName: "fn", EscapeDigits: "#"}.SetPausechr("Abc")},
17 | } {
18 | s, err := test.C.Command()
19 | assert.NoError(t, err)
20 | assert.Equal(t, test.S, s)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/_ami_parse_test.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import (
4 | "context"
5 | "encoding/xml"
6 | "log"
7 | "os"
8 | "testing"
9 | )
10 |
11 | func TestParse(t *testing.T) {
12 | f, _ := os.Open("out.xml")
13 | defer f.Close()
14 | dec := xml.NewDecoder(f)
15 | var doc Docs
16 | if err := dec.Decode(&doc); err != nil {
17 | log.Fatal(err)
18 | }
19 |
20 | ge := NewAMIGenerator()
21 | ge.Debug = true
22 | d := &AstDoc{}
23 |
24 | BuildAstDoc(&doc, d)
25 |
26 | err := ge.Generate(context.Background(), d)
27 | if err != nil {
28 | panic(err)
29 | }
30 | err = ge.Write(WriteConfig{
31 | Target: "./../../../ami/models",
32 | //DryRun: true,
33 | })
34 | if err != nil {
35 | panic(err)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ami/connect_demo_test.go:
--------------------------------------------------------------------------------
1 | package ami_test
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "github.com/wenerme/astgo/ami"
7 | )
8 |
9 | func ExampleConnect() {
10 | boot := make(chan *ami.Message, 1)
11 |
12 | conn, err := ami.Connect(
13 | "192.168.1.1:5038",
14 | ami.WithAuth("admin", "admin"), // AMI auth
15 | // add predefined subscriber
16 | ami.WithSubscribe(ami.SubscribeFullyBootedChanOnce(boot)),
17 | ami.WithSubscribe(func(ctx context.Context, msg *ami.Message) bool {
18 | fmt.Println(msg.Format()) // log everything
19 | return true // keep subscribe
20 | }, ami.SubscribeSend(), // subscribe send message - default recv only
21 | ))
22 | if err != nil {
23 | panic(err)
24 | }
25 | <-boot
26 | // AMI now FullyBooted
27 | _ = conn
28 | }
29 |
--------------------------------------------------------------------------------
/ami/handler.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import "context"
4 |
5 | func SubscribeChan(c chan *Message, names ...string) SubscribeFunc {
6 | m := make(map[string]struct{}, len(names))
7 | for _, v := range names {
8 | m[v] = struct{}{}
9 | }
10 | filter := func(ctx context.Context, msg *Message) bool {
11 | _, ok := m[msg.Name]
12 | return ok
13 | }
14 | if len(names) == 0 {
15 | filter = func(ctx context.Context, msg *Message) bool {
16 | return true
17 | }
18 | }
19 | return func(ctx context.Context, msg *Message) bool {
20 | if filter(ctx, msg) {
21 | c <- msg
22 | }
23 |
24 | return true
25 | }
26 | }
27 |
28 | func SubscribeFullyBootedChanOnce(c chan *Message) SubscribeFunc {
29 | return func(ctx context.Context, msg *Message) bool {
30 | if msg.Name == "FullyBooted" {
31 | c <- msg
32 | return false
33 | }
34 | return true
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/wenerme/astgo
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/Masterminds/goutils v1.1.1 // indirect
7 | github.com/Masterminds/semver v1.5.0 // indirect
8 | github.com/Masterminds/sprig v2.22.0+incompatible
9 | github.com/go-pg/pg v8.0.7+incompatible
10 | github.com/google/uuid v1.2.0 // indirect
11 | github.com/hashicorp/go-multierror v1.1.1
12 | github.com/huandu/xstrings v1.3.2
13 | github.com/iancoleman/strcase v0.1.3
14 | github.com/imdario/mergo v0.3.12 // indirect
15 | github.com/jinzhu/gorm v1.9.16
16 | github.com/mitchellh/copystructure v1.1.2 // indirect
17 | github.com/mitchellh/mapstructure v1.4.1
18 | github.com/onsi/ginkgo v1.15.2 // indirect
19 | github.com/onsi/gomega v1.11.0 // indirect
20 | github.com/pkg/errors v0.9.1
21 | github.com/sirupsen/logrus v1.8.1
22 | github.com/stretchr/testify v1.7.0
23 | go.uber.org/zap v1.16.0
24 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
25 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e
26 | mellium.im/sasl v0.2.1 // indirect
27 | )
28 |
--------------------------------------------------------------------------------
/agi/agimodels/iface.go:
--------------------------------------------------------------------------------
1 | package agimodels
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | type Command interface {
10 | Command() (string, error)
11 | }
12 | type Response interface {
13 | Err() error
14 | Val() (string, error)
15 | }
16 |
17 | type Handler interface {
18 | Command(cmd Command) Response
19 | }
20 | type HandlerFunc func(cmd Command) Response
21 |
22 | func (f HandlerFunc) Command(cmd Command) Response {
23 | return f(cmd)
24 | }
25 |
26 | type Client struct {
27 | Handler
28 | }
29 |
30 | func joinCommand(s []interface{}) string {
31 | sb := strings.Builder{}
32 | for _, param := range s {
33 | switch v := param.(type) {
34 | case string:
35 | sb.WriteString(v)
36 | case int:
37 | sb.WriteString(strconv.Itoa(v))
38 | case float64:
39 | sb.WriteString(fmt.Sprint(v))
40 | case *string:
41 | if v == nil {
42 | goto DONE
43 | }
44 | sb.WriteString(*v)
45 | case *int:
46 | if v == nil {
47 | goto DONE
48 | }
49 | sb.WriteString(strconv.Itoa(*v))
50 | case *float64:
51 | if v == nil {
52 | goto DONE
53 | }
54 | sb.WriteString(fmt.Sprint(*v))
55 | }
56 | sb.WriteRune(' ')
57 | }
58 | DONE:
59 | return strings.TrimSpace(sb.String())
60 | }
61 |
--------------------------------------------------------------------------------
/agi/agi_bin.go:
--------------------------------------------------------------------------------
1 | package agi
2 |
3 | import (
4 | "context"
5 | "os"
6 |
7 | "go.uber.org/zap"
8 | )
9 |
10 | type ConfEnv struct {
11 | ConfigDir string
12 | ConfigFile string
13 | ModuleDir string
14 | SpoolDir string
15 | MonitorDir string
16 | VarDir string
17 | DataDir string
18 | LogDir string
19 | AGIDir string
20 | KeyDir string
21 | RunDir string
22 | }
23 |
24 | func LoadConfEnv() ConfEnv {
25 | env := func(s string) string {
26 | v, _ := os.LookupEnv(s)
27 | return v
28 | }
29 | return ConfEnv{
30 | ConfigDir: env("AST_CONFIG_DIR"),
31 | ConfigFile: env("AST_CONFIG_FILE"),
32 | ModuleDir: env("AST_MODULE_DIR"),
33 | SpoolDir: env("AST_SPOOL_DIR"),
34 | MonitorDir: env("AST_MONITOR_DIR"),
35 | VarDir: env("AST_VAR_DIR"),
36 | DataDir: env("AST_DATA_DIR"),
37 | LogDir: env("AST_LOG_DIR"),
38 | AGIDir: env("AST_AGI_DIR"),
39 | KeyDir: env("AST_KEY_DIR"),
40 | RunDir: env("AST_RUN_DIR"),
41 | }
42 | }
43 |
44 | func Run(handler HandlerFunc) {
45 | ctx := context.Background()
46 | session, err := NewSession(ctx, os.Stdin, os.Stdout, nil)
47 | if err != nil {
48 | zap.S().With("err", err).Error("init session failed")
49 | os.Exit(1)
50 | }
51 | handler(session)
52 | }
53 |
--------------------------------------------------------------------------------
/ami/subscribe.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import "context"
4 |
5 | type subscribe struct {
6 | f SubscribeFunc
7 | ctx context.Context
8 | unsub bool
9 | onSent bool
10 | onRecv bool
11 | }
12 | type SubscribeFunc func(ctx context.Context, message *Message) bool
13 |
14 | type SubscribeOption func(o *subscribe) error
15 |
16 | func SubscribeSend() SubscribeOption {
17 | return func(o *subscribe) error {
18 | o.onSent = true
19 | return nil
20 | }
21 | }
22 |
23 | func SubscribeSetContext(ctx context.Context) SubscribeOption {
24 | return func(o *subscribe) error {
25 | o.ctx = ctx
26 | return nil
27 | }
28 | }
29 |
30 | func (c *Conn) Subscribe(cb SubscribeFunc, opts ...SubscribeOption) (func(), error) {
31 | c.subLoc.Lock()
32 | defer c.subLoc.Unlock()
33 |
34 | sub := &subscribe{
35 | f: cb,
36 | onRecv: true,
37 | }
38 | for _, v := range opts {
39 | err := v(sub)
40 | if err != nil {
41 | return nil, err
42 | }
43 | }
44 |
45 | c.subs = append(c.subs, sub)
46 |
47 | return func() {
48 | sub.unsub = true
49 | }, nil
50 | }
51 | func (c *Conn) cleanUnsub() {
52 | c.subLoc.Lock()
53 | defer c.subLoc.Unlock()
54 | var neo []*subscribe
55 | subs := c.subs
56 | for _, sub := range subs {
57 | if !sub.unsub {
58 | neo = append(neo, sub)
59 | }
60 | }
61 | c.subs = neo
62 | }
63 |
--------------------------------------------------------------------------------
/astdb/ps_model.go:
--------------------------------------------------------------------------------
1 | package astdb
2 |
3 | import "database/sql"
4 |
5 | type PsAor struct {
6 | ID string `gorm:"primary_key"`
7 | Contact sql.NullString
8 | // 3600
9 | DefaultExpiration int
10 | MinimumExpiration int
11 | MaximumExpiration int
12 | Mailboxes sql.NullString
13 | MaxContacts int
14 | QualifyFrequency int
15 | QualifyTimeout float64
16 | AuthenticateQualify YesNo
17 | OutboundProxy sql.NullString
18 | SupportPath YesNo
19 | VoicemailExtension sql.NullString
20 | }
21 |
22 | type PsContact struct {
23 | ID string `gorm:"primary_key"`
24 | URI string
25 | ExpirationTime string
26 | QualifyFrequency int
27 | }
28 | type PsDomainAlias struct {
29 | ID string `gorm:"primary_key"`
30 | Domain string
31 | }
32 | type PsEndpointIdIp struct {
33 | ID string `gorm:"primary_key"`
34 | Endpoint string
35 | Match string
36 | }
37 | type PsAuth struct {
38 | ID string `gorm:"primary_key"`
39 | // userpass
40 | AuthType string
41 | NonceLifetime sql.NullString
42 | Md5Cred sql.NullString
43 | Username string
44 | Password string
45 | Realm sql.NullString
46 | }
47 | type PsGlobal struct {
48 | ID string `gorm:"primary_key"`
49 | MaxForwards *int
50 | UserAgent *string
51 | DefaultOutboundEndpoint *string
52 | }
53 |
--------------------------------------------------------------------------------
/.golangci.yml:
--------------------------------------------------------------------------------
1 | run:
2 | skip-dirs-use-default: true
3 | skip-dirs:
4 | - vendor
5 | - ent
6 | - graph
7 | skip-files:
8 | - ".*\\.peg\\.go$"
9 | - ".*ignored_.*.go$"
10 | - "generated.go$"
11 | - model_gen.go
12 |
13 | linters:
14 | disable-all: true
15 | enable:
16 | - bodyclose
17 | - depguard
18 | - dogsled
19 | - dupl
20 | - funlen
21 | - goconst
22 | - gocritic
23 | - gocyclo
24 | - gofmt
25 | - goimports
26 | - golint
27 | - gomnd
28 | - gosec
29 | # - interfacer
30 | - misspell
31 | - unconvert
32 |
33 | # default
34 | - deadcode
35 | - errcheck
36 | - gosimple
37 | - govet
38 | - ineffassign
39 | - staticcheck
40 | - structcheck
41 | - typecheck
42 | - unused
43 | - varcheck
44 |
45 | linters-settings:
46 | dupl:
47 | threshold: 100
48 | funlen:
49 | lines: 100
50 | statements: 60
51 | depguard:
52 | list-type: blacklist
53 | packages:
54 | - golang.org/x/net/context
55 | - github.com/sirupsen/logrus
56 | - github.com/prometheus/common/log
57 |
58 | issues:
59 | # Excluding configuration per-path, per-linter, per-text and per-source
60 | exclude-rules:
61 | - path: _test\.go
62 | linters:
63 | - gomnd
64 | # https://github.com/go-critic/go-critic/issues/926
65 | - linters:
66 | - gocritic
67 | text: "unnecessaryDefer:"
68 |
--------------------------------------------------------------------------------
/astdb/model.go:
--------------------------------------------------------------------------------
1 | package astdb
2 |
3 | import "time"
4 |
5 | // https://wiki.asterisk.org/wiki/display/AST/Asterisk+12+CEL+Specification
6 | type CallEventLog struct {
7 | ID int64 `gorm:"primary_key"`
8 | EventType string `gorm:"column:eventtype"`
9 | EventTime *time.Time `gorm:"column:eventtime"`
10 | UserDefType string `gorm:"column:userdeftype"`
11 | CidName string
12 | CidNum string
13 | CidAni string
14 | CidRdnis string
15 | CidDnid string
16 | Exten string
17 | Context string
18 | ChanName string `gorm:"column:channame"`
19 | AppName string `gorm:"column:appname"`
20 | AppData string `gorm:"column:appdata"`
21 | AmaFlags int `gorm:"column:amaflags"`
22 | AccountCode string `gorm:"column:accountcode"`
23 | PeerAccount string `gorm:"column:peeraccount"`
24 | UniqueId string `gorm:"column:uniqueid"`
25 | LinkedId string `gorm:"column:linkedid"`
26 | UserField string `gorm:"column:userfield"`
27 | Peer string `gorm:"column:peer"`
28 | }
29 |
30 | func (CallEventLog) TableName() string {
31 | return "cel"
32 | }
33 |
34 | // https://wiki.asterisk.org/wiki/display/AST/Asterisk+12+CDR+Specification
35 | type CallDetailRecord struct {
36 | }
37 |
38 | func (CallDetailRecord) TableName() string {
39 | return "cdr"
40 | }
41 |
42 | type Extension struct {
43 | ID int `gorm:"primary_key"`
44 | Context string
45 | Exten string
46 | Priority int
47 | App string
48 | AppData string
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/_doc_test.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | "encoding/xml"
7 | "os"
8 | "testing"
9 |
10 | log "github.com/sirupsen/logrus"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestDocParse(t *testing.T) {
15 | f, _ := os.Open("out.xml")
16 | defer f.Close()
17 | dec := xml.NewDecoder(f)
18 | var doc DocModel
19 | if err := dec.Decode(&doc); err != nil {
20 | log.Fatal(err)
21 | }
22 | //for _, v := range doc.Agi {
23 | // if v.Name == "control stream file" {
24 | // indent, err := json.MarshalIndent(v, "", " ")
25 | // if err != nil {
26 | // log.Fatal(err)
27 | // }
28 | // fmt.Println(string(indent))
29 | // return
30 | // }
31 | //}
32 |
33 | ge := NewAGIGenerator()
34 | ge.Debug = true
35 | d := &Model{}
36 | BuildModel(&doc, d)
37 |
38 | {
39 | b, err := json.MarshalIndent(doc, "", " ")
40 | assert.NoError(t, err)
41 | err = os.WriteFile("doc.json", b, 0644)
42 | assert.NoError(t, err)
43 | }
44 | {
45 | b, err := json.MarshalIndent(d, "", " ")
46 | assert.NoError(t, err)
47 | err = os.WriteFile("gen.json", b, 0644)
48 | assert.NoError(t, err)
49 | }
50 |
51 | err := ge.Generate(context.Background(), d)
52 | if err != nil {
53 | panic(err)
54 | }
55 | err = ge.Write(WriteConfig{
56 | Target: "./../../../",
57 | //DryRun: true,
58 | })
59 | if err != nil {
60 | panic(err)
61 | }
62 | log.Println("AGI Commands", len(d.AGICommands))
63 | }
64 |
65 | //func TestName(t *testing.T) {
66 | // println(fieldName("Variablename"))
67 | // println(fieldName("Keytree"))
68 | //}
69 |
--------------------------------------------------------------------------------
/ami/amimodels/iface.go:
--------------------------------------------------------------------------------
1 | package amimodels
2 |
3 | import "errors"
4 |
5 | type Event interface {
6 | EventTypeName() string
7 | }
8 | type Action interface {
9 | ActionTypeName() string
10 | }
11 | type HasActionID interface {
12 | GetActionID() string
13 | SetActionID(actionID string)
14 | }
15 | type Handler interface {
16 | Request(req *Request) *Response
17 | }
18 | type HandlerFunc func(req *Request) *Response
19 |
20 | func (f HandlerFunc) Request(req *Request) *Response {
21 | return f(req)
22 | }
23 |
24 | type Client struct {
25 | Handler
26 | }
27 |
28 | func (cli *Client) Action(act Action, res interface{}, opts ...RequestOption) error {
29 | r, err := BuildRequest(act, res, opts...)
30 | if err != nil {
31 | return err
32 | }
33 | return cli.Request(r).Err()
34 | }
35 |
36 | type Response struct {
37 | Response string // Success, Error
38 | ActionID string
39 | Message string
40 | Timestamp string // 1621260071.803488
41 | Headers map[string]string
42 | Error error
43 | }
44 |
45 | func (res *Response) Err() error {
46 | if res.Error != nil {
47 | return res.Error
48 | }
49 | if res.Response == "Error" {
50 | return errors.New(res.Message)
51 | }
52 | return nil
53 | }
54 |
55 | type Request struct {
56 | Action Action
57 | Response *Response
58 | }
59 | type RequestOption func(r *Request) error
60 |
61 | func BuildRequest(act Action, res interface{}, opts ...RequestOption) (r *Request, err error) {
62 | r = &Request{
63 | Action: act,
64 | }
65 | for _, v := range opts {
66 | if err = v(r); err != nil {
67 | return nil, err
68 | }
69 | }
70 | return
71 | }
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### JetBrains template
3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
5 |
6 | # User-specific stuff:
7 | .idea/**/workspace.xml
8 | .idea/**/tasks.xml
9 | .idea/dictionaries
10 |
11 | # Sensitive or high-churn files:
12 | .idea/**/dataSources/
13 | .idea/**/dataSources.ids
14 | .idea/**/dataSources.xml
15 | .idea/**/dataSources.local.xml
16 | .idea/**/sqlDataSources.xml
17 | .idea/**/dynamic.xml
18 | .idea/**/uiDesigner.xml
19 |
20 | # Gradle:
21 | .idea/**/gradle.xml
22 | .idea/**/libraries
23 |
24 | # CMake
25 | cmake-build-debug/
26 |
27 | # Mongo Explorer plugin:
28 | .idea/**/mongoSettings.xml
29 |
30 | ## File-based project format:
31 | *.iws
32 |
33 | ## Plugin-specific files:
34 |
35 | # IntelliJ
36 | out/
37 |
38 | # mpeltonen/sbt-idea plugin
39 | .idea_modules/
40 |
41 | # JIRA plugin
42 | atlassian-ide-plugin.xml
43 |
44 | # Cursive Clojure plugin
45 | .idea/replstate.xml
46 |
47 | # Crashlytics plugin (for Android Studio and IntelliJ)
48 | com_crashlytics_export_strings.xml
49 | crashlytics.properties
50 | crashlytics-build.properties
51 | fabric.properties
52 | ### Go template
53 | # Binaries for programs and plugins
54 | *.exe
55 | *.dll
56 | *.so
57 | *.dylib
58 |
59 | # Test binary, build with `go test -c`
60 | *.test
61 |
62 | # Output of the go coverage tool, specifically when used with LiteIDE
63 | *.out
64 |
65 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
66 | .glide/
67 |
68 |
69 | *.log
70 | ignored
71 | .idea
72 | .cache
73 | dist
74 | .DS_Store
75 | ignored*
76 | *ignored_test.go
77 | bin/
78 | /sparkle.yaml
79 | *.local
80 | *.sqlite3
81 | *.sqlite
82 | *.db
83 |
--------------------------------------------------------------------------------
/ami/msg_test.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "io"
7 | "sort"
8 | "strings"
9 | "testing"
10 |
11 | "github.com/stretchr/testify/assert"
12 | "github.com/wenerme/astgo/ami/amimodels"
13 | )
14 |
15 | func TestMsgIO(t *testing.T) {
16 | for _, test := range []struct {
17 | msg *Message
18 | out string
19 | }{
20 | {
21 | msg: &Message{
22 | Type: MessageTypeEvent,
23 | Name: "Name",
24 | Attributes: map[string]interface{}{
25 | "Text": "12\r\n34",
26 | "More": "Yes",
27 | },
28 | },
29 | // more after multi line
30 | out: "Event: Name\r\nText: 12\r\n34\r\nMore: Yes\r\n\r\n",
31 | },
32 | {
33 | msg: &Message{
34 | Type: MessageTypeEvent,
35 | Name: "Name",
36 | Attributes: map[string]interface{}{
37 | "Text": "12\r\n34",
38 | },
39 | },
40 | // simple multi line
41 | out: "Event: Name\r\nText: 12\r\n34\r\n\r\n",
42 | },
43 |
44 | {
45 | msg: &Message{
46 | Type: MessageTypeEvent,
47 | Name: "FullyBooted",
48 | Attributes: map[string]interface{}{
49 | "Uptime": "1234",
50 | },
51 | },
52 | out: "Event: FullyBooted\r\nUptime: 1234\r\n\r\n",
53 | },
54 | {msg: MustConvertToMessage(amimodels.FullyBootedEvent{
55 | Uptime: "1234",
56 | }),
57 | out: "Event: FullyBooted\r\nUptime: 1234\r\n\r\n"},
58 | } {
59 | msg := test.msg
60 |
61 | // ignore order
62 | exp := strings.Split(test.out, "\r\n")
63 | act := strings.Split(msg.Format(), "\r\n")
64 | sort.Strings(exp)
65 | sort.Strings(act)
66 | assert.Equal(t, exp, act)
67 |
68 | r := bufio.NewReader(bytes.NewReader([]byte(test.out)))
69 | rm := &Message{}
70 | assert.NoError(t, rm.Read(r))
71 | assert.Equal(t, msg.Type, rm.Type)
72 | assert.Equal(t, msg.Name, rm.Name)
73 | assert.Equal(t, msg.Attributes, rm.Attributes)
74 | _, err := r.ReadByte()
75 | assert.Equal(t, io.EOF, err)
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/agi/command.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.AGICommand*/}}
2 | {{- define "agi/command"}}
3 | // {{.StructName}}Command {{.Synopsis}}
4 | {{- with .Description}}
5 | // {{end}}
6 | {{- with .Description}}{{template "comment" .}} {{end}}
7 | type {{.StructName}}Command struct {
8 | {{- range $_,$v:=.Syntax.Params}}
9 | {{- with $v.Description}} {{template "comment" (printf "%v %v" $v.Name .)}} {{end}}
10 | {{$v.Name}} {{with not $v.Required}}*{{end}}{{$v.Type}} {{with $v.Default}} // default to {{$v.Default}} {{end}}
11 | {{- end}}
12 | {{with .Syntax.Missing}} // has missing params {{- end}}
13 | }
14 | func(cmd {{.StructName}}Command)Command() (string, error) {
15 | s := []interface{}{cmd.CommandString(),{{- range $_,$v:=.Syntax.Params}} cmd.{{.Name}}, {{- end}}}
16 | return joinCommand(s), nil
17 | }
18 | func(cmd {{.StructName}}Command)CommandString()string {
19 | return "{{.Name | upper}}"
20 | }
21 |
22 | {{$s:=.}}
23 | {{- range $_,$v:=.Syntax.Params}}
24 | {{- if not $v.Required}}
25 | func (cmd {{$s.StructName}}Command)Set{{$v.Name}}(v {{$v.Type}}) {{$s.StructName}}Command {
26 | cmd.{{$v.Name}} = &v
27 | return cmd
28 | }
29 | {{- end}}
30 | {{- end}}
31 |
32 | func (c *Client) {{$s.StructName}}(
33 | {{- range $_,$v:=.Syntax.Params -}}
34 | {{- if $v.Required}} {{$v.Name | untitle}} {{$v.Type}}, {{- end -}}
35 | {{- end -}}
36 | ) Response {
37 | return c.Handler.Command({{$s.StructName}}Command{
38 | {{- range $_,$v:=.Syntax.Params}}
39 | {{- if $v.Required}}
40 | {{$v.Name}}: {{$v.Name | untitle}},
41 | {{- end}}
42 | {{- end}}
43 | })
44 | }
45 |
46 | {{- end}}
47 |
48 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.SyntaxParamDoc*/}}
49 | {{- define "agi/command/field"}}
50 | {{- with .Description}} {{template "comment" (printf "%v %v" $.Name .)}} {{end}}
51 | {{$.Name}} {{with not $.Required}}*{{end}}{{$.Type}} {{with $.Default}} // default to {{$.Default}} {{end}}
52 | {{- end}}
53 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/template/ami/action.tmpl:
--------------------------------------------------------------------------------
1 | {{/* gotype: github.com/wenerme/astgo/pkg/tools/xmlgen.ManagerAction*/}}
2 | {{- define "ami/action"}}
3 | {{with .Synopsis}} {{template "comment" (printf "%v %v" $.StructName .)}} {{end}}
4 | type {{.StructName}} struct {
5 | {{- template "ami/fields" .}}
6 | }
7 | func({{.StructName}})ActionTypeName() string{
8 | return "{{.Name}}"
9 | }
10 | func(a {{.StructName}})GetActionID() string{
11 | return a.ActionID
12 | }
13 | func(a*{{.StructName}})SetActionID(actionID string) {
14 | a.ActionID = actionID
15 | }
16 | {{- if eq (len .Responses) 1}}
17 | func(cli*Client){{.Name}}(req {{.StructName}},opts ...RequestOption)(res *{{(index .Responses 0).StructName}}, err error) {
18 | req := &{{.StructName}}{
19 | {{- range $_,$v:=.Syntax.Params}}
20 | {{- if $v.Required}}
21 | {{$v.Name}}: {{$v.Name | untitle}},
22 | {{- end}}
23 | {{- end}}
24 | }
25 | res = &{{(index .Responses 0).StructName}}{}
26 | return res, cli.Action(req,res)
27 | }
28 | {{- end}}
29 | {{- if eq (len .Responses) 0}}
30 | func(cli*Client){{.Name}}({{- range $_,$v:=.Syntax.Params -}}
31 | {{- if $v.Required}} {{$v.Name | ParamName}} {{$v.Type}}, {{- end -}}
32 | {{- end -}} opts ...RequestOption)(res *Response, err error) {
33 | req := &{{.StructName}}{
34 | {{- range $_,$v:=.Syntax.Params}}
35 | {{- if $v.Required}}
36 | {{$v.Name}}: {{$v.Name | ParamName}},
37 | {{- end}}
38 | {{- end}}
39 | }
40 | res = &Response{}
41 | return res, cli.Action(req,res,opts...)
42 | }
43 | {{- end}}
44 | {{- end}}
45 |
46 | {{- define "comment"}}
47 | {{regexReplaceAllLiteral "(?m)^" (. | trim) "// "}}
48 | {{- end}}
49 |
50 | {{- define "ami/fields" -}}
51 | {{- range $_,$v:=.Syntax.Params -}}
52 | {{- with $v.Description}} {{template "comment" (printf "%v %v" $v.Name .)}} {{end}}
53 | {{$v.Name}} {{$v.Type}} {{with $v.Default}} // default to {{$v.Default}} {{end}}
54 | {{- end}}
55 | {{with .Syntax.Missing}} // has missing params {{- end}}
56 | {{- end}}
57 |
--------------------------------------------------------------------------------
/ami/request.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import (
4 | "context"
5 | "time"
6 |
7 | "github.com/pkg/errors"
8 | )
9 |
10 | const attrActionID = "ActionID"
11 |
12 | type requestOptions struct {
13 | Timeout time.Duration
14 | OnComplete func(ctx context.Context, msg *Message, err error)
15 | }
16 | type RequestOption func(o *requestOptions) error
17 |
18 | func RequestTimeout(d time.Duration) RequestOption {
19 | return func(o *requestOptions) error {
20 | o.Timeout = d
21 | return nil
22 | }
23 | }
24 |
25 | // RequestResponseCallback will case Conn.Request run async, will not timeout
26 | func RequestResponseCallback(cb func(ctx context.Context, msg *Message, err error)) RequestOption {
27 | return func(o *requestOptions) error {
28 | o.OnComplete = cb
29 | return nil
30 | }
31 | }
32 |
33 | func (c *Conn) Request(r interface{}, opts ...RequestOption) (resp *Message, err error) {
34 | var msg *Message
35 | msg, err = ConvertToMessage(r)
36 | if err != nil {
37 | return nil, err
38 | }
39 | if msg.Type != MessageTypeAction {
40 | return nil, errors.Errorf("can only request action: %v", msg.Type)
41 | }
42 |
43 | async := &asyncMsg{
44 | id: c.nextID(),
45 | msg: msg,
46 | result: make(chan *asyncMsg, 1),
47 | ctx: context.Background(),
48 | }
49 | o := requestOptions{
50 | Timeout: time.Second * 30,
51 | }
52 | for _, opt := range opts {
53 | if err = opt(&o); err != nil {
54 | return
55 | }
56 | }
57 |
58 | onComplete := o.OnComplete
59 | if onComplete != nil {
60 | async.cb = func(v *asyncMsg) {
61 | onComplete(v.ctx, v.resp, v.err)
62 | }
63 | }
64 |
65 | msg.SetAttr(attrActionID, async.id)
66 |
67 | if async.cb == nil {
68 | var cancel context.CancelFunc
69 | // todo allowed custom timeout
70 | async.ctx, cancel = context.WithTimeout(async.ctx, o.Timeout)
71 | defer cancel()
72 | }
73 |
74 | // enqueue
75 | c.pending <- async
76 |
77 | if async.cb != nil {
78 | return nil, errors.New("No response yet")
79 | }
80 |
81 | select {
82 | case <-async.ctx.Done():
83 | return nil, async.ctx.Err()
84 | case <-async.result:
85 | err = async.err
86 | if err == nil && async.resp != nil {
87 | err = async.resp.Error()
88 | }
89 | return async.resp, err
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/gen_model_build.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | )
7 |
8 | func BuildModel(in *DocModel, out *Model) {
9 | for _, v := range in.Agi {
10 | out.AGICommands = append(out.AGICommands, in.AGIModel(v))
11 | }
12 | for _, v := range in.Manager {
13 | out.Actions = append(out.Actions, in.ManagerModel(v))
14 | }
15 | for _, v := range in.ManagerEvent {
16 | out.Events = append(out.Events, in.ManagerEventModel(v))
17 | }
18 | //
19 | Dedup(&out.Actions, func(i int) string {
20 | return out.Actions[i].Name
21 | })
22 | Dedup(&out.Events, func(i int) string {
23 | return out.Events[i].Name
24 | })
25 | for _, v := range out.Events {
26 | Dedup(&v.Syntax.Params, func(i int) string {
27 | return v.Syntax.Params[i].Name
28 | })
29 | }
30 |
31 | // add missing event, unify event
32 | events := map[string]*ManagerEvent{}
33 | for _, v := range out.Events {
34 | events[v.Name] = v
35 | }
36 | for _, action := range out.Actions {
37 | for k, v := range action.Responses {
38 | if e, ok := events[v.Name]; ok {
39 | action.Responses[k] = e
40 | } else {
41 | out.Events = append(out.Events, v)
42 | fmt.Println("Append Response Event", v.Name)
43 | }
44 | }
45 | }
46 |
47 | // add missing ActionID
48 | for _, v := range out.Actions {
49 | found := false
50 | for _, v := range v.Syntax.Params {
51 | if found = v.Name == "ActionID"; found {
52 | break
53 | }
54 | }
55 | if !found {
56 | o := []*Parameter{{
57 | Name: "ActionID",
58 | Type: "string",
59 | Description: "ActionID for this transaction. Will be returned.",
60 | }}
61 | v.Syntax.Params = append(o, v.Syntax.Params...)
62 | }
63 | }
64 | }
65 |
66 | func validGoTypeName(s string) string {
67 | s = invalid.ReplaceAllLiteralString(s, "")
68 | return s
69 | }
70 | func Dedup(arr interface{}, cond func(int) string) {
71 | m := map[string]bool{}
72 | Filter(arr, func(i int) bool {
73 | k := cond(i)
74 | if _, ok := m[k]; ok {
75 | return false
76 | }
77 | m[k] = true
78 | return true
79 | })
80 | }
81 |
82 | func Filter(arr interface{}, cond func(int) bool) {
83 | rv := reflect.ValueOf(arr).Elem()
84 | rt := rv.Type()
85 |
86 | neo := reflect.MakeSlice(rt, 0, 0)
87 | for i := 0; i < rv.Len(); i++ {
88 | if v := rv.Index(i); cond(i) {
89 | neo = reflect.Append(neo, v)
90 | }
91 | }
92 | rv.Set(neo)
93 | }
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Asterisk to Go [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][report-card-img]][report-card]
2 |
3 | Libs for Golang to work with Asterisk
4 |
5 | * AMI
6 | * AGI
7 |
8 | [doc-img]: http://img.shields.io/badge/GoDoc-Reference-blue.svg
9 | [doc]: https://pkg.go.dev/github.com/wenerme/astgo
10 |
11 | [ci-img]: https://github.com/wenerme/astgo/actions/workflows/ci.yml/badge.svg
12 | [ci]: https://github.com/wenerme/astgo/actions/workflows/ci.yml
13 |
14 | [cov-img]: https://codecov.io/gh/wenerme/astgo/branch/master/graph/badge.svg
15 | [cov]: https://codecov.io/gh/wenerme/astgo/branch/master
16 |
17 | [report-card-img]: https://goreportcard.com/badge/github.com/wenerme/astgo
18 | [report-card]: https://goreportcard.com/report/github.com/wenerme/astgo
19 |
20 | ## AMI
21 |
22 | * Async Action
23 | * Sync Action
24 | * Event Subscribe
25 | * Auto Reconnect
26 | * Generated Action with document
27 | * Generated Event with document
28 | * Generated Client - Action -> Response
29 |
30 | ```go
31 | package main
32 |
33 | import (
34 | "context"
35 | "fmt"
36 | "github.com/wenerme/astgo/ami"
37 | )
38 |
39 | func main() {
40 | boot := make(chan *ami.Message, 1)
41 |
42 | conn, err := ami.Connect(
43 | "192.168.1.1:5038",
44 | ami.WithAuth("admin", "admin"), // AMI auth
45 | // add predefined subscriber
46 | ami.WithSubscribe(ami.SubscribeFullyBootedChanOnce(boot)),
47 | ami.WithSubscribe(func(ctx context.Context, msg *ami.Message) bool {
48 | fmt.Println(msg.Format()) // log everything
49 | return true // keep subscribe
50 | }, ami.SubscribeSend(), // subscribe send message - default recv only
51 | ))
52 | if err != nil {
53 | panic(err)
54 | }
55 | <-boot
56 | // AMI now FullyBooted
57 | _ = conn
58 | }
59 | ```
60 |
61 | ## AGI
62 |
63 | * FastAGI
64 | * AGI Bin
65 | * Generated Command
66 | * Generated Client
67 |
68 | ```go
69 | package main
70 |
71 | import (
72 | "github.com/wenerme/astgo/agi"
73 | )
74 |
75 | func main() {
76 | // agi.Listen for FastAGI
77 | agi.Run(func(session *agi.Session) {
78 | client := session.Client()
79 | client.Answer()
80 | client.StreamFile("activated", "#")
81 | client.SetVariable("AGISTATUS", "SUCCESS")
82 | client.Hangup()
83 | })
84 | }
85 | ```
86 |
87 | ## Asterisk Database Model
88 | * GORM Based Model
89 |
90 | ## Roadmap
91 | * [-] Asterisk Database Model
92 | * [ ] Stasis
93 | * [ ] ARI
94 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/gen_model.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/huandu/xstrings"
7 | )
8 |
9 | type AstDoc struct {
10 | Actions []*Type
11 | Events []*Type
12 | }
13 | type Model struct {
14 | AGICommands []*AGICommand
15 | Actions []*ManagerAction
16 | Events []*ManagerEvent
17 | }
18 | type AGICommand struct {
19 | Name string
20 | Module string
21 | Syntax *Syntax
22 | Synopsis string
23 | Description string
24 | SeeAlso []*SeeAlso
25 | }
26 | type ManagerAction struct {
27 | Name string
28 | Synopsis string
29 | Syntax *Syntax
30 | Description string
31 | Response *ManagerEvent
32 | SeeAlso []*SeeAlso
33 | Responses []*ManagerEvent
34 | }
35 |
36 | func (m ManagerAction) StructName() string {
37 | return validGoTypeName(m.Name) + "Action"
38 | }
39 |
40 | type ManagerEvent struct {
41 | Name string
42 | Synopsis string
43 | Syntax *Syntax
44 | SeeAlso []*SeeAlso
45 | }
46 |
47 | func (m ManagerEvent) StructName() string {
48 | return validGoTypeName(m.Name) + "Event"
49 | }
50 |
51 | type SeeAlso struct {
52 | Type string
53 | Name string
54 | }
55 |
56 | var nameFixReplace = strings.NewReplacer("Callerid", "CallerID")
57 |
58 | func (a AGICommand) StructName() string {
59 | switch a.Name {
60 | case "set autohangup":
61 | return "SetAutoHangup"
62 | case "asyncagi break":
63 | return "AsyncAGIBreak"
64 | case "database deltree":
65 | return "DatabaseDelTree"
66 | }
67 | name := xstrings.ToCamelCase(a.Name)
68 | name = nameFixReplace.Replace(name)
69 | return name
70 | }
71 |
72 | type Syntax struct {
73 | Params []*Parameter
74 | Missing bool
75 | }
76 |
77 | func (d Syntax) HasRequiredParam() bool {
78 | for _, v := range d.Params {
79 | if v.Required {
80 | return true
81 | }
82 | }
83 | return false
84 | }
85 |
86 | type Parameter struct {
87 | RawName string
88 | Name string
89 | Type string
90 | Default string
91 | Required bool
92 | Description string
93 | /*
94 | enumlist
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | */
106 | }
107 |
--------------------------------------------------------------------------------
/ami/conn_internal.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "os"
7 | "time"
8 | )
9 |
10 | // promise like
11 | type asyncMsg struct {
12 | id string
13 | msg *Message
14 | resp *Message
15 | err error
16 | result chan *asyncMsg
17 | cb func(v *asyncMsg)
18 | ctx context.Context
19 | done bool
20 | }
21 |
22 | func (async *asyncMsg) complete() {
23 | if async.done {
24 | return
25 | }
26 | if async.result != nil {
27 | async.result <- async
28 | close(async.result)
29 | }
30 | if async.cb != nil {
31 | go func() {
32 | async.cb(async)
33 | }()
34 | }
35 | async.done = true
36 | }
37 |
38 | func (c *Conn) read(ctx context.Context) (err error) {
39 | log := c.logger
40 | log.Debug("start read loop")
41 | defer func() {
42 | log.Debug("done read loop")
43 | }()
44 | for {
45 | msg := &Message{}
46 |
47 | if err = msg.Read(c.reader); err != nil && !errors.Is(err, os.ErrDeadlineExceeded) {
48 | return
49 | }
50 |
51 | if msg.Type != "" {
52 | c.recv <- msg
53 | }
54 | if ctx.Err() != nil {
55 | return ctx.Err()
56 | }
57 | }
58 | }
59 |
60 | func (c *Conn) loop(ctx context.Context) (err error) {
61 | ids := map[string]*asyncMsg{}
62 | defer func() {
63 | for _, v := range ids {
64 | v.err = err
65 | v.complete()
66 | }
67 | }()
68 |
69 | log := c.logger
70 | cleanTicker := time.NewTicker(5 * time.Second)
71 |
72 | c.logger.Debug("start event loop")
73 | defer func() {
74 | log.Debug("done event loop")
75 | }()
76 | for {
77 | select {
78 | case <-ctx.Done():
79 | return ctx.Err()
80 | case <-cleanTicker.C:
81 | c.cleanUnsub()
82 | case async := <-c.pending:
83 | //err = c.conn.SetDeadline(time.Now().Add(1 * time.Second))
84 | //if err != nil {
85 | // return
86 | //}
87 |
88 | // send pending message
89 | msg := async.msg
90 | //log.Sugar().With("id", async.id, "type", msg.Type, "name", msg.Name).Debug("send message")
91 |
92 | err = msg.Write(c.conn)
93 |
94 | if err != nil {
95 | async.err = err
96 | async.complete()
97 | } else if async.id != "" {
98 | ids[async.id] = async
99 | }
100 | c.onSend(async)
101 | case msg := <-c.recv:
102 | // received
103 | if msg.Type == MessageTypeResponse {
104 | id := msg.AttrString(attrActionID)
105 | if id != "" {
106 | async := ids[id]
107 | if async == nil {
108 | log.Sugar().With("id", id).Warn("response untracked")
109 | } else {
110 | async.resp = msg
111 | async.complete()
112 | }
113 | }
114 | }
115 | c.onRecv(msg)
116 | }
117 | }
118 | }
119 |
120 | func (c *Conn) onSend(msg *asyncMsg) {
121 | subs := c.subs
122 |
123 | for _, v := range subs {
124 | if v.unsub || !v.onSent {
125 | continue
126 | }
127 | ctx := v.ctx
128 | if ctx == nil {
129 | ctx = c.ctx
130 | }
131 | v.unsub = !v.f(ctx, msg.msg)
132 | }
133 | }
134 |
135 | func (c *Conn) onRecv(msg *Message) {
136 | subs := c.subs
137 | for _, v := range subs {
138 | if v.unsub || !v.onRecv {
139 | continue
140 | }
141 | ctx := v.ctx
142 | if ctx == nil {
143 | ctx = c.ctx
144 | }
145 | // NOTE blocked
146 | v.unsub = !v.f(ctx, msg)
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/build.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import (
4 | "fmt"
5 | "log"
6 | "regexp"
7 | "strings"
8 | )
9 |
10 | func BuildAstDoc(doc *Docs, d *AstDoc) {
11 | byName := map[string]*Type{}
12 | byFieldName := map[string]map[string]*Field{}
13 | for _, e := range doc.Manager {
14 | typ, dup := byName[e.Name]
15 | if !dup {
16 | log.Println("duplicate action", e.Name)
17 | typ = &Type{
18 | Name: e.Name,
19 | Doc: strings.TrimSpace(e.Synopsis),
20 | }
21 | }
22 |
23 | if byFieldName[typ.Name] == nil {
24 | byFieldName[typ.Name] = map[string]*Field{}
25 | }
26 |
27 | for _, p := range e.Syntax.Parameter {
28 | name := p.Name
29 | fieldName := goName(name)
30 |
31 | field, dup := byFieldName[typ.Name][fieldName]
32 | if dup {
33 | log.Println("duplicate field", typ.Name, fieldName)
34 | continue
35 | }
36 |
37 | field = &Field{
38 | Name: fieldName,
39 | Required: p.Required != "",
40 | Default: p.Default,
41 | Type: &TypeInfo{Type: "string"},
42 | }
43 |
44 | var s []string
45 | for _, v := range p.Para {
46 | text := strings.TrimSpace(v.Text)
47 | if text != "" {
48 | s = append(s, text)
49 | } else {
50 | log.Println(v)
51 | }
52 | }
53 | field.Doc = strings.Join(s, "\n")
54 |
55 | if field.Name != name {
56 | field.StructTag = fmt.Sprintf(`json:"%s,omitempty"`, name)
57 | }
58 |
59 | byFieldName[typ.Name][fieldName] = field
60 | typ.Fields = append(typ.Fields, field)
61 | }
62 |
63 | if !dup {
64 | byName[typ.Name] = typ
65 | d.Actions = append(d.Actions, typ)
66 | }
67 | }
68 | {
69 | byName := map[string]*Type{}
70 | byFieldName := map[string]map[string]*Field{}
71 | for _, e := range doc.ManagerEvent {
72 | typeName := e.Name
73 | typ, dup := byName[typeName]
74 | e := e.ManagerEventInstance
75 | if !dup {
76 | log.Println("duplicate action", typeName)
77 | typ = &Type{
78 | Name: goName(typeName),
79 | Doc: strings.TrimSpace(e.Synopsis),
80 | }
81 | }
82 |
83 | if byFieldName[typ.Name] == nil {
84 | byFieldName[typ.Name] = map[string]*Field{}
85 | }
86 |
87 | for _, p := range e.Syntax.Parameter {
88 | name := p.Name
89 | fieldName := goName(name)
90 |
91 | _, dup := byFieldName[typ.Name][fieldName]
92 | if dup {
93 | log.Println("duplicate field", typ.Name, fieldName)
94 | continue
95 | }
96 |
97 | field := &Field{
98 | Name: fieldName,
99 | Required: p.Required != "",
100 | // Default: p.Default,
101 | Type: &TypeInfo{Type: "string"},
102 | }
103 |
104 | var s []string
105 | for _, v := range p.Para {
106 | text := strings.TrimSpace(v.Text)
107 | if text != "" {
108 | s = append(s, text)
109 | } else {
110 | log.Println(v)
111 | }
112 | }
113 | field.Doc = strings.Join(s, "\n")
114 |
115 | if field.Name != name {
116 | field.StructTag = fmt.Sprintf(`json:"%s,omitempty"`, name)
117 | }
118 |
119 | byFieldName[typ.Name][fieldName] = field
120 | typ.Fields = append(typ.Fields, field)
121 | }
122 |
123 | if !dup {
124 | byName[typ.Name] = typ
125 | d.Events = append(d.Events, typ)
126 | }
127 | }
128 | }
129 | for _, v := range d.Actions {
130 | _, ok := byFieldName[v.Name]["ActionID"]
131 | if !ok {
132 | v.Fields = append(v.Fields, &Field{
133 | Name: "ActionID",
134 | Doc: "ActionID for tx - compensate",
135 | Type: &TypeInfo{
136 | Type: "string",
137 | },
138 | })
139 | }
140 | }
141 |
142 | }
143 |
144 | var invalid = regexp.MustCompile(`[- ]|\(.*?\)`)
145 | var valid = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$")
146 |
147 | func goName(s string) string {
148 | s = invalid.ReplaceAllLiteralString(s, "")
149 | if s[0] >= '0' && s[0] <= '9' {
150 | s = "Field" + s
151 | }
152 | // UnitAmount(0)
153 | if !valid.MatchString(s) {
154 | panic("invalid id: " + s)
155 | }
156 | return s
157 | }
158 |
--------------------------------------------------------------------------------
/ami/msg.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import (
4 | "bufio"
5 | "bytes"
6 | "fmt"
7 | "io"
8 | "strings"
9 |
10 | "github.com/mitchellh/mapstructure"
11 | "github.com/pkg/errors"
12 | "github.com/wenerme/astgo/ami/amimodels"
13 | )
14 |
15 | type MessageType string
16 |
17 | const (
18 | MessageTypeAction MessageType = "Action"
19 | MessageTypeEvent MessageType = "Event"
20 | MessageTypeResponse MessageType = "Response"
21 | )
22 |
23 | type Message struct {
24 | Type MessageType // type of message
25 | Name string // name of message
26 | Attributes map[string]interface{}
27 | }
28 |
29 | func ReadMessage(m *Message, rd io.Reader) (err error) {
30 | r := bufio.NewReader(rd)
31 |
32 | m.Attributes = map[string]interface{}{}
33 | var line string
34 | line, err = r.ReadString('\n')
35 | if err != nil {
36 | return err
37 | }
38 | RETRY:
39 | line = strings.TrimSuffix(line, "\r\n")
40 | if line == "" {
41 | goto RETRY
42 | }
43 | sp := strings.SplitN(line, ":", 2)
44 | if len(sp) != 2 {
45 | return errors.Errorf("invalid type line read: %q", line)
46 | }
47 | m.Type = MessageType(sp[0])
48 | m.Name = strings.TrimSpace(sp[1])
49 | switch m.Type {
50 | case MessageTypeAction:
51 | case MessageTypeEvent:
52 | case MessageTypeResponse:
53 | default:
54 | return errors.Errorf("invalid message type: %q", sp[0])
55 | }
56 |
57 | var stack [][]string
58 | for {
59 | // may contain BOM
60 | line, err = r.ReadString('\n')
61 | if err != nil {
62 | return err
63 | }
64 | if line == "\r\n" {
65 | break
66 | }
67 | sp = strings.SplitN(line, ":", 2)
68 |
69 | switch {
70 | case len(sp) == 2 && strings.HasSuffix(line, "\r\n"):
71 | // valid line
72 | stack = append(stack, sp)
73 | case len(stack) == 0 && len(sp) == 2:
74 | // first line
75 | stack = append(stack, sp)
76 | case len(stack) != 0:
77 | // continue line
78 | stack = append(stack, []string{"", line})
79 | }
80 | }
81 |
82 | var k, v string
83 | for _, pair := range stack {
84 | switch {
85 | case pair[0] != "" && k != "":
86 | m.Attributes[k] = strings.TrimSuffix(v, "\r\n")
87 | k = ""
88 | v = ""
89 | fallthrough
90 | case pair[0] != "":
91 | k = pair[0]
92 | v = strings.TrimLeft(pair[1], " ")
93 | case pair[0] == "":
94 | v += pair[1]
95 | }
96 | }
97 | if k != "" {
98 | m.Attributes[k] = strings.TrimSuffix(v, "\r\n")
99 | }
100 | return
101 | }
102 | func WriteMessage(m *Message, w io.Writer) (err error) {
103 | wr := bufio.NewWriter(w)
104 | _, _ = wr.WriteString(fmt.Sprintf("%v: %v\r\n", m.Type, m.Name))
105 | for k, v := range m.Attributes {
106 | _, _ = wr.WriteString(fmt.Sprintf("%v: %v\r\n", k, v))
107 | }
108 | _, _ = wr.WriteString("\r\n")
109 | err = wr.Flush()
110 | return
111 | }
112 |
113 | func (m *Message) Read(r *bufio.Reader) (err error) {
114 | return ReadMessage(m, r)
115 | }
116 | func (m *Message) Write(w io.Writer) (err error) {
117 | return WriteMessage(m, w)
118 | }
119 |
120 | func (m Message) Format() string {
121 | b := bytes.Buffer{}
122 | _ = m.Write(&b)
123 | return b.String()
124 | }
125 |
126 | func (m *Message) AttrString(name string) string {
127 | if m.Attributes == nil {
128 | return ""
129 | }
130 | msg := m.Attributes[name]
131 | if msg == nil {
132 | return ""
133 | }
134 | return fmt.Sprint(msg)
135 | }
136 | func (m *Message) Message() string {
137 | return m.AttrString("Message")
138 | }
139 |
140 | func (m *Message) Success() bool {
141 | if m.Type == MessageTypeResponse && m.Name == "Success" {
142 | return true
143 | }
144 | return false
145 | }
146 |
147 | func (m *Message) Error() error {
148 | if m.Type == MessageTypeResponse && m.Name == "Error" {
149 | msg := m.Message()
150 | if msg == "" {
151 | msg = "error response"
152 | }
153 | return errors.New(msg)
154 | }
155 | return nil
156 | }
157 | func (m *Message) SetAttr(name string, val interface{}) {
158 | if m.Attributes == nil {
159 | m.Attributes = make(map[string]interface{})
160 | }
161 | m.Attributes[name] = val
162 | }
163 |
164 | func MustConvertToMessage(in interface{}) (msg *Message) {
165 | m, err := ConvertToMessage(in)
166 | if err != nil {
167 | panic(err)
168 | }
169 | return m
170 | }
171 | func ConvertToMessage(in interface{}) (msg *Message, err error) {
172 | msg = &Message{}
173 | switch a := in.(type) {
174 | case Message:
175 | return &a, err
176 | case *Message:
177 | return a, err
178 | case amimodels.Action:
179 | msg.Type = MessageTypeAction
180 | msg.Name = a.ActionTypeName()
181 | case amimodels.Event:
182 | msg.Type = MessageTypeEvent
183 | msg.Name = a.EventTypeName()
184 | default:
185 | return nil, errors.Errorf("invalid type: %T", in)
186 | }
187 | m := make(map[string]interface{})
188 | err = mapstructure.Decode(in, &m)
189 | // remove zero
190 | for k, v := range m {
191 | rm := v == nil
192 |
193 | // NOTE support require tag, prevent remove required empty value ?
194 | switch v := v.(type) {
195 | case string:
196 | rm = v == ""
197 | case int:
198 | rm = v == 0
199 | }
200 | if rm {
201 | delete(m, k)
202 | }
203 | }
204 | msg.Attributes = m
205 | return
206 | }
207 |
--------------------------------------------------------------------------------
/ami/connect.go:
--------------------------------------------------------------------------------
1 | package ami
2 |
3 | import (
4 | "bufio"
5 | "context"
6 | "fmt"
7 | "net"
8 | "regexp"
9 | "sync/atomic"
10 | "time"
11 |
12 | "github.com/hashicorp/go-multierror"
13 | "github.com/pkg/errors"
14 | "github.com/wenerme/astgo/ami/amimodels"
15 | "go.uber.org/zap"
16 | "golang.org/x/sync/errgroup"
17 | )
18 |
19 | // CustomDialer can be used to specify any dialer, not necessarily
20 | // a *net.Dialer.
21 | type CustomDialer interface {
22 | Dial(network, address string) (net.Conn, error)
23 | }
24 |
25 | type ConnErrHandler func(*Conn, error)
26 | type ConnHandler func(*Conn)
27 |
28 | type ConnectOptions struct {
29 | Context context.Context
30 | Timeout time.Duration
31 | AllowReconnect bool
32 | Username string // login username
33 | Secret string // login secret
34 | Logger *zap.Logger
35 | Dialer CustomDialer
36 | OnConnectErr ConnErrHandler
37 | OnConnected ConnHandler
38 | subscribers []struct {
39 | sub SubscribeFunc
40 | opts []SubscribeOption
41 | }
42 | }
43 | type ConnectOption func(c *ConnectOptions) error
44 |
45 | func WithAuth(username string, secret string) ConnectOption {
46 | return func(c *ConnectOptions) error {
47 | c.Username = username
48 | c.Secret = secret
49 | return nil
50 | }
51 | }
52 |
53 | func WithSubscribe(cb SubscribeFunc, opts ...SubscribeOption) ConnectOption {
54 | return func(c *ConnectOptions) error {
55 | c.subscribers = append(c.subscribers, struct {
56 | sub SubscribeFunc
57 | opts []SubscribeOption
58 | }{sub: cb, opts: opts})
59 | return nil
60 | }
61 | }
62 | func Connect(addr string, opts ...ConnectOption) (conn *Conn, err error) {
63 | opt := &ConnectOptions{
64 | Timeout: 10 * time.Second,
65 | Context: context.Background(),
66 | Logger: zap.L(),
67 | }
68 |
69 | for _, v := range opts {
70 | if err = v(opt); err != nil {
71 | return nil, err
72 | }
73 | }
74 | if opt.Dialer == nil {
75 | opt.Dialer = &net.Dialer{
76 | Timeout: opt.Timeout,
77 | }
78 | }
79 |
80 | var id uint64
81 | conn = &Conn{
82 | ctx: opt.Context,
83 | conf: opt,
84 | logger: opt.Logger,
85 | recv: make(chan *Message, 4096),
86 | pending: make(chan *asyncMsg, 100),
87 | nextID: func() string {
88 | return fmt.Sprint(atomic.AddUint64(&id, 1))
89 | },
90 | }
91 | for _, sub := range opt.subscribers {
92 | _, err = conn.Subscribe(sub.sub, sub.opts...)
93 | if err != nil {
94 | return nil, err
95 | }
96 | }
97 | return conn, conn.dial(addr)
98 | }
99 |
100 | func (c *Conn) Close() error {
101 | if c.closer != nil {
102 | c.closed = true
103 | c.closer()
104 | c.closer = nil
105 | err := c.g.Wait()
106 | if errors.Is(err, errClose) {
107 | return nil
108 | }
109 | return err
110 | }
111 | if c.closed {
112 | return nil
113 | }
114 | return errors.New("not init")
115 | }
116 |
117 | func (c *Conn) dial(addr string) (err error) {
118 | conf := c.conf
119 |
120 | if conf.AllowReconnect {
121 | // NOTE reconnect keep pending, but fail all async
122 | go func() {
123 | log := c.logger
124 | onErr := conf.OnConnectErr
125 | if onErr == nil {
126 | onErr = func(conn *Conn, err error) {
127 | }
128 | }
129 |
130 | var err error
131 | for !c.closed {
132 | err = c.dialOnce(addr)
133 | if err != nil {
134 | log.Sugar().With("err", err).Warn("ami.Conn: dial")
135 |
136 | onErr(c, err)
137 | // fixme improve wait strategy
138 | <-time.NewTimer(time.Second).C
139 | continue
140 | }
141 | if conf.OnConnected != nil {
142 | conf.OnConnected(c)
143 | log.Sugar().Info("ami.Conn: connected")
144 | }
145 | err = c.g.Wait()
146 | if err != nil {
147 | log.Sugar().With("err", err).Warn("ami.Conn: error")
148 | onErr(c, err)
149 | }
150 | c.g = nil
151 | }
152 | log.Sugar().Info("ami.Conn: stop reconnect, conn closed")
153 | }()
154 | return nil
155 | }
156 | return c.dialOnce(addr)
157 | }
158 |
159 | func (c *Conn) dialOnce(addr string) (err error) {
160 | conf := c.conf
161 | conn, err := conf.Dialer.Dial("tcp", addr)
162 | if err != nil {
163 | return err
164 | }
165 | defer func() {
166 | if err != nil {
167 | if e := conn.Close(); e != nil {
168 | err = multierror.Append(err, e)
169 | }
170 | }
171 | }()
172 | return c.connect(conn)
173 | }
174 |
175 | var errClose = errors.New("Close")
176 |
177 | func (c *Conn) connect(conn net.Conn) (err error) {
178 | log := c.logger
179 | r := bufio.NewReader(conn)
180 | c.reader = r
181 | c.conn = conn
182 |
183 | line, err := r.ReadString('\n')
184 | if err != nil {
185 | return errors.Wrap(err, "scan ami initial line")
186 | }
187 |
188 | // check connection
189 | match := regexp.MustCompile("Asterisk Call Manager/([0-9.]+)").FindStringSubmatch(line)
190 | if len(match) > 1 {
191 | c.version = match[1]
192 | log.Sugar().With("version", c.version).Debug("AMI Version")
193 | } else {
194 | err = errors.Errorf("Invalid server header: %q", line)
195 | return
196 | }
197 |
198 | ctx := c.ctx
199 | if ctx == nil {
200 | ctx = context.Background()
201 | }
202 | c.g, ctx = errgroup.WithContext(ctx)
203 | c.g.Go(func() error {
204 | return c.read(ctx)
205 | })
206 | c.g.Go(func() error {
207 | return c.loop(ctx)
208 | })
209 | // manual close
210 | waitCtx, closer := context.WithCancel(ctx)
211 | c.g.Go(func() error {
212 | <-ctx.Done()
213 | closer()
214 | return conn.Close()
215 | })
216 | c.g.Go(func() error {
217 | <-waitCtx.Done()
218 | return errClose
219 | })
220 | c.closer = closer
221 |
222 | conf := c.conf
223 | if conf.Username != "" {
224 | var resp *Message
225 | resp, err = c.Request(amimodels.LoginAction{
226 | UserName: conf.Username,
227 | Secret: conf.Secret,
228 | }, RequestTimeout(2*time.Second))
229 |
230 | if err != nil {
231 | err = errors.Wrap(err, "request login")
232 | } else if !resp.Success() {
233 | err = errors.Wrap(resp.Error(), "login")
234 | }
235 | if err != nil {
236 | log.Sugar().With("err", err).Info("login failed")
237 | return err
238 | }
239 | log.Info("login success")
240 | }
241 |
242 | //log.Sugar().Debug("do conn check ping")
243 | // be ready
244 | // may not FullyBooted
245 | // _, err = c.Request(amimodels.PingAction{})
246 | return
247 | }
248 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/tmpl.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "embed"
7 | "fmt"
8 | "go/format"
9 | "log"
10 | "os"
11 | "path/filepath"
12 | "strings"
13 | "text/template"
14 |
15 | "github.com/Masterminds/goutils"
16 | "github.com/Masterminds/sprig"
17 | "github.com/pkg/errors"
18 | "golang.org/x/tools/imports"
19 | )
20 |
21 | //go:embed template/*.tmpl template/**/*.tmpl
22 | var templateFS embed.FS
23 |
24 | func MustParseTemplates() *template.Template {
25 | //ext := pick(sprig.TxtFuncMap(), "ternary", "title")
26 | tpl := template.Must(
27 | template.New("gqlgen").
28 | //Funcs(gen.Funcs).
29 | //Funcs(ext).
30 | Funcs(sprig.TxtFuncMap()).
31 | Funcs(map[string]interface{}{
32 | "ParamName": ParamName,
33 | }).
34 | //Funcs(Funcs).
35 | ParseFS(templateFS, "template/*.tmpl", "template/**/*.tmpl"),
36 | )
37 | //return &gen.Template{
38 | // Template: tpl,
39 | // FuncMap: gen.Funcs,
40 | //}
41 | return tpl
42 | }
43 |
44 | func NewAMIGenerator() *Generator {
45 | return &Generator{
46 | Template: MustParseTemplates(),
47 | Formatter: GoFormatter,
48 | Templates: []TemplateGenerate{
49 | &GenerateTemplate{
50 | Name: "ami/actions",
51 | FormatName: "actions.go",
52 | },
53 | &GenerateTemplate{
54 | Name: "ami/events",
55 | FormatName: "events.go",
56 | },
57 | },
58 | }
59 | }
60 | func NewAGIGenerator() *Generator {
61 | return &Generator{
62 | Template: MustParseTemplates(),
63 | Formatter: GoFormatter,
64 | Templates: []TemplateGenerate{
65 | //&GenerateTemplate{
66 | // Name: "agi/commands",
67 | // FormatName: "commands.go",
68 | //},
69 | &GenerateTemplate{
70 | Name: "ami/actions",
71 | FormatName: "ami/amimodels/actions.go",
72 | },
73 | &GenerateTemplate{
74 | Name: "ami/events",
75 | FormatName: "ami/amimodels/events.go",
76 | },
77 | },
78 | }
79 | }
80 |
81 | type Generator struct {
82 | Files []File
83 | Template *template.Template
84 | Templates []TemplateGenerate
85 | Debug bool
86 | Formatter func(file *File) error
87 | Loader func() error
88 | }
89 | type File struct {
90 | Name string
91 | Content []byte
92 | }
93 | type WriteConfig struct {
94 | Target string
95 | DryRun bool
96 | }
97 |
98 | func (ge *Generator) Write(s WriteConfig) error {
99 | for _, v := range ge.Files {
100 | o := filepath.Join(s.Target, v.Name)
101 | // log.Println("write ", v.Name, " to ", o)
102 | if !s.DryRun {
103 | if err := os.WriteFile(o, v.Content, 0644); err != nil {
104 | return err
105 | }
106 | }
107 | if s.DryRun || ge.Debug {
108 | log.Println(o, "\n", strings.TrimSpace(string(v.Content)))
109 | }
110 | }
111 | return nil
112 | }
113 |
114 | func (ge *Generator) Generate(ctx context.Context, source interface{}) (err error) {
115 | if err = ge.init(); err != nil {
116 | return
117 | }
118 | var all []File
119 | for _, tmpl := range ge.Templates {
120 | var files []File
121 | files, err = tmpl.Generate(ctx, ge, source)
122 | if err != nil {
123 | return err
124 | }
125 | if ge.Formatter != nil {
126 | for i := range files {
127 | f := files[i]
128 | file := &files[i]
129 | if err = ge.Formatter(file); err != nil {
130 | if ge.Debug {
131 | log.Println(f.Name, err.Error(), "\n", lineNumber(string(f.Content)))
132 | }
133 | return errors.Wrapf(err, "format %v", file.Name)
134 | }
135 | }
136 | }
137 | all = append(all, files...)
138 | }
139 | ge.Files = append(ge.Files, all...)
140 | return
141 | }
142 |
143 | func (ge *Generator) init() error {
144 | if ge.Debug {
145 | log.Println("generating")
146 | }
147 | if ge.Loader != nil {
148 | if ge.Debug {
149 | log.Println("generator loading")
150 | }
151 | if err := ge.Loader(); err != nil {
152 | return err
153 | }
154 | }
155 | return nil
156 | }
157 |
158 | type TemplateGenerate interface {
159 | Generate(ctx context.Context, ge *Generator, source interface{}) ([]File, error)
160 | }
161 | type GenerateTemplate struct {
162 | Name string // template name.
163 | DeriveSource func(ctx context.Context, rootSource interface{}) interface{}
164 | Skip func(ctx context.Context, source interface{}) bool // skip condition (storage constraints or gated by a feature-flag).
165 | Format func(ctx context.Context, source interface{}) string // file name format.
166 | FormatName string // for single
167 | }
168 |
169 | func (tmpl *GenerateTemplate) Generate(ctx context.Context, ge *Generator, source interface{}) (files []File, err error) {
170 | if tmpl.DeriveSource != nil {
171 | source = tmpl.DeriveSource(ctx, source)
172 | }
173 | all, ok := source.([]interface{})
174 | if !ok {
175 | all = []interface{}{source}
176 | }
177 |
178 | for _, source := range all {
179 | f, err := tmpl.one(ctx, ge, source)
180 | if err != nil {
181 | return nil, err
182 | }
183 | if f.Name != "" {
184 | files = append(files, f)
185 | }
186 | }
187 | return
188 | }
189 | func (tmpl *GenerateTemplate) one(ctx context.Context, ge *Generator, source interface{}) (file File, err error) {
190 | if tmpl.Skip != nil {
191 | if tmpl.Skip(ctx, source) {
192 | return
193 | }
194 | }
195 |
196 | b := bytes.NewBuffer(nil)
197 | if err = ge.Template.ExecuteTemplate(b, tmpl.Name, source); err != nil {
198 | return file, fmt.Errorf("execute template %q: %w", tmpl.Name, err)
199 | }
200 |
201 | fn := tmpl.FormatName
202 | if tmpl.Format != nil {
203 | fn = tmpl.Format(ctx, source)
204 | }
205 | file.Name = fn
206 | file.Content = b.Bytes()
207 | if ge.Debug {
208 | log.Printf("generate %s with %T to %s", tmpl.Name, source, fn)
209 | }
210 | return
211 | }
212 |
213 | func GoFormatter(f *File) (err error) {
214 | f.Content, err = format.Source(f.Content)
215 | if err == nil {
216 | f.Content, err = imports.Process(f.Name, f.Content, nil)
217 | }
218 | return
219 | }
220 | func ReportFile(f *File) {
221 | log.Println(f.Name, "\n", lineNumber(string(f.Content)))
222 | }
223 | func lineNumber(s string) string {
224 | lines := strings.Split(s, "\n")
225 | c := strings.Builder{}
226 | for i, v := range lines {
227 | c.WriteString(fmt.Sprintf("%v: ", i))
228 | c.WriteString(v)
229 | c.WriteRune('\n')
230 | }
231 | return c.String()
232 | }
233 |
234 | func ParamName(s string) string {
235 | s = goutils.Uncapitalize(s)
236 | switch s {
237 | case "interface":
238 | s = "iface"
239 | }
240 | return s
241 | }
242 |
--------------------------------------------------------------------------------
/astdb/_enum_gen_test.go:
--------------------------------------------------------------------------------
1 | package astdb_test
2 |
3 | import (
4 | "bytes"
5 | "fmt"
6 | "os"
7 | "regexp"
8 | "sort"
9 | "strings"
10 | "testing"
11 | "text/template"
12 |
13 | "github.com/iancoleman/strcase"
14 | "github.com/stretchr/testify/assert"
15 | "github.com/wenerme/astgo/pkg/tools/xmlgen"
16 | )
17 |
18 | func TestEnumGen(t *testing.T) {
19 | // from exported pg sql
20 | s := `
21 | CREATE TYPE ast_bool_values AS ENUM ('0', '1', 'off', 'on', 'false', 'true', 'no', 'yes');
22 | CREATE TYPE iax_encryption_values AS ENUM ('yes', 'no', 'aes128');
23 | CREATE TYPE iax_requirecalltoken_values AS ENUM ('yes', 'no', 'auto');
24 | CREATE TYPE iax_transfer_values AS ENUM ('yes', 'no', 'mediaonly');
25 | CREATE TYPE moh_mode_values AS ENUM ('custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3');
26 | CREATE TYPE moh_mode_values AS ENUM ('custom', 'files', 'mp3nb', 'quietmp3nb', 'quietmp3', 'playlist');
27 | CREATE TYPE pjsip_100rel_values AS ENUM ('no', 'required', 'yes');
28 | CREATE TYPE pjsip_auth_type_values AS ENUM ('md5', 'userpass');
29 | CREATE TYPE pjsip_auth_type_values_v2 AS ENUM ('md5', 'userpass', 'google_oauth');
30 | CREATE TYPE pjsip_cid_privacy_values AS ENUM ('allowed_not_screened', 'allowed_passed_screened', 'allowed_failed_screened', 'allowed', 'prohib_not_screened', 'prohib_passed_screened', 'prohib_failed_screened', 'prohib', 'unavailable');
31 | CREATE TYPE pjsip_connected_line_method_values AS ENUM ('invite', 'reinvite', 'update');
32 | CREATE TYPE pjsip_direct_media_glare_mitigation_values AS ENUM ('none', 'outgoing', 'incoming');
33 | CREATE TYPE pjsip_dtls_setup_values AS ENUM ('active', 'passive', 'actpass');
34 | CREATE TYPE pjsip_dtmf_mode_values AS ENUM ('rfc4733', 'inband', 'info');
35 | CREATE TYPE pjsip_dtmf_mode_values_v2 AS ENUM ('rfc4733', 'inband', 'info', 'auto');
36 | CREATE TYPE pjsip_dtmf_mode_values_v3 AS ENUM ('rfc4733', 'inband', 'info', 'auto', 'auto_info');
37 | CREATE TYPE pjsip_identify_by_values AS ENUM ('username');
38 | CREATE TYPE pjsip_identify_by_values AS ENUM ('username', 'auth_username');
39 | CREATE TYPE pjsip_identify_by_values AS ENUM ('username', 'auth_username', 'ip');
40 | CREATE TYPE pjsip_media_encryption_values AS ENUM ('no', 'sdes', 'dtls');
41 | CREATE TYPE pjsip_redirect_method_values AS ENUM ('user', 'uri_core', 'uri_pjsip');
42 | CREATE TYPE pjsip_t38udptl_ec_values AS ENUM ('none', 'fec', 'redundancy');
43 | CREATE TYPE pjsip_taskprocessor_overload_trigger_values AS ENUM ('none', 'global', 'pjsip_only');
44 | CREATE TYPE pjsip_timer_values AS ENUM ('forced', 'no', 'required', 'yes');
45 | CREATE TYPE pjsip_transport_method_values AS ENUM ('default', 'unspecified', 'tlsv1', 'sslv2', 'sslv3', 'sslv23');
46 | CREATE TYPE pjsip_transport_protocol_values AS ENUM ('udp', 'tcp', 'tls', 'ws', 'wss');
47 | CREATE TYPE pjsip_transport_protocol_values_v2 AS ENUM ('udp', 'tcp', 'tls', 'ws', 'wss', 'flow');
48 | CREATE TYPE queue_autopause_values AS ENUM ('yes', 'no', 'all');
49 | CREATE TYPE queue_strategy_values AS ENUM ('ringall', 'leastrecent', 'fewestcalls', 'random', 'rrmemory', 'linear', 'wrandom', 'rrordered');
50 | CREATE TYPE sha_hash_values AS ENUM ('SHA-1', 'SHA-256');
51 | CREATE TYPE sip_callingpres_values AS ENUM ('allowed_not_screened', 'allowed_passed_screen', 'allowed_failed_screen', 'allowed', 'prohib_not_screened', 'prohib_passed_screen', 'prohib_failed_screen', 'prohib');
52 | CREATE TYPE sip_directmedia_values AS ENUM ('yes', 'no', 'nonat', 'update');
53 | CREATE TYPE sip_directmedia_values_v2 AS ENUM ('yes', 'no', 'nonat', 'update', 'outgoing');
54 | CREATE TYPE sip_dtmfmode_values AS ENUM ('rfc2833', 'info', 'shortinfo', 'inband', 'auto');
55 | CREATE TYPE sip_progressinband_values AS ENUM ('yes', 'no', 'never');
56 | CREATE TYPE sip_session_refresher_values AS ENUM ('uac', 'uas');
57 | CREATE TYPE sip_session_timers_values AS ENUM ('accept', 'refuse', 'originate');
58 | CREATE TYPE sip_transport_values AS ENUM ('udp', 'tcp', 'tls', 'ws', 'wss', 'udp,tcp', 'tcp,udp');
59 | CREATE TYPE type_values AS ENUM ('friend', 'user', 'peer');
60 | CREATE TYPE yes_no_values AS ENUM ('yes', 'no');
61 | CREATE TYPE yesno_values AS ENUM ('yes', 'no');
62 | `
63 |
64 | s = strings.TrimSpace(s)
65 | lines := strings.Split(s, "\n")
66 | reg := regexp.MustCompile(`CREATE TYPE (\S+) AS ENUM\s\(([^)]+)`)
67 | enumDedup := map[string]*EnumModel{}
68 | for _, v := range lines {
69 | m := reg.FindStringSubmatch(v)
70 | if len(m) < 1 {
71 | fmt.Println("Failed Match", v)
72 | continue
73 | }
74 | d := &EnumModel{
75 | Name: m[1],
76 | }
77 | for _, v := range strings.Split(strings.ReplaceAll(m[2], "'", ""), ",") {
78 | d.Values = append(d.Values, strings.TrimSpace(v))
79 | }
80 | d.Name = strings.TrimSuffix(d.Name, "_values")
81 | d.Name = strings.TrimSuffix(d.Name, "_values_v2")
82 | d.Name = strings.TrimSuffix(d.Name, "_values_v3")
83 | switch d.Name {
84 | case "yesno":
85 | d.Name = "yes_no"
86 | case "type":
87 | d.Name = "sip_peer_type"
88 | }
89 | enumDedup[strings.ReplaceAll(d.Name, "_", "")] = d
90 | }
91 | var enums []*EnumModel
92 | for _, def := range enumDedup {
93 | def.Values = dedup(def.Values)
94 | enums = append(enums, def)
95 | }
96 | sort.Slice(enums, func(i, j int) bool {
97 | return enums[i].Name < enums[j].Name
98 | })
99 | for _, d := range enums {
100 | fmt.Println("Enum", d.Name, d.Values)
101 | }
102 | strcase.ConfigureAcronym("TCP", "tcp")
103 | strcase.ConfigureAcronym("UDP", "udp")
104 | strcase.ConfigureAcronym("WS", "ws")
105 | strcase.ConfigureAcronym("WSS", "wss")
106 | strcase.ConfigureAcronym("TLS", "tls")
107 | strcase.ConfigureAcronym("SSL", "ttl")
108 |
109 | tpl := template.Must(template.New("enum").Parse(`
110 |
111 |
112 | {{define "enums"}}
113 | // Code generated by enums_test.go, DO NOT EDIT.
114 |
115 | package adb
116 | {{- range $_,$e := .Enums}}
117 | {{template "enum/type" $e}}
118 | {{- end}}
119 |
120 | {{- range $_,$e := .Enums}}
121 | {{template "enum/func" $e}}
122 | {{- end}}
123 | {{end}}
124 |
125 | {{define "enum/type"}}
126 | type {{.TypeName}} string
127 | {{$e := .}}
128 | const (
129 | {{- range $_,$v := $.Values}}
130 | {{$.ValueName $v}} {{$e.TypeName}} = "{{$v}}"
131 | {{- end}}
132 | )
133 | {{end}}
134 |
135 | {{define "enum/func"}}
136 | func (e {{.TypeName}}) String() string {
137 | return string(e)
138 | }
139 | func ({{.TypeName}}) Values() []string {
140 | return []string{
141 | {{- range $_,$v := $.Values}}
142 | "{{$v}}",
143 | {{- end}}
144 | }
145 | }
146 | {{end}}
147 | `))
148 | buffer := bytes.NewBuffer(nil)
149 | if assert.NoError(t, tpl.ExecuteTemplate(buffer, "enums", &EnumGenModel{
150 | Enums: enums,
151 | })) {
152 | f := &xmlgen.File{Name: "inmem", Content: buffer.Bytes()}
153 | if !assert.NoError(t, xmlgen.GoFormatter(f)) {
154 | xmlgen.ReportFile(f)
155 | } else {
156 | assert.NoError(t, os.WriteFile("enums.go", f.Content, 0644))
157 | }
158 | }
159 | }
160 |
161 | type EnumModel struct {
162 | Name string
163 | Values []string
164 | }
165 |
166 | func (e EnumModel) TypeName() string {
167 | return strcase.ToCamel(e.Name)
168 | }
169 | func (e EnumModel) ValueName(s string) string {
170 | return e.TypeName() + strcase.ToCamel(s)
171 | }
172 |
173 | type EnumGenModel struct {
174 | Enums []*EnumModel
175 | }
176 |
177 | func dedup(s []string) []string {
178 | m := map[string]bool{}
179 | for _, v := range s {
180 | m[v] = true
181 | }
182 | var o []string
183 | for k := range m {
184 | o = append(o, k)
185 | }
186 | sort.Strings(o)
187 | return o
188 | }
189 |
--------------------------------------------------------------------------------
/agi/agi.go:
--------------------------------------------------------------------------------
1 | package agi
2 |
3 | import (
4 | "bufio"
5 | "context"
6 | "io"
7 | "net"
8 | "sort"
9 | "strconv"
10 | "strings"
11 |
12 | "github.com/pkg/errors"
13 | "github.com/wenerme/astgo/agi/agimodels"
14 | "go.uber.org/zap"
15 | )
16 |
17 | const (
18 | // StatusOK indicates operation was completed successfully.
19 | StatusOK = 200
20 |
21 | // StatusInvalid indicates invalid or unknown command.
22 | StatusInvalid = 510
23 |
24 | // StatusDeadChannel indicates the command cant be executed on a dead (closed, terminated, hung up) channel.
25 | StatusDeadChannel = 511
26 |
27 | // StatusEndUsage indicates end of proper usage, when the command returns its syntax.
28 | StatusEndUsage = 520
29 | )
30 |
31 | type Request struct {
32 | }
33 | type Response struct {
34 | Error error // Error received, if any
35 | Status int // HTTP-style status code received
36 | Result int // Result is the numerical return (if parseable)
37 | ResultString string // Result value as a string
38 | Value string // Value is the (optional) string value returned
39 | }
40 |
41 | // Res returns the ResultString of a Response, as well as any error encountered. Depending on the command, this is sometimes more useful than Val()
42 | func (r *Response) Res() (string, error) {
43 | return r.ResultString, r.Error
44 | }
45 |
46 | // Err returns the error value from the response
47 | func (r *Response) Err() error {
48 | return r.Error
49 | }
50 |
51 | // Val returns the response value and error
52 | func (r *Response) Val() (string, error) {
53 | return r.Value, r.Error
54 | }
55 |
56 | type Session struct {
57 | Variables map[string]string
58 | r io.Reader
59 | w io.Writer
60 | ctx context.Context
61 | conn net.Conn
62 | }
63 |
64 | type HandlerFunc func(session *Session)
65 |
66 | func NewSession(c context.Context, r io.Reader, w io.Writer, conn net.Conn) (*Session, error) {
67 | session := &Session{
68 | ctx: c,
69 | r: r,
70 | w: w,
71 | conn: conn,
72 | Variables: make(map[string]string),
73 | }
74 | return session, session.scanVariables()
75 | }
76 | func (a *Session) scanVariables() error {
77 | s := bufio.NewScanner(a.r)
78 | for s.Scan() {
79 | if s.Text() == "" {
80 | break
81 | }
82 |
83 | terms := strings.SplitN(s.Text(), ":", 2)
84 | if len(terms) == 2 {
85 | a.Variables[strings.TrimSpace(terms[0])] = strings.TrimSpace(terms[1])
86 | }
87 | }
88 | return s.Err()
89 | }
90 |
91 | // Close closes any network connection associated with the AGI instance
92 | func (a *Session) Close() (err error) {
93 | if a.conn != nil {
94 | err = a.conn.Close()
95 | a.conn = nil
96 | }
97 | return
98 | }
99 | func ParseResponse(s string) *Response {
100 | sp := strings.SplitN(s, " ", 3)
101 | if len(sp) < 2 {
102 | return &Response{
103 | Error: errors.Errorf("invalid response: %q", s),
104 | }
105 | }
106 | r := &Response{}
107 | r.Status, r.Error = strconv.Atoi(sp[0])
108 | r.ResultString = sp[1][len("result="):]
109 | r.Result, _ = strconv.Atoi(r.ResultString)
110 | if len(sp) == 3 {
111 | r.Value = sp[2]
112 | }
113 | if r.Status != 200 {
114 | r.Error = errors.Errorf("status %v result %v extra %v", r.Status, r.ResultString, r.Value)
115 | }
116 | return r
117 | }
118 | func (a *Session) Command(cmd string) *Response {
119 | _, err := a.w.Write([]byte(cmd + "\n"))
120 | r := &Response{Error: err}
121 | if err != nil {
122 | return r
123 | }
124 | s := bufio.NewScanner(a.r)
125 | if s.Scan() {
126 | return ParseResponse(s.Text())
127 | }
128 | return r
129 | }
130 | func (a *Session) Client() *agimodels.Client {
131 | return &agimodels.Client{
132 | Handler: agimodels.HandlerFunc(func(cmd agimodels.Command) agimodels.Response {
133 | command, err := cmd.Command()
134 | if err != nil {
135 | return &Response{
136 | Error: err,
137 | }
138 | }
139 | return a.Command(command)
140 | }),
141 | }
142 | }
143 | func (a *Session) RequestVariable() *RequestVariable {
144 | rc := &RequestVariable{}
145 | rc.Load(a.Variables)
146 | return rc
147 | }
148 |
149 | // Listen binds an AGI HandlerFunc to the given TCP `host:port` address, creating a FastAGI service.
150 | func Listen(addr string, handler HandlerFunc) error {
151 | if addr == "" {
152 | addr = "0.0.0.0:4573"
153 | }
154 |
155 | l, err := net.Listen("tcp", addr)
156 | if err != nil {
157 | return errors.Wrap(err, "failed to bind server")
158 | }
159 | defer l.Close() // nolint: errcheck
160 |
161 | for {
162 | conn, err := l.Accept()
163 | if err != nil {
164 | return errors.Wrap(err, "failed to accept TCP connection")
165 | }
166 |
167 | session, err := NewSession(nil, conn, conn, conn)
168 | if err != nil {
169 | return errors.Wrap(err, "failed init session")
170 | }
171 | go func() {
172 | defer session.Close()
173 | handler(session)
174 | }()
175 | }
176 | }
177 |
178 | type RequestVariable struct {
179 | Request string
180 | Channel string
181 | Language string
182 | Type string
183 | UniqueID string
184 | Version string
185 | CallerID string
186 | CallerIDName string
187 | CallingPres int // presentation of callerid
188 | CallingAni2 int
189 | CallingTon int // ast_channel_caller(chan)->id.number.plan
190 | CallingTns int // ast_channel_dialed(chan)->transit_network_select)
191 | DNID string // ast_channel_dialed(chan)->number.str
192 | RDNIS string // ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str
193 | Context string
194 | Extension string
195 | Priority int
196 | Enhanced bool
197 | AccountCode string
198 | ThreadID int
199 | Args []string
200 | }
201 |
202 | func (rc *RequestVariable) Load(m map[string]string) {
203 | var args []struct {
204 | i int
205 | v string
206 | }
207 | for k, v := range m {
208 | if !strings.HasPrefix(k, "agi_") {
209 | continue
210 | }
211 | name := k[4:]
212 | if strings.HasPrefix(name, "arg_") {
213 | i, err := strconv.Atoi(name[4:])
214 | if err != nil {
215 | //return errors.Wrapf(err, "invalid arg %v", name)
216 | zap.S().With("arg", name).Warn("skip invalid request arg")
217 | }
218 | args = append(args, struct {
219 | i int
220 | v string
221 | }{i: i, v: v})
222 | continue
223 | }
224 | if v == "unknown" {
225 | continue
226 | }
227 | var err error
228 | switch name {
229 | case "request":
230 | rc.Request = v
231 | case "channel":
232 | rc.Channel = v
233 | case "language":
234 | rc.Language = v
235 | case "type":
236 | rc.Type = v
237 | case "uniqueid":
238 | rc.UniqueID = v
239 | case "version":
240 | rc.Version = v
241 | case "callerid":
242 | rc.CallerID = v
243 | case "calleridname":
244 | rc.CallerIDName = v
245 | case "callingpres":
246 | rc.CallingPres, err = strconv.Atoi(v)
247 | case "callingani2":
248 | rc.CallingAni2, err = strconv.Atoi(v)
249 | case "callington":
250 | rc.CallingTon, err = strconv.Atoi(v)
251 | case "callingtns":
252 | rc.CallingTns, err = strconv.Atoi(v)
253 | case "dnid":
254 | rc.DNID = v
255 | case "rdnis":
256 | rc.RDNIS = v
257 | case "context":
258 | rc.Context = v
259 | case "extension":
260 | rc.Extension = v
261 | case "priority":
262 | rc.Priority, err = strconv.Atoi(v)
263 | case "enhanced":
264 | rc.Enhanced = v == "1.0"
265 | case "accountcode":
266 | rc.AccountCode = v
267 | case "threadid":
268 | rc.ThreadID, err = strconv.Atoi(v)
269 | }
270 | if err != nil {
271 | zap.S().With("err", err, "name", k, "value", v).Warn("failed to handle request variable")
272 | }
273 | }
274 | sort.Slice(args, func(i, j int) bool {
275 | return args[i].i < args[j].i
276 | })
277 | for _, v := range args {
278 | rc.Args = append(rc.Args, v.v)
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/doc_model.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | //go:generate gomodifytags -file=doc_model.go -w -all -add-tags json -transform camelcase --skip-unexported -add-options json=omitempty
4 |
5 | import (
6 | "encoding/xml"
7 | "fmt"
8 | "log"
9 | "regexp"
10 | "strings"
11 |
12 | "github.com/iancoleman/strcase"
13 | )
14 |
15 | type AgiDocModel struct {
16 | Name string `xml:"name,attr" json:"name,omitempty"`
17 | Language string `xml:"language,attr" json:"language,omitempty"`
18 | Synopsis string `xml:"synopsis" json:"synopsis,omitempty"`
19 | Syntax *SyntaxDocModel `xml:"syntax" json:"syntax,omitempty"`
20 | SeeAlso *SeeAlsoModel `xml:"see-also" json:"seeAlso,omitempty"`
21 | Description *DescriptionModel `xml:"description" json:"description,omitempty"`
22 | }
23 |
24 | type ManagerResponseListElementModel struct {
25 | Text string `xml:",chardata" json:"text,omitempty"`
26 | ManagerEvent []*ManagerEventModel `xml:"managerEvent" json:"managerEvent,omitempty"`
27 | }
28 | type ManagerResponseModel struct {
29 | Text string `xml:",chardata" json:"text,omitempty"`
30 | ListElements *ManagerResponseListElementModel `xml:"list-elements" json:"listElements,omitempty"`
31 | ManagerEvent *ManagerEventModel `xml:"managerEvent" json:"managerEvent,omitempty"`
32 | }
33 |
34 | func (m ManagerResponseModel) Events() []*ManagerEventModel {
35 | var o []*ManagerEventModel
36 | if m.ManagerEvent != nil {
37 | o = append(o, m.ManagerEvent)
38 | }
39 | if m.ListElements != nil {
40 | o = append(o, m.ListElements.ManagerEvent...)
41 | }
42 | return o
43 | }
44 |
45 | type ManagerActionModel struct {
46 | Name string `xml:"name,attr" json:"name,omitempty"`
47 | Language string `xml:"language,attr" json:"language,omitempty"`
48 | Synopsis string `xml:"synopsis" json:"synopsis,omitempty"`
49 | Syntax *SyntaxDocModel `xml:"syntax" json:"syntax,omitempty"`
50 | SeeAlso *SeeAlsoModel `xml:"see-also" json:"seeAlso,omitempty"`
51 | Description *DescriptionModel `xml:"description" json:"description,omitempty"`
52 | Responses ManagerResponseModel `xml:"responses" json:"responses,omitempty"`
53 | }
54 | type ManagerEventInstanceModel struct {
55 | Text string `xml:",chardata"`
56 | Class string `xml:"class,attr"`
57 | Synopsis string `xml:"synopsis"`
58 | Language string `xml:"language,attr" json:"language,omitempty"`
59 | Syntax *SyntaxDocModel `xml:"syntax" json:"syntax,omitempty"`
60 | SeeAlso *SeeAlsoModel `xml:"see-also" json:"seeAlso,omitempty"`
61 | Description *DescriptionModel `xml:"description" json:"description,omitempty"`
62 | }
63 | type ManagerEventModel struct {
64 | Name string `xml:"name,attr" json:"name,omitempty"`
65 | Instance ManagerEventInstanceModel `xml:"managerEventInstance"`
66 | }
67 |
68 | type SyntaxDocModel struct {
69 | Parameter []SyntaxParameterDocModel `xml:"parameter" json:"parameter,omitempty"`
70 | ChannelSnapshot []struct {
71 | Text string `xml:",chardata"`
72 | Prefix string `xml:"prefix,attr"`
73 | } `xml:"channel_snapshot"`
74 | BridgeSnapshot []struct {
75 | Text string `xml:",chardata"`
76 | Prefix string `xml:"prefix,attr"`
77 | } `xml:"bridge_snapshot"`
78 | }
79 | type SyntaxParameterDocModel struct {
80 | Name string `xml:"name,attr" json:"name,omitempty"`
81 | Required bool `xml:"required,attr" json:"required,omitempty"`
82 | Para ParaRaw `xml:"para" json:"para,omitempty"`
83 | EnumList *EnumListModel `xml:"enumlist" json:"enumList,omitempty"`
84 |
85 | Note *struct {
86 | Text string `xml:",chardata"`
87 | Para struct {
88 | Text string `xml:",chardata"`
89 | Literal []string `xml:"literal"`
90 | Filename string `xml:"filename"`
91 | Replaceable string `xml:"replaceable"`
92 | } `xml:"para"`
93 | } `xml:"note"`
94 | }
95 | type DocModel struct {
96 | XMLName xml.Name `xml:"docs" json:"xmlName,omitempty"`
97 | Agi []*AgiDocModel `xml:"agi" json:"agi,omitempty"`
98 | Manager []*ManagerActionModel `xml:"manager" json:"manager,omitempty"`
99 | ManagerEvent []*ManagerEventModel `xml:"managerEvent" json:"managerEvent,omitempty"`
100 | }
101 |
102 | // ParaRaw contain ELEMENT astcli|literal|emphasis|filename|directory|replaceable|variable
103 | type ParaRaw struct {
104 | Data string `xml:",innerxml" json:"data,omitempty"`
105 | }
106 | type DescriptionModel struct {
107 | //Text string `xml:",chardata"`
108 | Para []ParaRaw `xml:"para" json:"para,omitempty"`
109 | EnumList *EnumListModel `xml:"enumlist" json:"enumList,omitempty"`
110 | VariableList *VariableListModel `xml:"variablelist" json:"variableList,omitempty"`
111 | Note *struct {
112 | Text string `xml:",chardata"`
113 | Para struct {
114 | Text string `xml:",chardata"`
115 | Filename string `xml:"filename"`
116 | } `xml:"para"`
117 | } `xml:"note"`
118 | }
119 |
120 | type VariableListVariableValueModel struct {
121 | Text string `xml:",chardata" json:"text,omitempty"`
122 | Name string `xml:"name,attr" json:"name,omitempty"`
123 | }
124 | type VariableListVariableModel struct {
125 | Name string `xml:"name,attr" json:"name,omitempty"`
126 | Para ParaRaw `xml:"para" json:"para,omitempty"`
127 | Value []VariableListVariableValueModel `xml:"value" json:"value,omitempty"`
128 | }
129 | type VariableListModel struct {
130 | Variable []VariableListVariableModel `xml:"variable" json:"variable,omitempty"`
131 | }
132 | type SeeAlsoModel struct {
133 | Ref []SeeAlsoRefModel `json:"ref,omitempty"`
134 | }
135 | type SeeAlsoRefModel struct {
136 | Text string `xml:",chardata" json:"text,omitempty"`
137 | Type string `xml:"type,attr" json:"type,omitempty"`
138 | }
139 |
140 | type EnumModel struct {
141 | //Text string `xml:",chardata"`
142 | Name string `xml:"name,attr" json:"name,omitempty"`
143 | Para ParaRaw `xml:"para" json:"para,omitempty"`
144 | }
145 | type EnumListModel struct {
146 | //Text string `xml:",chardata"`
147 | Enum []EnumModel `xml:"enum" json:"enum,omitempty"`
148 | }
149 |
150 | func (d *DocModel) Synopsis(in string) string {
151 | s := strings.TrimSpace(in)
152 | s = deindent(s)
153 | return s
154 | }
155 | func (d *DocModel) ManagerModel(in *ManagerActionModel) *ManagerAction {
156 | o := &ManagerAction{
157 | Name: in.Name,
158 | Synopsis: d.Synopsis(in.Synopsis),
159 | Syntax: d.Syntax(in.Syntax),
160 | SeeAlso: d.SeeAlso(in.SeeAlso),
161 | Description: d.Description(in.Description),
162 | }
163 | resp := in.Responses.Events()
164 |
165 | for _, v := range resp {
166 | o.Responses = append(o.Responses, d.ManagerEventModel(v))
167 | }
168 |
169 | if len(resp) > 1 {
170 | fmt.Println("Multi response", len(resp), o.Name)
171 | for _, v := range resp {
172 | fmt.Print(" ", v.Name)
173 | }
174 | fmt.Println()
175 | }
176 | return o
177 | }
178 |
179 | func (d *DocModel) ManagerEventModel(in *ManagerEventModel) *ManagerEvent {
180 | o := &ManagerEvent{
181 | Name: in.Name,
182 | Synopsis: d.Synopsis(in.Instance.Synopsis),
183 | Syntax: d.Syntax(in.Instance.Syntax),
184 | SeeAlso: d.SeeAlso(in.Instance.SeeAlso),
185 | }
186 | return o
187 | }
188 | func (d *DocModel) Description(in *DescriptionModel) string {
189 | if in == nil {
190 | return ""
191 | }
192 | var p []string
193 | for _, v := range in.Para {
194 | p = append(p, v.Data)
195 | }
196 | // ignore enum,note
197 | return formatParas(p)
198 | }
199 | func (d *DocModel) AGIModel(in *AgiDocModel) *AGICommand {
200 | o := &AGICommand{
201 | Name: in.Name,
202 | Synopsis: d.Synopsis(in.Synopsis),
203 | Syntax: d.Syntax(in.Syntax),
204 | SeeAlso: d.SeeAlso(in.SeeAlso),
205 | Description: d.Description(in.Description),
206 | }
207 | return o
208 | }
209 | func (d *DocModel) SeeAlso(in *SeeAlsoModel) (o []*SeeAlso) {
210 | if in == nil {
211 | return
212 | }
213 | for _, v := range in.Ref {
214 | o = append(o, &SeeAlso{
215 | Name: v.Text,
216 | Type: v.Type,
217 | })
218 | }
219 | return
220 | }
221 | func (d *DocModel) Syntax(in *SyntaxDocModel) *Syntax {
222 | o := &Syntax{}
223 |
224 | if in == nil {
225 | return o
226 | }
227 | for _, v := range in.Parameter {
228 | parameter := d.Parameter(&v)
229 | if parameter.Name == "" {
230 | log.Println("drop param", in)
231 | o.Missing = true
232 | continue
233 | }
234 | o.Params = append(o.Params, parameter)
235 | }
236 | return o
237 | }
238 |
239 | var regDefaultTo = regexp.MustCompile(`Defaults to\s*(.*?)`)
240 |
241 | func parseParaDefaultTo(s string) string {
242 | sub := regDefaultTo.FindStringSubmatch(s)
243 | if len(sub) > 1 {
244 | return sub[1]
245 | }
246 | return ""
247 | }
248 |
249 | var regIndent = regexp.MustCompile(`(?m)^\s+`)
250 |
251 | func deindent(s string) string {
252 | return regIndent.ReplaceAllString(s, "")
253 | }
254 |
255 | var paraTagReplace = strings.NewReplacer(
256 | "", "`", "", "`",
257 | "", "`", "", "`",
258 | "", "`", "", "`",
259 | "", " ", "", " ",
260 | "", " ", "", " ",
261 | "\n", " ",
262 | )
263 |
264 | func formatParas(s []string) string {
265 | sb := strings.Builder{}
266 | for _, v := range s {
267 | sb.WriteString(formatPara(v))
268 | sb.WriteString("\n\n")
269 | }
270 | return strings.TrimSpace(sb.String())
271 | }
272 | func formatPara(s string) string {
273 | s = deindent(s)
274 | return paraTagReplace.Replace(s)
275 | }
276 | func (*DocModel) Parameter(in *SyntaxParameterDocModel) *Parameter {
277 | o := &Parameter{
278 | RawName: in.Name,
279 | Required: in.Required,
280 | }
281 | para := strings.TrimSpace(in.Para.Data)
282 | if para != "" {
283 | o.Default = parseParaDefaultTo(para)
284 | if o.Default == "" {
285 | // description
286 | o.Description = formatPara(para)
287 | }
288 | }
289 | processParameter(o)
290 | return o
291 | }
292 |
293 | func processParameter(p *Parameter) {
294 | rawName := p.RawName
295 | var name string
296 | typ := "string"
297 | switch rawName {
298 | case "skipms":
299 | name = "SkipMS"
300 | case "offsetms":
301 | name = "OffsetMS"
302 | case "keytree":
303 | name = "KeyTree"
304 | }
305 | if name == "" {
306 | name = rawName
307 | // s=slicense
308 | name = strings.ReplaceAll(name, "=", "-")
309 | if len(name) > 4 {
310 | name = strings.ReplaceAll(name, "name", "Name")
311 | }
312 | // xstrings VariableName -> Variablename
313 | name = strcase.ToCamel(name)
314 | }
315 | switch name {
316 | case "SkipMS", "OffsetMS", "SampleOffset", "Priority", "Timeout":
317 | typ = "int"
318 | case "Time": // AutoHangup
319 | typ = "float64"
320 | case "":
321 | default:
322 | if name[0] >= '0' && name[0] <= '9' {
323 | name = "Field" + name
324 | }
325 | }
326 |
327 | p.Name = name
328 | p.Type = typ
329 | }
330 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/astdb/enums.go:
--------------------------------------------------------------------------------
1 | // Code generated by enums_test.go, DO NOT EDIT.
2 |
3 | package astdb
4 |
5 | type AstBool string
6 |
7 | const (
8 | AstBool0 AstBool = "0"
9 | AstBool1 AstBool = "1"
10 | AstBoolFalse AstBool = "false"
11 | AstBoolNo AstBool = "no"
12 | AstBoolOff AstBool = "off"
13 | AstBoolOn AstBool = "on"
14 | AstBoolTrue AstBool = "true"
15 | AstBoolYes AstBool = "yes"
16 | )
17 |
18 | type IaxEncryption string
19 |
20 | const (
21 | IaxEncryptionAes128 IaxEncryption = "aes128"
22 | IaxEncryptionNo IaxEncryption = "no"
23 | IaxEncryptionYes IaxEncryption = "yes"
24 | )
25 |
26 | type IaxRequirecalltoken string
27 |
28 | const (
29 | IaxRequirecalltokenAuto IaxRequirecalltoken = "auto"
30 | IaxRequirecalltokenNo IaxRequirecalltoken = "no"
31 | IaxRequirecalltokenYes IaxRequirecalltoken = "yes"
32 | )
33 |
34 | type IaxTransfer string
35 |
36 | const (
37 | IaxTransferMediaonly IaxTransfer = "mediaonly"
38 | IaxTransferNo IaxTransfer = "no"
39 | IaxTransferYes IaxTransfer = "yes"
40 | )
41 |
42 | type MohMode string
43 |
44 | const (
45 | MohModeCustom MohMode = "custom"
46 | MohModeFiles MohMode = "files"
47 | MohModeMp3Nb MohMode = "mp3nb"
48 | MohModePlaylist MohMode = "playlist"
49 | MohModeQuietmp3 MohMode = "quietmp3"
50 | MohModeQuietmp3Nb MohMode = "quietmp3nb"
51 | )
52 |
53 | type Pjsip100Rel string
54 |
55 | const (
56 | Pjsip100RelNo Pjsip100Rel = "no"
57 | Pjsip100RelRequired Pjsip100Rel = "required"
58 | Pjsip100RelYes Pjsip100Rel = "yes"
59 | )
60 |
61 | type PjsipAuthType string
62 |
63 | const (
64 | PjsipAuthTypeGoogleOauth PjsipAuthType = "google_oauth"
65 | PjsipAuthTypeMd5 PjsipAuthType = "md5"
66 | PjsipAuthTypeUserpass PjsipAuthType = "userpass"
67 | )
68 |
69 | type PjsipCidPrivacy string
70 |
71 | const (
72 | PjsipCidPrivacyAllowed PjsipCidPrivacy = "allowed"
73 | PjsipCidPrivacyAllowedFailedScreened PjsipCidPrivacy = "allowed_failed_screened"
74 | PjsipCidPrivacyAllowedNotScreened PjsipCidPrivacy = "allowed_not_screened"
75 | PjsipCidPrivacyAllowedPassedScreened PjsipCidPrivacy = "allowed_passed_screened"
76 | PjsipCidPrivacyProhib PjsipCidPrivacy = "prohib"
77 | PjsipCidPrivacyProhibFailedScreened PjsipCidPrivacy = "prohib_failed_screened"
78 | PjsipCidPrivacyProhibNotScreened PjsipCidPrivacy = "prohib_not_screened"
79 | PjsipCidPrivacyProhibPassedScreened PjsipCidPrivacy = "prohib_passed_screened"
80 | PjsipCidPrivacyUnavailable PjsipCidPrivacy = "unavailable"
81 | )
82 |
83 | type PjsipConnectedLineMethod string
84 |
85 | const (
86 | PjsipConnectedLineMethodInvite PjsipConnectedLineMethod = "invite"
87 | PjsipConnectedLineMethodReinvite PjsipConnectedLineMethod = "reinvite"
88 | PjsipConnectedLineMethodUpdate PjsipConnectedLineMethod = "update"
89 | )
90 |
91 | type PjsipDirectMediaGlareMitigation string
92 |
93 | const (
94 | PjsipDirectMediaGlareMitigationIncoming PjsipDirectMediaGlareMitigation = "incoming"
95 | PjsipDirectMediaGlareMitigationNone PjsipDirectMediaGlareMitigation = "none"
96 | PjsipDirectMediaGlareMitigationOutgoing PjsipDirectMediaGlareMitigation = "outgoing"
97 | )
98 |
99 | type PjsipDtlsSetup string
100 |
101 | const (
102 | PjsipDtlsSetupActive PjsipDtlsSetup = "active"
103 | PjsipDtlsSetupActpass PjsipDtlsSetup = "actpass"
104 | PjsipDtlsSetupPassive PjsipDtlsSetup = "passive"
105 | )
106 |
107 | type PjsipDtmfMode string
108 |
109 | const (
110 | PjsipDtmfModeAuto PjsipDtmfMode = "auto"
111 | PjsipDtmfModeAutoInfo PjsipDtmfMode = "auto_info"
112 | PjsipDtmfModeInband PjsipDtmfMode = "inband"
113 | PjsipDtmfModeInfo PjsipDtmfMode = "info"
114 | PjsipDtmfModeRfc4733 PjsipDtmfMode = "rfc4733"
115 | )
116 |
117 | type PjsipIdentifyBy string
118 |
119 | const (
120 | PjsipIdentifyByAuthUsername PjsipIdentifyBy = "auth_username"
121 | PjsipIdentifyByIp PjsipIdentifyBy = "ip"
122 | PjsipIdentifyByUsername PjsipIdentifyBy = "username"
123 | )
124 |
125 | type PjsipMediaEncryption string
126 |
127 | const (
128 | PjsipMediaEncryptionDtls PjsipMediaEncryption = "dtls"
129 | PjsipMediaEncryptionNo PjsipMediaEncryption = "no"
130 | PjsipMediaEncryptionSdes PjsipMediaEncryption = "sdes"
131 | )
132 |
133 | type PjsipRedirectMethod string
134 |
135 | const (
136 | PjsipRedirectMethodUriCore PjsipRedirectMethod = "uri_core"
137 | PjsipRedirectMethodUriPjsip PjsipRedirectMethod = "uri_pjsip"
138 | PjsipRedirectMethodUser PjsipRedirectMethod = "user"
139 | )
140 |
141 | type PjsipT38UdptlEc string
142 |
143 | const (
144 | PjsipT38UdptlEcFec PjsipT38UdptlEc = "fec"
145 | PjsipT38UdptlEcNone PjsipT38UdptlEc = "none"
146 | PjsipT38UdptlEcRedundancy PjsipT38UdptlEc = "redundancy"
147 | )
148 |
149 | type PjsipTaskprocessorOverloadTrigger string
150 |
151 | const (
152 | PjsipTaskprocessorOverloadTriggerGlobal PjsipTaskprocessorOverloadTrigger = "global"
153 | PjsipTaskprocessorOverloadTriggerNone PjsipTaskprocessorOverloadTrigger = "none"
154 | PjsipTaskprocessorOverloadTriggerPjsipOnly PjsipTaskprocessorOverloadTrigger = "pjsip_only"
155 | )
156 |
157 | type PjsipTimer string
158 |
159 | const (
160 | PjsipTimerForced PjsipTimer = "forced"
161 | PjsipTimerNo PjsipTimer = "no"
162 | PjsipTimerRequired PjsipTimer = "required"
163 | PjsipTimerYes PjsipTimer = "yes"
164 | )
165 |
166 | type PjsipTransportMethod string
167 |
168 | const (
169 | PjsipTransportMethodDefault PjsipTransportMethod = "default"
170 | PjsipTransportMethodSslv2 PjsipTransportMethod = "sslv2"
171 | PjsipTransportMethodSslv23 PjsipTransportMethod = "sslv23"
172 | PjsipTransportMethodSslv3 PjsipTransportMethod = "sslv3"
173 | PjsipTransportMethodTlsv1 PjsipTransportMethod = "tlsv1"
174 | PjsipTransportMethodUnspecified PjsipTransportMethod = "unspecified"
175 | )
176 |
177 | type PjsipTransportProtocol string
178 |
179 | const (
180 | PjsipTransportProtocolFlow PjsipTransportProtocol = "flow"
181 | PjsipTransportProtocolTcp PjsipTransportProtocol = "tcp"
182 | PjsipTransportProtocolTls PjsipTransportProtocol = "tls"
183 | PjsipTransportProtocolUdp PjsipTransportProtocol = "udp"
184 | PjsipTransportProtocolWs PjsipTransportProtocol = "ws"
185 | PjsipTransportProtocolWss PjsipTransportProtocol = "wss"
186 | )
187 |
188 | type QueueAutopause string
189 |
190 | const (
191 | QueueAutopauseAll QueueAutopause = "all"
192 | QueueAutopauseNo QueueAutopause = "no"
193 | QueueAutopauseYes QueueAutopause = "yes"
194 | )
195 |
196 | type QueueStrategy string
197 |
198 | const (
199 | QueueStrategyFewestcalls QueueStrategy = "fewestcalls"
200 | QueueStrategyLeastrecent QueueStrategy = "leastrecent"
201 | QueueStrategyLinear QueueStrategy = "linear"
202 | QueueStrategyRandom QueueStrategy = "random"
203 | QueueStrategyRingall QueueStrategy = "ringall"
204 | QueueStrategyRrmemory QueueStrategy = "rrmemory"
205 | QueueStrategyRrordered QueueStrategy = "rrordered"
206 | QueueStrategyWrandom QueueStrategy = "wrandom"
207 | )
208 |
209 | type ShaHash string
210 |
211 | const (
212 | ShaHashSHA1 ShaHash = "SHA-1"
213 | ShaHashSHA256 ShaHash = "SHA-256"
214 | )
215 |
216 | type SipCallingpres string
217 |
218 | const (
219 | SipCallingpresAllowed SipCallingpres = "allowed"
220 | SipCallingpresAllowedFailedScreen SipCallingpres = "allowed_failed_screen"
221 | SipCallingpresAllowedNotScreened SipCallingpres = "allowed_not_screened"
222 | SipCallingpresAllowedPassedScreen SipCallingpres = "allowed_passed_screen"
223 | SipCallingpresProhib SipCallingpres = "prohib"
224 | SipCallingpresProhibFailedScreen SipCallingpres = "prohib_failed_screen"
225 | SipCallingpresProhibNotScreened SipCallingpres = "prohib_not_screened"
226 | SipCallingpresProhibPassedScreen SipCallingpres = "prohib_passed_screen"
227 | )
228 |
229 | type SipDirectmedia string
230 |
231 | const (
232 | SipDirectmediaNo SipDirectmedia = "no"
233 | SipDirectmediaNonat SipDirectmedia = "nonat"
234 | SipDirectmediaOutgoing SipDirectmedia = "outgoing"
235 | SipDirectmediaUpdate SipDirectmedia = "update"
236 | SipDirectmediaYes SipDirectmedia = "yes"
237 | )
238 |
239 | type SipDtmfmode string
240 |
241 | const (
242 | SipDtmfmodeAuto SipDtmfmode = "auto"
243 | SipDtmfmodeInband SipDtmfmode = "inband"
244 | SipDtmfmodeInfo SipDtmfmode = "info"
245 | SipDtmfmodeRfc2833 SipDtmfmode = "rfc2833"
246 | SipDtmfmodeShortinfo SipDtmfmode = "shortinfo"
247 | )
248 |
249 | type SipPeerType string
250 |
251 | const (
252 | SipPeerTypeFriend SipPeerType = "friend"
253 | SipPeerTypePeer SipPeerType = "peer"
254 | SipPeerTypeUser SipPeerType = "user"
255 | )
256 |
257 | type SipProgressinband string
258 |
259 | const (
260 | SipProgressinbandNever SipProgressinband = "never"
261 | SipProgressinbandNo SipProgressinband = "no"
262 | SipProgressinbandYes SipProgressinband = "yes"
263 | )
264 |
265 | type SipSessionRefresher string
266 |
267 | const (
268 | SipSessionRefresherUac SipSessionRefresher = "uac"
269 | SipSessionRefresherUas SipSessionRefresher = "uas"
270 | )
271 |
272 | type SipSessionTimers string
273 |
274 | const (
275 | SipSessionTimersAccept SipSessionTimers = "accept"
276 | SipSessionTimersOriginate SipSessionTimers = "originate"
277 | SipSessionTimersRefuse SipSessionTimers = "refuse"
278 | )
279 |
280 | type SipTransport string
281 |
282 | const (
283 | SipTransportTcp SipTransport = "tcp"
284 | SipTransportTls SipTransport = "tls"
285 | SipTransportUdp SipTransport = "udp"
286 | SipTransportWs SipTransport = "ws"
287 | SipTransportWss SipTransport = "wss"
288 | )
289 |
290 | type YesNo string
291 |
292 | const (
293 | YesNoNo YesNo = "no"
294 | YesNoYes YesNo = "yes"
295 | )
296 |
297 | func (e AstBool) String() string {
298 | return string(e)
299 | }
300 | func (AstBool) Values() []string {
301 | return []string{
302 | "0",
303 | "1",
304 | "false",
305 | "no",
306 | "off",
307 | "on",
308 | "true",
309 | "yes",
310 | }
311 | }
312 |
313 | func (e IaxEncryption) String() string {
314 | return string(e)
315 | }
316 | func (IaxEncryption) Values() []string {
317 | return []string{
318 | "aes128",
319 | "no",
320 | "yes",
321 | }
322 | }
323 |
324 | func (e IaxRequirecalltoken) String() string {
325 | return string(e)
326 | }
327 | func (IaxRequirecalltoken) Values() []string {
328 | return []string{
329 | "auto",
330 | "no",
331 | "yes",
332 | }
333 | }
334 |
335 | func (e IaxTransfer) String() string {
336 | return string(e)
337 | }
338 | func (IaxTransfer) Values() []string {
339 | return []string{
340 | "mediaonly",
341 | "no",
342 | "yes",
343 | }
344 | }
345 |
346 | func (e MohMode) String() string {
347 | return string(e)
348 | }
349 | func (MohMode) Values() []string {
350 | return []string{
351 | "custom",
352 | "files",
353 | "mp3nb",
354 | "playlist",
355 | "quietmp3",
356 | "quietmp3nb",
357 | }
358 | }
359 |
360 | func (e Pjsip100Rel) String() string {
361 | return string(e)
362 | }
363 | func (Pjsip100Rel) Values() []string {
364 | return []string{
365 | "no",
366 | "required",
367 | "yes",
368 | }
369 | }
370 |
371 | func (e PjsipAuthType) String() string {
372 | return string(e)
373 | }
374 | func (PjsipAuthType) Values() []string {
375 | return []string{
376 | "google_oauth",
377 | "md5",
378 | "userpass",
379 | }
380 | }
381 |
382 | func (e PjsipCidPrivacy) String() string {
383 | return string(e)
384 | }
385 | func (PjsipCidPrivacy) Values() []string {
386 | return []string{
387 | "allowed",
388 | "allowed_failed_screened",
389 | "allowed_not_screened",
390 | "allowed_passed_screened",
391 | "prohib",
392 | "prohib_failed_screened",
393 | "prohib_not_screened",
394 | "prohib_passed_screened",
395 | "unavailable",
396 | }
397 | }
398 |
399 | func (e PjsipConnectedLineMethod) String() string {
400 | return string(e)
401 | }
402 | func (PjsipConnectedLineMethod) Values() []string {
403 | return []string{
404 | "invite",
405 | "reinvite",
406 | "update",
407 | }
408 | }
409 |
410 | func (e PjsipDirectMediaGlareMitigation) String() string {
411 | return string(e)
412 | }
413 | func (PjsipDirectMediaGlareMitigation) Values() []string {
414 | return []string{
415 | "incoming",
416 | "none",
417 | "outgoing",
418 | }
419 | }
420 |
421 | func (e PjsipDtlsSetup) String() string {
422 | return string(e)
423 | }
424 | func (PjsipDtlsSetup) Values() []string {
425 | return []string{
426 | "active",
427 | "actpass",
428 | "passive",
429 | }
430 | }
431 |
432 | func (e PjsipDtmfMode) String() string {
433 | return string(e)
434 | }
435 | func (PjsipDtmfMode) Values() []string {
436 | return []string{
437 | "auto",
438 | "auto_info",
439 | "inband",
440 | "info",
441 | "rfc4733",
442 | }
443 | }
444 |
445 | func (e PjsipIdentifyBy) String() string {
446 | return string(e)
447 | }
448 | func (PjsipIdentifyBy) Values() []string {
449 | return []string{
450 | "auth_username",
451 | "ip",
452 | "username",
453 | }
454 | }
455 |
456 | func (e PjsipMediaEncryption) String() string {
457 | return string(e)
458 | }
459 | func (PjsipMediaEncryption) Values() []string {
460 | return []string{
461 | "dtls",
462 | "no",
463 | "sdes",
464 | }
465 | }
466 |
467 | func (e PjsipRedirectMethod) String() string {
468 | return string(e)
469 | }
470 | func (PjsipRedirectMethod) Values() []string {
471 | return []string{
472 | "uri_core",
473 | "uri_pjsip",
474 | "user",
475 | }
476 | }
477 |
478 | func (e PjsipT38UdptlEc) String() string {
479 | return string(e)
480 | }
481 | func (PjsipT38UdptlEc) Values() []string {
482 | return []string{
483 | "fec",
484 | "none",
485 | "redundancy",
486 | }
487 | }
488 |
489 | func (e PjsipTaskprocessorOverloadTrigger) String() string {
490 | return string(e)
491 | }
492 | func (PjsipTaskprocessorOverloadTrigger) Values() []string {
493 | return []string{
494 | "global",
495 | "none",
496 | "pjsip_only",
497 | }
498 | }
499 |
500 | func (e PjsipTimer) String() string {
501 | return string(e)
502 | }
503 | func (PjsipTimer) Values() []string {
504 | return []string{
505 | "forced",
506 | "no",
507 | "required",
508 | "yes",
509 | }
510 | }
511 |
512 | func (e PjsipTransportMethod) String() string {
513 | return string(e)
514 | }
515 | func (PjsipTransportMethod) Values() []string {
516 | return []string{
517 | "default",
518 | "sslv2",
519 | "sslv23",
520 | "sslv3",
521 | "tlsv1",
522 | "unspecified",
523 | }
524 | }
525 |
526 | func (e PjsipTransportProtocol) String() string {
527 | return string(e)
528 | }
529 | func (PjsipTransportProtocol) Values() []string {
530 | return []string{
531 | "flow",
532 | "tcp",
533 | "tls",
534 | "udp",
535 | "ws",
536 | "wss",
537 | }
538 | }
539 |
540 | func (e QueueAutopause) String() string {
541 | return string(e)
542 | }
543 | func (QueueAutopause) Values() []string {
544 | return []string{
545 | "all",
546 | "no",
547 | "yes",
548 | }
549 | }
550 |
551 | func (e QueueStrategy) String() string {
552 | return string(e)
553 | }
554 | func (QueueStrategy) Values() []string {
555 | return []string{
556 | "fewestcalls",
557 | "leastrecent",
558 | "linear",
559 | "random",
560 | "ringall",
561 | "rrmemory",
562 | "rrordered",
563 | "wrandom",
564 | }
565 | }
566 |
567 | func (e ShaHash) String() string {
568 | return string(e)
569 | }
570 | func (ShaHash) Values() []string {
571 | return []string{
572 | "SHA-1",
573 | "SHA-256",
574 | }
575 | }
576 |
577 | func (e SipCallingpres) String() string {
578 | return string(e)
579 | }
580 | func (SipCallingpres) Values() []string {
581 | return []string{
582 | "allowed",
583 | "allowed_failed_screen",
584 | "allowed_not_screened",
585 | "allowed_passed_screen",
586 | "prohib",
587 | "prohib_failed_screen",
588 | "prohib_not_screened",
589 | "prohib_passed_screen",
590 | }
591 | }
592 |
593 | func (e SipDirectmedia) String() string {
594 | return string(e)
595 | }
596 | func (SipDirectmedia) Values() []string {
597 | return []string{
598 | "no",
599 | "nonat",
600 | "outgoing",
601 | "update",
602 | "yes",
603 | }
604 | }
605 |
606 | func (e SipDtmfmode) String() string {
607 | return string(e)
608 | }
609 | func (SipDtmfmode) Values() []string {
610 | return []string{
611 | "auto",
612 | "inband",
613 | "info",
614 | "rfc2833",
615 | "shortinfo",
616 | }
617 | }
618 |
619 | func (e SipPeerType) String() string {
620 | return string(e)
621 | }
622 | func (SipPeerType) Values() []string {
623 | return []string{
624 | "friend",
625 | "peer",
626 | "user",
627 | }
628 | }
629 |
630 | func (e SipProgressinband) String() string {
631 | return string(e)
632 | }
633 | func (SipProgressinband) Values() []string {
634 | return []string{
635 | "never",
636 | "no",
637 | "yes",
638 | }
639 | }
640 |
641 | func (e SipSessionRefresher) String() string {
642 | return string(e)
643 | }
644 | func (SipSessionRefresher) Values() []string {
645 | return []string{
646 | "uac",
647 | "uas",
648 | }
649 | }
650 |
651 | func (e SipSessionTimers) String() string {
652 | return string(e)
653 | }
654 | func (SipSessionTimers) Values() []string {
655 | return []string{
656 | "accept",
657 | "originate",
658 | "refuse",
659 | }
660 | }
661 |
662 | func (e SipTransport) String() string {
663 | return string(e)
664 | }
665 | func (SipTransport) Values() []string {
666 | return []string{
667 | "tcp",
668 | "tls",
669 | "udp",
670 | "ws",
671 | "wss",
672 | }
673 | }
674 |
675 | func (e YesNo) String() string {
676 | return string(e)
677 | }
678 | func (YesNo) Values() []string {
679 | return []string{
680 | "no",
681 | "yes",
682 | }
683 | }
684 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
3 | github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
4 | github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
5 | github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
6 | github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
7 | github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
8 | github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
9 | github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
10 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
11 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
13 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
15 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
16 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
17 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
18 | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
19 | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
20 | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
21 | github.com/go-pg/pg v8.0.7+incompatible h1:ty/sXL1OZLo+47KK9N8llRcmbA9tZasqbQ/OO4ld53g=
22 | github.com/go-pg/pg v8.0.7+incompatible/go.mod h1:a2oXow+aFOrvwcKs3eIA0lNFmMilrxK2sOkB5NWe0vA=
23 | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
24 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
25 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
26 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
27 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
28 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
29 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
30 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
31 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
32 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
33 | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
34 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
35 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
36 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
37 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
38 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
39 | github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
40 | github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
41 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
42 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
43 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
44 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
45 | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
46 | github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
47 | github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
48 | github.com/iancoleman/strcase v0.1.3 h1:dJBk1m2/qjL1twPLf68JND55vvivMupZ4wIzE8CTdBw=
49 | github.com/iancoleman/strcase v0.1.3/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
50 | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
51 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
52 | github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
53 | github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
54 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
55 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
56 | github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
57 | github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
58 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
59 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
60 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
61 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
62 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
63 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
64 | github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
65 | github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
66 | github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
67 | github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
68 | github.com/mitchellh/copystructure v1.1.2 h1:Th2TIvG1+6ma3e/0/bopBKohOTY7s4dA8V2q4EUcBJ0=
69 | github.com/mitchellh/copystructure v1.1.2/go.mod h1:EBArHfARyrSWO/+Wyr9zwEkc6XMFB9XyNgFNmRkZZU4=
70 | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
71 | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
72 | github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE=
73 | github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
74 | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
75 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
76 | github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
77 | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
78 | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
79 | github.com/onsi/ginkgo v1.15.2 h1:l77YT15o814C2qVL47NOyjV/6RbaP7kKdrvZnxQ3Org=
80 | github.com/onsi/ginkgo v1.15.2/go.mod h1:Dd6YFfwBW84ETqqtL0CPyPXillHgY6XhQH3uuCCTr/o=
81 | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
82 | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
83 | github.com/onsi/gomega v1.11.0 h1:+CqWgvj0OZycCaqclBD1pxKHAU+tOkHmQIWvDHq2aug=
84 | github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
85 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
86 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
87 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
88 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
89 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
90 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
91 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
92 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
93 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
94 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
95 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
96 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
97 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
98 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
99 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
100 | go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
101 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
102 | go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
103 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
104 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
105 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
106 | go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
107 | go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
108 | golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
109 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
110 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
111 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
112 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
113 | golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
114 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
115 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
116 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
117 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
118 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
119 | golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
120 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
121 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
122 | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
123 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
124 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
125 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
126 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
127 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
128 | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
129 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
130 | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U=
131 | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
132 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
133 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
134 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
135 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
136 | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
137 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
138 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
139 | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
140 | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
141 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
142 | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
143 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
144 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
145 | golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
146 | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
147 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
148 | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
149 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
150 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
151 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
152 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
153 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
154 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
155 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
156 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e h1:4nW4NLDYnU28ojHaHO8OVxFHk/aQ33U01a9cjED+pzE=
157 | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
158 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
159 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
160 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
161 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
162 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
163 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
164 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
165 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
166 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
167 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
168 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
169 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
170 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
171 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
172 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
173 | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
174 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
175 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
176 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
177 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
178 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
179 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
180 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
181 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
182 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
183 | honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
184 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
185 | mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w=
186 | mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ=
187 |
--------------------------------------------------------------------------------
/pkg/tools/xmlgen/model.go:
--------------------------------------------------------------------------------
1 | package xmlgen
2 |
3 | import "encoding/xml"
4 |
5 | type Docs struct {
6 | XMLName xml.Name `xml:"docs"`
7 | Text string `xml:",chardata"`
8 | Xi string `xml:"xi,attr"`
9 | ConfigInfo []struct {
10 | Text string `xml:",chardata"`
11 | Name string `xml:"name,attr"`
12 | Language string `xml:"language,attr"`
13 | Synopsis string `xml:"synopsis"`
14 | Description struct {
15 | Text string `xml:",chardata"`
16 | Para []struct {
17 | Text string `xml:",chardata"`
18 | Emphasis []string `xml:"emphasis"`
19 | Literal []string `xml:"literal"`
20 | Filename string `xml:"filename"`
21 | } `xml:"para"`
22 | Warning struct {
23 | Text string `xml:",chardata"`
24 | Para struct {
25 | Text string `xml:",chardata"`
26 | Emphasis string `xml:"emphasis"`
27 | } `xml:"para"`
28 | } `xml:"warning"`
29 | Note struct {
30 | Text string `xml:",chardata"`
31 | Para string `xml:"para"`
32 | } `xml:"note"`
33 | Enumlist []struct {
34 | Text string `xml:",chardata"`
35 | Enum []struct {
36 | Text string `xml:",chardata"`
37 | Name string `xml:"name,attr"`
38 | Para string `xml:"para"`
39 | } `xml:"enum"`
40 | } `xml:"enumlist"`
41 | } `xml:"description"`
42 | ConfigFile struct {
43 | Text string `xml:",chardata"`
44 | Name string `xml:"name,attr"`
45 | ConfigObject []struct {
46 | Text string `xml:",chardata"`
47 | Name string `xml:"name,attr"`
48 | Synopsis string `xml:"synopsis"`
49 | ConfigOption []struct {
50 | Text string `xml:",chardata"`
51 | Name string `xml:"name,attr"`
52 | Default string `xml:"default,attr"`
53 | Synopsis string `xml:"synopsis"`
54 | Description struct {
55 | Text string `xml:",chardata"`
56 | Para []struct {
57 | Text string `xml:",chardata"`
58 | Literal []string `xml:"literal"`
59 | Filename []string `xml:"filename"`
60 | Replaceable []string `xml:"replaceable"`
61 | Variable string `xml:"variable"`
62 | Emphasis []string `xml:"emphasis"`
63 | Astcli string `xml:"astcli"`
64 | } `xml:"para"`
65 | Enumlist struct {
66 | Text string `xml:",chardata"`
67 | Enum []struct {
68 | Text string `xml:",chardata"`
69 | Name string `xml:"name,attr"`
70 | Para []struct {
71 | Text string `xml:",chardata"`
72 | Literal []string `xml:"literal"`
73 | Replaceable string `xml:"replaceable"`
74 | Emphasis string `xml:"emphasis"`
75 | } `xml:"para"`
76 | Enumlist struct {
77 | Text string `xml:",chardata"`
78 | Enum []struct {
79 | Text string `xml:",chardata"`
80 | Name string `xml:"name,attr"`
81 | Para string `xml:"para"`
82 | } `xml:"enum"`
83 | } `xml:"enumlist"`
84 | Note struct {
85 | Text string `xml:",chardata"`
86 | Para struct {
87 | Text string `xml:",chardata"`
88 | Literal string `xml:"literal"`
89 | } `xml:"para"`
90 | } `xml:"note"`
91 | } `xml:"enum"`
92 | } `xml:"enumlist"`
93 | Note []struct {
94 | Text string `xml:",chardata"`
95 | Para []struct {
96 | Text string `xml:",chardata"`
97 | Variable string `xml:"variable"`
98 | Literal []string `xml:"literal"`
99 | Replaceable []string `xml:"replaceable"`
100 | Filename string `xml:"filename"`
101 | } `xml:"para"`
102 | } `xml:"note"`
103 | Include struct {
104 | Text string `xml:",chardata"`
105 | Xpointer string `xml:"xpointer,attr"`
106 | } `xml:"include"`
107 | Warning struct {
108 | Text string `xml:",chardata"`
109 | Para struct {
110 | Text string `xml:",chardata"`
111 | Literal string `xml:"literal"`
112 | } `xml:"para"`
113 | } `xml:"warning"`
114 | Variablelist struct {
115 | Text string `xml:",chardata"`
116 | Variable []struct {
117 | Text string `xml:",chardata"`
118 | Name string `xml:"name,attr"`
119 | Para struct {
120 | Text string `xml:",chardata"`
121 | Variable string `xml:"variable"`
122 | } `xml:"para"`
123 | } `xml:"variable"`
124 | } `xml:"variablelist"`
125 | Example []struct {
126 | Text string `xml:",chardata"`
127 | Title string `xml:"title,attr"`
128 | } `xml:"example"`
129 | } `xml:"description"`
130 | SeeAlso struct {
131 | Text string `xml:",chardata"`
132 | Ref []struct {
133 | Text string `xml:",chardata"`
134 | Type string `xml:"type,attr"`
135 | } `xml:"ref"`
136 | } `xml:"see-also"`
137 | Syntax struct {
138 | Text string `xml:",chardata"`
139 | Argsep string `xml:"argsep,attr"`
140 | Parameter []struct {
141 | Text string `xml:",chardata"`
142 | Name string `xml:"name,attr"`
143 | Required string `xml:"required,attr"`
144 | Para string `xml:"para"`
145 | Optionlist struct {
146 | Text string `xml:",chardata"`
147 | Option []struct {
148 | Text string `xml:",chardata"`
149 | Name string `xml:"name,attr"`
150 | Para string `xml:"para"`
151 | } `xml:"option"`
152 | } `xml:"optionlist"`
153 | Argument struct {
154 | Text string `xml:",chardata"`
155 | Name string `xml:"name,attr"`
156 | Required string `xml:"required,attr"`
157 | Para string `xml:"para"`
158 | } `xml:"argument"`
159 | } `xml:"parameter"`
160 | } `xml:"syntax"`
161 | } `xml:"configOption"`
162 | Description struct {
163 | Text string `xml:",chardata"`
164 | Include struct {
165 | Text string `xml:",chardata"`
166 | Xpointer string `xml:"xpointer,attr"`
167 | } `xml:"include"`
168 | Para []struct {
169 | Text string `xml:",chardata"`
170 | Literal []string `xml:"literal"`
171 | Replaceable []string `xml:"replaceable"`
172 | Emphasis []string `xml:"emphasis"`
173 | Filename string `xml:"filename"`
174 | } `xml:"para"`
175 | Enumlist struct {
176 | Text string `xml:",chardata"`
177 | Enum []struct {
178 | Text string `xml:",chardata"`
179 | Name string `xml:"name,attr"`
180 | Para string `xml:"para"`
181 | } `xml:"enum"`
182 | } `xml:"enumlist"`
183 | Note struct {
184 | Text string `xml:",chardata"`
185 | Para struct {
186 | Text string `xml:",chardata"`
187 | Emphasis string `xml:"emphasis"`
188 | Filename string `xml:"filename"`
189 | } `xml:"para"`
190 | } `xml:"note"`
191 | } `xml:"description"`
192 | } `xml:"configObject"`
193 | } `xml:"configFile"`
194 | } `xml:"configInfo"`
195 | Manager []struct {
196 | Text string `xml:",chardata"`
197 | Name string `xml:"name,attr"`
198 | Language string `xml:"language,attr"`
199 | Module string `xml:"module,attr"`
200 | Synopsis string `xml:"synopsis"`
201 | Syntax struct {
202 | Text string `xml:",chardata"`
203 | Include []struct {
204 | Text string `xml:",chardata"`
205 | Xpointer string `xml:"xpointer,attr"`
206 | } `xml:"include"`
207 | Parameter []struct {
208 | Text string `xml:",chardata"`
209 | Name string `xml:"name,attr"`
210 | Required string `xml:"required,attr"`
211 | Default string `xml:"default,attr"`
212 | Para []struct {
213 | Text string `xml:",chardata"`
214 | Replaceable []string `xml:"replaceable"`
215 | Literal []string `xml:"literal"`
216 | Variable string `xml:"variable"`
217 | Filename string `xml:"filename"`
218 | } `xml:"para"`
219 | Enumlist []struct {
220 | Text string `xml:",chardata"`
221 | Enum []struct {
222 | Text string `xml:",chardata"`
223 | Name string `xml:"name,attr"`
224 | Para struct {
225 | Text string `xml:",chardata"`
226 | Replaceable string `xml:"replaceable"`
227 | } `xml:"para"`
228 | Note struct {
229 | Text string `xml:",chardata"`
230 | Para struct {
231 | Text string `xml:",chardata"`
232 | Literal string `xml:"literal"`
233 | } `xml:"para"`
234 | } `xml:"note"`
235 | Enumlist struct {
236 | Text string `xml:",chardata"`
237 | Enum []struct {
238 | Text string `xml:",chardata"`
239 | Name string `xml:"name,attr"`
240 | Para []struct {
241 | Text string `xml:",chardata"`
242 | Literal string `xml:"literal"`
243 | } `xml:"para"`
244 | Include struct {
245 | Text string `xml:",chardata"`
246 | Xpointer string `xml:"xpointer,attr"`
247 | } `xml:"include"`
248 | } `xml:"enum"`
249 | } `xml:"enumlist"`
250 | } `xml:"enum"`
251 | } `xml:"enumlist"`
252 | Warning struct {
253 | Text string `xml:",chardata"`
254 | Para struct {
255 | Text string `xml:",chardata"`
256 | Variable []string `xml:"variable"`
257 | } `xml:"para"`
258 | } `xml:"warning"`
259 | Include struct {
260 | Text string `xml:",chardata"`
261 | Xpointer string `xml:"xpointer,attr"`
262 | } `xml:"include"`
263 | } `xml:"parameter"`
264 | } `xml:"syntax"`
265 | Description struct {
266 | Text string `xml:",chardata"`
267 | Para []struct {
268 | Text string `xml:",chardata"`
269 | Variable string `xml:"variable"`
270 | Literal []string `xml:"literal"`
271 | Replaceable []string `xml:"replaceable"`
272 | } `xml:"para"`
273 | Note struct {
274 | Text string `xml:",chardata"`
275 | Para struct {
276 | Text string `xml:",chardata"`
277 | Literal []string `xml:"literal"`
278 | Replaceable []string `xml:"replaceable"`
279 | } `xml:"para"`
280 | } `xml:"note"`
281 | Variablelist struct {
282 | Text string `xml:",chardata"`
283 | Variable struct {
284 | Text string `xml:",chardata"`
285 | Name string `xml:"name,attr"`
286 | Para string `xml:"para"`
287 | } `xml:"variable"`
288 | } `xml:"variablelist"`
289 | Warning struct {
290 | Text string `xml:",chardata"`
291 | Para struct {
292 | Text string `xml:",chardata"`
293 | Literal string `xml:"literal"`
294 | } `xml:"para"`
295 | } `xml:"warning"`
296 | } `xml:"description"`
297 | SeeAlso struct {
298 | Text string `xml:",chardata"`
299 | Ref []struct {
300 | Text string `xml:",chardata"`
301 | Type string `xml:"type,attr"`
302 | Module string `xml:"module,attr"`
303 | } `xml:"ref"`
304 | } `xml:"see-also"`
305 | Responses struct {
306 | Text string `xml:",chardata"`
307 | ListElements struct {
308 | Text string `xml:",chardata"`
309 | Include []struct {
310 | Text string `xml:",chardata"`
311 | Xpointer string `xml:"xpointer,attr"`
312 | } `xml:"include"`
313 | ManagerEvent struct {
314 | Text string `xml:",chardata"`
315 | Language string `xml:"language,attr"`
316 | Name string `xml:"name,attr"`
317 | ManagerEventInstance struct {
318 | Text string `xml:",chardata"`
319 | Class string `xml:"class,attr"`
320 | Synopsis string `xml:"synopsis"`
321 | Syntax struct {
322 | Text string `xml:",chardata"`
323 | ChannelSnapshot string `xml:"channel_snapshot"`
324 | } `xml:"syntax"`
325 | } `xml:"managerEventInstance"`
326 | } `xml:"managerEvent"`
327 | } `xml:"list-elements"`
328 | Include struct {
329 | Text string `xml:",chardata"`
330 | Xpointer string `xml:"xpointer,attr"`
331 | } `xml:"include"`
332 | ManagerEvent struct {
333 | Text string `xml:",chardata"`
334 | Name string `xml:"name,attr"`
335 | Language string `xml:"language,attr"`
336 | ManagerEventInstance struct {
337 | Text string `xml:",chardata"`
338 | Class string `xml:"class,attr"`
339 | Synopsis string `xml:"synopsis"`
340 | Syntax struct {
341 | Text string `xml:",chardata"`
342 | Parameter []struct {
343 | Text string `xml:",chardata"`
344 | Name string `xml:"name,attr"`
345 | Para string `xml:"para"`
346 | } `xml:"parameter"`
347 | BridgeSnapshot string `xml:"bridge_snapshot"`
348 | } `xml:"syntax"`
349 | } `xml:"managerEventInstance"`
350 | } `xml:"managerEvent"`
351 | } `xml:"responses"`
352 | } `xml:"manager"`
353 | Function []struct {
354 | Text string `xml:",chardata"`
355 | Name string `xml:"name,attr"`
356 | Language string `xml:"language,attr"`
357 | Module string `xml:"module,attr"`
358 | Synopsis string `xml:"synopsis"`
359 | Syntax struct {
360 | Text string `xml:",chardata"`
361 | Argsep string `xml:"argsep,attr"`
362 | Parameter []struct {
363 | Text string `xml:",chardata"`
364 | Name string `xml:"name,attr"`
365 | Required string `xml:"required,attr"`
366 | Argsep string `xml:"argsep,attr"`
367 | Multiple string `xml:"multiple,attr"`
368 | Default string `xml:"default,attr"`
369 | Para []struct {
370 | Text string `xml:",chardata"`
371 | Literal []string `xml:"literal"`
372 | Replaceable []string `xml:"replaceable"`
373 | Filename string `xml:"filename"`
374 | Emphasis string `xml:"emphasis"`
375 | } `xml:"para"`
376 | Enumlist struct {
377 | Text string `xml:",chardata"`
378 | Enum []struct {
379 | Text string `xml:",chardata"`
380 | Name string `xml:"name,attr"`
381 | Para []struct {
382 | Text string `xml:",chardata"`
383 | Replaceable []string `xml:"replaceable"`
384 | Literal []string `xml:"literal"`
385 | Include struct {
386 | Text string `xml:",chardata"`
387 | Xpointer string `xml:"xpointer,attr"`
388 | } `xml:"include"`
389 | Filename string `xml:"filename"`
390 | Emphasis []string `xml:"emphasis"`
391 | } `xml:"para"`
392 | Enumlist struct {
393 | Text string `xml:",chardata"`
394 | Enum []struct {
395 | Text string `xml:",chardata"`
396 | Name string `xml:"name,attr"`
397 | Para struct {
398 | Text string `xml:",chardata"`
399 | Literal string `xml:"literal"`
400 | } `xml:"para"`
401 | } `xml:"enum"`
402 | } `xml:"enumlist"`
403 | Warning struct {
404 | Text string `xml:",chardata"`
405 | Para string `xml:"para"`
406 | } `xml:"warning"`
407 | Note struct {
408 | Text string `xml:",chardata"`
409 | Para string `xml:"para"`
410 | } `xml:"note"`
411 | } `xml:"enum"`
412 | ConfigOptionToEnum struct {
413 | Text string `xml:",chardata"`
414 | Include struct {
415 | Text string `xml:",chardata"`
416 | Xpointer string `xml:"xpointer,attr"`
417 | } `xml:"include"`
418 | } `xml:"configOptionToEnum"`
419 | } `xml:"enumlist"`
420 | Optionlist struct {
421 | Text string `xml:",chardata"`
422 | Option []struct {
423 | Text string `xml:",chardata"`
424 | Name string `xml:"name,attr"`
425 | Para []struct {
426 | Text string `xml:",chardata"`
427 | Literal []string `xml:"literal"`
428 | Replaceable []string `xml:"replaceable"`
429 | } `xml:"para"`
430 | Argument []struct {
431 | Text string `xml:",chardata"`
432 | Name string `xml:"name,attr"`
433 | Required string `xml:"required,attr"`
434 | Para string `xml:"para"`
435 | } `xml:"argument"`
436 | } `xml:"option"`
437 | } `xml:"optionlist"`
438 | Argument []struct {
439 | Text string `xml:",chardata"`
440 | Name string `xml:"name,attr"`
441 | Required string `xml:"required,attr"`
442 | } `xml:"argument"`
443 | Include struct {
444 | Text string `xml:",chardata"`
445 | Xpointer string `xml:"xpointer,attr"`
446 | } `xml:"include"`
447 | Warning struct {
448 | Text string `xml:",chardata"`
449 | Para struct {
450 | Text string `xml:",chardata"`
451 | Variable []string `xml:"variable"`
452 | } `xml:"para"`
453 | } `xml:"warning"`
454 | Note struct {
455 | Text string `xml:",chardata"`
456 | Para string `xml:"para"`
457 | } `xml:"note"`
458 | } `xml:"parameter"`
459 | } `xml:"syntax"`
460 | Description struct {
461 | Text string `xml:",chardata"`
462 | Para []struct {
463 | Text string `xml:",chardata"`
464 | Replaceable []string `xml:"replaceable"`
465 | Literal []string `xml:"literal"`
466 | Variable []string `xml:"variable"`
467 | Filename []string `xml:"filename"`
468 | Emphasis string `xml:"emphasis"`
469 | } `xml:"para"`
470 | Warning struct {
471 | Text string `xml:",chardata"`
472 | Para struct {
473 | Text string `xml:",chardata"`
474 | Emphasis []string `xml:"emphasis"`
475 | Literal string `xml:"literal"`
476 | } `xml:"para"`
477 | } `xml:"warning"`
478 | Example []struct {
479 | Text string `xml:",chardata"`
480 | Title string `xml:"title,attr"`
481 | Language string `xml:"language,attr"`
482 | } `xml:"example"`
483 | Note []struct {
484 | Text string `xml:",chardata"`
485 | Para []struct {
486 | Text string `xml:",chardata"`
487 | Literal []string `xml:"literal"`
488 | Replaceable []string `xml:"replaceable"`
489 | Emphasis []string `xml:"emphasis"`
490 | } `xml:"para"`
491 | } `xml:"note"`
492 | Enumlist []struct {
493 | Text string `xml:",chardata"`
494 | Enum []struct {
495 | Text string `xml:",chardata"`
496 | Name string `xml:"name,attr"`
497 | Para string `xml:"para"`
498 | } `xml:"enum"`
499 | } `xml:"enumlist"`
500 | Include struct {
501 | Text string `xml:",chardata"`
502 | Xpointer string `xml:"xpointer,attr"`
503 | } `xml:"include"`
504 | Variablelist struct {
505 | Text string `xml:",chardata"`
506 | Variable struct {
507 | Text string `xml:",chardata"`
508 | Name string `xml:"name,attr"`
509 | Value []struct {
510 | Text string `xml:",chardata"`
511 | Name string `xml:"name,attr"`
512 | } `xml:"value"`
513 | Para string `xml:"para"`
514 | } `xml:"variable"`
515 | } `xml:"variablelist"`
516 | } `xml:"description"`
517 | SeeAlso struct {
518 | Text string `xml:",chardata"`
519 | Ref []struct {
520 | Text string `xml:",chardata"`
521 | Type string `xml:"type,attr"`
522 | Module string `xml:"module,attr"`
523 | } `xml:"ref"`
524 | } `xml:"see-also"`
525 | } `xml:"function"`
526 | Info []struct {
527 | Text string `xml:",chardata"`
528 | Name string `xml:"name,attr"`
529 | Language string `xml:"language,attr"`
530 | Tech string `xml:"tech,attr"`
531 | Enumlist struct {
532 | Text string `xml:",chardata"`
533 | Enum []struct {
534 | Text string `xml:",chardata"`
535 | Name string `xml:"name,attr"`
536 | Para []struct {
537 | Text string `xml:",chardata"`
538 | Replaceable string `xml:"replaceable"`
539 | Literal []string `xml:"literal"`
540 | } `xml:"para"`
541 | Parameter []struct {
542 | Text string `xml:",chardata"`
543 | Name string `xml:"name,attr"`
544 | Required string `xml:"required,attr"`
545 | Para struct {
546 | Text string `xml:",chardata"`
547 | Replaceable string `xml:"replaceable"`
548 | Literal string `xml:"literal"`
549 | } `xml:"para"`
550 | Enumlist struct {
551 | Text string `xml:",chardata"`
552 | Enum []struct {
553 | Text string `xml:",chardata"`
554 | Name string `xml:"name,attr"`
555 | Para []struct {
556 | Text string `xml:",chardata"`
557 | Literal []string `xml:"literal"`
558 | } `xml:"para"`
559 | Enumlist struct {
560 | Text string `xml:",chardata"`
561 | Enum []struct {
562 | Text string `xml:",chardata"`
563 | Name string `xml:"name,attr"`
564 | Para struct {
565 | Text string `xml:",chardata"`
566 | Literal string `xml:"literal"`
567 | } `xml:"para"`
568 | } `xml:"enum"`
569 | } `xml:"enumlist"`
570 | Note struct {
571 | Text string `xml:",chardata"`
572 | Para struct {
573 | Text string `xml:",chardata"`
574 | Literal string `xml:"literal"`
575 | } `xml:"para"`
576 | } `xml:"note"`
577 | } `xml:"enum"`
578 | } `xml:"enumlist"`
579 | } `xml:"parameter"`
580 | Enumlist struct {
581 | Text string `xml:",chardata"`
582 | Enum []struct {
583 | Text string `xml:",chardata"`
584 | Name string `xml:"name,attr"`
585 | Para string `xml:"para"`
586 | } `xml:"enum"`
587 | } `xml:"enumlist"`
588 | } `xml:"enum"`
589 | } `xml:"enumlist"`
590 | Example struct {
591 | Text string `xml:",chardata"`
592 | Title string `xml:"title,attr"`
593 | } `xml:"example"`
594 | Para struct {
595 | Text string `xml:",chardata"`
596 | Literal []string `xml:"literal"`
597 | } `xml:"para"`
598 | } `xml:"info"`
599 | Application []struct {
600 | Text string `xml:",chardata"`
601 | Name string `xml:"name,attr"`
602 | Language string `xml:"language,attr"`
603 | Module string `xml:"module,attr"`
604 | Synopsis string `xml:"synopsis"`
605 | Syntax struct {
606 | Text string `xml:",chardata"`
607 | Argsep string `xml:"argsep,attr"`
608 | Parameter []struct {
609 | Text string `xml:",chardata"`
610 | Name string `xml:"name,attr"`
611 | Required string `xml:"required,attr"`
612 | Argsep string `xml:"argsep,attr"`
613 | Multiple string `xml:"multiple,attr"`
614 | Hasparams string `xml:"hasparams,attr"`
615 | Para []struct {
616 | Text string `xml:",chardata"`
617 | Literal []string `xml:"literal"`
618 | Directory string `xml:"directory"`
619 | Filename string `xml:"filename"`
620 | Variable string `xml:"variable"`
621 | Replaceable []string `xml:"replaceable"`
622 | Emphasis string `xml:"emphasis"`
623 | } `xml:"para"`
624 | Enumlist struct {
625 | Text string `xml:",chardata"`
626 | Enum []struct {
627 | Text string `xml:",chardata"`
628 | Name string `xml:"name,attr"`
629 | Para string `xml:"para"`
630 | } `xml:"enum"`
631 | } `xml:"enumlist"`
632 | Optionlist struct {
633 | Text string `xml:",chardata"`
634 | Option []struct {
635 | Text string `xml:",chardata"`
636 | Name string `xml:"name,attr"`
637 | Implies string `xml:"implies,attr"`
638 | Argsep string `xml:"argsep,attr"`
639 | Hasparams string `xml:"hasparams,attr"`
640 | Para []struct {
641 | Text string `xml:",chardata"`
642 | Literal []string `xml:"literal"`
643 | Replaceable []string `xml:"replaceable"`
644 | Variable []string `xml:"variable"`
645 | Emphasis []string `xml:"emphasis"`
646 | Filename string `xml:"filename"`
647 | Directory string `xml:"directory"`
648 | } `xml:"para"`
649 | Argument []struct {
650 | Text string `xml:",chardata"`
651 | Name string `xml:"name,attr"`
652 | Required string `xml:"required,attr"`
653 | Hasparams string `xml:"hasparams,attr"`
654 | Argsep string `xml:"argsep,attr"`
655 | Multiple string `xml:"multiple,attr"`
656 | Para []struct {
657 | Text string `xml:",chardata"`
658 | Replaceable string `xml:"replaceable"`
659 | Variable string `xml:"variable"`
660 | Literal []string `xml:"literal"`
661 | Filename string `xml:"filename"`
662 | Emphasis string `xml:"emphasis"`
663 | } `xml:"para"`
664 | Argument []struct {
665 | Text string `xml:",chardata"`
666 | Name string `xml:"name,attr"`
667 | Multiple string `xml:"multiple,attr"`
668 | Required string `xml:"required,attr"`
669 | } `xml:"argument"`
670 | } `xml:"argument"`
671 | Enumlist struct {
672 | Text string `xml:",chardata"`
673 | Enum []struct {
674 | Text string `xml:",chardata"`
675 | Name string `xml:"name,attr"`
676 | Para string `xml:"para"`
677 | } `xml:"enum"`
678 | } `xml:"enumlist"`
679 | Warning struct {
680 | Text string `xml:",chardata"`
681 | Para struct {
682 | Text string `xml:",chardata"`
683 | Variable []string `xml:"variable"`
684 | } `xml:"para"`
685 | } `xml:"warning"`
686 | Note []struct {
687 | Text string `xml:",chardata"`
688 | Para struct {
689 | Text string `xml:",chardata"`
690 | Literal []string `xml:"literal"`
691 | Replaceable string `xml:"replaceable"`
692 | Variable string `xml:"variable"`
693 | } `xml:"para"`
694 | } `xml:"note"`
695 | Variablelist struct {
696 | Text string `xml:",chardata"`
697 | Variable []struct {
698 | Text string `xml:",chardata"`
699 | Name string `xml:"name,attr"`
700 | Para struct {
701 | Text string `xml:",chardata"`
702 | Replaceable []string `xml:"replaceable"`
703 | } `xml:"para"`
704 | Value []struct {
705 | Text string `xml:",chardata"`
706 | Name string `xml:"name,attr"`
707 | Default string `xml:"default,attr"`
708 | } `xml:"value"`
709 | } `xml:"variable"`
710 | } `xml:"variablelist"`
711 | } `xml:"option"`
712 | } `xml:"optionlist"`
713 | Argument []struct {
714 | Text string `xml:",chardata"`
715 | Name string `xml:"name,attr"`
716 | Argsep string `xml:"argsep,attr"`
717 | Required string `xml:"required,attr"`
718 | Multiple string `xml:"multiple,attr"`
719 | Hasparams string `xml:"hasparams,attr"`
720 | Argument []struct {
721 | Text string `xml:",chardata"`
722 | Name string `xml:"name,attr"`
723 | Required string `xml:"required,attr"`
724 | Multiple string `xml:"multiple,attr"`
725 | } `xml:"argument"`
726 | Para []struct {
727 | Text string `xml:",chardata"`
728 | Literal string `xml:"literal"`
729 | Replaceable []string `xml:"replaceable"`
730 | Filename string `xml:"filename"`
731 | } `xml:"para"`
732 | } `xml:"argument"`
733 | Warning struct {
734 | Text string `xml:",chardata"`
735 | Para struct {
736 | Text string `xml:",chardata"`
737 | Variable []string `xml:"variable"`
738 | } `xml:"para"`
739 | } `xml:"warning"`
740 | Note struct {
741 | Text string `xml:",chardata"`
742 | Para struct {
743 | Text string `xml:",chardata"`
744 | Replaceable []string `xml:"replaceable"`
745 | Emphasis string `xml:"emphasis"`
746 | Literal string `xml:"literal"`
747 | } `xml:"para"`
748 | } `xml:"note"`
749 | Include struct {
750 | Text string `xml:",chardata"`
751 | Xpointer string `xml:"xpointer,attr"`
752 | } `xml:"include"`
753 | } `xml:"parameter"`
754 | Include []struct {
755 | Text string `xml:",chardata"`
756 | Xpointer string `xml:"xpointer,attr"`
757 | } `xml:"include"`
758 | } `xml:"syntax"`
759 | Description struct {
760 | Text string `xml:",chardata"`
761 | Para []struct {
762 | Text string `xml:",chardata"`
763 | Replaceable []string `xml:"replaceable"`
764 | Literal []string `xml:"literal"`
765 | Emphasis string `xml:"emphasis"`
766 | Filename []string `xml:"filename"`
767 | Variable []string `xml:"variable"`
768 | Directory string `xml:"directory"`
769 | Astcli string `xml:"astcli"`
770 | } `xml:"para"`
771 | Note []struct {
772 | Text string `xml:",chardata"`
773 | Para []struct {
774 | Text string `xml:",chardata"`
775 | Literal []string `xml:"literal"`
776 | Replaceable []string `xml:"replaceable"`
777 | Variable []string `xml:"variable"`
778 | Filename string `xml:"filename"`
779 | } `xml:"para"`
780 | } `xml:"note"`
781 | Enumlist struct {
782 | Text string `xml:",chardata"`
783 | Enum []struct {
784 | Text string `xml:",chardata"`
785 | Name string `xml:"name,attr"`
786 | Para []struct {
787 | Text string `xml:",chardata"`
788 | Literal []string `xml:"literal"`
789 | Replaceable string `xml:"replaceable"`
790 | Directory string `xml:"directory"`
791 | Filename string `xml:"filename"`
792 | } `xml:"para"`
793 | } `xml:"enum"`
794 | } `xml:"enumlist"`
795 | Variablelist []struct {
796 | Text string `xml:",chardata"`
797 | Variable []struct {
798 | Text string `xml:",chardata"`
799 | Name string `xml:"name,attr"`
800 | Para []struct {
801 | Text string `xml:",chardata"`
802 | Literal []string `xml:"literal"`
803 | Emphasis string `xml:"emphasis"`
804 | Variable string `xml:"variable"`
805 | } `xml:"para"`
806 | Value []struct {
807 | Text string `xml:",chardata"`
808 | Name string `xml:"name,attr"`
809 | } `xml:"value"`
810 | } `xml:"variable"`
811 | } `xml:"variablelist"`
812 | Example []struct {
813 | Text string `xml:",chardata"`
814 | Title string `xml:"title,attr"`
815 | } `xml:"example"`
816 | Warning []struct {
817 | Text string `xml:",chardata"`
818 | Para struct {
819 | Text string `xml:",chardata"`
820 | Literal []string `xml:"literal"`
821 | Variable []string `xml:"variable"`
822 | } `xml:"para"`
823 | } `xml:"warning"`
824 | Include struct {
825 | Text string `xml:",chardata"`
826 | Xpointer string `xml:"xpointer,attr"`
827 | } `xml:"include"`
828 | } `xml:"description"`
829 | SeeAlso struct {
830 | Text string `xml:",chardata"`
831 | Ref []struct {
832 | Text string `xml:",chardata"`
833 | Type string `xml:"type,attr"`
834 | Module string `xml:"module,attr"`
835 | } `xml:"ref"`
836 | } `xml:"see-also"`
837 | } `xml:"application"`
838 | ManagerEvent []struct {
839 | Text string `xml:",chardata"`
840 | Language string `xml:"language,attr"`
841 | Name string `xml:"name,attr"`
842 | ManagerEventInstance struct {
843 | Text string `xml:",chardata"`
844 | Class string `xml:"class,attr"`
845 | Synopsis string `xml:"synopsis"`
846 | Syntax struct {
847 | Text string `xml:",chardata"`
848 | ChannelSnapshot []struct {
849 | Text string `xml:",chardata"`
850 | Prefix string `xml:"prefix,attr"`
851 | } `xml:"channel_snapshot"`
852 | Parameter []struct {
853 | Text string `xml:",chardata"`
854 | Name string `xml:"name,attr"`
855 | Required string `xml:"required,attr"`
856 | Multiple string `xml:"multiple,attr"`
857 | Para []struct {
858 | Text string `xml:",chardata"`
859 | Variable string `xml:"variable"`
860 | Literal []string `xml:"literal"`
861 | Replaceable []string `xml:"replaceable"`
862 | Include struct {
863 | Text string `xml:",chardata"`
864 | Xpointer string `xml:"xpointer,attr"`
865 | } `xml:"include"`
866 | } `xml:"para"`
867 | Note struct {
868 | Text string `xml:",chardata"`
869 | Para struct {
870 | Text string `xml:",chardata"`
871 | Literal []string `xml:"literal"`
872 | Filename string `xml:"filename"`
873 | Replaceable string `xml:"replaceable"`
874 | } `xml:"para"`
875 | } `xml:"note"`
876 | Enumlist struct {
877 | Text string `xml:",chardata"`
878 | Enum []struct {
879 | Text string `xml:",chardata"`
880 | Name string `xml:"name,attr"`
881 | Para []struct {
882 | Text string `xml:",chardata"`
883 | Literal string `xml:"literal"`
884 | } `xml:"para"`
885 | Note struct {
886 | Text string `xml:",chardata"`
887 | Para struct {
888 | Text string `xml:",chardata"`
889 | Filename string `xml:"filename"`
890 | Literal []string `xml:"literal"`
891 | Replaceable string `xml:"replaceable"`
892 | } `xml:"para"`
893 | } `xml:"note"`
894 | } `xml:"enum"`
895 | } `xml:"enumlist"`
896 | } `xml:"parameter"`
897 | Include []struct {
898 | Text string `xml:",chardata"`
899 | Xpointer string `xml:"xpointer,attr"`
900 | } `xml:"include"`
901 | BridgeSnapshot []struct {
902 | Text string `xml:",chardata"`
903 | Prefix string `xml:"prefix,attr"`
904 | } `xml:"bridge_snapshot"`
905 | } `xml:"syntax"`
906 | SeeAlso struct {
907 | Text string `xml:",chardata"`
908 | Ref []struct {
909 | Text string `xml:",chardata"`
910 | Type string `xml:"type,attr"`
911 | } `xml:"ref"`
912 | } `xml:"see-also"`
913 | Description struct {
914 | Text string `xml:",chardata"`
915 | Para []struct {
916 | Text string `xml:",chardata"`
917 | Literal []string `xml:"literal"`
918 | Replaceable string `xml:"replaceable"`
919 | Filename string `xml:"filename"`
920 | } `xml:"para"`
921 | Note struct {
922 | Text string `xml:",chardata"`
923 | Para struct {
924 | Text string `xml:",chardata"`
925 | Filename string `xml:"filename"`
926 | } `xml:"para"`
927 | } `xml:"note"`
928 | } `xml:"description"`
929 | } `xml:"managerEventInstance"`
930 | } `xml:"managerEvent"`
931 | Agi []struct {
932 | Text string `xml:",chardata"`
933 | Name string `xml:"name,attr"`
934 | Language string `xml:"language,attr"`
935 | Synopsis string `xml:"synopsis"`
936 | Syntax struct {
937 | Text string `xml:",chardata"`
938 | Parameter []struct {
939 | Text string `xml:",chardata"`
940 | Name string `xml:"name,attr"`
941 | Required string `xml:"required,attr"`
942 | Para struct {
943 | Text string `xml:",chardata"`
944 | Literal string `xml:"literal"`
945 | Replaceable []string `xml:"replaceable"`
946 | Filename string `xml:"filename"`
947 | } `xml:"para"`
948 | Enumlist struct {
949 | Text string `xml:",chardata"`
950 | Enum []struct {
951 | Text string `xml:",chardata"`
952 | Name string `xml:"name,attr"`
953 | Parameter struct {
954 | Text string `xml:",chardata"`
955 | Name string `xml:"name,attr"`
956 | Literal string `xml:"literal,attr"`
957 | Required string `xml:"required,attr"`
958 | } `xml:"parameter"`
959 | } `xml:"enum"`
960 | } `xml:"enumlist"`
961 | } `xml:"parameter"`
962 | } `xml:"syntax"`
963 | Description struct {
964 | Text string `xml:",chardata"`
965 | Para []struct {
966 | Text string `xml:",chardata"`
967 | Literal []string `xml:"literal"`
968 | Replaceable []string `xml:"replaceable"`
969 | } `xml:"para"`
970 | Enumlist struct {
971 | Text string `xml:",chardata"`
972 | Enum []struct {
973 | Text string `xml:",chardata"`
974 | Name string `xml:"name,attr"`
975 | Para string `xml:"para"`
976 | } `xml:"enum"`
977 | } `xml:"enumlist"`
978 | Variablelist struct {
979 | Text string `xml:",chardata"`
980 | Variable []struct {
981 | Text string `xml:",chardata"`
982 | Name string `xml:"name,attr"`
983 | Para struct {
984 | Text string `xml:",chardata"`
985 | Literal string `xml:"literal"`
986 | } `xml:"para"`
987 | Value []struct {
988 | Text string `xml:",chardata"`
989 | Name string `xml:"name,attr"`
990 | } `xml:"value"`
991 | } `xml:"variable"`
992 | } `xml:"variablelist"`
993 | } `xml:"description"`
994 | SeeAlso struct {
995 | Text string `xml:",chardata"`
996 | Ref []struct {
997 | Text string `xml:",chardata"`
998 | Type string `xml:"type,attr"`
999 | } `xml:"ref"`
1000 | } `xml:"see-also"`
1001 | } `xml:"agi"`
1002 | }
1003 |
--------------------------------------------------------------------------------
/agi/agimodels/commands.go:
--------------------------------------------------------------------------------
1 | // Code generated by xmlgen. DO NOT EDIT.
2 |
3 | package agimodels
4 |
5 | // GosubCommand Cause the channel to execute the specified dialplan subroutine.
6 | //
7 | // Cause the channel to execute the specified dialplan subroutine, returning to the dialplan with execution of a Return().
8 | type GosubCommand struct {
9 | Context string
10 | Extension string
11 | Priority int
12 | OptionalArgument *string
13 | }
14 |
15 | func (cmd GosubCommand) Command() (string, error) {
16 | s := []interface{}{cmd.CommandString(), cmd.Context, cmd.Extension, cmd.Priority, cmd.OptionalArgument}
17 | return joinCommand(s), nil
18 | }
19 | func (cmd GosubCommand) CommandString() string {
20 | return "GOSUB"
21 | }
22 |
23 | func (cmd GosubCommand) SetOptionalArgument(v string) GosubCommand {
24 | cmd.OptionalArgument = &v
25 | return cmd
26 | }
27 |
28 | func (c *Client) Gosub(context string, extension string, priority int) Response {
29 | return c.Handler.Command(GosubCommand{
30 | Context: context,
31 | Extension: extension,
32 | Priority: priority,
33 | })
34 | }
35 |
36 | // AnswerCommand Answer channel
37 | //
38 | // Answers channel if not already in answer state. Returns `-1` on channel failure, or `0` if successful.
39 | type AnswerCommand struct {
40 | }
41 |
42 | func (cmd AnswerCommand) Command() (string, error) {
43 | s := []interface{}{cmd.CommandString()}
44 | return joinCommand(s), nil
45 | }
46 | func (cmd AnswerCommand) CommandString() string {
47 | return "ANSWER"
48 | }
49 |
50 | func (c *Client) Answer() Response {
51 | return c.Handler.Command(AnswerCommand{})
52 | }
53 |
54 | // AsyncAGIBreakCommand Interrupts Async AGI
55 | //
56 | // Interrupts expected flow of Async AGI commands and returns control to previous source (typically, the PBX dialplan).
57 | type AsyncAGIBreakCommand struct {
58 | }
59 |
60 | func (cmd AsyncAGIBreakCommand) Command() (string, error) {
61 | s := []interface{}{cmd.CommandString()}
62 | return joinCommand(s), nil
63 | }
64 | func (cmd AsyncAGIBreakCommand) CommandString() string {
65 | return "ASYNCAGI BREAK"
66 | }
67 |
68 | func (c *Client) AsyncAGIBreak() Response {
69 | return c.Handler.Command(AsyncAGIBreakCommand{})
70 | }
71 |
72 | // ChannelStatusCommand Returns status of the connected channel.
73 | //
74 | // Returns the status of the specified channelname . If no channel name is given then returns the status of the current channel.
75 | //
76 | // Return values:
77 | type ChannelStatusCommand struct {
78 | ChannelName *string
79 | }
80 |
81 | func (cmd ChannelStatusCommand) Command() (string, error) {
82 | s := []interface{}{cmd.CommandString(), cmd.ChannelName}
83 | return joinCommand(s), nil
84 | }
85 | func (cmd ChannelStatusCommand) CommandString() string {
86 | return "CHANNEL STATUS"
87 | }
88 |
89 | func (cmd ChannelStatusCommand) SetChannelName(v string) ChannelStatusCommand {
90 | cmd.ChannelName = &v
91 | return cmd
92 | }
93 |
94 | func (c *Client) ChannelStatus() Response {
95 | return c.Handler.Command(ChannelStatusCommand{})
96 | }
97 |
98 | // ControlStreamFileCommand Sends audio file on channel and allows the listener to control the stream.
99 | //
100 | // Send the given file, allowing playback to be controlled by the given digits, if any. Use double quotes for the digits if you wish none to be permitted. If offsetms is provided then the audio will seek to offsetms before play starts. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed, or `-1` on error or if the channel was disconnected. Returns the position where playback was terminated as endpos.
101 | //
102 | // It sets the following channel variables upon completion:
103 | type ControlStreamFileCommand struct {
104 | // FileName The file extension must not be included in the filename.
105 | FileName string
106 | EscapeDigits string
107 | SkipMS *int
108 | Ffchar *string // default to #
109 | Rewchr *string // default to *
110 | Pausechr *string
111 | // OffsetMS Offset, in milliseconds, to start the audio playback
112 | OffsetMS *int
113 | }
114 |
115 | func (cmd ControlStreamFileCommand) Command() (string, error) {
116 | s := []interface{}{cmd.CommandString(), cmd.FileName, cmd.EscapeDigits, cmd.SkipMS, cmd.Ffchar, cmd.Rewchr, cmd.Pausechr, cmd.OffsetMS}
117 | return joinCommand(s), nil
118 | }
119 | func (cmd ControlStreamFileCommand) CommandString() string {
120 | return "CONTROL STREAM FILE"
121 | }
122 |
123 | func (cmd ControlStreamFileCommand) SetSkipMS(v int) ControlStreamFileCommand {
124 | cmd.SkipMS = &v
125 | return cmd
126 | }
127 | func (cmd ControlStreamFileCommand) SetFfchar(v string) ControlStreamFileCommand {
128 | cmd.Ffchar = &v
129 | return cmd
130 | }
131 | func (cmd ControlStreamFileCommand) SetRewchr(v string) ControlStreamFileCommand {
132 | cmd.Rewchr = &v
133 | return cmd
134 | }
135 | func (cmd ControlStreamFileCommand) SetPausechr(v string) ControlStreamFileCommand {
136 | cmd.Pausechr = &v
137 | return cmd
138 | }
139 | func (cmd ControlStreamFileCommand) SetOffsetMS(v int) ControlStreamFileCommand {
140 | cmd.OffsetMS = &v
141 | return cmd
142 | }
143 |
144 | func (c *Client) ControlStreamFile(fileName string, escapeDigits string) Response {
145 | return c.Handler.Command(ControlStreamFileCommand{
146 | FileName: fileName,
147 | EscapeDigits: escapeDigits,
148 | })
149 | }
150 |
151 | // DatabaseDelCommand Removes database key/value
152 | //
153 | // Deletes an entry in the Asterisk database for a given family and key .
154 | //
155 | // Returns `1` if successful, `0` otherwise.
156 | type DatabaseDelCommand struct {
157 | Family string
158 | Key string
159 | }
160 |
161 | func (cmd DatabaseDelCommand) Command() (string, error) {
162 | s := []interface{}{cmd.CommandString(), cmd.Family, cmd.Key}
163 | return joinCommand(s), nil
164 | }
165 | func (cmd DatabaseDelCommand) CommandString() string {
166 | return "DATABASE DEL"
167 | }
168 |
169 | func (c *Client) DatabaseDel(family string, key string) Response {
170 | return c.Handler.Command(DatabaseDelCommand{
171 | Family: family,
172 | Key: key,
173 | })
174 | }
175 |
176 | // DatabaseDelTreeCommand Removes database keytree/value
177 | //
178 | // Deletes a family or specific keytree within a family in the Asterisk database.
179 | //
180 | // Returns `1` if successful, `0` otherwise.
181 | type DatabaseDelTreeCommand struct {
182 | Family string
183 | KeyTree *string
184 | }
185 |
186 | func (cmd DatabaseDelTreeCommand) Command() (string, error) {
187 | s := []interface{}{cmd.CommandString(), cmd.Family, cmd.KeyTree}
188 | return joinCommand(s), nil
189 | }
190 | func (cmd DatabaseDelTreeCommand) CommandString() string {
191 | return "DATABASE DELTREE"
192 | }
193 |
194 | func (cmd DatabaseDelTreeCommand) SetKeyTree(v string) DatabaseDelTreeCommand {
195 | cmd.KeyTree = &v
196 | return cmd
197 | }
198 |
199 | func (c *Client) DatabaseDelTree(family string) Response {
200 | return c.Handler.Command(DatabaseDelTreeCommand{
201 | Family: family,
202 | })
203 | }
204 |
205 | // DatabaseGetCommand Gets database value
206 | //
207 | // Retrieves an entry in the Asterisk database for a given family and key .
208 | //
209 | // Returns `0` if key is not set. Returns `1` if key is set and returns the variable in parenthesis.
210 | //
211 | // Example return code: 200 result=1 (testvariable)
212 | type DatabaseGetCommand struct {
213 | Family string
214 | Key string
215 | }
216 |
217 | func (cmd DatabaseGetCommand) Command() (string, error) {
218 | s := []interface{}{cmd.CommandString(), cmd.Family, cmd.Key}
219 | return joinCommand(s), nil
220 | }
221 | func (cmd DatabaseGetCommand) CommandString() string {
222 | return "DATABASE GET"
223 | }
224 |
225 | func (c *Client) DatabaseGet(family string, key string) Response {
226 | return c.Handler.Command(DatabaseGetCommand{
227 | Family: family,
228 | Key: key,
229 | })
230 | }
231 |
232 | // DatabasePutCommand Adds/updates database value
233 | //
234 | // Adds or updates an entry in the Asterisk database for a given family , key , and value .
235 | //
236 | // Returns `1` if successful, `0` otherwise.
237 | type DatabasePutCommand struct {
238 | Family string
239 | Key string
240 | Value string
241 | }
242 |
243 | func (cmd DatabasePutCommand) Command() (string, error) {
244 | s := []interface{}{cmd.CommandString(), cmd.Family, cmd.Key, cmd.Value}
245 | return joinCommand(s), nil
246 | }
247 | func (cmd DatabasePutCommand) CommandString() string {
248 | return "DATABASE PUT"
249 | }
250 |
251 | func (c *Client) DatabasePut(family string, key string, value string) Response {
252 | return c.Handler.Command(DatabasePutCommand{
253 | Family: family,
254 | Key: key,
255 | Value: value,
256 | })
257 | }
258 |
259 | // ExecCommand Executes a given Application
260 | //
261 | // Executes application with given options .
262 | //
263 | // Returns whatever the application returns, or `-2` on failure to find application .
264 | type ExecCommand struct {
265 | Application string
266 | Options string
267 | }
268 |
269 | func (cmd ExecCommand) Command() (string, error) {
270 | s := []interface{}{cmd.CommandString(), cmd.Application, cmd.Options}
271 | return joinCommand(s), nil
272 | }
273 | func (cmd ExecCommand) CommandString() string {
274 | return "EXEC"
275 | }
276 |
277 | func (c *Client) Exec(application string, options string) Response {
278 | return c.Handler.Command(ExecCommand{
279 | Application: application,
280 | Options: options,
281 | })
282 | }
283 |
284 | // GetDataCommand Prompts for DTMF on a channel
285 | //
286 | // Stream the given file , and receive DTMF data.
287 | //
288 | // Returns the digits received from the channel at the other end.
289 | type GetDataCommand struct {
290 | File string
291 | Timeout *int
292 | Maxdigits *string
293 | }
294 |
295 | func (cmd GetDataCommand) Command() (string, error) {
296 | s := []interface{}{cmd.CommandString(), cmd.File, cmd.Timeout, cmd.Maxdigits}
297 | return joinCommand(s), nil
298 | }
299 | func (cmd GetDataCommand) CommandString() string {
300 | return "GET DATA"
301 | }
302 |
303 | func (cmd GetDataCommand) SetTimeout(v int) GetDataCommand {
304 | cmd.Timeout = &v
305 | return cmd
306 | }
307 | func (cmd GetDataCommand) SetMaxdigits(v string) GetDataCommand {
308 | cmd.Maxdigits = &v
309 | return cmd
310 | }
311 |
312 | func (c *Client) GetData(file string) Response {
313 | return c.Handler.Command(GetDataCommand{
314 | File: file,
315 | })
316 | }
317 |
318 | // GetFullVariableCommand Evaluates a channel expression
319 | //
320 | // Evaluates the given expression against the channel specified by channelname , or the current channel if channelname is not provided.
321 | //
322 | // Unlike GET VARIABLE, the expression is processed in a manner similar to dialplan evaluation, allowing complex and built-in variables to be accessed, e.g. `The time is ${EPOCH} `
323 | //
324 | // Returns `0` if no channel matching channelname exists, `1` otherwise.
325 | //
326 | // Example return code: 200 result=1 (The time is 1578493800)
327 | type GetFullVariableCommand struct {
328 | Expression string
329 | ChannelName *string
330 | }
331 |
332 | func (cmd GetFullVariableCommand) Command() (string, error) {
333 | s := []interface{}{cmd.CommandString(), cmd.Expression, cmd.ChannelName}
334 | return joinCommand(s), nil
335 | }
336 | func (cmd GetFullVariableCommand) CommandString() string {
337 | return "GET FULL VARIABLE"
338 | }
339 |
340 | func (cmd GetFullVariableCommand) SetChannelName(v string) GetFullVariableCommand {
341 | cmd.ChannelName = &v
342 | return cmd
343 | }
344 |
345 | func (c *Client) GetFullVariable(expression string) Response {
346 | return c.Handler.Command(GetFullVariableCommand{
347 | Expression: expression,
348 | })
349 | }
350 |
351 | // GetOptionCommand Stream file, prompt for DTMF, with timeout.
352 | //
353 | // Behaves similar to STREAM FILE but used with a timeout option.
354 | type GetOptionCommand struct {
355 | FileName string
356 | EscapeDigits string
357 | Timeout *int
358 | }
359 |
360 | func (cmd GetOptionCommand) Command() (string, error) {
361 | s := []interface{}{cmd.CommandString(), cmd.FileName, cmd.EscapeDigits, cmd.Timeout}
362 | return joinCommand(s), nil
363 | }
364 | func (cmd GetOptionCommand) CommandString() string {
365 | return "GET OPTION"
366 | }
367 |
368 | func (cmd GetOptionCommand) SetTimeout(v int) GetOptionCommand {
369 | cmd.Timeout = &v
370 | return cmd
371 | }
372 |
373 | func (c *Client) GetOption(fileName string, escapeDigits string) Response {
374 | return c.Handler.Command(GetOptionCommand{
375 | FileName: fileName,
376 | EscapeDigits: escapeDigits,
377 | })
378 | }
379 |
380 | // GetVariableCommand Gets a channel variable.
381 | //
382 | // Returns `0` if variablename is not set. Returns `1` if variablename is set and returns the variable in parentheses.
383 | //
384 | // Example return code: 200 result=1 (testvariable)
385 | type GetVariableCommand struct {
386 | VariableName string
387 | }
388 |
389 | func (cmd GetVariableCommand) Command() (string, error) {
390 | s := []interface{}{cmd.CommandString(), cmd.VariableName}
391 | return joinCommand(s), nil
392 | }
393 | func (cmd GetVariableCommand) CommandString() string {
394 | return "GET VARIABLE"
395 | }
396 |
397 | func (c *Client) GetVariable(variableName string) Response {
398 | return c.Handler.Command(GetVariableCommand{
399 | VariableName: variableName,
400 | })
401 | }
402 |
403 | // HangupCommand Hangup a channel.
404 | //
405 | // Hangs up the specified channel. If no channel name is given, hangs up the current channel
406 | type HangupCommand struct {
407 | ChannelName *string
408 | }
409 |
410 | func (cmd HangupCommand) Command() (string, error) {
411 | s := []interface{}{cmd.CommandString(), cmd.ChannelName}
412 | return joinCommand(s), nil
413 | }
414 | func (cmd HangupCommand) CommandString() string {
415 | return "HANGUP"
416 | }
417 |
418 | func (cmd HangupCommand) SetChannelName(v string) HangupCommand {
419 | cmd.ChannelName = &v
420 | return cmd
421 | }
422 |
423 | func (c *Client) Hangup() Response {
424 | return c.Handler.Command(HangupCommand{})
425 | }
426 |
427 | // NoopCommand Does nothing.
428 | //
429 | // Does nothing.
430 | type NoopCommand struct {
431 | }
432 |
433 | func (cmd NoopCommand) Command() (string, error) {
434 | s := []interface{}{cmd.CommandString()}
435 | return joinCommand(s), nil
436 | }
437 | func (cmd NoopCommand) CommandString() string {
438 | return "NOOP"
439 | }
440 |
441 | func (c *Client) Noop() Response {
442 | return c.Handler.Command(NoopCommand{})
443 | }
444 |
445 | // ReceiveCharCommand Receives one character from channels supporting it.
446 | //
447 | // Receives a character of text on a channel. Most channels do not support the reception of text. Returns the decimal value of the character if one is received, or `0` if the channel does not support text reception. Returns `-1` only on error/hangup.
448 | type ReceiveCharCommand struct {
449 | // Timeout The maximum time to wait for input in milliseconds, or `0` for infinite. Most channels
450 | Timeout int
451 | }
452 |
453 | func (cmd ReceiveCharCommand) Command() (string, error) {
454 | s := []interface{}{cmd.CommandString(), cmd.Timeout}
455 | return joinCommand(s), nil
456 | }
457 | func (cmd ReceiveCharCommand) CommandString() string {
458 | return "RECEIVE CHAR"
459 | }
460 |
461 | func (c *Client) ReceiveChar(timeout int) Response {
462 | return c.Handler.Command(ReceiveCharCommand{
463 | Timeout: timeout,
464 | })
465 | }
466 |
467 | // ReceiveTextCommand Receives text from channels supporting it.
468 | //
469 | // Receives a string of text on a channel. Most channels do not support the reception of text. Returns `-1` for failure or `1` for success, and the string in parenthesis.
470 | type ReceiveTextCommand struct {
471 | // Timeout The timeout to be the maximum time to wait for input in milliseconds, or `0` for infinite.
472 | Timeout int
473 | }
474 |
475 | func (cmd ReceiveTextCommand) Command() (string, error) {
476 | s := []interface{}{cmd.CommandString(), cmd.Timeout}
477 | return joinCommand(s), nil
478 | }
479 | func (cmd ReceiveTextCommand) CommandString() string {
480 | return "RECEIVE TEXT"
481 | }
482 |
483 | func (c *Client) ReceiveText(timeout int) Response {
484 | return c.Handler.Command(ReceiveTextCommand{
485 | Timeout: timeout,
486 | })
487 | }
488 |
489 | // RecordFileCommand Records to a given file.
490 | //
491 | // Record to a file until a given dtmf digit in the sequence is received. Returns `-1` on hangup or error. The format will specify what kind of file will be recorded. The timeout is the maximum record time in milliseconds, or `-1` for no timeout . offset samples is optional, and, if provided, will seek to the offset without exceeding the end of the file. beep can take any value, and causes Asterisk to play a beep to the channel that is about to be recorded. silence is the number of seconds of silence allowed before the function returns despite the lack of dtmf digits or reaching timeout . silence value must be preceded by `s=` and is also optional.
492 | type RecordFileCommand struct {
493 | // FileName The destination filename of the recorded audio.
494 | FileName string
495 | // Format The audio format in which to save the resulting file.
496 | Format string
497 | // EscapeDigits The DTMF digits that will terminate the recording process.
498 | EscapeDigits string
499 | // Timeout The maximum recording time in milliseconds. Set to -1 for no limit.
500 | Timeout int
501 | // OffsetSamples Causes the recording to first seek to the specified offset before recording begins.
502 | OffsetSamples *string
503 | // Beep Causes Asterisk to play a beep as recording begins. This argument can take any value.
504 | Beep *string
505 | // SSilence The number of seconds of silence that are permitted before the recording is terminated, regardless of the escape_digits or timeout arguments. If specified, this parameter must be preceded by `s=`.
506 | SSilence *string
507 | }
508 |
509 | func (cmd RecordFileCommand) Command() (string, error) {
510 | s := []interface{}{cmd.CommandString(), cmd.FileName, cmd.Format, cmd.EscapeDigits, cmd.Timeout, cmd.OffsetSamples, cmd.Beep, cmd.SSilence}
511 | return joinCommand(s), nil
512 | }
513 | func (cmd RecordFileCommand) CommandString() string {
514 | return "RECORD FILE"
515 | }
516 |
517 | func (cmd RecordFileCommand) SetOffsetSamples(v string) RecordFileCommand {
518 | cmd.OffsetSamples = &v
519 | return cmd
520 | }
521 | func (cmd RecordFileCommand) SetBeep(v string) RecordFileCommand {
522 | cmd.Beep = &v
523 | return cmd
524 | }
525 | func (cmd RecordFileCommand) SetSSilence(v string) RecordFileCommand {
526 | cmd.SSilence = &v
527 | return cmd
528 | }
529 |
530 | func (c *Client) RecordFile(fileName string, format string, escapeDigits string, timeout int) Response {
531 | return c.Handler.Command(RecordFileCommand{
532 | FileName: fileName,
533 | Format: format,
534 | EscapeDigits: escapeDigits,
535 | Timeout: timeout,
536 | })
537 | }
538 |
539 | // SayAlphaCommand Says a given character string.
540 | //
541 | // Say a given character string, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or `-1` on error/hangup.
542 | type SayAlphaCommand struct {
543 | Number string
544 | EscapeDigits string
545 | }
546 |
547 | func (cmd SayAlphaCommand) Command() (string, error) {
548 | s := []interface{}{cmd.CommandString(), cmd.Number, cmd.EscapeDigits}
549 | return joinCommand(s), nil
550 | }
551 | func (cmd SayAlphaCommand) CommandString() string {
552 | return "SAY ALPHA"
553 | }
554 |
555 | func (c *Client) SayAlpha(number string, escapeDigits string) Response {
556 | return c.Handler.Command(SayAlphaCommand{
557 | Number: number,
558 | EscapeDigits: escapeDigits,
559 | })
560 | }
561 |
562 | // SayDigitsCommand Says a given digit string.
563 | //
564 | // Say a given digit string, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or `-1` on error/hangup.
565 | type SayDigitsCommand struct {
566 | Number string
567 | EscapeDigits string
568 | }
569 |
570 | func (cmd SayDigitsCommand) Command() (string, error) {
571 | s := []interface{}{cmd.CommandString(), cmd.Number, cmd.EscapeDigits}
572 | return joinCommand(s), nil
573 | }
574 | func (cmd SayDigitsCommand) CommandString() string {
575 | return "SAY DIGITS"
576 | }
577 |
578 | func (c *Client) SayDigits(number string, escapeDigits string) Response {
579 | return c.Handler.Command(SayDigitsCommand{
580 | Number: number,
581 | EscapeDigits: escapeDigits,
582 | })
583 | }
584 |
585 | // SayNumberCommand Says a given number.
586 | //
587 | // Say a given number, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or `-1` on error/hangup.
588 | type SayNumberCommand struct {
589 | Number string
590 | EscapeDigits string
591 | Gender *string
592 | }
593 |
594 | func (cmd SayNumberCommand) Command() (string, error) {
595 | s := []interface{}{cmd.CommandString(), cmd.Number, cmd.EscapeDigits, cmd.Gender}
596 | return joinCommand(s), nil
597 | }
598 | func (cmd SayNumberCommand) CommandString() string {
599 | return "SAY NUMBER"
600 | }
601 |
602 | func (cmd SayNumberCommand) SetGender(v string) SayNumberCommand {
603 | cmd.Gender = &v
604 | return cmd
605 | }
606 |
607 | func (c *Client) SayNumber(number string, escapeDigits string) Response {
608 | return c.Handler.Command(SayNumberCommand{
609 | Number: number,
610 | EscapeDigits: escapeDigits,
611 | })
612 | }
613 |
614 | // SayPhoneticCommand Says a given character string with phonetics.
615 | //
616 | // Say a given character string with phonetics, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit pressed, the ASCII numerical value of the digit if one was pressed, or `-1` on error/hangup.
617 | type SayPhoneticCommand struct {
618 | String string
619 | EscapeDigits string
620 | }
621 |
622 | func (cmd SayPhoneticCommand) Command() (string, error) {
623 | s := []interface{}{cmd.CommandString(), cmd.String, cmd.EscapeDigits}
624 | return joinCommand(s), nil
625 | }
626 | func (cmd SayPhoneticCommand) CommandString() string {
627 | return "SAY PHONETIC"
628 | }
629 |
630 | func (c *Client) SayPhonetic(string string, escapeDigits string) Response {
631 | return c.Handler.Command(SayPhoneticCommand{
632 | String: string,
633 | EscapeDigits: escapeDigits,
634 | })
635 | }
636 |
637 | // SayDateCommand Says a given date.
638 | //
639 | // Say a given date, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or `-1` on error/hangup.
640 | type SayDateCommand struct {
641 | // Date Is number of seconds elapsed since 00:00:00 on January 1, 1970. Coordinated Universal Time (UTC).
642 | Date string
643 | EscapeDigits string
644 | }
645 |
646 | func (cmd SayDateCommand) Command() (string, error) {
647 | s := []interface{}{cmd.CommandString(), cmd.Date, cmd.EscapeDigits}
648 | return joinCommand(s), nil
649 | }
650 | func (cmd SayDateCommand) CommandString() string {
651 | return "SAY DATE"
652 | }
653 |
654 | func (c *Client) SayDate(date string, escapeDigits string) Response {
655 | return c.Handler.Command(SayDateCommand{
656 | Date: date,
657 | EscapeDigits: escapeDigits,
658 | })
659 | }
660 |
661 | // SayTimeCommand Says a given time.
662 | //
663 | // Say a given time, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or `-1` on error/hangup.
664 | type SayTimeCommand struct {
665 | // Time Is number of seconds elapsed since 00:00:00 on January 1, 1970. Coordinated Universal Time (UTC).
666 | Time float64
667 | EscapeDigits string
668 | }
669 |
670 | func (cmd SayTimeCommand) Command() (string, error) {
671 | s := []interface{}{cmd.CommandString(), cmd.Time, cmd.EscapeDigits}
672 | return joinCommand(s), nil
673 | }
674 | func (cmd SayTimeCommand) CommandString() string {
675 | return "SAY TIME"
676 | }
677 |
678 | func (c *Client) SayTime(time float64, escapeDigits string) Response {
679 | return c.Handler.Command(SayTimeCommand{
680 | Time: time,
681 | EscapeDigits: escapeDigits,
682 | })
683 | }
684 |
685 | // SayDatetimeCommand Says a given time as specified by the format given.
686 | //
687 | // Say a given time, returning early if any of the given DTMF digits are received on the channel. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed or `-1` on error/hangup.
688 | type SayDatetimeCommand struct {
689 | // Time Is number of seconds elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC)
690 | Time float64
691 | EscapeDigits string
692 | // Format Is the format the time should be said in. See voicemail.conf (defaults to `ABdY 'digits/at' IMp`).
693 | Format *string
694 | // Timezone Acceptable values can be found in /usr/share/zoneinfo Defaults to machine default.
695 | Timezone *string
696 | }
697 |
698 | func (cmd SayDatetimeCommand) Command() (string, error) {
699 | s := []interface{}{cmd.CommandString(), cmd.Time, cmd.EscapeDigits, cmd.Format, cmd.Timezone}
700 | return joinCommand(s), nil
701 | }
702 | func (cmd SayDatetimeCommand) CommandString() string {
703 | return "SAY DATETIME"
704 | }
705 |
706 | func (cmd SayDatetimeCommand) SetFormat(v string) SayDatetimeCommand {
707 | cmd.Format = &v
708 | return cmd
709 | }
710 | func (cmd SayDatetimeCommand) SetTimezone(v string) SayDatetimeCommand {
711 | cmd.Timezone = &v
712 | return cmd
713 | }
714 |
715 | func (c *Client) SayDatetime(time float64, escapeDigits string) Response {
716 | return c.Handler.Command(SayDatetimeCommand{
717 | Time: time,
718 | EscapeDigits: escapeDigits,
719 | })
720 | }
721 |
722 | // SendImageCommand Sends images to channels supporting it.
723 | //
724 | // Sends the given image on a channel. Most channels do not support the transmission of images. Returns `0` if image is sent, or if the channel does not support image transmission. Returns `-1` only on error/hangup. Image names should not include extensions.
725 | type SendImageCommand struct {
726 | Image string
727 | }
728 |
729 | func (cmd SendImageCommand) Command() (string, error) {
730 | s := []interface{}{cmd.CommandString(), cmd.Image}
731 | return joinCommand(s), nil
732 | }
733 | func (cmd SendImageCommand) CommandString() string {
734 | return "SEND IMAGE"
735 | }
736 |
737 | func (c *Client) SendImage(image string) Response {
738 | return c.Handler.Command(SendImageCommand{
739 | Image: image,
740 | })
741 | }
742 |
743 | // SendTextCommand Sends text to channels supporting it.
744 | //
745 | // Sends the given text on a channel. Most channels do not support the transmission of text. Returns `0` if text is sent, or if the channel does not support text transmission. Returns `-1` only on error/hangup.
746 | type SendTextCommand struct {
747 | // TextToSend Text consisting of greater than one word should be placed in quotes since the command only accepts a single argument.
748 | TextToSend string
749 | }
750 |
751 | func (cmd SendTextCommand) Command() (string, error) {
752 | s := []interface{}{cmd.CommandString(), cmd.TextToSend}
753 | return joinCommand(s), nil
754 | }
755 | func (cmd SendTextCommand) CommandString() string {
756 | return "SEND TEXT"
757 | }
758 |
759 | func (c *Client) SendText(textToSend string) Response {
760 | return c.Handler.Command(SendTextCommand{
761 | TextToSend: textToSend,
762 | })
763 | }
764 |
765 | // SetAutoHangupCommand Autohangup channel in some time.
766 | //
767 | // Cause the channel to automatically hangup at time seconds in the future. Of course it can be hungup before then as well. Setting to `0` will cause the autohangup feature to be disabled on this channel.
768 | type SetAutoHangupCommand struct {
769 | Time float64
770 | }
771 |
772 | func (cmd SetAutoHangupCommand) Command() (string, error) {
773 | s := []interface{}{cmd.CommandString(), cmd.Time}
774 | return joinCommand(s), nil
775 | }
776 | func (cmd SetAutoHangupCommand) CommandString() string {
777 | return "SET AUTOHANGUP"
778 | }
779 |
780 | func (c *Client) SetAutoHangup(time float64) Response {
781 | return c.Handler.Command(SetAutoHangupCommand{
782 | Time: time,
783 | })
784 | }
785 |
786 | // SetCallerIDCommand Sets callerid for the current channel.
787 | //
788 | // Changes the callerid of the current channel.
789 | type SetCallerIDCommand struct {
790 | Number string
791 | }
792 |
793 | func (cmd SetCallerIDCommand) Command() (string, error) {
794 | s := []interface{}{cmd.CommandString(), cmd.Number}
795 | return joinCommand(s), nil
796 | }
797 | func (cmd SetCallerIDCommand) CommandString() string {
798 | return "SET CALLERID"
799 | }
800 |
801 | func (c *Client) SetCallerID(number string) Response {
802 | return c.Handler.Command(SetCallerIDCommand{
803 | Number: number,
804 | })
805 | }
806 |
807 | // SetContextCommand Sets channel context.
808 | //
809 | // Sets the context for continuation upon exiting the application.
810 | type SetContextCommand struct {
811 | DesiredContext string
812 | }
813 |
814 | func (cmd SetContextCommand) Command() (string, error) {
815 | s := []interface{}{cmd.CommandString(), cmd.DesiredContext}
816 | return joinCommand(s), nil
817 | }
818 | func (cmd SetContextCommand) CommandString() string {
819 | return "SET CONTEXT"
820 | }
821 |
822 | func (c *Client) SetContext(desiredContext string) Response {
823 | return c.Handler.Command(SetContextCommand{
824 | DesiredContext: desiredContext,
825 | })
826 | }
827 |
828 | // SetExtensionCommand Changes channel extension.
829 | //
830 | // Changes the extension for continuation upon exiting the application.
831 | type SetExtensionCommand struct {
832 | NewExtension string
833 | }
834 |
835 | func (cmd SetExtensionCommand) Command() (string, error) {
836 | s := []interface{}{cmd.CommandString(), cmd.NewExtension}
837 | return joinCommand(s), nil
838 | }
839 | func (cmd SetExtensionCommand) CommandString() string {
840 | return "SET EXTENSION"
841 | }
842 |
843 | func (c *Client) SetExtension(newExtension string) Response {
844 | return c.Handler.Command(SetExtensionCommand{
845 | NewExtension: newExtension,
846 | })
847 | }
848 |
849 | // SetMusicCommand Enable/Disable Music on hold generator
850 | //
851 | // Enables/Disables the music on hold generator. If class is not specified, then the `default` music on hold class will be used. This generator will be stopped automatically when playing a file.
852 | //
853 | // Always returns `0`.
854 | type SetMusicCommand struct {
855 | Class string
856 | // has missing params
857 | }
858 |
859 | func (cmd SetMusicCommand) Command() (string, error) {
860 | s := []interface{}{cmd.CommandString(), cmd.Class}
861 | return joinCommand(s), nil
862 | }
863 | func (cmd SetMusicCommand) CommandString() string {
864 | return "SET MUSIC"
865 | }
866 |
867 | func (c *Client) SetMusic(class string) Response {
868 | return c.Handler.Command(SetMusicCommand{
869 | Class: class,
870 | })
871 | }
872 |
873 | // SetPriorityCommand Set channel dialplan priority.
874 | //
875 | // Changes the priority for continuation upon exiting the application. The priority must be a valid priority or label.
876 | type SetPriorityCommand struct {
877 | Priority int
878 | }
879 |
880 | func (cmd SetPriorityCommand) Command() (string, error) {
881 | s := []interface{}{cmd.CommandString(), cmd.Priority}
882 | return joinCommand(s), nil
883 | }
884 | func (cmd SetPriorityCommand) CommandString() string {
885 | return "SET PRIORITY"
886 | }
887 |
888 | func (c *Client) SetPriority(priority int) Response {
889 | return c.Handler.Command(SetPriorityCommand{
890 | Priority: priority,
891 | })
892 | }
893 |
894 | // SetVariableCommand Sets a channel variable.
895 | //
896 | // Sets a variable to the current channel.
897 | type SetVariableCommand struct {
898 | VariableName string
899 | Value string
900 | }
901 |
902 | func (cmd SetVariableCommand) Command() (string, error) {
903 | s := []interface{}{cmd.CommandString(), cmd.VariableName, cmd.Value}
904 | return joinCommand(s), nil
905 | }
906 | func (cmd SetVariableCommand) CommandString() string {
907 | return "SET VARIABLE"
908 | }
909 |
910 | func (c *Client) SetVariable(variableName string, value string) Response {
911 | return c.Handler.Command(SetVariableCommand{
912 | VariableName: variableName,
913 | Value: value,
914 | })
915 | }
916 |
917 | // StreamFileCommand Sends audio file on channel.
918 | //
919 | // Send the given file, allowing playback to be interrupted by the given digits, if any. Returns `0` if playback completes without a digit being pressed, or the ASCII numerical value of the digit if one was pressed, or `-1` on error or if the channel was disconnected. If musiconhold is playing before calling stream file it will be automatically stopped and will not be restarted after completion.
920 | //
921 | // It sets the following channel variables upon completion:
922 | type StreamFileCommand struct {
923 | // FileName File name to play. The file extension must not be included in the filename .
924 | FileName string
925 | // EscapeDigits Use double quotes for the digits if you wish none to be permitted.
926 | EscapeDigits string
927 | // SampleOffset If sample offset is provided then the audio will seek to sample offset before play starts.
928 | SampleOffset *int
929 | }
930 |
931 | func (cmd StreamFileCommand) Command() (string, error) {
932 | s := []interface{}{cmd.CommandString(), cmd.FileName, cmd.EscapeDigits, cmd.SampleOffset}
933 | return joinCommand(s), nil
934 | }
935 | func (cmd StreamFileCommand) CommandString() string {
936 | return "STREAM FILE"
937 | }
938 |
939 | func (cmd StreamFileCommand) SetSampleOffset(v int) StreamFileCommand {
940 | cmd.SampleOffset = &v
941 | return cmd
942 | }
943 |
944 | func (c *Client) StreamFile(fileName string, escapeDigits string) Response {
945 | return c.Handler.Command(StreamFileCommand{
946 | FileName: fileName,
947 | EscapeDigits: escapeDigits,
948 | })
949 | }
950 |
951 | // TddModeCommand Toggles TDD mode (for the deaf).
952 | //
953 | // Enable/Disable TDD transmission/reception on a channel. Returns `1` if successful, or `0` if channel is not TDD-capable.
954 | type TddModeCommand struct {
955 | Boolean string
956 | }
957 |
958 | func (cmd TddModeCommand) Command() (string, error) {
959 | s := []interface{}{cmd.CommandString(), cmd.Boolean}
960 | return joinCommand(s), nil
961 | }
962 | func (cmd TddModeCommand) CommandString() string {
963 | return "TDD MODE"
964 | }
965 |
966 | func (c *Client) TddMode(boolean string) Response {
967 | return c.Handler.Command(TddModeCommand{
968 | Boolean: boolean,
969 | })
970 | }
971 |
972 | // VerboseCommand Logs a message to the asterisk verbose log.
973 | //
974 | // Sends message to the console via verbose message system. level is the verbose level (1-4). Always returns `1`
975 | type VerboseCommand struct {
976 | Message string
977 | Level string
978 | }
979 |
980 | func (cmd VerboseCommand) Command() (string, error) {
981 | s := []interface{}{cmd.CommandString(), cmd.Message, cmd.Level}
982 | return joinCommand(s), nil
983 | }
984 | func (cmd VerboseCommand) CommandString() string {
985 | return "VERBOSE"
986 | }
987 |
988 | func (c *Client) Verbose(message string, level string) Response {
989 | return c.Handler.Command(VerboseCommand{
990 | Message: message,
991 | Level: level,
992 | })
993 | }
994 |
995 | // WaitForDigitCommand Waits for a digit to be pressed.
996 | //
997 | // Waits up to timeout milliseconds for channel to receive a DTMF digit. Returns `-1` on channel failure, `0` if no digit is received in the timeout, or the numerical value of the ascii of the digit if one is received. Use `-1` for the timeout value if you desire the call to block indefinitely.
998 | type WaitForDigitCommand struct {
999 | Timeout int
1000 | }
1001 |
1002 | func (cmd WaitForDigitCommand) Command() (string, error) {
1003 | s := []interface{}{cmd.CommandString(), cmd.Timeout}
1004 | return joinCommand(s), nil
1005 | }
1006 | func (cmd WaitForDigitCommand) CommandString() string {
1007 | return "WAIT FOR DIGIT"
1008 | }
1009 |
1010 | func (c *Client) WaitForDigit(timeout int) Response {
1011 | return c.Handler.Command(WaitForDigitCommand{
1012 | Timeout: timeout,
1013 | })
1014 | }
1015 |
1016 | // SpeechCreateCommand Creates a speech object.
1017 | //
1018 | // Create a speech object to be used by the other Speech AGI commands.
1019 | type SpeechCreateCommand struct {
1020 | Engine string
1021 | }
1022 |
1023 | func (cmd SpeechCreateCommand) Command() (string, error) {
1024 | s := []interface{}{cmd.CommandString(), cmd.Engine}
1025 | return joinCommand(s), nil
1026 | }
1027 | func (cmd SpeechCreateCommand) CommandString() string {
1028 | return "SPEECH CREATE"
1029 | }
1030 |
1031 | func (c *Client) SpeechCreate(engine string) Response {
1032 | return c.Handler.Command(SpeechCreateCommand{
1033 | Engine: engine,
1034 | })
1035 | }
1036 |
1037 | // SpeechSetCommand Sets a speech engine setting.
1038 | //
1039 | // Set an engine-specific setting.
1040 | type SpeechSetCommand struct {
1041 | Name string
1042 | Value string
1043 | }
1044 |
1045 | func (cmd SpeechSetCommand) Command() (string, error) {
1046 | s := []interface{}{cmd.CommandString(), cmd.Name, cmd.Value}
1047 | return joinCommand(s), nil
1048 | }
1049 | func (cmd SpeechSetCommand) CommandString() string {
1050 | return "SPEECH SET"
1051 | }
1052 |
1053 | func (c *Client) SpeechSet(name string, value string) Response {
1054 | return c.Handler.Command(SpeechSetCommand{
1055 | Name: name,
1056 | Value: value,
1057 | })
1058 | }
1059 |
1060 | // SpeechDestroyCommand Destroys a speech object.
1061 | //
1062 | // Destroy the speech object created by `SPEECH CREATE`.
1063 | type SpeechDestroyCommand struct {
1064 | }
1065 |
1066 | func (cmd SpeechDestroyCommand) Command() (string, error) {
1067 | s := []interface{}{cmd.CommandString()}
1068 | return joinCommand(s), nil
1069 | }
1070 | func (cmd SpeechDestroyCommand) CommandString() string {
1071 | return "SPEECH DESTROY"
1072 | }
1073 |
1074 | func (c *Client) SpeechDestroy() Response {
1075 | return c.Handler.Command(SpeechDestroyCommand{})
1076 | }
1077 |
1078 | // SpeechLoadGrammarCommand Loads a grammar.
1079 | //
1080 | // Loads the specified grammar as the specified name.
1081 | type SpeechLoadGrammarCommand struct {
1082 | GrammarName string
1083 | PathToGrammar string
1084 | }
1085 |
1086 | func (cmd SpeechLoadGrammarCommand) Command() (string, error) {
1087 | s := []interface{}{cmd.CommandString(), cmd.GrammarName, cmd.PathToGrammar}
1088 | return joinCommand(s), nil
1089 | }
1090 | func (cmd SpeechLoadGrammarCommand) CommandString() string {
1091 | return "SPEECH LOAD GRAMMAR"
1092 | }
1093 |
1094 | func (c *Client) SpeechLoadGrammar(grammarName string, pathToGrammar string) Response {
1095 | return c.Handler.Command(SpeechLoadGrammarCommand{
1096 | GrammarName: grammarName,
1097 | PathToGrammar: pathToGrammar,
1098 | })
1099 | }
1100 |
1101 | // SpeechUnloadGrammarCommand Unloads a grammar.
1102 | //
1103 | // Unloads the specified grammar.
1104 | type SpeechUnloadGrammarCommand struct {
1105 | GrammarName string
1106 | }
1107 |
1108 | func (cmd SpeechUnloadGrammarCommand) Command() (string, error) {
1109 | s := []interface{}{cmd.CommandString(), cmd.GrammarName}
1110 | return joinCommand(s), nil
1111 | }
1112 | func (cmd SpeechUnloadGrammarCommand) CommandString() string {
1113 | return "SPEECH UNLOAD GRAMMAR"
1114 | }
1115 |
1116 | func (c *Client) SpeechUnloadGrammar(grammarName string) Response {
1117 | return c.Handler.Command(SpeechUnloadGrammarCommand{
1118 | GrammarName: grammarName,
1119 | })
1120 | }
1121 |
1122 | // SpeechActivateGrammarCommand Activates a grammar.
1123 | //
1124 | // Activates the specified grammar on the speech object.
1125 | type SpeechActivateGrammarCommand struct {
1126 | GrammarName string
1127 | }
1128 |
1129 | func (cmd SpeechActivateGrammarCommand) Command() (string, error) {
1130 | s := []interface{}{cmd.CommandString(), cmd.GrammarName}
1131 | return joinCommand(s), nil
1132 | }
1133 | func (cmd SpeechActivateGrammarCommand) CommandString() string {
1134 | return "SPEECH ACTIVATE GRAMMAR"
1135 | }
1136 |
1137 | func (c *Client) SpeechActivateGrammar(grammarName string) Response {
1138 | return c.Handler.Command(SpeechActivateGrammarCommand{
1139 | GrammarName: grammarName,
1140 | })
1141 | }
1142 |
1143 | // SpeechDeactivateGrammarCommand Deactivates a grammar.
1144 | //
1145 | // Deactivates the specified grammar on the speech object.
1146 | type SpeechDeactivateGrammarCommand struct {
1147 | GrammarName string
1148 | }
1149 |
1150 | func (cmd SpeechDeactivateGrammarCommand) Command() (string, error) {
1151 | s := []interface{}{cmd.CommandString(), cmd.GrammarName}
1152 | return joinCommand(s), nil
1153 | }
1154 | func (cmd SpeechDeactivateGrammarCommand) CommandString() string {
1155 | return "SPEECH DEACTIVATE GRAMMAR"
1156 | }
1157 |
1158 | func (c *Client) SpeechDeactivateGrammar(grammarName string) Response {
1159 | return c.Handler.Command(SpeechDeactivateGrammarCommand{
1160 | GrammarName: grammarName,
1161 | })
1162 | }
1163 |
1164 | // SpeechRecognizeCommand Recognizes speech.
1165 | //
1166 | // Plays back given prompt while listening for speech and dtmf.
1167 | type SpeechRecognizeCommand struct {
1168 | Prompt string
1169 | Timeout int
1170 | Offset *string
1171 | }
1172 |
1173 | func (cmd SpeechRecognizeCommand) Command() (string, error) {
1174 | s := []interface{}{cmd.CommandString(), cmd.Prompt, cmd.Timeout, cmd.Offset}
1175 | return joinCommand(s), nil
1176 | }
1177 | func (cmd SpeechRecognizeCommand) CommandString() string {
1178 | return "SPEECH RECOGNIZE"
1179 | }
1180 |
1181 | func (cmd SpeechRecognizeCommand) SetOffset(v string) SpeechRecognizeCommand {
1182 | cmd.Offset = &v
1183 | return cmd
1184 | }
1185 |
1186 | func (c *Client) SpeechRecognize(prompt string, timeout int) Response {
1187 | return c.Handler.Command(SpeechRecognizeCommand{
1188 | Prompt: prompt,
1189 | Timeout: timeout,
1190 | })
1191 | }
1192 |
--------------------------------------------------------------------------------