├── .github └── workflows │ └── go.yml ├── .gitignore ├── LICENSE ├── README.md ├── ami ├── agent.go ├── agi.go ├── atxfer.go ├── bridge.go ├── channel.go ├── client.go ├── confbridge.go ├── dahd.go ├── db.go ├── dialplan.go ├── encode.go ├── encode_test.go ├── extension.go ├── fax.go ├── iax.go ├── khomp.go ├── mailbox.go ├── manager.go ├── manager_test.go ├── meetme.go ├── message.go ├── mock_test.go ├── monitor.go ├── pjsip.go ├── presence.go ├── pri.go ├── queue.go ├── response.go ├── sip.go ├── skinny.go ├── socket.go ├── socket_test.go ├── sorcery.go ├── types.go ├── utils.go ├── utils_test.go └── voicemail.go ├── example ├── Makefile ├── asterisk.go ├── docker-compose.yml └── main.go ├── go.mod └── vendor ├── github.com ├── davecgh │ └── go-spew │ │ ├── LICENSE │ │ └── spew │ │ ├── bypass.go │ │ ├── bypasssafe.go │ │ ├── common.go │ │ ├── config.go │ │ ├── doc.go │ │ ├── dump.go │ │ ├── format.go │ │ └── spew.go └── facebookgo │ ├── ensure │ ├── .travis.yml │ ├── ensure.go │ ├── license │ ├── patents │ └── readme.md │ ├── stack │ ├── .travis.yml │ ├── license │ ├── patents │ ├── readme.md │ └── stack.go │ └── subset │ ├── .travis.yml │ ├── license │ ├── patents │ ├── readme.md │ └── subset.go └── modules.txt /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | build: 12 | name: Build 13 | runs-on: ubuntu-latest 14 | steps: 15 | 16 | - name: Set up Go 1.16 17 | uses: actions/setup-go@v1 18 | with: 19 | go-version: 1.16 20 | id: go 21 | 22 | - name: Check out code into the Go module directory 23 | uses: actions/checkout@v1 24 | 25 | - name: Get dependencies 26 | run: | 27 | go get -v -t -d ./... 28 | if [ -f Gopkg.toml ]; then 29 | curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh 30 | dep ensure 31 | fi 32 | 33 | - name: Test 34 | run: | 35 | go test -cpu=2 -race -v ./... 36 | go test -cpu=2 -covermode=atomic ./... 37 | 38 | - name: Vet 39 | run: go vet ./... 40 | 41 | - name: Build 42 | run: go build -v ./... 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | .*.swp 7 | .*.swo 8 | main 9 | 10 | # Folders 11 | _obj 12 | _test 13 | 14 | #ignore example binary 15 | example/example 16 | *.coverprofile 17 | 18 | /.vscode/ 19 | /go.sum 20 | 21 | *.exe 22 | .idea/ 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Helton Marques 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | goami 2 | ===== 3 | Asterisk Manager Interface (AMI) client in Go. 4 | 5 | ## About 6 | This code is based on C [libami](http://sourceforge.net/projects/amsuite/files/libami/) library interface 7 | 8 | ## Installation and Requirements 9 | 10 | The following command will install the AMI client. 11 | 12 | ```sh 13 | go get -u github.com/heltonmarx/goami/ami 14 | ``` 15 | 16 | To test this package with Asterisk it's necessary set the file `/etc/asterisk/manager.conf` with configuration bellow: 17 | 18 | [general] 19 | enabled = yes 20 | port = 5038 21 | bindaddr = 127.0.0.1 22 | 23 | [admin] 24 | secret = admin 25 | deny = 0.0.0.0/0.0.0.0 26 | permit = 127.0.0.1/255.255.255.255 27 | read = all,system,call,log,verbose,command,agent,user,config 28 | write = all,system,call,log,verbose,command,agent,user,config 29 | 30 | ## Using the code 31 | 32 | Login/Logoff: 33 | ```Go 34 | package main 35 | 36 | import ( 37 | "flag" 38 | "fmt" 39 | "log" 40 | 41 | "github.com/heltonmarx/goami/ami" 42 | ) 43 | 44 | var ( 45 | username = flag.String("username", "admin", "AMI username") 46 | secret = flag.String("secret", "admin", "AMI secret") 47 | host = flag.String("host", "127.0.0.1:5038", "AMI host address") 48 | ) 49 | 50 | func main() { 51 | flag.Parse() 52 | 53 | ctx, cancel := context.WithCancel(context.Background()) 54 | defer cancel() 55 | 56 | socket, err := ami.NewSocket(ctx, *host) 57 | if err != nil { 58 | log.Fatalf("socket error: %v\n", err) 59 | } 60 | if _, err := ami.Connect(ctx, socket); err != nil { 61 | log.Fatalf("connect error: %v\n", err) 62 | } 63 | //Login 64 | uuid, _ := ami.GetUUID() 65 | if err := ami.Login(ctx, socket, *username, *secret, "Off", uuid); err != nil { 66 | log.Fatalf("login error: %v\n", err) 67 | } 68 | fmt.Printf("login ok!\n") 69 | 70 | //Logoff 71 | fmt.Printf("logoff\n") 72 | if err := ami.Logoff(ctx, socket, uuid); err != nil { 73 | log.Fatalf("logoff error: (%v)\n", err) 74 | } 75 | fmt.Printf("goodbye !\n") 76 | } 77 | ``` 78 | 79 | ## Documentation 80 | 81 | This projects documentation can be found on godoc at [goami](http://godoc.org/github.com/heltonmarx/goami/ami) 82 | and supports: 83 | - *master*: [Asterisk 14 AMI Actions](https://wiki.asterisk.org/wiki/display/AST/Asterisk+14+AMI+Actions) 84 | - ami.v10: [Asterisk 10 AMI Actions](https://wiki.asterisk.org/wiki/display/AST/Asterisk+10+AMI+Actions) 85 | - ami.v13: [Asterisk 13 AMI Actions](https://wiki.asterisk.org/wiki/display/AST/Asterisk+13+AMI+Actions) 86 | - ami.v14: [Asterisk 14 AMI Actions](https://wiki.asterisk.org/wiki/display/AST/Asterisk+14+AMI+Actions) 87 | 88 | ## License 89 | 90 | MIT-LICENSE. See [LICENSE](https://github.com/heltonmarx/goami/blob/master/LICENSE) 91 | or the LICENSE file provided in the repository for details. 92 | -------------------------------------------------------------------------------- /ami/agent.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "strconv" 6 | ) 7 | 8 | // Agents lists agents and their status. 9 | func Agents(ctx context.Context, client Client, actionID string) ([]Response, error) { 10 | return requestList(ctx, client, "Agents", actionID, "Agents", "AgentsComplete") 11 | } 12 | 13 | // AgentLogoff sets an agent as no longer logged in. 14 | func AgentLogoff(ctx context.Context, client Client, actionID, agent string, soft bool) (Response, error) { 15 | return send(ctx, client, "AgentLogoff", actionID, map[string]string{ 16 | "Agent": agent, 17 | "Soft": strconv.FormatBool(soft), 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /ami/agi.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // AGIControl represents the control type to playback actions 6 | type AGIControl string 7 | 8 | const ( 9 | // Stop the playback operation 10 | Stop AGIControl = "stop" 11 | // Forward move the current position in the media forward. 12 | Forward = "forward" 13 | // Reverse move the current poistion in the media backward. 14 | Reverse = "reverse" 15 | // Pause pause/unpause the playback operation. 16 | Pause = "pause" 17 | // Restart the playback operation. 18 | Restart = "restart" 19 | ) 20 | 21 | // AGI add an AGI command to execute by Async AGI. 22 | func AGI(ctx context.Context, client Client, actionID, channel, agiCommand, agiCommandID string) (Response, error) { 23 | return send(ctx, client, "AGI", actionID, map[string]string{ 24 | "Channel": channel, 25 | "Command": agiCommand, 26 | "CommandID": agiCommandID, 27 | }) 28 | } 29 | 30 | // ControlPlayback control the playback of a file being played to a channel. 31 | func ControlPlayback(ctx context.Context, client Client, actionID, channel string, control AGIControl) (Response, error) { 32 | return send(ctx, client, "ControlPlayback", actionID, map[string]interface{}{ 33 | "Channel": channel, 34 | "Control": control, 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /ami/atxfer.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // Atxfer attended transfer. 6 | func Atxfer(ctx context.Context, client Client, actionID, channel, exten, context string) (Response, error) { 7 | return send(ctx, client, "Atxfer", actionID, map[string]string{ 8 | "Channel": channel, 9 | "Exten": exten, 10 | "Context": context, 11 | }) 12 | } 13 | 14 | // CancelAtxfer cancel an attended transfer. 15 | func CancelAtxfer(ctx context.Context, client Client, actionID, channel string) (Response, error) { 16 | return send(ctx, client, "CancelAtxfer", actionID, map[string]string{ 17 | "Channel": channel, 18 | }) 19 | } 20 | -------------------------------------------------------------------------------- /ami/bridge.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // Bridge bridges two channels already in the PBX. 6 | func Bridge(ctx context.Context, client Client, actionID, channel1, channel2 string, tone string) (Response, error) { 7 | return send(ctx, client, "Bridge", actionID, map[string]string{ 8 | "Channel1": channel1, 9 | "Channel2": channel2, 10 | "Tone": tone, 11 | }) 12 | } 13 | 14 | // BlindTransfer blind transfer channel(s) to the given destination. 15 | func BlindTransfer(ctx context.Context, client Client, actionID, channel, context, extension string) (Response, error) { 16 | return send(ctx, client, "BlindTransfer", actionID, map[string]string{ 17 | "Channel": channel, 18 | "Context": context, 19 | "Exten": extension, 20 | }) 21 | } 22 | 23 | // BridgeDestroy destroy a bridge. 24 | func BridgeDestroy(ctx context.Context, client Client, actionID, bridgeUniqueID string) (Response, error) { 25 | return send(ctx, client, "BridgeDestroy", actionID, map[string]string{ 26 | "BridgeUniqueid": bridgeUniqueID, 27 | }) 28 | } 29 | 30 | // BridgeInfo get information about a bridge. 31 | func BridgeInfo(ctx context.Context, client Client, actionID, bridgeUniqueID string) (Response, error) { 32 | return send(ctx, client, "BridgeInfo", actionID, map[string]string{ 33 | "BridgeUniqueid": bridgeUniqueID, 34 | }) 35 | } 36 | 37 | // BridgeKick kick a channel from a bridge. 38 | func BridgeKick(ctx context.Context, client Client, actionID, bridgeUniqueID, channel string) (Response, error) { 39 | params := map[string]string{ 40 | "Channel": channel, 41 | } 42 | if bridgeUniqueID != "" { 43 | params["BridgeUniqueid"] = bridgeUniqueID 44 | } 45 | return send(ctx, client, "BridgeKick", actionID, params) 46 | } 47 | 48 | // BridgeList get a list of bridges in the system. 49 | func BridgeList(ctx context.Context, client Client, actionID, bridgeType string) (Response, error) { 50 | return send(ctx, client, "BridgeList", actionID, map[string]string{ 51 | "BridgeType": bridgeType, 52 | }) 53 | } 54 | 55 | // BridgeTechnologyList list available bridging technologies and their statuses. 56 | func BridgeTechnologyList(ctx context.Context, client Client, actionID string) ([]Response, error) { 57 | return requestList(ctx, client, "BridgeTechnologyList", actionID, 58 | "BridgeTechnologyListItem", "BridgeTechnologyListComplete") 59 | } 60 | 61 | // BridgeTechnologySuspend suspend a bridging technology. 62 | func BridgeTechnologySuspend(ctx context.Context, client Client, actionID, bridgeTechnology string) (Response, error) { 63 | return send(ctx, client, "BridgeTechnologySuspend", actionID, map[string]string{ 64 | "BridgeTechnology": bridgeTechnology, 65 | }) 66 | } 67 | 68 | // BridgeTechnologyUnsuspend unsuspend a bridging technology. 69 | func BridgeTechnologyUnsuspend(ctx context.Context, client Client, actionID, bridgeTechnology string) (Response, error) { 70 | return send(ctx, client, "BridgeTechnologyUnsuspend", actionID, map[string]string{ 71 | "BridgeTechnology": bridgeTechnology, 72 | }) 73 | } 74 | -------------------------------------------------------------------------------- /ami/channel.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "strconv" 6 | ) 7 | 8 | // AbsoluteTimeout set absolute timeout. 9 | // Hangup a channel after a certain time. Acknowledges set time with Timeout Set message. 10 | func AbsoluteTimeout(ctx context.Context, client Client, actionID, channel string, timeout int) (Response, error) { 11 | return send(ctx, client, "AbsoluteTimeout", actionID, map[string]interface{}{ 12 | "Channel": channel, 13 | "Timeout": timeout, 14 | }) 15 | } 16 | 17 | // CoreShowChannels list currently active channels. 18 | func CoreShowChannels(ctx context.Context, client Client, actionID string) ([]Response, error) { 19 | return requestList(ctx, client, "CoreShowChannels", actionID, "CoreShowChannel", "CoreShowChannelsComplete") 20 | } 21 | 22 | // Hangup hangups channel. 23 | func Hangup(ctx context.Context, client Client, actionID, channel, cause string) (Response, error) { 24 | return send(ctx, client, "Hangup", actionID, map[string]string{ 25 | "Channel": channel, 26 | "Cause": cause, 27 | }) 28 | } 29 | 30 | // Originate originates a call. 31 | // Generates an outgoing call to a Extension/Context/Priority or Application/Data. 32 | func Originate(ctx context.Context, client Client, actionID string, originate OriginateData) (Response, error) { 33 | return send(ctx, client, "Originate", actionID, originate) 34 | } 35 | 36 | // Park parks a channel. 37 | func Park(ctx context.Context, client Client, actionID, channel1, channel2 string, timeout int, parkinglot string) (Response, error) { 38 | return send(ctx, client, "Park", actionID, map[string]interface{}{ 39 | "Channel": channel1, 40 | "Channel2": channel2, 41 | "Timeout": timeout, 42 | "Parkinglot": parkinglot, 43 | }) 44 | } 45 | 46 | // ParkedCalls list parked calls. 47 | func ParkedCalls(ctx context.Context, client Client, actionID string) ([]Response, error) { 48 | return requestList(ctx, client, "ParkedCalls", actionID, "ParkedCall", "ParkedCallsComplete") 49 | } 50 | 51 | // Parkinglots get a list of parking lots. 52 | func Parkinglots(ctx context.Context, client Client, actionID string) ([]Response, error) { 53 | return requestList(ctx, client, "Parkinglots", actionID, "ParkedCall", "ParkinglotsComplete") 54 | } 55 | 56 | // PlayDTMF plays DTMF signal on a specific channel. 57 | func PlayDTMF(ctx context.Context, client Client, actionID, channel, digit string, duration int) (Response, error) { 58 | return send(ctx, client, "PlayDTMF", actionID, map[string]string{ 59 | "Channel": channel, 60 | "Digit": digit, 61 | "Duration": strconv.Itoa(duration), 62 | }) 63 | } 64 | 65 | // Redirect redirects (transfer) a call. 66 | func Redirect(ctx context.Context, client Client, actionID string, call CallData) (Response, error) { 67 | return send(ctx, client, "Redirect", actionID, call) 68 | } 69 | 70 | // SendText sends text message to channel. 71 | func SendText(ctx context.Context, client Client, actionID, channel, msg string) (Response, error) { 72 | return send(ctx, client, "SendText", actionID, map[string]string{ 73 | "Channel": channel, 74 | "Message": msg, 75 | }) 76 | } 77 | 78 | // Setvar sets a channel variable. Sets a global or local channel variable. 79 | // Note: If a channel name is not provided then the variable is global. 80 | func Setvar(ctx context.Context, client Client, actionID, channel, variable, value string) (Response, error) { 81 | return send(ctx, client, "Setvar", actionID, map[string]string{ 82 | "Channel": channel, 83 | "Variable": variable, 84 | "Value": value, 85 | }) 86 | } 87 | 88 | // Status lists channel status. 89 | // Will return the status information of each channel along with the value for the specified channel variables. 90 | func Status(ctx context.Context, client Client, actionID, channel, variables string) (Response, error) { 91 | return send(ctx, client, "Status", actionID, map[string]string{ 92 | "Channel": channel, 93 | "Variables": variables, 94 | }) 95 | } 96 | 97 | // AOCMessage generates an Advice of Charge message on a channel. 98 | func AOCMessage(ctx context.Context, client Client, actionID string, aocData AOCData) (Response, error) { 99 | return send(ctx, client, "AOCMessage", actionID, aocData) 100 | } 101 | 102 | // Getvar gets a channel variable. 103 | func Getvar(ctx context.Context, client Client, actionID, channel, variable string) (Response, error) { 104 | return send(ctx, client, "Getvar", actionID, map[string]string{ 105 | "Channel": channel, 106 | "Variable": variable, 107 | }) 108 | } 109 | 110 | // LocalOptimizeAway optimize away a local channel when possible. 111 | // A local channel created with "/n" will not automatically optimize away. 112 | // Calling this command on the local channel will clear that flag and allow it to optimize away if it's bridged or when it becomes bridged. 113 | func LocalOptimizeAway(ctx context.Context, client Client, actionID, channel string) (Response, error) { 114 | return send(ctx, client, "LocalOptimizeAway", actionID, map[string]string{ 115 | "Channel": channel, 116 | }) 117 | } 118 | 119 | // MuteAudio mute an audio stream. 120 | func MuteAudio(ctx context.Context, client Client, actionID, channel, direction string, state bool) (Response, error) { 121 | stateMap := map[bool]string{false: "off", true: "on"} 122 | return send(ctx, client, "MuteAudio", actionID, map[string]string{ 123 | "Channel": channel, 124 | "Direction": direction, 125 | "State": stateMap[state], 126 | }) 127 | } 128 | -------------------------------------------------------------------------------- /ami/client.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // Client defines an interface to client socket. 6 | type Client interface { 7 | // Connected returns the client status. 8 | Connected() bool 9 | 10 | // Close closes the client connection. 11 | Close(ctx context.Context) error 12 | 13 | // Send sends data from client to server. 14 | Send(message string) error 15 | 16 | // Recv receives a string from server. 17 | Recv(ctx context.Context) (string, error) 18 | } 19 | -------------------------------------------------------------------------------- /ami/confbridge.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // ConfbridgeList lists all users in a particular ConfBridge conference. 6 | func ConfbridgeList(ctx context.Context, client Client, actionID string, conference string) ([]Response, error) { 7 | return requestList(ctx, client, "ConfbridgeList", actionID, "ConfbridgeList", "ConfbridgeListComplete", map[string]string{ 8 | "Conference": conference, 9 | }) 10 | } 11 | 12 | // ConfbridgeListRooms lists data about all active conferences. 13 | func ConfbridgeListRooms(ctx context.Context, client Client, actionID string) ([]Response, error) { 14 | return requestList(ctx, client, "ConfbridgeListRooms", actionID, "ConfbridgeListRooms", "ConfbridgeListRoomsComplete") 15 | } 16 | 17 | // ConfbridgeMute mutes a specified user in a specified conference. 18 | func ConfbridgeMute(ctx context.Context, client Client, actionID string, conference string, channel string) (Response, error) { 19 | return send(ctx, client, "ConfbridgeMute", actionID, map[string]string{ 20 | "Conference": conference, 21 | "Channel": channel, 22 | }) 23 | } 24 | 25 | // ConfbridgeUnmute unmutes a specified user in a specified conferene. 26 | func ConfbridgeUnmute(ctx context.Context, client Client, actionID string, conference string, channel string) (Response, error) { 27 | return send(ctx, client, "ConfbridgeUnmute", actionID, map[string]string{ 28 | "Conference": conference, 29 | "Channel": channel, 30 | }) 31 | } 32 | 33 | // ConfbridgeKick removes a specified user from a specified conference. 34 | func ConfbridgeKick(ctx context.Context, client Client, actionID string, conference string, channel string) (Response, error) { 35 | return send(ctx, client, "ConfbridgeKick", actionID, map[string]string{ 36 | "Conference": conference, 37 | "Channel": channel, 38 | }) 39 | } 40 | 41 | // ConfbridgeLock locks a specified conference. 42 | func ConfbridgeLock(ctx context.Context, client Client, actionID string, conference string, channel string) (Response, error) { 43 | return send(ctx, client, "ConfbridgeLock", actionID, map[string]string{ 44 | "Conference": conference, 45 | }) 46 | } 47 | 48 | // ConfbridgeUnlock unlocks a specified conference. 49 | func ConfbridgeUnlock(ctx context.Context, client Client, actionID string, conference string, channel string) (Response, error) { 50 | return send(ctx, client, "ConfbridgeUnlock", actionID, map[string]string{ 51 | "Conference": conference, 52 | }) 53 | } 54 | 55 | // ConfbridgeSetSingleVideoSrc sets a conference user as the single video source distributed to all other video-capable participants. 56 | func ConfbridgeSetSingleVideoSrc(ctx context.Context, client Client, actionID string, conference string, channel string) (Response, error) { 57 | return send(ctx, client, "ConfbridgeSetSingleVideoSrc", actionID, map[string]string{ 58 | "Conference": conference, 59 | "Channel": channel, 60 | }) 61 | } 62 | 63 | // ConfbridgeStartRecord starts a recording in the context of given conference and creates a file with the name specified by recordFile 64 | func ConfbridgeStartRecord(ctx context.Context, client Client, actionID string, conference string, recordFile string) (Response, error) { 65 | params := map[string]string{ 66 | "Conference": conference, 67 | } 68 | if recordFile != "" { 69 | params["RecordFile"] = recordFile 70 | } 71 | return send(ctx, client, "ConfbridgeStartRecord", actionID, params) 72 | } 73 | 74 | // ConfbridgeStopRecord stops a recording pertaining to the given conference 75 | func ConfbridgeStopRecord(ctx context.Context, client Client, actionID string, conference string) (Response, error) { 76 | return send(ctx, client, "ConfbridgeStopRecord", actionID, map[string]string{ 77 | "Conference": conference, 78 | }) 79 | } 80 | -------------------------------------------------------------------------------- /ami/dahd.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // DAHDIDialOffhook dials over DAHDI channel while offhook. 6 | // Generate DTMF control frames to the bridged peer. 7 | func DAHDIDialOffhook(ctx context.Context, client Client, actionID, channel, number string) (Response, error) { 8 | return send(ctx, client, "DAHDIDialOffhook", actionID, map[string]string{ 9 | "DAHDIChannel": channel, 10 | "Number": number, 11 | }) 12 | } 13 | 14 | // DAHDIDNDoff toggles DAHDI channel Do Not Disturb status OFF. 15 | func DAHDIDNDoff(ctx context.Context, client Client, actionID, channel string) (Response, error) { 16 | return send(ctx, client, "DAHDIDNDoff", actionID, map[string]string{ 17 | "DAHDIChannel": channel, 18 | }) 19 | } 20 | 21 | // DAHDIDNDon toggles DAHDI channel Do Not Disturb status ON. 22 | func DAHDIDNDon(ctx context.Context, client Client, actionID, channel string) (Response, error) { 23 | return send(ctx, client, "DAHDIDNDon", actionID, map[string]string{ 24 | "DAHDIChannel": channel, 25 | }) 26 | } 27 | 28 | // DAHDIHangup hangups DAHDI Channel. 29 | func DAHDIHangup(ctx context.Context, client Client, actionID, channel string) (Response, error) { 30 | return send(ctx, client, "DAHDIHangup", actionID, map[string]string{ 31 | "DAHDIChannel": channel, 32 | }) 33 | } 34 | 35 | // DAHDIRestart fully Restart DAHDI channels (terminates calls). 36 | func DAHDIRestart(ctx context.Context, client Client, actionID string) (Response, error) { 37 | return send(ctx, client, "DAHDIRestart", actionID, nil) 38 | } 39 | 40 | // DAHDIShowChannels show status of DAHDI channels. 41 | func DAHDIShowChannels(ctx context.Context, client Client, actionID, channel string) ([]Response, error) { 42 | return requestList(ctx, client, "DAHDIShowChannels", actionID, "DAHDIShowChannels", "DAHDIShowChannelsComplete", map[string]string{ 43 | "DAHDIChannel": channel, 44 | }) 45 | } 46 | 47 | // DAHDITransfer transfers DAHDI Channel. 48 | func DAHDITransfer(ctx context.Context, client Client, actionID, channel string) (Response, error) { 49 | return send(ctx, client, "DAHDITransfer", actionID, map[string]string{ 50 | "DAHDIChannel": channel, 51 | }) 52 | } 53 | -------------------------------------------------------------------------------- /ami/db.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | ) 7 | 8 | // DBDel Delete DB entry. 9 | func DBDel(ctx context.Context, client Client, actionID, family, key string) (Response, error) { 10 | return send(ctx, client, "DBDel", actionID, dbData{ 11 | Family: family, 12 | Key: key, 13 | }) 14 | } 15 | 16 | // DBDelTree delete DB tree. 17 | func DBDelTree(ctx context.Context, client Client, actionID, family, key string) (Response, error) { 18 | return send(ctx, client, "DBDelTree", actionID, dbData{ 19 | Family: family, 20 | Key: key, 21 | }) 22 | } 23 | 24 | // DBPut puts DB entry. 25 | func DBPut(ctx context.Context, client Client, actionID, family, key, val string) (Response, error) { 26 | return send(ctx, client, "DBPut", actionID, dbData{ 27 | Family: family, 28 | Key: key, 29 | Value: val, 30 | }) 31 | } 32 | 33 | // DBGet gets DB Entry. 34 | func DBGet(ctx context.Context, client Client, actionID, family, key string) (Response, error) { 35 | data := dbData{ 36 | Family: family, 37 | Key: key, 38 | } 39 | 40 | responses, err := requestList(ctx, client, "DBGet", actionID, "DBGetResponse", "DBGetComplete", data) 41 | 42 | switch { 43 | case err != nil: 44 | return nil, err 45 | case len(responses) == 0: 46 | return nil, fmt.Errorf("there is no db entries: family:%s key:%s", family, key) 47 | } 48 | 49 | return responses[0], nil 50 | } 51 | 52 | type dbData struct { 53 | Family string `ami:"Family"` 54 | Key string `ami:"Key"` 55 | Value string `ami:"Val,omitempty"` 56 | } 57 | -------------------------------------------------------------------------------- /ami/dialplan.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // DialplanExtensionAdd add an extension to the dialplan. 6 | func DialplanExtensionAdd(ctx context.Context, client Client, actionID string, extension ExtensionData) (Response, error) { 7 | return send(ctx, client, "DialplanExtensionAdd", actionID, extension) 8 | } 9 | 10 | // DialplanExtensionRemove remove an extension from the dialplan. 11 | func DialplanExtensionRemove(ctx context.Context, client Client, actionID string, extension ExtensionData) (Response, error) { 12 | return send(ctx, client, "DialplanExtensionRemove", actionID, extension) 13 | } 14 | -------------------------------------------------------------------------------- /ami/encode.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "reflect" 7 | "strconv" 8 | "strings" 9 | ) 10 | 11 | func marshal(v interface{}) ([]byte, error) { 12 | var buf bytes.Buffer 13 | if err := encode(&buf, "", reflect.ValueOf(v)); err != nil { 14 | return nil, err 15 | } 16 | buf.WriteString("\r\n") 17 | return buf.Bytes(), nil 18 | } 19 | 20 | func writeString(buf *bytes.Buffer, tag, value string) { 21 | if tag != "" { 22 | buf.WriteString(tag) 23 | buf.WriteString(": ") 24 | } 25 | buf.WriteString(value) 26 | buf.WriteString("\r\n") 27 | } 28 | 29 | func encode(buf *bytes.Buffer, tag string, v reflect.Value) error { 30 | switch v.Kind() { 31 | case reflect.String: 32 | writeString(buf, tag, v.String()) 33 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 34 | writeString(buf, tag, strconv.FormatInt(v.Int(), 10)) 35 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 36 | writeString(buf, tag, strconv.FormatUint(v.Uint(), 10)) 37 | case reflect.Bool: 38 | writeString(buf, tag, strconv.FormatBool(v.Bool())) 39 | case reflect.Float32: 40 | writeString(buf, tag, strconv.FormatFloat(v.Float(), 'E', -1, 32)) 41 | case reflect.Float64: 42 | writeString(buf, tag, strconv.FormatFloat(v.Float(), 'E', -1, 64)) 43 | case reflect.Ptr, reflect.Interface: 44 | if !v.IsNil() { 45 | return encode(buf, tag, v.Elem()) 46 | } 47 | case reflect.Struct: 48 | return encodeStruct(buf, v) 49 | case reflect.Map: 50 | return encodeMap(buf, v) 51 | case reflect.Slice: 52 | for i := 0; i < v.Len(); i++ { 53 | elem := v.Index(i) 54 | if !isZero(elem) { 55 | if err := encode(buf, tag, elem); err != nil { 56 | return err 57 | } 58 | } 59 | } 60 | default: 61 | return fmt.Errorf("unsupported kind %v", v.Kind()) 62 | } 63 | return nil 64 | } 65 | 66 | func isOmitempty(tag string) (string, bool, error) { 67 | fields := strings.Split(tag, ",") 68 | if len(fields) > 1 { 69 | for _, flag := range fields[1:] { 70 | if strings.TrimSpace(flag) == "omitempty" { 71 | return fields[0], true, nil 72 | } 73 | return tag, false, fmt.Errorf("unsupported flag %q in tag %q", flag, tag) 74 | } 75 | } 76 | return tag, false, nil 77 | } 78 | 79 | func isZero(v reflect.Value) bool { 80 | switch v.Kind() { 81 | case reflect.String: 82 | return len(v.String()) == 0 83 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 84 | return v.Int() == 0 85 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 86 | return v.Uint() == 0 87 | case reflect.Bool: 88 | return !v.Bool() 89 | case reflect.Float32, reflect.Float64: 90 | return v.Float() == 0 91 | case reflect.Struct: 92 | for i := v.NumField() - 1; i >= 0; i-- { 93 | if !isZero(v.Field(i)) { 94 | return false 95 | } 96 | } 97 | return true 98 | case reflect.Ptr, reflect.Interface: 99 | return v.IsNil() 100 | } 101 | return false 102 | } 103 | 104 | func encodeStruct(buf *bytes.Buffer, v reflect.Value) error { 105 | var omitempty bool 106 | var err error 107 | for i := 0; i < v.NumField(); i++ { 108 | field := v.Type().Field(i) 109 | tag, ok := field.Tag.Lookup("ami") 110 | switch { 111 | case !ok: 112 | tag = string(field.Tag) 113 | case tag == "-": 114 | continue 115 | } 116 | tag, omitempty, err = isOmitempty(tag) 117 | if err != nil { 118 | return err 119 | } 120 | value := v.Field(i) 121 | if omitempty && isZero(value) { 122 | continue 123 | } 124 | 125 | if err := encode(buf, tag, value); err != nil { 126 | return err 127 | } 128 | } 129 | return nil 130 | } 131 | 132 | func encodeMap(buf *bytes.Buffer, v reflect.Value) error { 133 | for _, key := range v.MapKeys() { 134 | value := v.MapIndex(key) 135 | if key.Kind() == reflect.String { 136 | tag := key.String() 137 | if err := encode(buf, tag, value); err != nil { 138 | return err 139 | } 140 | } 141 | } 142 | return nil 143 | } 144 | -------------------------------------------------------------------------------- /ami/encode_test.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "math" 7 | "reflect" 8 | "strconv" 9 | "testing" 10 | 11 | "github.com/facebookgo/ensure" 12 | ) 13 | 14 | func TestEncodeBool(t *testing.T) { 15 | var buf bytes.Buffer 16 | 17 | b := true 18 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(b))) 19 | ensure.DeepEqual(t, "true\r\n", buf.String()) 20 | buf.Reset() 21 | 22 | b = false 23 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(b))) 24 | ensure.DeepEqual(t, "false\r\n", buf.String()) 25 | } 26 | 27 | func TestEncodeInt(t *testing.T) { 28 | var buf bytes.Buffer 29 | 30 | // int 31 | var i int 32 | i = 11 33 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i))) 34 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i), buf.String()) 35 | buf.Reset() 36 | 37 | // Int8 38 | var i8 int8 39 | i8 = math.MaxInt8 40 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i8))) 41 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i8), buf.String()) 42 | buf.Reset() 43 | 44 | i8 = math.MinInt8 45 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i8))) 46 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i8), buf.String()) 47 | buf.Reset() 48 | 49 | // Int16 50 | var i16 int16 51 | i16 = math.MaxInt16 52 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i16))) 53 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i16), buf.String()) 54 | buf.Reset() 55 | 56 | i16 = math.MinInt16 57 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i16))) 58 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i16), buf.String()) 59 | buf.Reset() 60 | 61 | // Int32 62 | var i32 int32 63 | i32 = math.MaxInt32 64 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i32))) 65 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i32), buf.String()) 66 | buf.Reset() 67 | 68 | i32 = math.MinInt32 69 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i32))) 70 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i32), buf.String()) 71 | buf.Reset() 72 | 73 | // Int64 74 | var i64 int64 75 | i64 = math.MaxInt64 76 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i64))) 77 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i64), buf.String()) 78 | buf.Reset() 79 | 80 | i64 = math.MinInt64 81 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(i64))) 82 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", i64), buf.String()) 83 | buf.Reset() 84 | 85 | } 86 | 87 | func TestEncodeUint(t *testing.T) { 88 | var buf bytes.Buffer 89 | 90 | // Uint8 91 | var ui8 uint8 92 | ui8 = math.MaxUint8 93 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(ui8))) 94 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", ui8), buf.String()) 95 | buf.Reset() 96 | 97 | // Uint16 98 | var ui16 uint16 99 | ui16 = math.MaxUint16 100 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(ui16))) 101 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", ui16), buf.String()) 102 | buf.Reset() 103 | 104 | // Uint32 105 | var ui32 uint32 106 | ui32 = math.MaxUint32 107 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(ui32))) 108 | ensure.DeepEqual(t, fmt.Sprintf("%d\r\n", ui32), buf.String()) 109 | buf.Reset() 110 | 111 | // Uint64 112 | var ui64 uint64 113 | ui64 = math.MaxUint64 114 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(ui64))) 115 | ensure.DeepEqual(t, fmt.Sprintf("%v\r\n", ui64), buf.String()) 116 | buf.Reset() 117 | } 118 | 119 | func TestEncodeFloat(t *testing.T) { 120 | var buf bytes.Buffer 121 | 122 | var f32 float32 123 | f32 = math.MaxFloat32 124 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(f32))) 125 | s := strconv.FormatFloat(float64(f32), 'E', -1, 32) + "\r\n" 126 | ensure.DeepEqual(t, s, buf.String()) 127 | buf.Reset() 128 | 129 | var f64 float64 130 | f64 = math.MaxFloat64 131 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(f64))) 132 | s = strconv.FormatFloat(f64, 'E', -1, 64) + "\r\n" 133 | ensure.DeepEqual(t, s, buf.String()) 134 | buf.Reset() 135 | } 136 | 137 | func TestEncodeMap(t *testing.T) { 138 | var buf bytes.Buffer 139 | m := map[string]interface{}{ 140 | "Name": "foobar", 141 | "Age": 99, 142 | "Valid": true, 143 | } 144 | expect := "Name: foobar\r\nAge: 99\r\nValid: true\r\n" 145 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(m))) 146 | verifyResponse(t, buf.String(), expect) 147 | } 148 | 149 | func TestEncodeStruct(t *testing.T) { 150 | var buf bytes.Buffer 151 | st := struct { 152 | Action string `ami:"Action"` 153 | ID string `ami:"ActionID"` 154 | Foo int `ami:"Foo,omitempty"` 155 | Bar string `ami:"-"` 156 | }{ 157 | Action: "A", ID: "B", Bar: "C", 158 | } 159 | expect := "Action: A\r\nActionID: B\r\n" 160 | ensure.Nil(t, encode(&buf, "", reflect.ValueOf(st))) 161 | ensure.DeepEqual(t, expect, buf.String()) 162 | } 163 | -------------------------------------------------------------------------------- /ami/extension.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // ExtensionState checks extension status. 6 | func ExtensionState(ctx context.Context, client Client, actionID, exten, context string) (Response, error) { 7 | return send(ctx, client, "ExtensionState", actionID, map[string]string{ 8 | "Exten": exten, 9 | "Context": context, 10 | }) 11 | } 12 | 13 | // ExtensionStateList list the current known extension states. 14 | func ExtensionStateList(ctx context.Context, client Client, actionID string) ([]Response, error) { 15 | return requestList(ctx, client, "ExtensionStateList", actionID, "ExtensionStatus", "ExtensionStateListComplete") 16 | } 17 | -------------------------------------------------------------------------------- /ami/fax.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // FAXSession responds with a detailed description of a single FAX session. 6 | func FAXSession(ctx context.Context, client Client, actionID, sessionNumber string) (Response, error) { 7 | return send(ctx, client, "FAXSession", actionID, map[string]string{ 8 | "SessionNumber": sessionNumber, 9 | }) 10 | } 11 | 12 | // FAXSessions list active FAX sessions. 13 | func FAXSessions(ctx context.Context, client Client, actionID string) ([]Response, error) { 14 | return requestList(ctx, client, "FAXSessions", actionID, "FAXSessionsEntry", "FAXSessionsComplete") 15 | } 16 | 17 | // FAXStats responds with fax statistics. 18 | func FAXStats(ctx context.Context, client Client, actionID string) (Response, error) { 19 | return send(ctx, client, "FAXStats", actionID, nil) 20 | } 21 | -------------------------------------------------------------------------------- /ami/iax.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | const ( 6 | iaxEvent = "PeerEntry" 7 | iaxComplete = "PeerlistComplete" 8 | ) 9 | 10 | // IAXnetstats show IAX channels network statistics. 11 | func IAXnetstats(ctx context.Context, client Client, actionID string) ([]Response, error) { 12 | return requestList(ctx, client, "IAXnetstats", actionID, iaxEvent, iaxComplete) 13 | } 14 | 15 | // IAXpeerlist show IAX channels network statistics. 16 | func IAXpeerlist(ctx context.Context, client Client, actionID string) ([]Response, error) { 17 | return requestList(ctx, client, "IAXpeerlist", actionID, iaxEvent, iaxComplete) 18 | } 19 | 20 | // IAXpeers list IAX peers. 21 | func IAXpeers(ctx context.Context, client Client, actionID string) ([]Response, error) { 22 | return requestList(ctx, client, "IAXpeers", actionID, iaxEvent, iaxComplete) 23 | } 24 | 25 | // IAXregistry show IAX registrations. 26 | func IAXregistry(ctx context.Context, client Client, actionID string) ([]Response, error) { 27 | return requestList(ctx, client, "IAXregistry", actionID, iaxEvent, iaxComplete) 28 | } 29 | -------------------------------------------------------------------------------- /ami/khomp.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // KSendSMS sends a SMS using KHOMP device. 6 | func KSendSMS(ctx context.Context, client Client, actionID string, data KhompSMSData) (Response, error) { 7 | return send(ctx, client, "KSendSMS", actionID, data) 8 | } 9 | -------------------------------------------------------------------------------- /ami/mailbox.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // MailboxCount checks Mailbox Message Count. 6 | func MailboxCount(ctx context.Context, client Client, actionID, mailbox string) (Response, error) { 7 | return send(ctx, client, "MailboxCount", actionID, map[string]string{ 8 | "Mailbox": mailbox, 9 | }) 10 | } 11 | 12 | // MailboxStatus checks Mailbox Message Count. 13 | func MailboxStatus(ctx context.Context, client Client, actionID, mailbox string) (Response, error) { 14 | return send(ctx, client, "MailboxStatus", actionID, map[string]string{ 15 | "Mailbox": mailbox, 16 | }) 17 | } 18 | 19 | // MWIDelete delete selected mailboxes. 20 | func MWIDelete(ctx context.Context, client Client, actionID, mailbox string) (Response, error) { 21 | return send(ctx, client, "MWIDelete", actionID, map[string]string{ 22 | "Mailbox": mailbox, 23 | }) 24 | } 25 | 26 | // MWIGet get selected mailboxes with message counts. 27 | func MWIGet(ctx context.Context, client Client, actionID, mailbox string) (Response, error) { 28 | return send(ctx, client, "MWIGet", actionID, map[string]string{ 29 | "Mailbox": mailbox, 30 | }) 31 | } 32 | 33 | // MWIUpdate update the mailbox message counts. 34 | func MWIUpdate(ctx context.Context, client Client, actionID, mailbox, oldMessages, newMessages string) (Response, error) { 35 | return send(ctx, client, "MWIUpdate", actionID, map[string]string{ 36 | "Mailbox": mailbox, 37 | "OldMessages": oldMessages, 38 | "NewMessages": newMessages, 39 | }) 40 | } 41 | -------------------------------------------------------------------------------- /ami/manager.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | "strings" 8 | ) 9 | 10 | // Connect verify connect response. 11 | func Connect(ctx context.Context, client Client) (bool, error) { 12 | if answer, err := client.Recv(ctx); err != nil || !strings.Contains(answer, "Asterisk Call Manager") { 13 | return false, errors.New("manager: Invalid parameters") 14 | } 15 | return true, nil 16 | } 17 | 18 | // Login provides the login manager. 19 | func Login(ctx context.Context, client Client, user, secret, events, actionID string) error { 20 | var login = struct { 21 | Username string `ami:"Username"` 22 | Secret string `ami:"Secret"` 23 | Events string `ami:"Events,omitempty"` 24 | }{Username: user, Secret: secret, Events: events} 25 | resp, err := send(ctx, client, "Login", actionID, login) 26 | if err != nil { 27 | return err 28 | } 29 | if ok := resp.Get("Response"); ok != "Success" { 30 | return fmt.Errorf("login failed: %v", resp.Get("Message")) 31 | } 32 | return nil 33 | } 34 | 35 | // Logoff logoff the current manager session. 36 | func Logoff(ctx context.Context, client Client, actionID string) error { 37 | resp, err := send(ctx, client, "Logoff", actionID, nil) 38 | if err != nil { 39 | return err 40 | } 41 | if msg := resp.Get("Response"); msg != "Goodbye" { 42 | return fmt.Errorf("logout failed: %v", resp.Get("Message")) 43 | } 44 | return nil 45 | } 46 | 47 | // Ping action will ellicit a 'Pong' response. 48 | // Used to keep the manager connection open. 49 | func Ping(ctx context.Context, client Client, actionID string) error { 50 | resp, err := send(ctx, client, "Ping", actionID, nil) 51 | if err != nil { 52 | return err 53 | } 54 | if ok := resp.Get("Response"); ok != "Success" { 55 | return fmt.Errorf("ping failed: %v", resp.Get("Message")) 56 | } 57 | return nil 58 | } 59 | 60 | // Challenge generates a challenge for MD5 authentication. 61 | func Challenge(ctx context.Context, client Client, actionID string) (Response, error) { 62 | return send(ctx, client, "Challenge", actionID, map[string]string{ 63 | "AuthType": "MD5", 64 | }) 65 | } 66 | 67 | // Command executes an Asterisk CLI Command. 68 | func Command(ctx context.Context, client Client, actionID, cmd string) (Response, error) { 69 | return send(ctx, client, "Command", actionID, map[string]string{ 70 | "Command": cmd, 71 | }) 72 | } 73 | 74 | // CoreSettings shows PBX core settings (version etc). 75 | func CoreSettings(ctx context.Context, client Client, actionID string) (Response, error) { 76 | return send(ctx, client, "CoreSettings", actionID, nil) 77 | } 78 | 79 | // CoreStatus shows PBX core status variables. 80 | func CoreStatus(ctx context.Context, client Client, actionID string) (Response, error) { 81 | return send(ctx, client, "CoreStatus", actionID, nil) 82 | } 83 | 84 | // CreateConfig creates an empty file in the configuration directory. 85 | // This action will create an empty file in the configuration directory. 86 | // This action is intended to be used before an UpdateConfig action. 87 | func CreateConfig(ctx context.Context, client Client, actionID, filename string) (Response, error) { 88 | return send(ctx, client, "CreateConfig", actionID, map[string]string{ 89 | "Filename": filename, 90 | }) 91 | } 92 | 93 | // DataGet retrieves the data api tree. 94 | func DataGet(ctx context.Context, client Client, actionID, path, search, filter string) (Response, error) { 95 | return send(ctx, client, "DataGet", actionID, map[string]string{ 96 | "Path": path, 97 | "Search": search, 98 | "Filter": filter, 99 | }) 100 | } 101 | 102 | // EventFlow control Event Flow. 103 | // Enable/Disable sending of events to this manager client. 104 | func EventFlow(ctx context.Context, client Client, actionID, eventMask string) (Response, error) { 105 | return send(ctx, client, "Events", actionID, map[string]string{ 106 | "EventMask": eventMask, 107 | }) 108 | } 109 | 110 | // GetConfig retrieves configuration. 111 | // This action will dump the contents of a configuration file by category and contents or optionally by specified category only. 112 | func GetConfig(ctx context.Context, client Client, actionID, filename, category, filter string) (Response, error) { 113 | return send(ctx, client, "GetConfig", actionID, map[string]string{ 114 | "Filename": filename, 115 | "Category": category, 116 | "Filter": filter, 117 | }) 118 | } 119 | 120 | // GetConfigJSON retrieves configuration (JSON format). 121 | // This action will dump the contents of a configuration file by category and contents in JSON format. 122 | // This only makes sense to be used using rawman over the HTTP interface. 123 | func GetConfigJSON(ctx context.Context, client Client, actionID, filename, category, filter string) (Response, error) { 124 | return send(ctx, client, "GetConfigJSON", actionID, map[string]string{ 125 | "Filename": filename, 126 | "Category": category, 127 | "Filter": filter, 128 | }) 129 | } 130 | 131 | // JabberSend sends a message to a Jabber Client 132 | func JabberSend(ctx context.Context, client Client, actionID, jabber, jid, message string) (Response, error) { 133 | return send(ctx, client, "JabberSend", actionID, map[string]interface{}{ 134 | "Jabber": jabber, 135 | "JID": jid, 136 | "Message": message, 137 | }) 138 | } 139 | 140 | // ListCommands lists available manager commands. 141 | // Returns the action name and synopsis for every action that is available to the user 142 | func ListCommands(ctx context.Context, client Client, actionID string) (Response, error) { 143 | return send(ctx, client, "ListCommands", actionID, nil) 144 | } 145 | 146 | // ListCategories lists categories in configuration file. 147 | func ListCategories(ctx context.Context, client Client, actionID, filename string) (Response, error) { 148 | return send(ctx, client, "ListCategories", actionID, map[string]string{ 149 | "Filename": filename, 150 | }) 151 | } 152 | 153 | // ModuleCheck checks if module is loaded. 154 | // Checks if Asterisk module is loaded. Will return Success/Failure. For success returns, the module revision number is included. 155 | func ModuleCheck(ctx context.Context, client Client, actionID, module string) (Response, error) { 156 | return send(ctx, client, "ModuleCheck", actionID, map[string]string{ 157 | "Module": module, 158 | }) 159 | } 160 | 161 | // ModuleLoad module management. 162 | // Loads, unloads or reloads an Asterisk module in a running system. 163 | func ModuleLoad(ctx context.Context, client Client, actionID, module, loadType string) (Response, error) { 164 | return send(ctx, client, "ModuleLoad", actionID, map[string]string{ 165 | "Module": module, 166 | "LoadType": loadType, 167 | }) 168 | } 169 | 170 | // Reload Sends a reload event. 171 | func Reload(ctx context.Context, client Client, actionID, module string) (Response, error) { 172 | return send(ctx, client, "Reload", actionID, map[string]string{ 173 | "Module": module, 174 | }) 175 | } 176 | 177 | // ShowDialPlan shows dialplan contexts and extensions 178 | // Be aware that showing the full dialplan may take a lot of capacity. 179 | func ShowDialPlan(ctx context.Context, client Client, actionID, extension, context string) ([]Response, error) { 180 | return requestList(ctx, client, "ShowDialPlan", actionID, "ListDialplan", "ShowDialPlanComplete", map[string]string{ 181 | "Extension": extension, 182 | "Context": context, 183 | }) 184 | } 185 | 186 | // Events gets events from current client connection 187 | // It is mandatory set 'events' of ami.Login with "system,call,all,user", to received events. 188 | func Events(ctx context.Context, client Client) (Response, error) { 189 | return read(ctx, client) 190 | } 191 | 192 | // Filter dinamically add filters for the current manager session. 193 | func Filter(ctx context.Context, client Client, actionID, operation, filter string) (Response, error) { 194 | return send(ctx, client, "Filter", actionID, map[string]string{ 195 | "Operation": operation, 196 | "Filter": filter, 197 | }) 198 | } 199 | 200 | // DeviceStateList list the current known device states. 201 | func DeviceStateList(ctx context.Context, client Client, actionID string) ([]Response, error) { 202 | return requestList(ctx, client, "DeviceStateList", actionID, 203 | "DeviceStateChange", "DeviceStateListComplete") 204 | } 205 | 206 | // LoggerRotate reload and rotate the Asterisk logger. 207 | func LoggerRotate(ctx context.Context, client Client, actionID string) (Response, error) { 208 | return send(ctx, client, "LoggerRotate", actionID, nil) 209 | } 210 | 211 | // UpdateConfig Updates a config file. 212 | // Dynamically updates an Asterisk configuration file. 213 | func UpdateConfig(ctx context.Context, client Client, actionID, srcFilename, dstFilename string, reload bool, actions ...UpdateConfigAction) (Response, error) { 214 | options := make(map[string]string) 215 | options["SrcFilename"] = srcFilename 216 | options["DstFilename"] = dstFilename 217 | if reload { 218 | options["Reload"] = "yes" 219 | } 220 | for i, a := range actions { 221 | actionNumber := fmt.Sprintf("%06d", i) 222 | options["Action-"+actionNumber] = a.Action 223 | options["Cat-"+actionNumber] = a.Category 224 | if a.Var != "" { 225 | options["Var-"+actionNumber] = a.Var 226 | options["Value-"+actionNumber] = a.Value 227 | 228 | } 229 | } 230 | return send(ctx, client, "UpdateConfig", actionID, options) 231 | } 232 | -------------------------------------------------------------------------------- /ami/manager_test.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/facebookgo/ensure" 8 | ) 9 | 10 | func TestLogin(t *testing.T) { 11 | var ( 12 | actionID = "testid" 13 | user = "testuser" 14 | secret = "testsecret" 15 | events = "Off" 16 | login = "Action: Login\r\nActionID: testid\r\nUsername: testuser\r\nSecret: testsecret\r\nEvents: Off\r\n\r\n" 17 | response = "Asterisk Call Manager/1.0\r\nResponse: Success\r\nMessage: Authentication accepted\r\n\r\n" 18 | ) 19 | ctx := context.Background() 20 | client := newClientMock(t, login, response) 21 | err := Login(ctx, client, user, secret, events, actionID) 22 | ensure.Nil(t, err) 23 | } 24 | 25 | func TestLogoff(t *testing.T) { 26 | var ( 27 | actionID = "testid" 28 | logoff = "Action: Logoff\r\nActionID: testid\r\n\r\n" 29 | response = "Response: Goodbye\r\n\r\n" 30 | ) 31 | ctx := context.Background() 32 | client := newClientMock(t, logoff, response) 33 | err := Logoff(ctx, client, actionID) 34 | ensure.Nil(t, err) 35 | } 36 | 37 | func TestPing(t *testing.T) { 38 | var ( 39 | actionID = "testid" 40 | ping = "Action: Ping\r\nActionID: testid\r\n\r\n" 41 | response = "Response: Success\r\n\r\n" 42 | ) 43 | ctx := context.Background() 44 | client := newClientMock(t, ping, response) 45 | err := Ping(ctx, client, actionID) 46 | ensure.Nil(t, err) 47 | } 48 | 49 | func TestChallenge(t *testing.T) { 50 | var ( 51 | actionID = "testid" 52 | challenge = "Action: Challenge\r\nActionID: testid\r\nAuthType: MD5\r\n\r\n" 53 | response = "Response: Success\r\nChallenge: 840415273\r\n\r\n" 54 | ) 55 | ctx := context.Background() 56 | client := newClientMock(t, challenge, response) 57 | rsp, err := Challenge(ctx, client, actionID) 58 | ensure.Nil(t, err) 59 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 60 | ensure.DeepEqual(t, rsp.Get("Challenge"), "840415273") 61 | } 62 | 63 | func TestCommand(t *testing.T) { 64 | var ( 65 | actionID = "testid" 66 | cmd = "Show Channels" 67 | input = "Action: Command\r\nActionID: testid\r\nCommand: Show Channels\r\n\r\n" 68 | response = "Response: Follows\r\nChannel (Context Extension Pri ) State Appl. Data\r\n0 active channel(s)\r\n--END COMMAND--\r\n\r\n" 69 | ) 70 | ctx := context.Background() 71 | client := newClientMock(t, input, response) 72 | rsp, err := Command(ctx, client, actionID, cmd) 73 | ensure.Nil(t, err) 74 | ensure.DeepEqual(t, rsp.Get("Response"), "Follows") 75 | } 76 | 77 | func TestCoreSettings(t *testing.T) { 78 | var ( 79 | actionID = "testid" 80 | input = "Action: CoreSettings\r\nActionID: testid\r\n\r\n" 81 | response = "Response: Success\r\n\r\n" 82 | ) 83 | ctx := context.Background() 84 | client := newClientMock(t, input, response) 85 | rsp, err := CoreSettings(ctx, client, actionID) 86 | ensure.Nil(t, err) 87 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 88 | } 89 | 90 | func TestCoreStatus(t *testing.T) { 91 | var ( 92 | actionID = "testid" 93 | input = "Action: CoreStatus\r\nActionID: testid\r\n\r\n" 94 | response = "Response: Success\r\n\r\n" 95 | ) 96 | ctx := context.Background() 97 | client := newClientMock(t, input, response) 98 | rsp, err := CoreStatus(ctx, client, actionID) 99 | ensure.Nil(t, err) 100 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 101 | } 102 | 103 | func TestCreateConfig(t *testing.T) { 104 | var ( 105 | filename = "filename.txt" 106 | actionID = "testid" 107 | input = "Action: CreateConfig\r\nActionID: testid\r\nFilename: filename.txt\r\n\r\n" 108 | response = "Response: Success\r\n\r\n" 109 | ) 110 | ctx := context.Background() 111 | client := newClientMock(t, input, response) 112 | rsp, err := CreateConfig(ctx, client, actionID, filename) 113 | ensure.Nil(t, err) 114 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 115 | } 116 | 117 | func TestDataGet(t *testing.T) { 118 | var ( 119 | path = "testpath" 120 | search = "testsearch" 121 | filter = "testfilter" 122 | actionID = "testid" 123 | input = "Action: DataGet\r\nActionID: testid\r\nPath: testpath\r\nSearch: testsearch\r\nFilter: testfilter\r\n\r\n" 124 | response = "Response: Success\r\n\r\n" 125 | ) 126 | ctx := context.Background() 127 | client := newClientMock(t, input, response) 128 | rsp, err := DataGet(ctx, client, actionID, path, search, filter) 129 | ensure.Nil(t, err) 130 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 131 | } 132 | 133 | func TestEventFlow(t *testing.T) { 134 | var ( 135 | eventMask = "off" 136 | actionID = "testid" 137 | input = "Action: Events\r\nActionID: testid\r\nEventMask: off\r\n\r\n" 138 | response = "Response: Events Off\r\n\r\n" 139 | ) 140 | ctx := context.Background() 141 | client := newClientMock(t, input, response) 142 | rsp, err := EventFlow(ctx, client, actionID, eventMask) 143 | ensure.Nil(t, err) 144 | ensure.DeepEqual(t, rsp.Get("Response"), "Events Off") 145 | } 146 | 147 | func TestGetConfigJSON(t *testing.T) { 148 | var ( 149 | filename = "filename.txt" 150 | actionID = "testid" 151 | category = "category" 152 | filter = "filter" 153 | input = "Action: GetConfigJSON\r\nActionID: testid\r\nFilename: filename.txt\r\nCategory: category\r\nFilter: filter\r\n\r\n" 154 | response = "Response: Success\r\n\r\n" 155 | ) 156 | ctx := context.Background() 157 | client := newClientMock(t, input, response) 158 | rsp, err := GetConfigJSON(ctx, client, actionID, filename, category, filter) 159 | ensure.Nil(t, err) 160 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 161 | } 162 | 163 | func TestJabberSend(t *testing.T) { 164 | var ( 165 | jabber = "testjaber" 166 | jid = "1234567890" 167 | message = "foobar" 168 | actionID = "testid" 169 | input = "Action: JabberSend\r\nActionID: testid\r\nJabber: testjaber\r\nJID: 1234567890\r\nMessage: foobar\r\n\r\n" 170 | response = "Response: Success\r\n\r\n" 171 | ) 172 | ctx := context.Background() 173 | client := newClientMock(t, input, response) 174 | rsp, err := JabberSend(ctx, client, actionID, jabber, jid, message) 175 | ensure.Nil(t, err) 176 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 177 | } 178 | 179 | func TestListCommands(t *testing.T) { 180 | var ( 181 | actionID = "testid" 182 | input = "Action: ListCommands\r\nActionID: testid\r\n\r\n" 183 | response = "Response: Success\r\n\r\n" 184 | ) 185 | ctx := context.Background() 186 | client := newClientMock(t, input, response) 187 | rsp, err := ListCommands(ctx, client, actionID) 188 | ensure.Nil(t, err) 189 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 190 | } 191 | 192 | func TestListCategories(t *testing.T) { 193 | var ( 194 | filename = "testfile.txt" 195 | actionID = "testid" 196 | input = "Action: ListCategories\r\nActionID: testid\r\nFilename: testfile.txt\r\n\r\n" 197 | response = "Response: Success\r\n\r\n" 198 | ) 199 | ctx := context.Background() 200 | client := newClientMock(t, input, response) 201 | rsp, err := ListCategories(ctx, client, actionID, filename) 202 | ensure.Nil(t, err) 203 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 204 | } 205 | -------------------------------------------------------------------------------- /ami/meetme.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // MeetmeList lists all users in a particular MeetMe conference. 6 | // Will follow as separate events, followed by a final event called MeetmeListComplete. 7 | func MeetmeList(ctx context.Context, client Client, actionID, conference string) ([]Response, error) { 8 | return requestList(ctx, client, "MeetmeList", actionID, "MeetmeEntry", "MeetmeListComplete") 9 | } 10 | 11 | // MeetmeMute mute a Meetme user. 12 | func MeetmeMute(ctx context.Context, client Client, actionID, meetme, usernum string) (Response, error) { 13 | return send(ctx, client, "MeetmeMute", actionID, map[string]string{ 14 | "Meetme": meetme, 15 | "Usernum": usernum, 16 | }) 17 | } 18 | 19 | // MeetmeUnMute unmute a Meetme user. 20 | func MeetmeUnMute(ctx context.Context, client Client, actionID, meetme, usernum string) (Response, error) { 21 | return send(ctx, client, "MeetmeUnMute", actionID, map[string]string{ 22 | "Meetme": meetme, 23 | "Usernum": usernum, 24 | }) 25 | } 26 | 27 | // MeetmeListRooms list active conferences. 28 | func MeetmeListRooms(ctx context.Context, client Client, actionID string) ([]Response, error) { 29 | return requestList(ctx, client, "MeetmeListRooms", actionID, "MeetmeEntry", "MeetmeListRoomsComplete") 30 | } 31 | -------------------------------------------------------------------------------- /ami/message.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // MessageSend send an out of call message to an endpoint. 6 | func MessageSend(ctx context.Context, client Client, actionID string, message MessageData) (Response, error) { 7 | return send(ctx, client, "MessageSend", actionID, message) 8 | } 9 | -------------------------------------------------------------------------------- /ami/mock_test.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/facebookgo/ensure" 9 | ) 10 | 11 | type mockClient struct { 12 | connectedFn func() bool 13 | closeFn func() error 14 | sendFn func(message string) error 15 | recvFn func() (string, error) 16 | } 17 | 18 | func (m mockClient) Connected() bool { 19 | return m.connectedFn() 20 | } 21 | 22 | func (m mockClient) Close(ctx context.Context) error { 23 | return m.closeFn() 24 | } 25 | 26 | func (m mockClient) Send(message string) error { 27 | return m.sendFn(message) 28 | } 29 | 30 | func (m mockClient) Recv(ctx context.Context) (string, error) { 31 | return m.recvFn() 32 | } 33 | 34 | func newClientMock(t *testing.T, input, output string) mockClient { 35 | return mockClient{ 36 | connectedFn: func() bool { 37 | return true 38 | }, 39 | closeFn: func() error { 40 | return nil 41 | }, 42 | sendFn: func(message string) error { 43 | verifyResponse(t, message, input) 44 | return nil 45 | }, 46 | recvFn: func() (string, error) { 47 | return output, nil 48 | }, 49 | } 50 | } 51 | 52 | func verifyResponse(t *testing.T, actual, expect string) { 53 | as := strings.Split(actual, "\r\n") 54 | es := strings.Split(expect, "\r\n") 55 | 56 | ensure.DeepEqual(t, len(as), len(es)) 57 | for _, m := range as { 58 | found := false 59 | for _, n := range es { 60 | if m == n { 61 | found = true 62 | } 63 | } 64 | ensure.True(t, found) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ami/monitor.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // Monitor monitors a channel. 6 | // This action may be used to record the audio on a specified channel. 7 | func Monitor(ctx context.Context, client Client, actionID, channel, file, format string, mix bool) (Response, error) { 8 | return send(ctx, client, "Monitor", actionID, monitorData{ 9 | Channel: channel, 10 | File: file, 11 | Format: format, 12 | Mix: mix, 13 | }) 14 | } 15 | 16 | // ChangeMonitor changes monitoring filename of a channel. 17 | // This action may be used to change the file started by a previous 'Monitor' action. 18 | func ChangeMonitor(ctx context.Context, client Client, actionID, channel, file string) (Response, error) { 19 | return send(ctx, client, "ChangeMonitor", actionID, monitorData{ 20 | Channel: channel, 21 | File: file, 22 | }) 23 | } 24 | 25 | // MixMonitor record a call and mix the audio during the recording. 26 | func MixMonitor(ctx context.Context, client Client, actionID, channel, file, options, command string) (Response, error) { 27 | return send(ctx, client, "MixMonitor", actionID, map[string]string{ 28 | "Channel": channel, 29 | "File": file, 30 | "options": options, 31 | "Command": command, 32 | }) 33 | } 34 | 35 | // MixMonitorMute Mute / unMute a Mixmonitor recording. 36 | // This action may be used to mute a MixMonitor recording. 37 | func MixMonitorMute(ctx context.Context, client Client, actionID, channel, direction string, state bool) (Response, error) { 38 | s := map[bool]string{false: "0", true: "1"} 39 | return send(ctx, client, "MixMonitorMute", actionID, monitorData{ 40 | Channel: channel, 41 | Direction: direction, 42 | State: s[state], 43 | }) 44 | } 45 | 46 | // PauseMonitor pauses monitoring of a channel. 47 | // This action may be used to temporarily stop the recording of a channel. 48 | func PauseMonitor(ctx context.Context, client Client, actionID, channel string) (Response, error) { 49 | return send(ctx, client, "PauseMonitor", actionID, monitorData{ 50 | Channel: channel, 51 | }) 52 | } 53 | 54 | // UnpauseMonitor unpause monitoring of a channel. 55 | // This action may be used to re-enable recording of a channel after calling PauseMonitor. 56 | func UnpauseMonitor(ctx context.Context, client Client, actionID, channel string) (Response, error) { 57 | return send(ctx, client, "UnpauseMonitor", actionID, monitorData{ 58 | Channel: channel, 59 | }) 60 | } 61 | 62 | // StopMonitor stops monitoring a channel. 63 | // This action may be used to end a previously started 'Monitor' action. 64 | func StopMonitor(ctx context.Context, client Client, actionID, channel string) (Response, error) { 65 | return send(ctx, client, "StopMonitor", actionID, monitorData{ 66 | Channel: channel, 67 | }) 68 | } 69 | 70 | // StopMixMonitor stop recording a call through MixMonitor, and free the recording's file handle. 71 | func StopMixMonitor(ctx context.Context, client Client, actionID, channel, mixMonitorID string) (Response, error) { 72 | return send(ctx, client, "StopMixMonitor", actionID, monitorData{ 73 | Channel: channel, 74 | MixMonitorID: mixMonitorID, 75 | }) 76 | } 77 | 78 | type monitorData struct { 79 | Channel string `ami:"Channel"` 80 | Direction string `ami:"Direction,omitempty"` 81 | State string `ami:"State,omitempty"` 82 | File string `ami:"File, omitempty"` 83 | Format string `ami:"Format,omitempty"` 84 | Mix bool `ami:"Mix,omitempty"` 85 | MixMonitorID string `ami:"MixMonitorID,omitempty"` 86 | } 87 | -------------------------------------------------------------------------------- /ami/pjsip.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // PJSIPNotify send NOTIFY to either an endpoint, an arbitrary URI, or inside a SIP dialog. 6 | func PJSIPNotify(ctx context.Context, client Client, actionID, endpoint, uri, variable string) (Response, error) { 7 | params := map[string]string{ 8 | "Variable": variable, 9 | } 10 | if endpoint != "" { 11 | params["Endpoint"] = endpoint 12 | } 13 | if uri != "" { 14 | params["URI"] = uri 15 | } 16 | return send(ctx, client, "PJSIPNotify", actionID, params) 17 | } 18 | 19 | // PJSIPQualify qualify a chan_pjsip endpoint. 20 | func PJSIPQualify(ctx context.Context, client Client, actionID, endpoint string) (Response, error) { 21 | return send(ctx, client, "PJSIPQualify", actionID, map[string]string{ 22 | "Endpoint": endpoint, 23 | }) 24 | } 25 | 26 | // PJSIPRegister register an outbound registration. 27 | func PJSIPRegister(ctx context.Context, client Client, actionID, registration string) (Response, error) { 28 | return send(ctx, client, "PJSIPRegister", actionID, map[string]string{ 29 | "Registration": registration, 30 | }) 31 | } 32 | 33 | // PJSIPUnregister unregister an outbound registration. 34 | func PJSIPUnregister(ctx context.Context, client Client, actionID, registration string) (Response, error) { 35 | return send(ctx, client, "PJSIPUnregister", actionID, map[string]string{ 36 | "Registration": registration, 37 | }) 38 | } 39 | 40 | // PJSIPShowEndpoint detail listing of an endpoint and its objects. 41 | func PJSIPShowEndpoint(ctx context.Context, client Client, actionID, endpoint string) ([]Response, error) { 42 | return requestMultiEvent(ctx, client, "PJSIPShowEndpoint", actionID, []string{"EndpointDetail", "ContactStatusDetail", "AorDetail", "AuthDetail", "TransportDetail", "IdentifyDetail"}, "EndpointDetailComplete", map[string]string{ 43 | "Endpoint": endpoint, 44 | }) 45 | } 46 | 47 | // PJSIPShowEndpoints list pjsip endpoints. 48 | func PJSIPShowEndpoints(ctx context.Context, client Client, actionID string) ([]Response, error) { 49 | return requestList(ctx, client, "PJSIPShowEndpoints", actionID, "EndpointList", "EndpointListComplete") 50 | } 51 | 52 | // PJSIPShowContacts list pjsip contacts. 53 | func PJSIPShowContacts(ctx context.Context, client Client, actionID string) ([]Response, error) { 54 | return requestList(ctx, client, "PJSIPShowContacts", actionID, "ContactList", "ContactListComplete") 55 | } 56 | 57 | // PJSIPShowRegistrationInboundContactStatuses lists ContactStatuses for PJSIP inbound registrations. 58 | func PJSIPShowRegistrationInboundContactStatuses(ctx context.Context, client Client, actionID string) ([]Response, error) { 59 | return requestList(ctx, client, "PJSIPShowRegistrationInboundContactStatuses", actionID, "ContactStatusDetail", "ContactStatusDetailComplete") 60 | } 61 | 62 | // PJSIPShowRegistrationsInbound lists PJSIP inbound registrations. 63 | func PJSIPShowRegistrationsInbound(ctx context.Context, client Client, actionID string) ([]Response, error) { 64 | return requestList(ctx, client, "PJSIPShowRegistrationsInbound", actionID, "InboundRegistrationDetail", "InboundRegistrationDetailComplete") 65 | } 66 | 67 | // PJSIPShowRegistrationsOutbound lists PJSIP outbound registrations. 68 | func PJSIPShowRegistrationsOutbound(ctx context.Context, client Client, actionID string) ([]Response, error) { 69 | return requestList(ctx, client, "PJSIPShowRegistrationsOutbound", actionID, "OutboundRegistrationDetail", "OutboundRegistrationDetailComplete") 70 | } 71 | 72 | // PJSIPShowResourceLists displays settings for configured resource lists. 73 | func PJSIPShowResourceLists(ctx context.Context, client Client, actionID string) ([]Response, error) { 74 | return requestList(ctx, client, "PJSIPShowResourceLists", actionID, "ResourceListDetail", "ResourceListDetailComplete") 75 | } 76 | 77 | // PJSIPShowSubscriptionsInbound list of inbound subscriptions. 78 | func PJSIPShowSubscriptionsInbound(ctx context.Context, client Client, actionID string) ([]Response, error) { 79 | return requestList(ctx, client, "PJSIPShowSubscriptionsInbound", actionID, "InboundSubscriptionDetail", "InboundSubscriptionDetailComplete") 80 | } 81 | 82 | // PJSIPShowSubscriptionsOutbound list of outbound subscriptions. 83 | func PJSIPShowSubscriptionsOutbound(ctx context.Context, client Client, actionID string) ([]Response, error) { 84 | return requestList(ctx, client, "PJSIPShowSubscriptionsOutbound", actionID, "OutboundSubscriptionDetail", "OutboundSubscriptionDetailComplete") 85 | } 86 | -------------------------------------------------------------------------------- /ami/presence.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // PresenceState check presence state. 6 | func PresenceState(ctx context.Context, client Client, actionID, provider string) (Response, error) { 7 | return send(ctx, client, "PresenceState", actionID, map[string]string{ 8 | "Provider": provider, 9 | }) 10 | } 11 | 12 | // PresenceStateList list the current known presence states. 13 | func PresenceStateList(ctx context.Context, client Client, actionID string) ([]Response, error) { 14 | return requestList(ctx, client, "PresenceStateList", actionID, 15 | "Agents", "PresenceStateListComplete") 16 | } 17 | -------------------------------------------------------------------------------- /ami/pri.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // PRIDebugFileSet set the file used for PRI debug message output. 6 | func PRIDebugFileSet(ctx context.Context, client Client, actionID, filename string) (Response, error) { 7 | return send(ctx, client, "PRIDebugFileSet", actionID, map[string]string{ 8 | "File": filename, 9 | }) 10 | } 11 | 12 | // PRIDebugFileUnset disables file output for PRI debug messages. 13 | func PRIDebugFileUnset(ctx context.Context, client Client, actionID string) (Response, error) { 14 | return send(ctx, client, "PRIDebugFileUnset", actionID, nil) 15 | } 16 | 17 | // PRIDebugSet set PRI debug levels for a span. 18 | func PRIDebugSet(ctx context.Context, client Client, actionID, span, level string) (Response, error) { 19 | return send(ctx, client, "PRIDebugSet", actionID, map[string]string{ 20 | "Span": span, 21 | "Level": level, 22 | }) 23 | } 24 | 25 | // PRIShowSpans show status of PRI spans. 26 | func PRIShowSpans(ctx context.Context, client Client, actionID, span string) ([]Response, error) { 27 | return requestList(ctx, client, "PRIShowSpans", actionID, "PRIShowSpans", "PRIShowSpansComplete", map[string]string{ 28 | "Span": span, 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /ami/queue.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // QueueAdd adds interface to queue. 6 | func QueueAdd(ctx context.Context, client Client, actionID string, queueData QueueData) (Response, error) { 7 | return send(ctx, client, "QueueAdd", actionID, queueData) 8 | } 9 | 10 | // QueueLog adds custom entry in queue_log. 11 | func QueueLog(ctx context.Context, client Client, actionID string, queueData QueueData) (Response, error) { 12 | return send(ctx, client, "QueueLog", actionID, queueData) 13 | } 14 | 15 | // QueuePause makes a queue member temporarily unavailable. 16 | func QueuePause(ctx context.Context, client Client, actionID string, queueData QueueData) (Response, error) { 17 | return send(ctx, client, "QueuePause", actionID, queueData) 18 | } 19 | 20 | // QueuePenalty sets the penalty for a queue member. 21 | func QueuePenalty(ctx context.Context, client Client, actionID string, queueData QueueData) (Response, error) { 22 | return send(ctx, client, "QueuePenalty", actionID, queueData) 23 | } 24 | 25 | // QueueReload reloads a queue, queues, or any sub-section of a queue or queues. 26 | func QueueReload(ctx context.Context, client Client, actionID string, queueData QueueData) (Response, error) { 27 | return send(ctx, client, "QueueReload", actionID, queueData) 28 | } 29 | 30 | // QueueRemove removes interface from queue. 31 | func QueueRemove(ctx context.Context, client Client, actionID string, queueData QueueData) (Response, error) { 32 | return send(ctx, client, "QueueRemove", actionID, queueData) 33 | } 34 | 35 | // QueueReset resets queue statistics. 36 | func QueueReset(ctx context.Context, client Client, actionID, queue string) (Response, error) { 37 | return send(ctx, client, "QueueReset", actionID, QueueData{Queue: queue}) 38 | } 39 | 40 | // QueueRule queues Rules. 41 | func QueueRule(ctx context.Context, client Client, actionID, rule string) (Response, error) { 42 | return send(ctx, client, "QueueRule", actionID, map[string]string{ 43 | "Rule": rule, 44 | }) 45 | } 46 | 47 | // QueueStatus show queue status by member. 48 | func QueueStatus(ctx context.Context, client Client, actionID, queue, member string) (Response, error) { 49 | return send(ctx, client, "QueueStatus", actionID, map[string]string{ 50 | "Queue": queue, 51 | "Member": member, 52 | }) 53 | } 54 | 55 | // QueueStatuses show status all members in queue. 56 | func QueueStatuses(ctx context.Context, client Client, actionID, queue string) ([]Response, error) { 57 | return requestMultiEvent(ctx, client, "QueueStatus", actionID, []string{"QueueMember", "QueueEntry"}, "QueueStatusComplete", map[string]string{ 58 | "Queue": queue, 59 | }) 60 | } 61 | 62 | // QueueSummary show queue summary. 63 | func QueueSummary(ctx context.Context, client Client, actionID, queue string) ([]Response, error) { 64 | return requestList(ctx, client, "QueueSummary", actionID, "QueueSummary", "QueueSummaryComplete", map[string]string{ 65 | "Queue": queue, 66 | }) 67 | } 68 | 69 | // QueueMemberRingInUse set the ringinuse value for a queue member. 70 | func QueueMemberRingInUse(ctx context.Context, client Client, actionID, iface, ringInUse, queue string) (Response, error) { 71 | return send(ctx, client, "QueueMemberRingInUse", actionID, map[string]string{ 72 | "Interface": iface, 73 | "RingInUse": ringInUse, 74 | "Queue": queue, 75 | }) 76 | } 77 | -------------------------------------------------------------------------------- /ami/response.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | // Response maps a string key to a list of values. 4 | type Response map[string][]string 5 | 6 | // Get gets the first value associated with the given key. 7 | func (r Response) Get(key string) string { 8 | if r == nil { 9 | return "" 10 | } 11 | rs := r[key] 12 | if len(rs) == 0 { 13 | return "" 14 | } 15 | return rs[0] 16 | } 17 | -------------------------------------------------------------------------------- /ami/sip.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // SIPNotify sends a SIP notify 6 | func SIPNotify(ctx context.Context, client Client, actionID string, channel string, variable string) (Response, error) { 7 | return send(ctx, client, "SIPnotify", actionID, map[string]string{ 8 | "Channel": channel, 9 | "Variable": variable, 10 | }) 11 | } 12 | 13 | // SIPPeers lists SIP peers in text format with details on current status. 14 | // Peerlist will follow as separate events, followed by a final event called PeerlistComplete 15 | func SIPPeers(ctx context.Context, client Client, actionID string) ([]Response, error) { 16 | return requestList(ctx, client, "SIPpeers", actionID, "PeerEntry", "PeerlistComplete") 17 | } 18 | 19 | // SIPPeerStatus show the status of one or all of the sip peers. 20 | func SIPPeerStatus(ctx context.Context, client Client, actionID string, peer string) ([]Response, error) { 21 | if peer == "" { 22 | return requestList(ctx, client, "SIPpeerstatus", actionID, "PeerStatus", "SIPpeerstatusComplete") 23 | } 24 | return requestList(ctx, client, "SIPpeerstatus", actionID, "PeerStatus", "SIPpeerstatusComplete", 25 | map[string]string{"Peer": peer}) 26 | } 27 | 28 | // SIPQualifyPeer qualify SIP peers. 29 | func SIPQualifyPeer(ctx context.Context, client Client, actionID string, peer string) (Response, error) { 30 | return send(ctx, client, "SIPqualifypeer", actionID, map[string]string{ 31 | "Peer": peer, 32 | }) 33 | } 34 | 35 | // SIPShowPeer shows one SIP peer with details on current status. 36 | func SIPShowPeer(ctx context.Context, client Client, actionID string, peer string) (Response, error) { 37 | return send(ctx, client, "SIPshowpeer", actionID, map[string]string{ 38 | "Peer": peer, 39 | }) 40 | } 41 | 42 | // SIPShowRegistry shows SIP registrations (text format). 43 | func SIPShowRegistry(ctx context.Context, client Client, actionID string) ([]Response, error) { 44 | return requestList(ctx, client, "SIPshowregistry", actionID, "RegistrationEntry", "RegistrationsComplete") 45 | } 46 | -------------------------------------------------------------------------------- /ami/skinny.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // SKINNYdevices lists SKINNY devices (text format). 6 | // Lists Skinny devices in text format with details on current status. 7 | // Devicelist will follow as separate events, 8 | // followed by a final event called DevicelistComplete. 9 | func SKINNYdevices(ctx context.Context, client Client, actionID string) ([]Response, error) { 10 | return requestList(ctx, client, "SKINNYdevices", actionID, "DeviceEntry", "DevicelistComplete") 11 | } 12 | 13 | // SKINNYlines lists SKINNY lines (text format). 14 | // Lists Skinny lines in text format with details on current status. 15 | // Linelist will follow as separate events, 16 | // followed by a final event called LinelistComplete. 17 | func SKINNYlines(ctx context.Context, client Client, actionID string) ([]Response, error) { 18 | return requestList(ctx, client, "SKINNYlines", actionID, "LineEntry", "LinelistComplete") 19 | } 20 | 21 | // SKINNYshowdevice show SKINNY device (text format). 22 | // Show one SKINNY device with details on current status. 23 | func SKINNYshowdevice(ctx context.Context, client Client, actionID, device string) (Response, error) { 24 | return send(ctx, client, "SKINNYshowdevice", actionID, map[string]string{ 25 | "Device": device, 26 | }) 27 | } 28 | 29 | // SKINNYshowline shows SKINNY line (text format). 30 | // Show one SKINNY line with details on current status. 31 | func SKINNYshowline(ctx context.Context, client Client, actionID, line string) (Response, error) { 32 | return send(ctx, client, "SKINNYshowline", actionID, map[string]string{ 33 | "Line": line, 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /ami/socket.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "fmt" 8 | "io" 9 | "net" 10 | "strings" 11 | ) 12 | 13 | // Socket holds the socket client connection data. 14 | type Socket struct { 15 | conn net.Conn 16 | incoming chan string 17 | shutdown chan struct{} 18 | errors chan error 19 | } 20 | 21 | // NewSocket provides a new socket client, connecting to a tcp server. 22 | func NewSocket(ctx context.Context, address string) (*Socket, error) { 23 | var dialer net.Dialer 24 | conn, err := dialer.DialContext(ctx, "tcp", address) 25 | if err != nil { 26 | return nil, err 27 | } 28 | s := &Socket{ 29 | conn: conn, 30 | incoming: make(chan string, 32), 31 | shutdown: make(chan struct{}), 32 | errors: make(chan error, 2), 33 | } 34 | go s.run(ctx, conn) 35 | return s, nil 36 | } 37 | 38 | // Connected returns the socket status, true for connected, 39 | // false for disconnected. 40 | func (s *Socket) Connected() bool { 41 | return s.conn != nil 42 | } 43 | 44 | // Close closes socket connection. 45 | func (s *Socket) Close(ctx context.Context) error { 46 | close(s.shutdown) 47 | if s.conn != nil { 48 | return s.conn.Close() 49 | } 50 | return nil 51 | } 52 | 53 | // Send sends data to socket using fprintf format. 54 | func (s *Socket) Send(message string) error { 55 | _, err := fmt.Fprintf(s.conn, message) 56 | return err 57 | } 58 | 59 | // Recv receives a string from socket server. 60 | func (s *Socket) Recv(ctx context.Context) (string, error) { 61 | var buffer bytes.Buffer 62 | for { 63 | select { 64 | case msg, ok := <-s.incoming: 65 | if !ok { 66 | return buffer.String(), io.EOF 67 | } 68 | buffer.WriteString(msg) 69 | if strings.HasSuffix(buffer.String(), "\r\n") { 70 | return buffer.String(), nil 71 | } 72 | case err := <-s.errors: 73 | return buffer.String(), err 74 | case <-s.shutdown: 75 | return buffer.String(), io.EOF 76 | case <-ctx.Done(): 77 | return buffer.String(), io.EOF 78 | } 79 | } 80 | } 81 | 82 | func (s *Socket) run(ctx context.Context, conn net.Conn) { 83 | reader := bufio.NewReader(conn) 84 | for { 85 | msg, err := reader.ReadString('\n') 86 | if err != nil { 87 | s.errors <- err 88 | return 89 | } 90 | s.incoming <- msg 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ami/socket_test.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "context" 7 | "fmt" 8 | "net" 9 | "strings" 10 | "sync" 11 | "testing" 12 | "time" 13 | 14 | "github.com/facebookgo/ensure" 15 | ) 16 | 17 | func TestSocketSend(t *testing.T) { 18 | const message = "Action: Login\r\nUsername: testuser\r\nSecret: testsecret\r\n\r\n" 19 | 20 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 21 | defer cancel() 22 | 23 | ln, err := net.Listen("tcp", ":") 24 | ensure.Nil(t, err) 25 | defer ln.Close() 26 | 27 | incoming := make(chan string) 28 | 29 | var wg sync.WaitGroup 30 | 31 | wg.Add(1) 32 | go func() { 33 | defer wg.Done() 34 | 35 | conn, err := ln.Accept() 36 | ensure.Nil(t, err) 37 | defer conn.Close() 38 | 39 | size := 0 40 | reader := bufio.NewReader(conn) 41 | for { 42 | msg, err := reader.ReadString('\n') 43 | ensure.Nil(t, err) 44 | incoming <- msg 45 | size += len(msg) 46 | if size == len(message) { 47 | return 48 | } 49 | } 50 | }() 51 | 52 | wg.Add(1) 53 | go func() { 54 | defer wg.Done() 55 | 56 | var buffer bytes.Buffer 57 | for { 58 | select { 59 | case msg, ok := <-incoming: 60 | ensure.True(t, ok) 61 | buffer.WriteString(msg) 62 | if strings.HasSuffix(buffer.String(), "\r\n\r\n") { 63 | ensure.DeepEqual(t, buffer.String(), message) 64 | return 65 | } 66 | } 67 | } 68 | }() 69 | socket, err := NewSocket(ctx, ln.Addr().String()) 70 | ensure.Nil(t, err) 71 | 72 | err = socket.Send(message) 73 | ensure.Nil(t, err) 74 | 75 | wg.Wait() 76 | 77 | err = socket.Close(ctx) 78 | ensure.Nil(t, err) 79 | } 80 | 81 | func TestSocketRecv(t *testing.T) { 82 | const response = "Asterisk Call Manager/1.0\r\n" 83 | 84 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 85 | defer cancel() 86 | 87 | ln, err := net.Listen("tcp", ":") 88 | if err != nil { 89 | t.Fatal(err) 90 | } 91 | defer ln.Close() 92 | 93 | var wg sync.WaitGroup 94 | wg.Add(1) 95 | go func(ctx context.Context, ln net.Listener) { 96 | defer wg.Done() 97 | 98 | conn, err := ln.Accept() 99 | ensure.Nil(t, err) 100 | defer conn.Close() 101 | 102 | n, err := fmt.Fprintf(conn, response) 103 | ensure.Nil(t, err) 104 | ensure.True(t, n == len(response)) 105 | }(ctx, ln) 106 | 107 | socket, err := NewSocket(ctx, ln.Addr().String()) 108 | ensure.Nil(t, err) 109 | 110 | rsp, err := socket.Recv(ctx) 111 | ensure.Nil(t, err) 112 | ensure.DeepEqual(t, rsp, response) 113 | 114 | wg.Wait() 115 | } 116 | -------------------------------------------------------------------------------- /ami/sorcery.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "strconv" 6 | ) 7 | 8 | // SorceryMemoryCacheExpire expire (remove) all objects from a sorcery memory cache. 9 | func SorceryMemoryCacheExpire(ctx context.Context, client Client, actionID, cache string) (Response, error) { 10 | return send(ctx, client, "SorceryMemoryCacheExpire", actionID, map[string]string{ 11 | "Cache": cache, 12 | }) 13 | } 14 | 15 | // SorceryMemoryCacheExpireObject expire (remove) an object from a sorcery memory cache. 16 | func SorceryMemoryCacheExpireObject(ctx context.Context, client Client, actionID, cache, object string) (Response, error) { 17 | return send(ctx, client, "SorceryMemoryCacheExpireObject", actionID, map[string]string{ 18 | "Cache": cache, 19 | "Object": object, 20 | }) 21 | } 22 | 23 | // SorceryMemoryCachePopulate expire all objects from a memory cache and populate it with all objects from the backend. 24 | func SorceryMemoryCachePopulate(ctx context.Context, client Client, actionID, cache string) (Response, error) { 25 | return send(ctx, client, "SorceryMemoryCachePopulate", actionID, map[string]string{ 26 | "Cache": cache, 27 | }) 28 | } 29 | 30 | // SorceryMemoryCacheStale marks all objects in a sorcery memory cache as stale. 31 | func SorceryMemoryCacheStale(ctx context.Context, client Client, actionID, cache string) (Response, error) { 32 | return send(ctx, client, "SorceryMemoryCacheStale", actionID, map[string]string{ 33 | "Cache": cache, 34 | }) 35 | } 36 | 37 | // SorceryMemoryCacheStaleObject mark an object in a sorcery memory cache as stale. 38 | func SorceryMemoryCacheStaleObject(ctx context.Context, client Client, actionID, cache, object string, reload bool) (Response, error) { 39 | return send(ctx, client, "SorceryMemoryCacheStaleObject", actionID, map[string]string{ 40 | "Cache": cache, 41 | "Object": object, 42 | "Reload": strconv.FormatBool(reload), 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /ami/types.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | // AOCData holds the information to generate an Advice of Charge message on a channel. 4 | // Channel - Channel name to generate the AOC message on. 5 | // ChannelPrefix - Partial channel prefix. By using this option one can match the beginning part of a channel name without having to put the entire name in. 6 | // For example if a channel name is SIP/snom-00000001 and this value is set to SIP/snom, then that channel matches and the message will be sent. 7 | // Note however that only the first matched channel has the message sent on it. 8 | // 9 | // MsgType - Defines what type of AOC message to create, AOC-D or AOC-E 10 | // D 11 | // E 12 | // 13 | // ChargeType - Defines what kind of charge this message represents. 14 | // NA 15 | // FREE 16 | // Currency 17 | // Unit 18 | // 19 | // UnitAmount(0) - This represents the amount of units charged. The ETSI AOC standard specifies that this value along with the optional UnitType value are entries in a list. 20 | // To accommodate this these values take an index value starting at 0 which can be used to generate this list of unit entries. 21 | // For Example, If two unit entires were required this could be achieved by setting the paramter UnitAmount(0)=1234 and UnitAmount(1)=5678. 22 | // Note that UnitAmount at index 0 is required when ChargeType=Unit, all other entries in the list are optional. 23 | // 24 | // UnitType(0) - Defines the type of unit. ETSI AOC standard specifies this as an integer value between 1 and 16, but this value is left open to accept any positive integer. 25 | // Like the UnitAmount parameter, this value represents a list entry and has an index parameter that starts at 0. 26 | // CurrencyName - Specifies the currency's name. Note that this value is truncated after 10 characters. 27 | // CurrencyAmount - Specifies the charge unit amount as a positive integer. This value is required when ChargeType==Currency. 28 | // 29 | // CurrencyMultiplier - Specifies the currency multiplier. This value is required when ChargeType==Currency. 30 | // OneThousandth 31 | // OneHundredth 32 | // OneTenth 33 | // One 34 | // Ten 35 | // Hundred 36 | // Thousand 37 | // 38 | // TotalType - Defines what kind of AOC-D total is represented. 39 | // Total 40 | // SubTotal 41 | // 42 | // AOCBillingId - Represents a billing ID associated with an AOC-D or AOC-E message. Note that only the first 3 items of the enum are valid AOC-D billing IDs 43 | // Normal 44 | // ReverseCharge 45 | // CreditCard 46 | // CallFwdUnconditional 47 | // CallFwdBusy 48 | // CallFwdNoReply 49 | // CallDeflection 50 | // CallTransfer 51 | // 52 | // ChargingAssociationId - Charging association identifier. This is optional for AOC-E and can be set to any value between -32768 and 32767 53 | // ChargingAssociationNumber - Represents the charging association party number. This value is optional for AOC-E. 54 | // ChargingAssociationPlan - Integer representing the charging plan associated with the ChargingAssociationNumber. 55 | // The value is bits 7 through 1 of the Q.931 octet containing the type-of-number and numbering-plan-identification fields. 56 | // 57 | type AOCData struct { 58 | Channel string `ami:"Channel"` 59 | ChannelPrefix string `ami:"ChannelPrefix"` 60 | MsgType string `ami:"MsgType"` 61 | ChargeType string `ami:"ChargeType"` 62 | UnitAmount string `ami:"UnitAmount(0)"` 63 | UnitType string `ami:"UnitType(0)"` 64 | CurrencyName string `ami:"CurrencyName"` 65 | CurrencyAmount string `ami:"CurrencyAmount"` 66 | CurrencyMultiplier string `ami:"CurrencyMultiplier"` 67 | TotalType string `ami:"TotalType"` 68 | AOCBillingID string `ami:"AOCBillingId"` 69 | ChargingAssociationID string `ami:"ChargingAssociationId"` 70 | ChargingAssociationNumber string `ami:"ChargingAssociationNumber"` 71 | ChargingAssociationPlan string `ami:"ChargingAssociationPlan"` 72 | } 73 | 74 | // OriginateData holds information used to originate outgoing calls. 75 | // Channel - Channel name to call. 76 | // Exten - Extension to use (requires Context and Priority) 77 | // Context - Context to use (requires Exten and Priority) 78 | // Priority - Priority to use (requires Exten and Context) 79 | // Application - Application to execute. 80 | // Data - Data to use (requires Application). 81 | // Timeout - How long to wait for call to be answered (in ms.). 82 | // CallerID - Caller ID to be set on the outgoing channel. 83 | // Variable - Channel variable to set, multiple Variable: headers are allowed. 84 | // Account - Account code. 85 | // EarlyMedia - Set to true to force call bridge on early media. 86 | // Async - Set to true for fast origination. 87 | // Codecs - Comma-separated list of codecs to use for this call. 88 | // ChannelId - Channel UniqueId to be set on the channel. 89 | // OtherChannelId - Channel UniqueId to be set on the second local channel. 90 | type OriginateData struct { 91 | Channel string `ami:"Channel,omitempty"` 92 | Exten string `ami:"Exten,omitempty"` 93 | Context string `ami:"Context,omitempty"` 94 | Priority int `ami:"Priority,omitempty"` 95 | Application string `ami:"Application,omitempty"` 96 | Data string `ami:"Data,omitempty"` 97 | Timeout int `ami:"Timeout,omitempty"` 98 | CallerID string `ami:"CallerID,omitempty"` 99 | Variable []string `ami:"Variable,omitempty"` 100 | Account string `ami:"Account,omitempty"` 101 | EarlyMedia string `ami:"EarlyMedia,omitempty"` 102 | Async string `ami:"Async,omitempty"` 103 | Codecs string `ami:"Codecs,omitempty"` 104 | ChannelID string `ami:"ChannelId,omitempty"` 105 | OtherChannelID string `ami:"OtherChannelId,omitempty"` 106 | } 107 | 108 | // QueueData holds to queue calls. 109 | // used in functions: 110 | // QueueAdd, QueueLog, QueuePause, 111 | // QueuePenalty, QueueReload, QueueRemove, 112 | // QueueReset 113 | type QueueData struct { 114 | Queue string `ami:"Queue,omitempty"` 115 | Interface string `ami:"Interface,omitempty"` 116 | Penalty string `ami:"Penalty,omitempty"` 117 | Paused string `ami:"Paused,omitempty"` 118 | MemberName string `ami:"MemberName,omitempty"` 119 | StateInterface string `ami:"StateInterface,omitempty"` 120 | Event string `ami:"Event,omitempty"` 121 | UniqueID string `ami:"UniqueID,omitempty"` 122 | Message string `ami:"Message,omitempty"` 123 | Reason string `ami:"Reason,omitempty"` 124 | Members string `ami:"Members,omitempty"` 125 | Rules string `ami:"Rules,omitempty"` 126 | Parameters string `ami:"Parameters,omitempty"` 127 | } 128 | 129 | // KhompSMSData holds the Khomp SMS information. 130 | type KhompSMSData struct { 131 | Device string `ami:"Device"` 132 | Destination string `ami:"Destination"` 133 | Confirmation bool `ami:"Confirmation"` 134 | Message string `ami:"Message"` 135 | } 136 | 137 | // CallData holds the call data to transfer. 138 | type CallData struct { 139 | Channel string `ami:"Channel"` 140 | ExtraChannel string `ami:"ExtraChannel,omitempty"` 141 | Exten string `ami:"Exten"` 142 | ExtraExten string `ami:"ExtraExten,omitempty"` 143 | Context string `ami:"Context"` 144 | ExtraContext string `ami:"ExtraContext,omitempty"` 145 | Priority string `ami:"Priority"` 146 | ExtraPriority string `ami:"ExtraPriority,omitempty"` 147 | } 148 | 149 | // ExtensionData holds the extension data to dialplan. 150 | type ExtensionData struct { 151 | Context string `ami:"Context"` 152 | Extension string `ami:"Extension"` 153 | Priority string `ami:"Priority,omitempty"` 154 | Application string `ami:"Application,omitempty"` 155 | ApplicationData string `ami:"ApplicationData,omitempty"` 156 | Replace string `ami:"Replace,omitempty"` 157 | } 158 | 159 | // MessageData holds the message data to message send command. 160 | type MessageData struct { 161 | To string `ami:"To"` 162 | From string `ami:"From"` 163 | Body string `ami:"Body"` 164 | Base64Body string `ami:"Base64Body,omitempty"` 165 | Variable string `ami:"Variable"` 166 | } 167 | 168 | // UpdateConfigAction holds the params for an action in UpdateConfig AMI command. 169 | // 170 | // example 171 | // actions := make([]ami.UpdateConfigAction, 0) 172 | // actions = append(actions, ami.UpdateConfigAction{ 173 | // Action: "EmptyCat", 174 | // Category: "test01", 175 | // }) 176 | // actions = append(actions, ami.UpdateConfigAction{ 177 | // Action: "Append", 178 | // Category: "test01", 179 | // Var: "type", 180 | // Value: "peer", 181 | // }) 182 | type UpdateConfigAction struct { 183 | Action string `ami:"Action"` 184 | Category string `ami:"Category"` 185 | Var string `ami:"Var,omitempty"` 186 | Value string `ami:"Value,omitempty"` 187 | } 188 | -------------------------------------------------------------------------------- /ami/utils.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "errors" 7 | "fmt" 8 | "os" 9 | "strings" 10 | ) 11 | 12 | // GetUUID returns a new UUID based on /dev/urandom (unix). 13 | func GetUUID() (string, error) { 14 | f, err := os.Open("/dev/urandom") 15 | if err != nil { 16 | return "", fmt.Errorf("open /dev/urandom error:[%v]", err) 17 | } 18 | defer func() { 19 | if err := f.Close(); err != nil { 20 | fmt.Printf("Error closing file: %s\n", err) 21 | } 22 | }() 23 | b := make([]byte, 16) 24 | 25 | _, err = f.Read(b) 26 | if err != nil { 27 | return "", err 28 | } 29 | uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) 30 | return uuid, nil 31 | } 32 | 33 | func command(action string, id string, v ...interface{}) ([]byte, error) { 34 | if action == "" { 35 | return nil, errors.New("invalid Action") 36 | } 37 | return marshal(&struct { 38 | Action string `ami:"Action"` 39 | ID string `ami:"ActionID, omitempty"` 40 | V []interface{} 41 | }{Action: action, ID: id, V: v}) 42 | } 43 | 44 | func send(ctx context.Context, client Client, action, id string, v interface{}) (Response, error) { 45 | b, err := command(action, id, v) 46 | if err != nil { 47 | return nil, err 48 | } 49 | if err := client.Send(string(b)); err != nil { 50 | return nil, err 51 | } 52 | return read(ctx, client) 53 | } 54 | 55 | func read(ctx context.Context, client Client) (Response, error) { 56 | var buffer bytes.Buffer 57 | for { 58 | input, err := client.Recv(ctx) 59 | if err != nil { 60 | return nil, err 61 | } 62 | buffer.WriteString(input) 63 | if strings.HasSuffix(buffer.String(), "\r\n\r\n") { 64 | break 65 | } 66 | } 67 | return parseResponse(buffer.String()) 68 | } 69 | 70 | func parseResponse(input string) (Response, error) { 71 | resp := make(Response) 72 | lines := strings.Split(input, "\r\n") 73 | for _, line := range lines { 74 | keys := strings.SplitAfterN(line, ":", 2) 75 | if len(keys) == 2 { 76 | key := strings.TrimSpace(strings.Trim(keys[0], ":")) 77 | value := strings.TrimSpace(keys[1]) 78 | resp[key] = append(resp[key], value) 79 | } else if strings.Contains(line, "\r\n\r\n") || line == "" { 80 | return resp, nil 81 | } 82 | } 83 | return resp, nil 84 | } 85 | 86 | func requestList(ctx context.Context, client Client, action, id, event, complete string, v ...interface{}) ([]Response, error) { 87 | b, err := command(action, id, v) 88 | if err != nil { 89 | return nil, err 90 | } 91 | if err := client.Send(string(b)); err != nil { 92 | return nil, err 93 | } 94 | 95 | response := make([]Response, 0) 96 | for { 97 | rsp, err := read(ctx, client) 98 | if err != nil { 99 | return nil, err 100 | } 101 | e := rsp.Get("Event") 102 | r := rsp.Get("Response") 103 | if e == event { 104 | response = append(response, rsp) 105 | } else if e == complete || r != "" && r != "Success" { 106 | break 107 | } 108 | } 109 | return response, nil 110 | } 111 | 112 | // requestMultiEvent allows for a list of events to be specified, used in cases where a command 113 | // returns multiple types of events. 114 | func requestMultiEvent(ctx context.Context, client Client, action, id string, events []string, complete string, v ...interface{}) ([]Response, error) { 115 | 116 | set := make(map[string]struct{}, len(events)) 117 | for _, evt := range events { 118 | set[evt] = struct{}{} 119 | } 120 | 121 | b, err := command(action, id, v) 122 | if err != nil { 123 | return nil, err 124 | } 125 | if err := client.Send(string(b)); err != nil { 126 | return nil, err 127 | } 128 | 129 | response := make([]Response, 0) 130 | for { 131 | rsp, err := read(ctx, client) 132 | if err != nil { 133 | return nil, err 134 | } 135 | e := rsp.Get("Event") 136 | r := rsp.Get("Response") 137 | 138 | _, ok := set[e] 139 | if ok { 140 | response = append(response, rsp) 141 | } else if e == complete || r != "" && r != "Success" { 142 | break 143 | } 144 | } 145 | return response, nil 146 | } 147 | -------------------------------------------------------------------------------- /ami/utils_test.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | "github.com/facebookgo/ensure" 8 | ) 9 | 10 | func TestParseResponse(t *testing.T) { 11 | response := "Asterisk Call Manager/1.0\r\nResponse: Success\r\nMessage: Authentication accepted\r\n\r\n" 12 | rsp, err := parseResponse(response) 13 | ensure.Nil(t, err) 14 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 15 | ensure.DeepEqual(t, rsp.Get("Message"), "Authentication accepted") 16 | } 17 | 18 | func TestSend(t *testing.T) { 19 | var ( 20 | login = "Action: Login\r\nActionID: testid\r\n\r\n" 21 | response = "Asterisk Call Manager/1.0\r\nResponse: Success\r\nMessage: Authentication accepted\r\n\r\n" 22 | ) 23 | ctx := context.Background() 24 | client := newClientMock(t, login, response) 25 | rsp, err := send(ctx, client, "Login", "testid", nil) 26 | ensure.Nil(t, err) 27 | ensure.DeepEqual(t, rsp.Get("Response"), "Success") 28 | ensure.DeepEqual(t, rsp.Get("Message"), "Authentication accepted") 29 | } 30 | -------------------------------------------------------------------------------- /ami/voicemail.go: -------------------------------------------------------------------------------- 1 | package ami 2 | 3 | import "context" 4 | 5 | // VoicemailRefresh tell asterisk to poll mailboxes for a change. 6 | func VoicemailRefresh(ctx context.Context, client Client, actionID, context, mailbox string) (Response, error) { 7 | return send(ctx, client, "VoicemailRefresh", actionID, map[string]string{ 8 | "Context": context, 9 | "Mailbox": mailbox, 10 | }) 11 | } 12 | 13 | // VoicemailUsersList list all voicemail user information. 14 | func VoicemailUsersList(ctx context.Context, client Client, actionID string) ([]Response, error) { 15 | return requestList(ctx, client, "VoicemailUsersList", actionID, "VoicemailUserEntry", "VoicemailUserEntryComplete") 16 | } 17 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | GO ?= go 2 | BUILDFLAGS := -v -i -tags 'netgo' 3 | TESTFLAGS := -cover 4 | TESTPKG := $(shell go list ./... | grep -v /vendor/) 5 | 6 | export GOOS := $(subst Darwin,darwin,$(subst Linux,linux,$(subst FreeBSD,freebsd,$(shell uname)))) 7 | export CGO_ENABLED := 0 8 | export GOGC := 400 9 | 10 | .PHONY: build 11 | build: 12 | $(GO) build $(BUILDFLAGS) 13 | 14 | .PHONY: test 15 | test: 16 | @$(GO) test $(TESTFLAGS) $(TESTPKG) 17 | 18 | .PHONY: clean 19 | clean: 20 | @$(GO) clean 21 | 22 | -------------------------------------------------------------------------------- /example/asterisk.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "log" 7 | "sync" 8 | 9 | "github.com/heltonmarx/goami/ami" 10 | ) 11 | 12 | type Asterisk struct { 13 | socket *ami.Socket 14 | uuid string 15 | 16 | events chan ami.Response 17 | stop chan struct{} 18 | wg sync.WaitGroup 19 | } 20 | 21 | // NewAsterisk initializes the AMI socket with a login and capturing the events. 22 | func NewAsterisk(ctx context.Context, host string, username string, secret string) (*Asterisk, error) { 23 | socket, err := ami.NewSocket(ctx, host) 24 | if err != nil { 25 | return nil, err 26 | } 27 | uuid, err := ami.GetUUID() 28 | if err != nil { 29 | return nil, err 30 | } 31 | const events = "system,call,all,user" 32 | err = ami.Login(ctx, socket, username, secret, events, uuid) 33 | if err != nil { 34 | return nil, err 35 | } 36 | as := &Asterisk{ 37 | socket: socket, 38 | uuid: uuid, 39 | events: make(chan ami.Response), 40 | stop: make(chan struct{}), 41 | } 42 | as.wg.Add(1) 43 | go as.run(ctx) 44 | return as, nil 45 | } 46 | 47 | // Logoff closes the current session with AMI. 48 | func (as *Asterisk) Logoff(ctx context.Context) error { 49 | close(as.stop) 50 | as.wg.Wait() 51 | 52 | return ami.Logoff(ctx, as.socket, as.uuid) 53 | } 54 | 55 | // Events returns an channel with events received from AMI. 56 | func (as *Asterisk) Events() <-chan ami.Response { 57 | return as.events 58 | } 59 | 60 | // SIPPeers fetch the list of SIP peers present on asterisk. 61 | func (as *Asterisk) SIPPeers(ctx context.Context) ([]ami.Response, error) { 62 | var peers []ami.Response 63 | resp, err := ami.SIPPeers(ctx, as.socket, as.uuid) 64 | switch { 65 | case err != nil: 66 | return nil, err 67 | case len(resp) == 0: 68 | return nil, errors.New("there's no sip peers configured") 69 | default: 70 | for _, v := range resp { 71 | peer, err := ami.SIPShowPeer(ctx, as.socket, as.uuid, v.Get("ObjectName")) 72 | if err != nil { 73 | return nil, err 74 | } 75 | peers = append(peers, peer) 76 | } 77 | } 78 | return peers, nil 79 | } 80 | 81 | func (as *Asterisk) run(ctx context.Context) { 82 | defer as.wg.Done() 83 | for { 84 | select { 85 | case <-as.stop: 86 | return 87 | case <-ctx.Done(): 88 | return 89 | default: 90 | events, err := ami.Events(ctx, as.socket) 91 | if err != nil { 92 | log.Printf("AMI events failed: %v\n", err) 93 | return 94 | } 95 | as.events <- events 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /example/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.1' 2 | 3 | services: 4 | # asterisk ============================ 5 | asterisk: 6 | image: "lenz/asterisk-load-test-13" 7 | container_name: asterisk 8 | ports: 9 | - "5060:5060" 10 | - "5038:5038" 11 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "flag" 6 | "log" 7 | ) 8 | 9 | var ( 10 | username = flag.String("username", "admin", "AMI username") 11 | secret = flag.String("secret", "dials", "AMI secret") 12 | host = flag.String("host", "127.0.0.1:5038", "AMI host address") 13 | ) 14 | 15 | func main() { 16 | flag.Parse() 17 | 18 | ctx, cancel := context.WithCancel(context.Background()) 19 | defer cancel() 20 | 21 | asterisk, err := NewAsterisk(ctx, *host, *username, *secret) 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | defer asterisk.Logoff(ctx) 26 | 27 | log.Printf("connected with asterisk\n") 28 | 29 | peers, err := asterisk.SIPPeers(ctx) 30 | if err != nil { 31 | log.Fatal(err) 32 | } 33 | log.Printf("peers: %v\n", peers) 34 | } 35 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/heltonmarx/goami 2 | 3 | go 1.12 4 | 5 | require ( 6 | github.com/davecgh/go-spew v1.1.1 // indirect 7 | github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c 8 | github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect 9 | github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect 10 | ) 11 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build !js,!appengine,!safe,!disableunsafe 20 | 21 | package spew 22 | 23 | import ( 24 | "reflect" 25 | "unsafe" 26 | ) 27 | 28 | const ( 29 | // UnsafeDisabled is a build-time constant which specifies whether or 30 | // not access to the unsafe package is available. 31 | UnsafeDisabled = false 32 | 33 | // ptrSize is the size of a pointer on the current arch. 34 | ptrSize = unsafe.Sizeof((*byte)(nil)) 35 | ) 36 | 37 | var ( 38 | // offsetPtr, offsetScalar, and offsetFlag are the offsets for the 39 | // internal reflect.Value fields. These values are valid before golang 40 | // commit ecccf07e7f9d which changed the format. The are also valid 41 | // after commit 82f48826c6c7 which changed the format again to mirror 42 | // the original format. Code in the init function updates these offsets 43 | // as necessary. 44 | offsetPtr = uintptr(ptrSize) 45 | offsetScalar = uintptr(0) 46 | offsetFlag = uintptr(ptrSize * 2) 47 | 48 | // flagKindWidth and flagKindShift indicate various bits that the 49 | // reflect package uses internally to track kind information. 50 | // 51 | // flagRO indicates whether or not the value field of a reflect.Value is 52 | // read-only. 53 | // 54 | // flagIndir indicates whether the value field of a reflect.Value is 55 | // the actual data or a pointer to the data. 56 | // 57 | // These values are valid before golang commit 90a7c3c86944 which 58 | // changed their positions. Code in the init function updates these 59 | // flags as necessary. 60 | flagKindWidth = uintptr(5) 61 | flagKindShift = uintptr(flagKindWidth - 1) 62 | flagRO = uintptr(1 << 0) 63 | flagIndir = uintptr(1 << 1) 64 | ) 65 | 66 | func init() { 67 | // Older versions of reflect.Value stored small integers directly in the 68 | // ptr field (which is named val in the older versions). Versions 69 | // between commits ecccf07e7f9d and 82f48826c6c7 added a new field named 70 | // scalar for this purpose which unfortunately came before the flag 71 | // field, so the offset of the flag field is different for those 72 | // versions. 73 | // 74 | // This code constructs a new reflect.Value from a known small integer 75 | // and checks if the size of the reflect.Value struct indicates it has 76 | // the scalar field. When it does, the offsets are updated accordingly. 77 | vv := reflect.ValueOf(0xf00) 78 | if unsafe.Sizeof(vv) == (ptrSize * 4) { 79 | offsetScalar = ptrSize * 2 80 | offsetFlag = ptrSize * 3 81 | } 82 | 83 | // Commit 90a7c3c86944 changed the flag positions such that the low 84 | // order bits are the kind. This code extracts the kind from the flags 85 | // field and ensures it's the correct type. When it's not, the flag 86 | // order has been changed to the newer format, so the flags are updated 87 | // accordingly. 88 | upf := unsafe.Pointer(uintptr(unsafe.Pointer(&vv)) + offsetFlag) 89 | upfv := *(*uintptr)(upf) 90 | flagKindMask := uintptr((1<>flagKindShift != uintptr(reflect.Int) { 92 | flagKindShift = 0 93 | flagRO = 1 << 5 94 | flagIndir = 1 << 6 95 | 96 | // Commit adf9b30e5594 modified the flags to separate the 97 | // flagRO flag into two bits which specifies whether or not the 98 | // field is embedded. This causes flagIndir to move over a bit 99 | // and means that flagRO is the combination of either of the 100 | // original flagRO bit and the new bit. 101 | // 102 | // This code detects the change by extracting what used to be 103 | // the indirect bit to ensure it's set. When it's not, the flag 104 | // order has been changed to the newer format, so the flags are 105 | // updated accordingly. 106 | if upfv&flagIndir == 0 { 107 | flagRO = 3 << 5 108 | flagIndir = 1 << 7 109 | } 110 | } 111 | } 112 | 113 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 114 | // the typical safety restrictions preventing access to unaddressable and 115 | // unexported data. It works by digging the raw pointer to the underlying 116 | // value out of the protected value and generating a new unprotected (unsafe) 117 | // reflect.Value to it. 118 | // 119 | // This allows us to check for implementations of the Stringer and error 120 | // interfaces to be used for pretty printing ordinarily unaddressable and 121 | // inaccessible values such as unexported struct fields. 122 | func unsafeReflectValue(v reflect.Value) (rv reflect.Value) { 123 | indirects := 1 124 | vt := v.Type() 125 | upv := unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetPtr) 126 | rvf := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + offsetFlag)) 127 | if rvf&flagIndir != 0 { 128 | vt = reflect.PtrTo(v.Type()) 129 | indirects++ 130 | } else if offsetScalar != 0 { 131 | // The value is in the scalar field when it's not one of the 132 | // reference types. 133 | switch vt.Kind() { 134 | case reflect.Uintptr: 135 | case reflect.Chan: 136 | case reflect.Func: 137 | case reflect.Map: 138 | case reflect.Ptr: 139 | case reflect.UnsafePointer: 140 | default: 141 | upv = unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + 142 | offsetScalar) 143 | } 144 | } 145 | 146 | pv := reflect.NewAt(vt, upv) 147 | rv = pv 148 | for i := 0; i < indirects; i++ { 149 | rv = rv.Elem() 150 | } 151 | return rv 152 | } 153 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "io" 23 | "reflect" 24 | "sort" 25 | "strconv" 26 | ) 27 | 28 | // Some constants in the form of bytes to avoid string overhead. This mirrors 29 | // the technique used in the fmt package. 30 | var ( 31 | panicBytes = []byte("(PANIC=") 32 | plusBytes = []byte("+") 33 | iBytes = []byte("i") 34 | trueBytes = []byte("true") 35 | falseBytes = []byte("false") 36 | interfaceBytes = []byte("(interface {})") 37 | commaNewlineBytes = []byte(",\n") 38 | newlineBytes = []byte("\n") 39 | openBraceBytes = []byte("{") 40 | openBraceNewlineBytes = []byte("{\n") 41 | closeBraceBytes = []byte("}") 42 | asteriskBytes = []byte("*") 43 | colonBytes = []byte(":") 44 | colonSpaceBytes = []byte(": ") 45 | openParenBytes = []byte("(") 46 | closeParenBytes = []byte(")") 47 | spaceBytes = []byte(" ") 48 | pointerChainBytes = []byte("->") 49 | nilAngleBytes = []byte("") 50 | maxNewlineBytes = []byte("\n") 51 | maxShortBytes = []byte("") 52 | circularBytes = []byte("") 53 | circularShortBytes = []byte("") 54 | invalidAngleBytes = []byte("") 55 | openBracketBytes = []byte("[") 56 | closeBracketBytes = []byte("]") 57 | percentBytes = []byte("%") 58 | precisionBytes = []byte(".") 59 | openAngleBytes = []byte("<") 60 | closeAngleBytes = []byte(">") 61 | openMapBytes = []byte("map[") 62 | closeMapBytes = []byte("]") 63 | lenEqualsBytes = []byte("len=") 64 | capEqualsBytes = []byte("cap=") 65 | ) 66 | 67 | // hexDigits is used to map a decimal value to a hex digit. 68 | var hexDigits = "0123456789abcdef" 69 | 70 | // catchPanic handles any panics that might occur during the handleMethods 71 | // calls. 72 | func catchPanic(w io.Writer, v reflect.Value) { 73 | if err := recover(); err != nil { 74 | w.Write(panicBytes) 75 | fmt.Fprintf(w, "%v", err) 76 | w.Write(closeParenBytes) 77 | } 78 | } 79 | 80 | // handleMethods attempts to call the Error and String methods on the underlying 81 | // type the passed reflect.Value represents and outputes the result to Writer w. 82 | // 83 | // It handles panics in any called methods by catching and displaying the error 84 | // as the formatted value. 85 | func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handled bool) { 86 | // We need an interface to check if the type implements the error or 87 | // Stringer interface. However, the reflect package won't give us an 88 | // interface on certain things like unexported struct fields in order 89 | // to enforce visibility rules. We use unsafe, when it's available, 90 | // to bypass these restrictions since this package does not mutate the 91 | // values. 92 | if !v.CanInterface() { 93 | if UnsafeDisabled { 94 | return false 95 | } 96 | 97 | v = unsafeReflectValue(v) 98 | } 99 | 100 | // Choose whether or not to do error and Stringer interface lookups against 101 | // the base type or a pointer to the base type depending on settings. 102 | // Technically calling one of these methods with a pointer receiver can 103 | // mutate the value, however, types which choose to satisify an error or 104 | // Stringer interface with a pointer receiver should not be mutating their 105 | // state inside these interface methods. 106 | if !cs.DisablePointerMethods && !UnsafeDisabled && !v.CanAddr() { 107 | v = unsafeReflectValue(v) 108 | } 109 | if v.CanAddr() { 110 | v = v.Addr() 111 | } 112 | 113 | // Is it an error or Stringer? 114 | switch iface := v.Interface().(type) { 115 | case error: 116 | defer catchPanic(w, v) 117 | if cs.ContinueOnMethod { 118 | w.Write(openParenBytes) 119 | w.Write([]byte(iface.Error())) 120 | w.Write(closeParenBytes) 121 | w.Write(spaceBytes) 122 | return false 123 | } 124 | 125 | w.Write([]byte(iface.Error())) 126 | return true 127 | 128 | case fmt.Stringer: 129 | defer catchPanic(w, v) 130 | if cs.ContinueOnMethod { 131 | w.Write(openParenBytes) 132 | w.Write([]byte(iface.String())) 133 | w.Write(closeParenBytes) 134 | w.Write(spaceBytes) 135 | return false 136 | } 137 | w.Write([]byte(iface.String())) 138 | return true 139 | } 140 | return false 141 | } 142 | 143 | // printBool outputs a boolean value as true or false to Writer w. 144 | func printBool(w io.Writer, val bool) { 145 | if val { 146 | w.Write(trueBytes) 147 | } else { 148 | w.Write(falseBytes) 149 | } 150 | } 151 | 152 | // printInt outputs a signed integer value to Writer w. 153 | func printInt(w io.Writer, val int64, base int) { 154 | w.Write([]byte(strconv.FormatInt(val, base))) 155 | } 156 | 157 | // printUint outputs an unsigned integer value to Writer w. 158 | func printUint(w io.Writer, val uint64, base int) { 159 | w.Write([]byte(strconv.FormatUint(val, base))) 160 | } 161 | 162 | // printFloat outputs a floating point value using the specified precision, 163 | // which is expected to be 32 or 64bit, to Writer w. 164 | func printFloat(w io.Writer, val float64, precision int) { 165 | w.Write([]byte(strconv.FormatFloat(val, 'g', -1, precision))) 166 | } 167 | 168 | // printComplex outputs a complex value using the specified float precision 169 | // for the real and imaginary parts to Writer w. 170 | func printComplex(w io.Writer, c complex128, floatPrecision int) { 171 | r := real(c) 172 | w.Write(openParenBytes) 173 | w.Write([]byte(strconv.FormatFloat(r, 'g', -1, floatPrecision))) 174 | i := imag(c) 175 | if i >= 0 { 176 | w.Write(plusBytes) 177 | } 178 | w.Write([]byte(strconv.FormatFloat(i, 'g', -1, floatPrecision))) 179 | w.Write(iBytes) 180 | w.Write(closeParenBytes) 181 | } 182 | 183 | // printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' 184 | // prefix to Writer w. 185 | func printHexPtr(w io.Writer, p uintptr) { 186 | // Null pointer. 187 | num := uint64(p) 188 | if num == 0 { 189 | w.Write(nilAngleBytes) 190 | return 191 | } 192 | 193 | // Max uint64 is 16 bytes in hex + 2 bytes for '0x' prefix 194 | buf := make([]byte, 18) 195 | 196 | // It's simpler to construct the hex string right to left. 197 | base := uint64(16) 198 | i := len(buf) - 1 199 | for num >= base { 200 | buf[i] = hexDigits[num%base] 201 | num /= base 202 | i-- 203 | } 204 | buf[i] = hexDigits[num] 205 | 206 | // Add '0x' prefix. 207 | i-- 208 | buf[i] = 'x' 209 | i-- 210 | buf[i] = '0' 211 | 212 | // Strip unused leading bytes. 213 | buf = buf[i:] 214 | w.Write(buf) 215 | } 216 | 217 | // valuesSorter implements sort.Interface to allow a slice of reflect.Value 218 | // elements to be sorted. 219 | type valuesSorter struct { 220 | values []reflect.Value 221 | strings []string // either nil or same len and values 222 | cs *ConfigState 223 | } 224 | 225 | // newValuesSorter initializes a valuesSorter instance, which holds a set of 226 | // surrogate keys on which the data should be sorted. It uses flags in 227 | // ConfigState to decide if and how to populate those surrogate keys. 228 | func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Interface { 229 | vs := &valuesSorter{values: values, cs: cs} 230 | if canSortSimply(vs.values[0].Kind()) { 231 | return vs 232 | } 233 | if !cs.DisableMethods { 234 | vs.strings = make([]string, len(values)) 235 | for i := range vs.values { 236 | b := bytes.Buffer{} 237 | if !handleMethods(cs, &b, vs.values[i]) { 238 | vs.strings = nil 239 | break 240 | } 241 | vs.strings[i] = b.String() 242 | } 243 | } 244 | if vs.strings == nil && cs.SpewKeys { 245 | vs.strings = make([]string, len(values)) 246 | for i := range vs.values { 247 | vs.strings[i] = Sprintf("%#v", vs.values[i].Interface()) 248 | } 249 | } 250 | return vs 251 | } 252 | 253 | // canSortSimply tests whether a reflect.Kind is a primitive that can be sorted 254 | // directly, or whether it should be considered for sorting by surrogate keys 255 | // (if the ConfigState allows it). 256 | func canSortSimply(kind reflect.Kind) bool { 257 | // This switch parallels valueSortLess, except for the default case. 258 | switch kind { 259 | case reflect.Bool: 260 | return true 261 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 262 | return true 263 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 264 | return true 265 | case reflect.Float32, reflect.Float64: 266 | return true 267 | case reflect.String: 268 | return true 269 | case reflect.Uintptr: 270 | return true 271 | case reflect.Array: 272 | return true 273 | } 274 | return false 275 | } 276 | 277 | // Len returns the number of values in the slice. It is part of the 278 | // sort.Interface implementation. 279 | func (s *valuesSorter) Len() int { 280 | return len(s.values) 281 | } 282 | 283 | // Swap swaps the values at the passed indices. It is part of the 284 | // sort.Interface implementation. 285 | func (s *valuesSorter) Swap(i, j int) { 286 | s.values[i], s.values[j] = s.values[j], s.values[i] 287 | if s.strings != nil { 288 | s.strings[i], s.strings[j] = s.strings[j], s.strings[i] 289 | } 290 | } 291 | 292 | // valueSortLess returns whether the first value should sort before the second 293 | // value. It is used by valueSorter.Less as part of the sort.Interface 294 | // implementation. 295 | func valueSortLess(a, b reflect.Value) bool { 296 | switch a.Kind() { 297 | case reflect.Bool: 298 | return !a.Bool() && b.Bool() 299 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 300 | return a.Int() < b.Int() 301 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 302 | return a.Uint() < b.Uint() 303 | case reflect.Float32, reflect.Float64: 304 | return a.Float() < b.Float() 305 | case reflect.String: 306 | return a.String() < b.String() 307 | case reflect.Uintptr: 308 | return a.Uint() < b.Uint() 309 | case reflect.Array: 310 | // Compare the contents of both arrays. 311 | l := a.Len() 312 | for i := 0; i < l; i++ { 313 | av := a.Index(i) 314 | bv := b.Index(i) 315 | if av.Interface() == bv.Interface() { 316 | continue 317 | } 318 | return valueSortLess(av, bv) 319 | } 320 | } 321 | return a.String() < b.String() 322 | } 323 | 324 | // Less returns whether the value at index i should sort before the 325 | // value at index j. It is part of the sort.Interface implementation. 326 | func (s *valuesSorter) Less(i, j int) bool { 327 | if s.strings == nil { 328 | return valueSortLess(s.values[i], s.values[j]) 329 | } 330 | return s.strings[i] < s.strings[j] 331 | } 332 | 333 | // sortValues is a sort function that handles both native types and any type that 334 | // can be converted to error or Stringer. Other inputs are sorted according to 335 | // their Value.String() value to ensure display stability. 336 | func sortValues(values []reflect.Value, cs *ConfigState) { 337 | if len(values) == 0 { 338 | return 339 | } 340 | sort.Sort(newValuesSorter(values, cs)) 341 | } 342 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "io" 23 | "os" 24 | ) 25 | 26 | // ConfigState houses the configuration options used by spew to format and 27 | // display values. There is a global instance, Config, that is used to control 28 | // all top-level Formatter and Dump functionality. Each ConfigState instance 29 | // provides methods equivalent to the top-level functions. 30 | // 31 | // The zero value for ConfigState provides no indentation. You would typically 32 | // want to set it to a space or a tab. 33 | // 34 | // Alternatively, you can use NewDefaultConfig to get a ConfigState instance 35 | // with default settings. See the documentation of NewDefaultConfig for default 36 | // values. 37 | type ConfigState struct { 38 | // Indent specifies the string to use for each indentation level. The 39 | // global config instance that all top-level functions use set this to a 40 | // single space by default. If you would like more indentation, you might 41 | // set this to a tab with "\t" or perhaps two spaces with " ". 42 | Indent string 43 | 44 | // MaxDepth controls the maximum number of levels to descend into nested 45 | // data structures. The default, 0, means there is no limit. 46 | // 47 | // NOTE: Circular data structures are properly detected, so it is not 48 | // necessary to set this value unless you specifically want to limit deeply 49 | // nested data structures. 50 | MaxDepth int 51 | 52 | // DisableMethods specifies whether or not error and Stringer interfaces are 53 | // invoked for types that implement them. 54 | DisableMethods bool 55 | 56 | // DisablePointerMethods specifies whether or not to check for and invoke 57 | // error and Stringer interfaces on types which only accept a pointer 58 | // receiver when the current type is not a pointer. 59 | // 60 | // NOTE: This might be an unsafe action since calling one of these methods 61 | // with a pointer receiver could technically mutate the value, however, 62 | // in practice, types which choose to satisify an error or Stringer 63 | // interface with a pointer receiver should not be mutating their state 64 | // inside these interface methods. As a result, this option relies on 65 | // access to the unsafe package, so it will not have any effect when 66 | // running in environments without access to the unsafe package such as 67 | // Google App Engine or with the "safe" build tag specified. 68 | DisablePointerMethods bool 69 | 70 | // DisablePointerAddresses specifies whether to disable the printing of 71 | // pointer addresses. This is useful when diffing data structures in tests. 72 | DisablePointerAddresses bool 73 | 74 | // DisableCapacities specifies whether to disable the printing of capacities 75 | // for arrays, slices, maps and channels. This is useful when diffing 76 | // data structures in tests. 77 | DisableCapacities bool 78 | 79 | // ContinueOnMethod specifies whether or not recursion should continue once 80 | // a custom error or Stringer interface is invoked. The default, false, 81 | // means it will print the results of invoking the custom error or Stringer 82 | // interface and return immediately instead of continuing to recurse into 83 | // the internals of the data type. 84 | // 85 | // NOTE: This flag does not have any effect if method invocation is disabled 86 | // via the DisableMethods or DisablePointerMethods options. 87 | ContinueOnMethod bool 88 | 89 | // SortKeys specifies map keys should be sorted before being printed. Use 90 | // this to have a more deterministic, diffable output. Note that only 91 | // native types (bool, int, uint, floats, uintptr and string) and types 92 | // that support the error or Stringer interfaces (if methods are 93 | // enabled) are supported, with other types sorted according to the 94 | // reflect.Value.String() output which guarantees display stability. 95 | SortKeys bool 96 | 97 | // SpewKeys specifies that, as a last resort attempt, map keys should 98 | // be spewed to strings and sorted by those strings. This is only 99 | // considered if SortKeys is true. 100 | SpewKeys bool 101 | } 102 | 103 | // Config is the active configuration of the top-level functions. 104 | // The configuration can be changed by modifying the contents of spew.Config. 105 | var Config = ConfigState{Indent: " "} 106 | 107 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 108 | // passed with a Formatter interface returned by c.NewFormatter. It returns 109 | // the formatted string as a value that satisfies error. See NewFormatter 110 | // for formatting details. 111 | // 112 | // This function is shorthand for the following syntax: 113 | // 114 | // fmt.Errorf(format, c.NewFormatter(a), c.NewFormatter(b)) 115 | func (c *ConfigState) Errorf(format string, a ...interface{}) (err error) { 116 | return fmt.Errorf(format, c.convertArgs(a)...) 117 | } 118 | 119 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 120 | // passed with a Formatter interface returned by c.NewFormatter. It returns 121 | // the number of bytes written and any write error encountered. See 122 | // NewFormatter for formatting details. 123 | // 124 | // This function is shorthand for the following syntax: 125 | // 126 | // fmt.Fprint(w, c.NewFormatter(a), c.NewFormatter(b)) 127 | func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, err error) { 128 | return fmt.Fprint(w, c.convertArgs(a)...) 129 | } 130 | 131 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 132 | // passed with a Formatter interface returned by c.NewFormatter. It returns 133 | // the number of bytes written and any write error encountered. See 134 | // NewFormatter for formatting details. 135 | // 136 | // This function is shorthand for the following syntax: 137 | // 138 | // fmt.Fprintf(w, format, c.NewFormatter(a), c.NewFormatter(b)) 139 | func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 140 | return fmt.Fprintf(w, format, c.convertArgs(a)...) 141 | } 142 | 143 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 144 | // passed with a Formatter interface returned by c.NewFormatter. See 145 | // NewFormatter for formatting details. 146 | // 147 | // This function is shorthand for the following syntax: 148 | // 149 | // fmt.Fprintln(w, c.NewFormatter(a), c.NewFormatter(b)) 150 | func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 151 | return fmt.Fprintln(w, c.convertArgs(a)...) 152 | } 153 | 154 | // Print is a wrapper for fmt.Print that treats each argument as if it were 155 | // passed with a Formatter interface returned by c.NewFormatter. It returns 156 | // the number of bytes written and any write error encountered. See 157 | // NewFormatter for formatting details. 158 | // 159 | // This function is shorthand for the following syntax: 160 | // 161 | // fmt.Print(c.NewFormatter(a), c.NewFormatter(b)) 162 | func (c *ConfigState) Print(a ...interface{}) (n int, err error) { 163 | return fmt.Print(c.convertArgs(a)...) 164 | } 165 | 166 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 167 | // passed with a Formatter interface returned by c.NewFormatter. It returns 168 | // the number of bytes written and any write error encountered. See 169 | // NewFormatter for formatting details. 170 | // 171 | // This function is shorthand for the following syntax: 172 | // 173 | // fmt.Printf(format, c.NewFormatter(a), c.NewFormatter(b)) 174 | func (c *ConfigState) Printf(format string, a ...interface{}) (n int, err error) { 175 | return fmt.Printf(format, c.convertArgs(a)...) 176 | } 177 | 178 | // Println is a wrapper for fmt.Println that treats each argument as if it were 179 | // passed with a Formatter interface returned by c.NewFormatter. It returns 180 | // the number of bytes written and any write error encountered. See 181 | // NewFormatter for formatting details. 182 | // 183 | // This function is shorthand for the following syntax: 184 | // 185 | // fmt.Println(c.NewFormatter(a), c.NewFormatter(b)) 186 | func (c *ConfigState) Println(a ...interface{}) (n int, err error) { 187 | return fmt.Println(c.convertArgs(a)...) 188 | } 189 | 190 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 191 | // passed with a Formatter interface returned by c.NewFormatter. It returns 192 | // the resulting string. See NewFormatter for formatting details. 193 | // 194 | // This function is shorthand for the following syntax: 195 | // 196 | // fmt.Sprint(c.NewFormatter(a), c.NewFormatter(b)) 197 | func (c *ConfigState) Sprint(a ...interface{}) string { 198 | return fmt.Sprint(c.convertArgs(a)...) 199 | } 200 | 201 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 202 | // passed with a Formatter interface returned by c.NewFormatter. It returns 203 | // the resulting string. See NewFormatter for formatting details. 204 | // 205 | // This function is shorthand for the following syntax: 206 | // 207 | // fmt.Sprintf(format, c.NewFormatter(a), c.NewFormatter(b)) 208 | func (c *ConfigState) Sprintf(format string, a ...interface{}) string { 209 | return fmt.Sprintf(format, c.convertArgs(a)...) 210 | } 211 | 212 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 213 | // were passed with a Formatter interface returned by c.NewFormatter. It 214 | // returns the resulting string. See NewFormatter for formatting details. 215 | // 216 | // This function is shorthand for the following syntax: 217 | // 218 | // fmt.Sprintln(c.NewFormatter(a), c.NewFormatter(b)) 219 | func (c *ConfigState) Sprintln(a ...interface{}) string { 220 | return fmt.Sprintln(c.convertArgs(a)...) 221 | } 222 | 223 | /* 224 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter 225 | interface. As a result, it integrates cleanly with standard fmt package 226 | printing functions. The formatter is useful for inline printing of smaller data 227 | types similar to the standard %v format specifier. 228 | 229 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 230 | addresses), %#v (adds types), and %#+v (adds types and pointer addresses) verb 231 | combinations. Any other verbs such as %x and %q will be sent to the the 232 | standard fmt package for formatting. In addition, the custom formatter ignores 233 | the width and precision arguments (however they will still work on the format 234 | specifiers not handled by the custom formatter). 235 | 236 | Typically this function shouldn't be called directly. It is much easier to make 237 | use of the custom formatter by calling one of the convenience functions such as 238 | c.Printf, c.Println, or c.Printf. 239 | */ 240 | func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter { 241 | return newFormatter(c, v) 242 | } 243 | 244 | // Fdump formats and displays the passed arguments to io.Writer w. It formats 245 | // exactly the same as Dump. 246 | func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) { 247 | fdump(c, w, a...) 248 | } 249 | 250 | /* 251 | Dump displays the passed parameters to standard out with newlines, customizable 252 | indentation, and additional debug information such as complete types and all 253 | pointer addresses used to indirect to the final value. It provides the 254 | following features over the built-in printing facilities provided by the fmt 255 | package: 256 | 257 | * Pointers are dereferenced and followed 258 | * Circular data structures are detected and handled properly 259 | * Custom Stringer/error interfaces are optionally invoked, including 260 | on unexported types 261 | * Custom types which only implement the Stringer/error interfaces via 262 | a pointer receiver are optionally invoked when passing non-pointer 263 | variables 264 | * Byte arrays and slices are dumped like the hexdump -C command which 265 | includes offsets, byte values in hex, and ASCII output 266 | 267 | The configuration options are controlled by modifying the public members 268 | of c. See ConfigState for options documentation. 269 | 270 | See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to 271 | get the formatted result as a string. 272 | */ 273 | func (c *ConfigState) Dump(a ...interface{}) { 274 | fdump(c, os.Stdout, a...) 275 | } 276 | 277 | // Sdump returns a string with the passed arguments formatted exactly the same 278 | // as Dump. 279 | func (c *ConfigState) Sdump(a ...interface{}) string { 280 | var buf bytes.Buffer 281 | fdump(c, &buf, a...) 282 | return buf.String() 283 | } 284 | 285 | // convertArgs accepts a slice of arguments and returns a slice of the same 286 | // length with each argument converted to a spew Formatter interface using 287 | // the ConfigState associated with s. 288 | func (c *ConfigState) convertArgs(args []interface{}) (formatters []interface{}) { 289 | formatters = make([]interface{}, len(args)) 290 | for index, arg := range args { 291 | formatters[index] = newFormatter(c, arg) 292 | } 293 | return formatters 294 | } 295 | 296 | // NewDefaultConfig returns a ConfigState with the following default settings. 297 | // 298 | // Indent: " " 299 | // MaxDepth: 0 300 | // DisableMethods: false 301 | // DisablePointerMethods: false 302 | // ContinueOnMethod: false 303 | // SortKeys: false 304 | func NewDefaultConfig() *ConfigState { 305 | return &ConfigState{Indent: " "} 306 | } 307 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | /* 18 | Package spew implements a deep pretty printer for Go data structures to aid in 19 | debugging. 20 | 21 | A quick overview of the additional features spew provides over the built-in 22 | printing facilities for Go data types are as follows: 23 | 24 | * Pointers are dereferenced and followed 25 | * Circular data structures are detected and handled properly 26 | * Custom Stringer/error interfaces are optionally invoked, including 27 | on unexported types 28 | * Custom types which only implement the Stringer/error interfaces via 29 | a pointer receiver are optionally invoked when passing non-pointer 30 | variables 31 | * Byte arrays and slices are dumped like the hexdump -C command which 32 | includes offsets, byte values in hex, and ASCII output (only when using 33 | Dump style) 34 | 35 | There are two different approaches spew allows for dumping Go data structures: 36 | 37 | * Dump style which prints with newlines, customizable indentation, 38 | and additional debug information such as types and all pointer addresses 39 | used to indirect to the final value 40 | * A custom Formatter interface that integrates cleanly with the standard fmt 41 | package and replaces %v, %+v, %#v, and %#+v to provide inline printing 42 | similar to the default %v while providing the additional functionality 43 | outlined above and passing unsupported format verbs such as %x and %q 44 | along to fmt 45 | 46 | Quick Start 47 | 48 | This section demonstrates how to quickly get started with spew. See the 49 | sections below for further details on formatting and configuration options. 50 | 51 | To dump a variable with full newlines, indentation, type, and pointer 52 | information use Dump, Fdump, or Sdump: 53 | spew.Dump(myVar1, myVar2, ...) 54 | spew.Fdump(someWriter, myVar1, myVar2, ...) 55 | str := spew.Sdump(myVar1, myVar2, ...) 56 | 57 | Alternatively, if you would prefer to use format strings with a compacted inline 58 | printing style, use the convenience wrappers Printf, Fprintf, etc with 59 | %v (most compact), %+v (adds pointer addresses), %#v (adds types), or 60 | %#+v (adds types and pointer addresses): 61 | spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) 62 | spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 63 | spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) 64 | spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 65 | 66 | Configuration Options 67 | 68 | Configuration of spew is handled by fields in the ConfigState type. For 69 | convenience, all of the top-level functions use a global state available 70 | via the spew.Config global. 71 | 72 | It is also possible to create a ConfigState instance that provides methods 73 | equivalent to the top-level functions. This allows concurrent configuration 74 | options. See the ConfigState documentation for more details. 75 | 76 | The following configuration options are available: 77 | * Indent 78 | String to use for each indentation level for Dump functions. 79 | It is a single space by default. A popular alternative is "\t". 80 | 81 | * MaxDepth 82 | Maximum number of levels to descend into nested data structures. 83 | There is no limit by default. 84 | 85 | * DisableMethods 86 | Disables invocation of error and Stringer interface methods. 87 | Method invocation is enabled by default. 88 | 89 | * DisablePointerMethods 90 | Disables invocation of error and Stringer interface methods on types 91 | which only accept pointer receivers from non-pointer variables. 92 | Pointer method invocation is enabled by default. 93 | 94 | * DisablePointerAddresses 95 | DisablePointerAddresses specifies whether to disable the printing of 96 | pointer addresses. This is useful when diffing data structures in tests. 97 | 98 | * DisableCapacities 99 | DisableCapacities specifies whether to disable the printing of 100 | capacities for arrays, slices, maps and channels. This is useful when 101 | diffing data structures in tests. 102 | 103 | * ContinueOnMethod 104 | Enables recursion into types after invoking error and Stringer interface 105 | methods. Recursion after method invocation is disabled by default. 106 | 107 | * SortKeys 108 | Specifies map keys should be sorted before being printed. Use 109 | this to have a more deterministic, diffable output. Note that 110 | only native types (bool, int, uint, floats, uintptr and string) 111 | and types which implement error or Stringer interfaces are 112 | supported with other types sorted according to the 113 | reflect.Value.String() output which guarantees display 114 | stability. Natural map order is used by default. 115 | 116 | * SpewKeys 117 | Specifies that, as a last resort attempt, map keys should be 118 | spewed to strings and sorted by those strings. This is only 119 | considered if SortKeys is true. 120 | 121 | Dump Usage 122 | 123 | Simply call spew.Dump with a list of variables you want to dump: 124 | 125 | spew.Dump(myVar1, myVar2, ...) 126 | 127 | You may also call spew.Fdump if you would prefer to output to an arbitrary 128 | io.Writer. For example, to dump to standard error: 129 | 130 | spew.Fdump(os.Stderr, myVar1, myVar2, ...) 131 | 132 | A third option is to call spew.Sdump to get the formatted output as a string: 133 | 134 | str := spew.Sdump(myVar1, myVar2, ...) 135 | 136 | Sample Dump Output 137 | 138 | See the Dump example for details on the setup of the types and variables being 139 | shown here. 140 | 141 | (main.Foo) { 142 | unexportedField: (*main.Bar)(0xf84002e210)({ 143 | flag: (main.Flag) flagTwo, 144 | data: (uintptr) 145 | }), 146 | ExportedField: (map[interface {}]interface {}) (len=1) { 147 | (string) (len=3) "one": (bool) true 148 | } 149 | } 150 | 151 | Byte (and uint8) arrays and slices are displayed uniquely like the hexdump -C 152 | command as shown. 153 | ([]uint8) (len=32 cap=32) { 154 | 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... | 155 | 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0| 156 | 00000020 31 32 |12| 157 | } 158 | 159 | Custom Formatter 160 | 161 | Spew provides a custom formatter that implements the fmt.Formatter interface 162 | so that it integrates cleanly with standard fmt package printing functions. The 163 | formatter is useful for inline printing of smaller data types similar to the 164 | standard %v format specifier. 165 | 166 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 167 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb 168 | combinations. Any other verbs such as %x and %q will be sent to the the 169 | standard fmt package for formatting. In addition, the custom formatter ignores 170 | the width and precision arguments (however they will still work on the format 171 | specifiers not handled by the custom formatter). 172 | 173 | Custom Formatter Usage 174 | 175 | The simplest way to make use of the spew custom formatter is to call one of the 176 | convenience functions such as spew.Printf, spew.Println, or spew.Printf. The 177 | functions have syntax you are most likely already familiar with: 178 | 179 | spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2) 180 | spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 181 | spew.Println(myVar, myVar2) 182 | spew.Fprintf(os.Stderr, "myVar1: %v -- myVar2: %+v", myVar1, myVar2) 183 | spew.Fprintf(os.Stderr, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4) 184 | 185 | See the Index for the full list convenience functions. 186 | 187 | Sample Formatter Output 188 | 189 | Double pointer to a uint8: 190 | %v: <**>5 191 | %+v: <**>(0xf8400420d0->0xf8400420c8)5 192 | %#v: (**uint8)5 193 | %#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5 194 | 195 | Pointer to circular struct with a uint8 field and a pointer to itself: 196 | %v: <*>{1 <*>} 197 | %+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)} 198 | %#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)} 199 | %#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)} 200 | 201 | See the Printf example for details on the setup of variables being shown 202 | here. 203 | 204 | Errors 205 | 206 | Since it is possible for custom Stringer/error interfaces to panic, spew 207 | detects them and handles them internally by printing the panic information 208 | inline with the output. Since spew is intended to provide deep pretty printing 209 | capabilities on structures, it intentionally does not return any errors. 210 | */ 211 | package spew 212 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/dump.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "encoding/hex" 22 | "fmt" 23 | "io" 24 | "os" 25 | "reflect" 26 | "regexp" 27 | "strconv" 28 | "strings" 29 | ) 30 | 31 | var ( 32 | // uint8Type is a reflect.Type representing a uint8. It is used to 33 | // convert cgo types to uint8 slices for hexdumping. 34 | uint8Type = reflect.TypeOf(uint8(0)) 35 | 36 | // cCharRE is a regular expression that matches a cgo char. 37 | // It is used to detect character arrays to hexdump them. 38 | cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") 39 | 40 | // cUnsignedCharRE is a regular expression that matches a cgo unsigned 41 | // char. It is used to detect unsigned character arrays to hexdump 42 | // them. 43 | cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") 44 | 45 | // cUint8tCharRE is a regular expression that matches a cgo uint8_t. 46 | // It is used to detect uint8_t arrays to hexdump them. 47 | cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") 48 | ) 49 | 50 | // dumpState contains information about the state of a dump operation. 51 | type dumpState struct { 52 | w io.Writer 53 | depth int 54 | pointers map[uintptr]int 55 | ignoreNextType bool 56 | ignoreNextIndent bool 57 | cs *ConfigState 58 | } 59 | 60 | // indent performs indentation according to the depth level and cs.Indent 61 | // option. 62 | func (d *dumpState) indent() { 63 | if d.ignoreNextIndent { 64 | d.ignoreNextIndent = false 65 | return 66 | } 67 | d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth)) 68 | } 69 | 70 | // unpackValue returns values inside of non-nil interfaces when possible. 71 | // This is useful for data types like structs, arrays, slices, and maps which 72 | // can contain varying types packed inside an interface. 73 | func (d *dumpState) unpackValue(v reflect.Value) reflect.Value { 74 | if v.Kind() == reflect.Interface && !v.IsNil() { 75 | v = v.Elem() 76 | } 77 | return v 78 | } 79 | 80 | // dumpPtr handles formatting of pointers by indirecting them as necessary. 81 | func (d *dumpState) dumpPtr(v reflect.Value) { 82 | // Remove pointers at or below the current depth from map used to detect 83 | // circular refs. 84 | for k, depth := range d.pointers { 85 | if depth >= d.depth { 86 | delete(d.pointers, k) 87 | } 88 | } 89 | 90 | // Keep list of all dereferenced pointers to show later. 91 | pointerChain := make([]uintptr, 0) 92 | 93 | // Figure out how many levels of indirection there are by dereferencing 94 | // pointers and unpacking interfaces down the chain while detecting circular 95 | // references. 96 | nilFound := false 97 | cycleFound := false 98 | indirects := 0 99 | ve := v 100 | for ve.Kind() == reflect.Ptr { 101 | if ve.IsNil() { 102 | nilFound = true 103 | break 104 | } 105 | indirects++ 106 | addr := ve.Pointer() 107 | pointerChain = append(pointerChain, addr) 108 | if pd, ok := d.pointers[addr]; ok && pd < d.depth { 109 | cycleFound = true 110 | indirects-- 111 | break 112 | } 113 | d.pointers[addr] = d.depth 114 | 115 | ve = ve.Elem() 116 | if ve.Kind() == reflect.Interface { 117 | if ve.IsNil() { 118 | nilFound = true 119 | break 120 | } 121 | ve = ve.Elem() 122 | } 123 | } 124 | 125 | // Display type information. 126 | d.w.Write(openParenBytes) 127 | d.w.Write(bytes.Repeat(asteriskBytes, indirects)) 128 | d.w.Write([]byte(ve.Type().String())) 129 | d.w.Write(closeParenBytes) 130 | 131 | // Display pointer information. 132 | if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { 133 | d.w.Write(openParenBytes) 134 | for i, addr := range pointerChain { 135 | if i > 0 { 136 | d.w.Write(pointerChainBytes) 137 | } 138 | printHexPtr(d.w, addr) 139 | } 140 | d.w.Write(closeParenBytes) 141 | } 142 | 143 | // Display dereferenced value. 144 | d.w.Write(openParenBytes) 145 | switch { 146 | case nilFound == true: 147 | d.w.Write(nilAngleBytes) 148 | 149 | case cycleFound == true: 150 | d.w.Write(circularBytes) 151 | 152 | default: 153 | d.ignoreNextType = true 154 | d.dump(ve) 155 | } 156 | d.w.Write(closeParenBytes) 157 | } 158 | 159 | // dumpSlice handles formatting of arrays and slices. Byte (uint8 under 160 | // reflection) arrays and slices are dumped in hexdump -C fashion. 161 | func (d *dumpState) dumpSlice(v reflect.Value) { 162 | // Determine whether this type should be hex dumped or not. Also, 163 | // for types which should be hexdumped, try to use the underlying data 164 | // first, then fall back to trying to convert them to a uint8 slice. 165 | var buf []uint8 166 | doConvert := false 167 | doHexDump := false 168 | numEntries := v.Len() 169 | if numEntries > 0 { 170 | vt := v.Index(0).Type() 171 | vts := vt.String() 172 | switch { 173 | // C types that need to be converted. 174 | case cCharRE.MatchString(vts): 175 | fallthrough 176 | case cUnsignedCharRE.MatchString(vts): 177 | fallthrough 178 | case cUint8tCharRE.MatchString(vts): 179 | doConvert = true 180 | 181 | // Try to use existing uint8 slices and fall back to converting 182 | // and copying if that fails. 183 | case vt.Kind() == reflect.Uint8: 184 | // We need an addressable interface to convert the type 185 | // to a byte slice. However, the reflect package won't 186 | // give us an interface on certain things like 187 | // unexported struct fields in order to enforce 188 | // visibility rules. We use unsafe, when available, to 189 | // bypass these restrictions since this package does not 190 | // mutate the values. 191 | vs := v 192 | if !vs.CanInterface() || !vs.CanAddr() { 193 | vs = unsafeReflectValue(vs) 194 | } 195 | if !UnsafeDisabled { 196 | vs = vs.Slice(0, numEntries) 197 | 198 | // Use the existing uint8 slice if it can be 199 | // type asserted. 200 | iface := vs.Interface() 201 | if slice, ok := iface.([]uint8); ok { 202 | buf = slice 203 | doHexDump = true 204 | break 205 | } 206 | } 207 | 208 | // The underlying data needs to be converted if it can't 209 | // be type asserted to a uint8 slice. 210 | doConvert = true 211 | } 212 | 213 | // Copy and convert the underlying type if needed. 214 | if doConvert && vt.ConvertibleTo(uint8Type) { 215 | // Convert and copy each element into a uint8 byte 216 | // slice. 217 | buf = make([]uint8, numEntries) 218 | for i := 0; i < numEntries; i++ { 219 | vv := v.Index(i) 220 | buf[i] = uint8(vv.Convert(uint8Type).Uint()) 221 | } 222 | doHexDump = true 223 | } 224 | } 225 | 226 | // Hexdump the entire slice as needed. 227 | if doHexDump { 228 | indent := strings.Repeat(d.cs.Indent, d.depth) 229 | str := indent + hex.Dump(buf) 230 | str = strings.Replace(str, "\n", "\n"+indent, -1) 231 | str = strings.TrimRight(str, d.cs.Indent) 232 | d.w.Write([]byte(str)) 233 | return 234 | } 235 | 236 | // Recursively call dump for each item. 237 | for i := 0; i < numEntries; i++ { 238 | d.dump(d.unpackValue(v.Index(i))) 239 | if i < (numEntries - 1) { 240 | d.w.Write(commaNewlineBytes) 241 | } else { 242 | d.w.Write(newlineBytes) 243 | } 244 | } 245 | } 246 | 247 | // dump is the main workhorse for dumping a value. It uses the passed reflect 248 | // value to figure out what kind of object we are dealing with and formats it 249 | // appropriately. It is a recursive function, however circular data structures 250 | // are detected and handled properly. 251 | func (d *dumpState) dump(v reflect.Value) { 252 | // Handle invalid reflect values immediately. 253 | kind := v.Kind() 254 | if kind == reflect.Invalid { 255 | d.w.Write(invalidAngleBytes) 256 | return 257 | } 258 | 259 | // Handle pointers specially. 260 | if kind == reflect.Ptr { 261 | d.indent() 262 | d.dumpPtr(v) 263 | return 264 | } 265 | 266 | // Print type information unless already handled elsewhere. 267 | if !d.ignoreNextType { 268 | d.indent() 269 | d.w.Write(openParenBytes) 270 | d.w.Write([]byte(v.Type().String())) 271 | d.w.Write(closeParenBytes) 272 | d.w.Write(spaceBytes) 273 | } 274 | d.ignoreNextType = false 275 | 276 | // Display length and capacity if the built-in len and cap functions 277 | // work with the value's kind and the len/cap itself is non-zero. 278 | valueLen, valueCap := 0, 0 279 | switch v.Kind() { 280 | case reflect.Array, reflect.Slice, reflect.Chan: 281 | valueLen, valueCap = v.Len(), v.Cap() 282 | case reflect.Map, reflect.String: 283 | valueLen = v.Len() 284 | } 285 | if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { 286 | d.w.Write(openParenBytes) 287 | if valueLen != 0 { 288 | d.w.Write(lenEqualsBytes) 289 | printInt(d.w, int64(valueLen), 10) 290 | } 291 | if !d.cs.DisableCapacities && valueCap != 0 { 292 | if valueLen != 0 { 293 | d.w.Write(spaceBytes) 294 | } 295 | d.w.Write(capEqualsBytes) 296 | printInt(d.w, int64(valueCap), 10) 297 | } 298 | d.w.Write(closeParenBytes) 299 | d.w.Write(spaceBytes) 300 | } 301 | 302 | // Call Stringer/error interfaces if they exist and the handle methods flag 303 | // is enabled 304 | if !d.cs.DisableMethods { 305 | if (kind != reflect.Invalid) && (kind != reflect.Interface) { 306 | if handled := handleMethods(d.cs, d.w, v); handled { 307 | return 308 | } 309 | } 310 | } 311 | 312 | switch kind { 313 | case reflect.Invalid: 314 | // Do nothing. We should never get here since invalid has already 315 | // been handled above. 316 | 317 | case reflect.Bool: 318 | printBool(d.w, v.Bool()) 319 | 320 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 321 | printInt(d.w, v.Int(), 10) 322 | 323 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 324 | printUint(d.w, v.Uint(), 10) 325 | 326 | case reflect.Float32: 327 | printFloat(d.w, v.Float(), 32) 328 | 329 | case reflect.Float64: 330 | printFloat(d.w, v.Float(), 64) 331 | 332 | case reflect.Complex64: 333 | printComplex(d.w, v.Complex(), 32) 334 | 335 | case reflect.Complex128: 336 | printComplex(d.w, v.Complex(), 64) 337 | 338 | case reflect.Slice: 339 | if v.IsNil() { 340 | d.w.Write(nilAngleBytes) 341 | break 342 | } 343 | fallthrough 344 | 345 | case reflect.Array: 346 | d.w.Write(openBraceNewlineBytes) 347 | d.depth++ 348 | if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { 349 | d.indent() 350 | d.w.Write(maxNewlineBytes) 351 | } else { 352 | d.dumpSlice(v) 353 | } 354 | d.depth-- 355 | d.indent() 356 | d.w.Write(closeBraceBytes) 357 | 358 | case reflect.String: 359 | d.w.Write([]byte(strconv.Quote(v.String()))) 360 | 361 | case reflect.Interface: 362 | // The only time we should get here is for nil interfaces due to 363 | // unpackValue calls. 364 | if v.IsNil() { 365 | d.w.Write(nilAngleBytes) 366 | } 367 | 368 | case reflect.Ptr: 369 | // Do nothing. We should never get here since pointers have already 370 | // been handled above. 371 | 372 | case reflect.Map: 373 | // nil maps should be indicated as different than empty maps 374 | if v.IsNil() { 375 | d.w.Write(nilAngleBytes) 376 | break 377 | } 378 | 379 | d.w.Write(openBraceNewlineBytes) 380 | d.depth++ 381 | if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { 382 | d.indent() 383 | d.w.Write(maxNewlineBytes) 384 | } else { 385 | numEntries := v.Len() 386 | keys := v.MapKeys() 387 | if d.cs.SortKeys { 388 | sortValues(keys, d.cs) 389 | } 390 | for i, key := range keys { 391 | d.dump(d.unpackValue(key)) 392 | d.w.Write(colonSpaceBytes) 393 | d.ignoreNextIndent = true 394 | d.dump(d.unpackValue(v.MapIndex(key))) 395 | if i < (numEntries - 1) { 396 | d.w.Write(commaNewlineBytes) 397 | } else { 398 | d.w.Write(newlineBytes) 399 | } 400 | } 401 | } 402 | d.depth-- 403 | d.indent() 404 | d.w.Write(closeBraceBytes) 405 | 406 | case reflect.Struct: 407 | d.w.Write(openBraceNewlineBytes) 408 | d.depth++ 409 | if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) { 410 | d.indent() 411 | d.w.Write(maxNewlineBytes) 412 | } else { 413 | vt := v.Type() 414 | numFields := v.NumField() 415 | for i := 0; i < numFields; i++ { 416 | d.indent() 417 | vtf := vt.Field(i) 418 | d.w.Write([]byte(vtf.Name)) 419 | d.w.Write(colonSpaceBytes) 420 | d.ignoreNextIndent = true 421 | d.dump(d.unpackValue(v.Field(i))) 422 | if i < (numFields - 1) { 423 | d.w.Write(commaNewlineBytes) 424 | } else { 425 | d.w.Write(newlineBytes) 426 | } 427 | } 428 | } 429 | d.depth-- 430 | d.indent() 431 | d.w.Write(closeBraceBytes) 432 | 433 | case reflect.Uintptr: 434 | printHexPtr(d.w, uintptr(v.Uint())) 435 | 436 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: 437 | printHexPtr(d.w, v.Pointer()) 438 | 439 | // There were not any other types at the time this code was written, but 440 | // fall back to letting the default fmt package handle it in case any new 441 | // types are added. 442 | default: 443 | if v.CanInterface() { 444 | fmt.Fprintf(d.w, "%v", v.Interface()) 445 | } else { 446 | fmt.Fprintf(d.w, "%v", v.String()) 447 | } 448 | } 449 | } 450 | 451 | // fdump is a helper function to consolidate the logic from the various public 452 | // methods which take varying writers and config states. 453 | func fdump(cs *ConfigState, w io.Writer, a ...interface{}) { 454 | for _, arg := range a { 455 | if arg == nil { 456 | w.Write(interfaceBytes) 457 | w.Write(spaceBytes) 458 | w.Write(nilAngleBytes) 459 | w.Write(newlineBytes) 460 | continue 461 | } 462 | 463 | d := dumpState{w: w, cs: cs} 464 | d.pointers = make(map[uintptr]int) 465 | d.dump(reflect.ValueOf(arg)) 466 | d.w.Write(newlineBytes) 467 | } 468 | } 469 | 470 | // Fdump formats and displays the passed arguments to io.Writer w. It formats 471 | // exactly the same as Dump. 472 | func Fdump(w io.Writer, a ...interface{}) { 473 | fdump(&Config, w, a...) 474 | } 475 | 476 | // Sdump returns a string with the passed arguments formatted exactly the same 477 | // as Dump. 478 | func Sdump(a ...interface{}) string { 479 | var buf bytes.Buffer 480 | fdump(&Config, &buf, a...) 481 | return buf.String() 482 | } 483 | 484 | /* 485 | Dump displays the passed parameters to standard out with newlines, customizable 486 | indentation, and additional debug information such as complete types and all 487 | pointer addresses used to indirect to the final value. It provides the 488 | following features over the built-in printing facilities provided by the fmt 489 | package: 490 | 491 | * Pointers are dereferenced and followed 492 | * Circular data structures are detected and handled properly 493 | * Custom Stringer/error interfaces are optionally invoked, including 494 | on unexported types 495 | * Custom types which only implement the Stringer/error interfaces via 496 | a pointer receiver are optionally invoked when passing non-pointer 497 | variables 498 | * Byte arrays and slices are dumped like the hexdump -C command which 499 | includes offsets, byte values in hex, and ASCII output 500 | 501 | The configuration options are controlled by an exported package global, 502 | spew.Config. See ConfigState for options documentation. 503 | 504 | See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to 505 | get the formatted result as a string. 506 | */ 507 | func Dump(a ...interface{}) { 508 | fdump(&Config, os.Stdout, a...) 509 | } 510 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/format.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "bytes" 21 | "fmt" 22 | "reflect" 23 | "strconv" 24 | "strings" 25 | ) 26 | 27 | // supportedFlags is a list of all the character flags supported by fmt package. 28 | const supportedFlags = "0-+# " 29 | 30 | // formatState implements the fmt.Formatter interface and contains information 31 | // about the state of a formatting operation. The NewFormatter function can 32 | // be used to get a new Formatter which can be used directly as arguments 33 | // in standard fmt package printing calls. 34 | type formatState struct { 35 | value interface{} 36 | fs fmt.State 37 | depth int 38 | pointers map[uintptr]int 39 | ignoreNextType bool 40 | cs *ConfigState 41 | } 42 | 43 | // buildDefaultFormat recreates the original format string without precision 44 | // and width information to pass in to fmt.Sprintf in the case of an 45 | // unrecognized type. Unless new types are added to the language, this 46 | // function won't ever be called. 47 | func (f *formatState) buildDefaultFormat() (format string) { 48 | buf := bytes.NewBuffer(percentBytes) 49 | 50 | for _, flag := range supportedFlags { 51 | if f.fs.Flag(int(flag)) { 52 | buf.WriteRune(flag) 53 | } 54 | } 55 | 56 | buf.WriteRune('v') 57 | 58 | format = buf.String() 59 | return format 60 | } 61 | 62 | // constructOrigFormat recreates the original format string including precision 63 | // and width information to pass along to the standard fmt package. This allows 64 | // automatic deferral of all format strings this package doesn't support. 65 | func (f *formatState) constructOrigFormat(verb rune) (format string) { 66 | buf := bytes.NewBuffer(percentBytes) 67 | 68 | for _, flag := range supportedFlags { 69 | if f.fs.Flag(int(flag)) { 70 | buf.WriteRune(flag) 71 | } 72 | } 73 | 74 | if width, ok := f.fs.Width(); ok { 75 | buf.WriteString(strconv.Itoa(width)) 76 | } 77 | 78 | if precision, ok := f.fs.Precision(); ok { 79 | buf.Write(precisionBytes) 80 | buf.WriteString(strconv.Itoa(precision)) 81 | } 82 | 83 | buf.WriteRune(verb) 84 | 85 | format = buf.String() 86 | return format 87 | } 88 | 89 | // unpackValue returns values inside of non-nil interfaces when possible and 90 | // ensures that types for values which have been unpacked from an interface 91 | // are displayed when the show types flag is also set. 92 | // This is useful for data types like structs, arrays, slices, and maps which 93 | // can contain varying types packed inside an interface. 94 | func (f *formatState) unpackValue(v reflect.Value) reflect.Value { 95 | if v.Kind() == reflect.Interface { 96 | f.ignoreNextType = false 97 | if !v.IsNil() { 98 | v = v.Elem() 99 | } 100 | } 101 | return v 102 | } 103 | 104 | // formatPtr handles formatting of pointers by indirecting them as necessary. 105 | func (f *formatState) formatPtr(v reflect.Value) { 106 | // Display nil if top level pointer is nil. 107 | showTypes := f.fs.Flag('#') 108 | if v.IsNil() && (!showTypes || f.ignoreNextType) { 109 | f.fs.Write(nilAngleBytes) 110 | return 111 | } 112 | 113 | // Remove pointers at or below the current depth from map used to detect 114 | // circular refs. 115 | for k, depth := range f.pointers { 116 | if depth >= f.depth { 117 | delete(f.pointers, k) 118 | } 119 | } 120 | 121 | // Keep list of all dereferenced pointers to possibly show later. 122 | pointerChain := make([]uintptr, 0) 123 | 124 | // Figure out how many levels of indirection there are by derferencing 125 | // pointers and unpacking interfaces down the chain while detecting circular 126 | // references. 127 | nilFound := false 128 | cycleFound := false 129 | indirects := 0 130 | ve := v 131 | for ve.Kind() == reflect.Ptr { 132 | if ve.IsNil() { 133 | nilFound = true 134 | break 135 | } 136 | indirects++ 137 | addr := ve.Pointer() 138 | pointerChain = append(pointerChain, addr) 139 | if pd, ok := f.pointers[addr]; ok && pd < f.depth { 140 | cycleFound = true 141 | indirects-- 142 | break 143 | } 144 | f.pointers[addr] = f.depth 145 | 146 | ve = ve.Elem() 147 | if ve.Kind() == reflect.Interface { 148 | if ve.IsNil() { 149 | nilFound = true 150 | break 151 | } 152 | ve = ve.Elem() 153 | } 154 | } 155 | 156 | // Display type or indirection level depending on flags. 157 | if showTypes && !f.ignoreNextType { 158 | f.fs.Write(openParenBytes) 159 | f.fs.Write(bytes.Repeat(asteriskBytes, indirects)) 160 | f.fs.Write([]byte(ve.Type().String())) 161 | f.fs.Write(closeParenBytes) 162 | } else { 163 | if nilFound || cycleFound { 164 | indirects += strings.Count(ve.Type().String(), "*") 165 | } 166 | f.fs.Write(openAngleBytes) 167 | f.fs.Write([]byte(strings.Repeat("*", indirects))) 168 | f.fs.Write(closeAngleBytes) 169 | } 170 | 171 | // Display pointer information depending on flags. 172 | if f.fs.Flag('+') && (len(pointerChain) > 0) { 173 | f.fs.Write(openParenBytes) 174 | for i, addr := range pointerChain { 175 | if i > 0 { 176 | f.fs.Write(pointerChainBytes) 177 | } 178 | printHexPtr(f.fs, addr) 179 | } 180 | f.fs.Write(closeParenBytes) 181 | } 182 | 183 | // Display dereferenced value. 184 | switch { 185 | case nilFound == true: 186 | f.fs.Write(nilAngleBytes) 187 | 188 | case cycleFound == true: 189 | f.fs.Write(circularShortBytes) 190 | 191 | default: 192 | f.ignoreNextType = true 193 | f.format(ve) 194 | } 195 | } 196 | 197 | // format is the main workhorse for providing the Formatter interface. It 198 | // uses the passed reflect value to figure out what kind of object we are 199 | // dealing with and formats it appropriately. It is a recursive function, 200 | // however circular data structures are detected and handled properly. 201 | func (f *formatState) format(v reflect.Value) { 202 | // Handle invalid reflect values immediately. 203 | kind := v.Kind() 204 | if kind == reflect.Invalid { 205 | f.fs.Write(invalidAngleBytes) 206 | return 207 | } 208 | 209 | // Handle pointers specially. 210 | if kind == reflect.Ptr { 211 | f.formatPtr(v) 212 | return 213 | } 214 | 215 | // Print type information unless already handled elsewhere. 216 | if !f.ignoreNextType && f.fs.Flag('#') { 217 | f.fs.Write(openParenBytes) 218 | f.fs.Write([]byte(v.Type().String())) 219 | f.fs.Write(closeParenBytes) 220 | } 221 | f.ignoreNextType = false 222 | 223 | // Call Stringer/error interfaces if they exist and the handle methods 224 | // flag is enabled. 225 | if !f.cs.DisableMethods { 226 | if (kind != reflect.Invalid) && (kind != reflect.Interface) { 227 | if handled := handleMethods(f.cs, f.fs, v); handled { 228 | return 229 | } 230 | } 231 | } 232 | 233 | switch kind { 234 | case reflect.Invalid: 235 | // Do nothing. We should never get here since invalid has already 236 | // been handled above. 237 | 238 | case reflect.Bool: 239 | printBool(f.fs, v.Bool()) 240 | 241 | case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: 242 | printInt(f.fs, v.Int(), 10) 243 | 244 | case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: 245 | printUint(f.fs, v.Uint(), 10) 246 | 247 | case reflect.Float32: 248 | printFloat(f.fs, v.Float(), 32) 249 | 250 | case reflect.Float64: 251 | printFloat(f.fs, v.Float(), 64) 252 | 253 | case reflect.Complex64: 254 | printComplex(f.fs, v.Complex(), 32) 255 | 256 | case reflect.Complex128: 257 | printComplex(f.fs, v.Complex(), 64) 258 | 259 | case reflect.Slice: 260 | if v.IsNil() { 261 | f.fs.Write(nilAngleBytes) 262 | break 263 | } 264 | fallthrough 265 | 266 | case reflect.Array: 267 | f.fs.Write(openBracketBytes) 268 | f.depth++ 269 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 270 | f.fs.Write(maxShortBytes) 271 | } else { 272 | numEntries := v.Len() 273 | for i := 0; i < numEntries; i++ { 274 | if i > 0 { 275 | f.fs.Write(spaceBytes) 276 | } 277 | f.ignoreNextType = true 278 | f.format(f.unpackValue(v.Index(i))) 279 | } 280 | } 281 | f.depth-- 282 | f.fs.Write(closeBracketBytes) 283 | 284 | case reflect.String: 285 | f.fs.Write([]byte(v.String())) 286 | 287 | case reflect.Interface: 288 | // The only time we should get here is for nil interfaces due to 289 | // unpackValue calls. 290 | if v.IsNil() { 291 | f.fs.Write(nilAngleBytes) 292 | } 293 | 294 | case reflect.Ptr: 295 | // Do nothing. We should never get here since pointers have already 296 | // been handled above. 297 | 298 | case reflect.Map: 299 | // nil maps should be indicated as different than empty maps 300 | if v.IsNil() { 301 | f.fs.Write(nilAngleBytes) 302 | break 303 | } 304 | 305 | f.fs.Write(openMapBytes) 306 | f.depth++ 307 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 308 | f.fs.Write(maxShortBytes) 309 | } else { 310 | keys := v.MapKeys() 311 | if f.cs.SortKeys { 312 | sortValues(keys, f.cs) 313 | } 314 | for i, key := range keys { 315 | if i > 0 { 316 | f.fs.Write(spaceBytes) 317 | } 318 | f.ignoreNextType = true 319 | f.format(f.unpackValue(key)) 320 | f.fs.Write(colonBytes) 321 | f.ignoreNextType = true 322 | f.format(f.unpackValue(v.MapIndex(key))) 323 | } 324 | } 325 | f.depth-- 326 | f.fs.Write(closeMapBytes) 327 | 328 | case reflect.Struct: 329 | numFields := v.NumField() 330 | f.fs.Write(openBraceBytes) 331 | f.depth++ 332 | if (f.cs.MaxDepth != 0) && (f.depth > f.cs.MaxDepth) { 333 | f.fs.Write(maxShortBytes) 334 | } else { 335 | vt := v.Type() 336 | for i := 0; i < numFields; i++ { 337 | if i > 0 { 338 | f.fs.Write(spaceBytes) 339 | } 340 | vtf := vt.Field(i) 341 | if f.fs.Flag('+') || f.fs.Flag('#') { 342 | f.fs.Write([]byte(vtf.Name)) 343 | f.fs.Write(colonBytes) 344 | } 345 | f.format(f.unpackValue(v.Field(i))) 346 | } 347 | } 348 | f.depth-- 349 | f.fs.Write(closeBraceBytes) 350 | 351 | case reflect.Uintptr: 352 | printHexPtr(f.fs, uintptr(v.Uint())) 353 | 354 | case reflect.UnsafePointer, reflect.Chan, reflect.Func: 355 | printHexPtr(f.fs, v.Pointer()) 356 | 357 | // There were not any other types at the time this code was written, but 358 | // fall back to letting the default fmt package handle it if any get added. 359 | default: 360 | format := f.buildDefaultFormat() 361 | if v.CanInterface() { 362 | fmt.Fprintf(f.fs, format, v.Interface()) 363 | } else { 364 | fmt.Fprintf(f.fs, format, v.String()) 365 | } 366 | } 367 | } 368 | 369 | // Format satisfies the fmt.Formatter interface. See NewFormatter for usage 370 | // details. 371 | func (f *formatState) Format(fs fmt.State, verb rune) { 372 | f.fs = fs 373 | 374 | // Use standard formatting for verbs that are not v. 375 | if verb != 'v' { 376 | format := f.constructOrigFormat(verb) 377 | fmt.Fprintf(fs, format, f.value) 378 | return 379 | } 380 | 381 | if f.value == nil { 382 | if fs.Flag('#') { 383 | fs.Write(interfaceBytes) 384 | } 385 | fs.Write(nilAngleBytes) 386 | return 387 | } 388 | 389 | f.format(reflect.ValueOf(f.value)) 390 | } 391 | 392 | // newFormatter is a helper function to consolidate the logic from the various 393 | // public methods which take varying config states. 394 | func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter { 395 | fs := &formatState{value: v, cs: cs} 396 | fs.pointers = make(map[uintptr]int) 397 | return fs 398 | } 399 | 400 | /* 401 | NewFormatter returns a custom formatter that satisfies the fmt.Formatter 402 | interface. As a result, it integrates cleanly with standard fmt package 403 | printing functions. The formatter is useful for inline printing of smaller data 404 | types similar to the standard %v format specifier. 405 | 406 | The custom formatter only responds to the %v (most compact), %+v (adds pointer 407 | addresses), %#v (adds types), or %#+v (adds types and pointer addresses) verb 408 | combinations. Any other verbs such as %x and %q will be sent to the the 409 | standard fmt package for formatting. In addition, the custom formatter ignores 410 | the width and precision arguments (however they will still work on the format 411 | specifiers not handled by the custom formatter). 412 | 413 | Typically this function shouldn't be called directly. It is much easier to make 414 | use of the custom formatter by calling one of the convenience functions such as 415 | Printf, Println, or Fprintf. 416 | */ 417 | func NewFormatter(v interface{}) fmt.Formatter { 418 | return newFormatter(&Config, v) 419 | } 420 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/spew.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | ) 23 | 24 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 25 | // passed with a default Formatter interface returned by NewFormatter. It 26 | // returns the formatted string as a value that satisfies error. See 27 | // NewFormatter for formatting details. 28 | // 29 | // This function is shorthand for the following syntax: 30 | // 31 | // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 32 | func Errorf(format string, a ...interface{}) (err error) { 33 | return fmt.Errorf(format, convertArgs(a)...) 34 | } 35 | 36 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 37 | // passed with a default Formatter interface returned by NewFormatter. It 38 | // returns the number of bytes written and any write error encountered. See 39 | // NewFormatter for formatting details. 40 | // 41 | // This function is shorthand for the following syntax: 42 | // 43 | // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) 44 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 45 | return fmt.Fprint(w, convertArgs(a)...) 46 | } 47 | 48 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 49 | // passed with a default Formatter interface returned by NewFormatter. It 50 | // returns the number of bytes written and any write error encountered. See 51 | // NewFormatter for formatting details. 52 | // 53 | // This function is shorthand for the following syntax: 54 | // 55 | // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) 56 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 57 | return fmt.Fprintf(w, format, convertArgs(a)...) 58 | } 59 | 60 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 61 | // passed with a default Formatter interface returned by NewFormatter. See 62 | // NewFormatter for formatting details. 63 | // 64 | // This function is shorthand for the following syntax: 65 | // 66 | // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) 67 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 68 | return fmt.Fprintln(w, convertArgs(a)...) 69 | } 70 | 71 | // Print is a wrapper for fmt.Print that treats each argument as if it were 72 | // passed with a default Formatter interface returned by NewFormatter. It 73 | // returns the number of bytes written and any write error encountered. See 74 | // NewFormatter for formatting details. 75 | // 76 | // This function is shorthand for the following syntax: 77 | // 78 | // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) 79 | func Print(a ...interface{}) (n int, err error) { 80 | return fmt.Print(convertArgs(a)...) 81 | } 82 | 83 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 84 | // passed with a default Formatter interface returned by NewFormatter. It 85 | // returns the number of bytes written and any write error encountered. See 86 | // NewFormatter for formatting details. 87 | // 88 | // This function is shorthand for the following syntax: 89 | // 90 | // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 91 | func Printf(format string, a ...interface{}) (n int, err error) { 92 | return fmt.Printf(format, convertArgs(a)...) 93 | } 94 | 95 | // Println is a wrapper for fmt.Println that treats each argument as if it were 96 | // passed with a default Formatter interface returned by NewFormatter. It 97 | // returns the number of bytes written and any write error encountered. See 98 | // NewFormatter for formatting details. 99 | // 100 | // This function is shorthand for the following syntax: 101 | // 102 | // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) 103 | func Println(a ...interface{}) (n int, err error) { 104 | return fmt.Println(convertArgs(a)...) 105 | } 106 | 107 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 108 | // passed with a default Formatter interface returned by NewFormatter. It 109 | // returns the resulting string. See NewFormatter for formatting details. 110 | // 111 | // This function is shorthand for the following syntax: 112 | // 113 | // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) 114 | func Sprint(a ...interface{}) string { 115 | return fmt.Sprint(convertArgs(a)...) 116 | } 117 | 118 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 119 | // passed with a default Formatter interface returned by NewFormatter. It 120 | // returns the resulting string. See NewFormatter for formatting details. 121 | // 122 | // This function is shorthand for the following syntax: 123 | // 124 | // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 125 | func Sprintf(format string, a ...interface{}) string { 126 | return fmt.Sprintf(format, convertArgs(a)...) 127 | } 128 | 129 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 130 | // were passed with a default Formatter interface returned by NewFormatter. It 131 | // returns the resulting string. See NewFormatter for formatting details. 132 | // 133 | // This function is shorthand for the following syntax: 134 | // 135 | // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) 136 | func Sprintln(a ...interface{}) string { 137 | return fmt.Sprintln(convertArgs(a)...) 138 | } 139 | 140 | // convertArgs accepts a slice of arguments and returns a slice of the same 141 | // length with each argument converted to a default spew Formatter interface. 142 | func convertArgs(args []interface{}) (formatters []interface{}) { 143 | formatters = make([]interface{}, len(args)) 144 | for index, arg := range args { 145 | formatters[index] = NewFormatter(arg) 146 | } 147 | return formatters 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/ensure/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.5 5 | 6 | before_install: 7 | - go get -v golang.org/x/tools/cmd/vet 8 | - go get -v golang.org/x/tools/cmd/cover 9 | - go get -v github.com/golang/lint/golint 10 | 11 | install: 12 | - go install -race -v std 13 | - go get -race -t -v ./... 14 | - go install -race -v ./... 15 | 16 | script: 17 | - go vet ./... 18 | - $HOME/gopath/bin/golint . 19 | - go test -cpu=2 -race -v ./... 20 | - go test -cpu=2 -covermode=atomic ./... 21 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/ensure/ensure.go: -------------------------------------------------------------------------------- 1 | // Package ensure provides utilities for testing to ensure the 2 | // given conditions are met and Fatal if they aren't satisified. 3 | // 4 | // The various functions here show a useful error message automatically 5 | // including identifying source location. They additionally support arbitary 6 | // arguments which will be printed using the spew library. 7 | package ensure 8 | 9 | import ( 10 | "bytes" 11 | "fmt" 12 | "path/filepath" 13 | "reflect" 14 | "regexp" 15 | "strings" 16 | 17 | "github.com/davecgh/go-spew/spew" 18 | "github.com/facebookgo/stack" 19 | subsetp "github.com/facebookgo/subset" 20 | ) 21 | 22 | // Fataler defines the minimal interface necessary to trigger a Fatal when a 23 | // condition is hit. testing.T & testing.B satisfy this for example. 24 | type Fataler interface { 25 | Fatal(a ...interface{}) 26 | } 27 | 28 | // cond represents a condition that wasn't satisfied, and is useful to generate 29 | // log messages. 30 | type cond struct { 31 | Fataler Fataler 32 | Skip int 33 | Format string 34 | FormatArgs []interface{} 35 | Extra []interface{} 36 | DisableDeleteSelf bool 37 | } 38 | 39 | // This deletes "ensure.go:xx" removing a confusing piece of information since 40 | // it will be an internal reference. 41 | var deleteSelf = strings.Repeat("\b", 15) 42 | 43 | func (c cond) String() string { 44 | var b bytes.Buffer 45 | if c.DisableDeleteSelf { 46 | fmt.Fprint(&b, "\n") 47 | } else { 48 | fmt.Fprint(&b, deleteSelf) 49 | } 50 | fmt.Fprint(&b, pstack(stack.Callers(c.Skip+1), c.DisableDeleteSelf)) 51 | if c.Format != "" { 52 | fmt.Fprintf(&b, c.Format, c.FormatArgs...) 53 | } 54 | if len(c.Extra) != 0 { 55 | fmt.Fprint(&b, "\n") 56 | fmt.Fprint(&b, tsdump(c.Extra...)) 57 | } 58 | return b.String() 59 | } 60 | 61 | // fatal triggers the fatal and logs the cond's message. It adds 2 to Skip, to 62 | // skip itself as well as the caller. 63 | func fatal(c cond) { 64 | c.Skip = c.Skip + 2 65 | c.Fataler.Fatal(c.String()) 66 | } 67 | 68 | // Err ensures the error satisfies the given regular expression. 69 | func Err(t Fataler, err error, re *regexp.Regexp, a ...interface{}) { 70 | if err == nil && re == nil { 71 | return 72 | } 73 | 74 | if err == nil && re != nil { 75 | fatal(cond{ 76 | Fataler: t, 77 | Format: `expected error: "%s" but got a nil error`, 78 | FormatArgs: []interface{}{re}, 79 | Extra: a, 80 | }) 81 | return 82 | } 83 | 84 | if err != nil && re == nil { 85 | fatal(cond{ 86 | Fataler: t, 87 | Format: `unexpected error: %s`, 88 | FormatArgs: []interface{}{err}, 89 | Extra: a, 90 | }) 91 | return 92 | } 93 | 94 | if !re.MatchString(err.Error()) { 95 | fatal(cond{ 96 | Fataler: t, 97 | Format: `expected error: "%s" but got "%s"`, 98 | FormatArgs: []interface{}{re, err}, 99 | Extra: a, 100 | }) 101 | } 102 | } 103 | 104 | // DeepEqual ensures actual and expected are equal. It does so using 105 | // reflect.DeepEqual. 106 | func DeepEqual(t Fataler, actual, expected interface{}, a ...interface{}) { 107 | if !reflect.DeepEqual(actual, expected) { 108 | fatal(cond{ 109 | Fataler: t, 110 | Format: "expected these to be equal:\nACTUAL:\n%s\nEXPECTED:\n%s", 111 | FormatArgs: []interface{}{spew.Sdump(actual), tsdump(expected)}, 112 | Extra: a, 113 | }) 114 | } 115 | } 116 | 117 | // NotDeepEqual ensures actual and expected are not equal. It does so using 118 | // reflect.DeepEqual. 119 | func NotDeepEqual(t Fataler, actual, expected interface{}, a ...interface{}) { 120 | if reflect.DeepEqual(actual, expected) { 121 | fatal(cond{ 122 | Fataler: t, 123 | Format: "expected two different values, but got the same:\n%s", 124 | FormatArgs: []interface{}{tsdump(actual)}, 125 | Extra: a, 126 | }) 127 | } 128 | } 129 | 130 | // Subset ensures actual matches subset. 131 | func Subset(t Fataler, actual, subset interface{}, a ...interface{}) { 132 | if !subsetp.Check(subset, actual) { 133 | fatal(cond{ 134 | Fataler: t, 135 | Format: "expected subset not found:\nACTUAL:\n%s\nEXPECTED SUBSET\n%s", 136 | FormatArgs: []interface{}{spew.Sdump(actual), tsdump(subset)}, 137 | Extra: a, 138 | }) 139 | } 140 | } 141 | 142 | // DisorderedSubset attempts to find all the given subsets in the list of actuals. 143 | // Does not allow one actual to match more than one subset, be warray of the 144 | // possibility of insufficiently specific subsets. 145 | func DisorderedSubset(t Fataler, a, s interface{}, extra ...interface{}) { 146 | actuals := toInterfaceSlice(a) 147 | subsets := toInterfaceSlice(s) 148 | 149 | used := make([]bool, len(actuals)) 150 | matches := 0 151 | for _, subset := range subsets { 152 | for i, actual := range actuals { 153 | if used[i] { 154 | continue 155 | } 156 | if subsetp.Check(subset, actual) { 157 | matches++ 158 | used[i] = true 159 | break 160 | } 161 | } 162 | } 163 | if matches != len(subsets) { 164 | fatal(cond{ 165 | Fataler: t, 166 | Format: "expected subsets not found:\nACTUAL:\n%s\nEXPECTED SUBSET\n%s", 167 | FormatArgs: []interface{}{spew.Sdump(actuals), tsdump(subsets)}, 168 | Extra: extra, 169 | }) 170 | } 171 | } 172 | 173 | // Nil ensures v is nil. 174 | func Nil(t Fataler, v interface{}, a ...interface{}) { 175 | vs := tsdump(v) 176 | sp := " " 177 | if strings.Contains(vs[:len(vs)-1], "\n") { 178 | sp = "\n" 179 | } 180 | 181 | if v != nil { 182 | // Special case errors for prettier output. 183 | if _, ok := v.(error); ok { 184 | fatal(cond{ 185 | Fataler: t, 186 | Format: `unexpected error: %s`, 187 | FormatArgs: []interface{}{v}, 188 | Extra: a, 189 | }) 190 | } else { 191 | fatal(cond{ 192 | Fataler: t, 193 | Format: "expected nil value but got:%s%s", 194 | FormatArgs: []interface{}{sp, vs}, 195 | Extra: a, 196 | }) 197 | } 198 | } 199 | } 200 | 201 | // NotNil ensures v is not nil. 202 | func NotNil(t Fataler, v interface{}, a ...interface{}) { 203 | if v == nil { 204 | fatal(cond{ 205 | Fataler: t, 206 | Format: "expected a value but got nil", 207 | Extra: a, 208 | }) 209 | } 210 | } 211 | 212 | // True ensures v is true. 213 | func True(t Fataler, v bool, a ...interface{}) { 214 | if !v { 215 | fatal(cond{ 216 | Fataler: t, 217 | Format: "expected true but got false", 218 | Extra: a, 219 | }) 220 | } 221 | } 222 | 223 | // False ensures v is false. 224 | func False(t Fataler, v bool, a ...interface{}) { 225 | if v { 226 | fatal(cond{ 227 | Fataler: t, 228 | Format: "expected false but got true", 229 | Extra: a, 230 | }) 231 | } 232 | } 233 | 234 | // StringContains ensures string s contains the string substr. 235 | func StringContains(t Fataler, s, substr string, a ...interface{}) { 236 | if !strings.Contains(s, substr) { 237 | format := `expected substring "%s" was not found in "%s"` 238 | 239 | // use multi line output if either string contains newlines 240 | if strings.Contains(s, "\n") || strings.Contains(substr, "\n") { 241 | format = "expected substring was not found:\nEXPECTED SUBSTRING:\n%s\nACTUAL:\n%s" 242 | } 243 | 244 | fatal(cond{ 245 | Fataler: t, 246 | Format: format, 247 | FormatArgs: []interface{}{substr, s}, 248 | Extra: a, 249 | }) 250 | } 251 | } 252 | 253 | // StringDoesNotContain ensures string s does not contain the string substr. 254 | func StringDoesNotContain(t Fataler, s, substr string, a ...interface{}) { 255 | if strings.Contains(s, substr) { 256 | fatal(cond{ 257 | Fataler: t, 258 | Format: `substring "%s" was not supposed to be found in "%s"`, 259 | FormatArgs: []interface{}{substr, s}, 260 | Extra: a, 261 | }) 262 | } 263 | } 264 | 265 | // SameElements ensures the two given slices contain the same elements, 266 | // ignoring the order. It uses DeepEqual for element comparison. 267 | func SameElements(t Fataler, actual, expected interface{}, extra ...interface{}) { 268 | actualSlice := toInterfaceSlice(actual) 269 | expectedSlice := toInterfaceSlice(expected) 270 | if len(actualSlice) != len(expectedSlice) { 271 | fatal(cond{ 272 | Fataler: t, 273 | Format: "expected same elements but found slices of different lengths:\nACTUAL:\n%s\nEXPECTED\n%s", 274 | FormatArgs: []interface{}{tsdump(actual), tsdump(expected)}, 275 | Extra: extra, 276 | }) 277 | } 278 | 279 | used := map[int]bool{} 280 | outer: 281 | for _, a := range expectedSlice { 282 | for i, b := range actualSlice { 283 | if !used[i] && reflect.DeepEqual(a, b) { 284 | used[i] = true 285 | continue outer 286 | } 287 | } 288 | fatal(cond{ 289 | Fataler: t, 290 | Format: "missing expected element:\nACTUAL:\n%s\nEXPECTED:\n%s\nMISSING ELEMENT\n%s", 291 | FormatArgs: []interface{}{tsdump(actual), tsdump(expected), tsdump(a)}, 292 | Extra: extra, 293 | }) 294 | } 295 | } 296 | 297 | // PanicDeepEqual ensures a panic occurs and the recovered value is DeepEqual 298 | // to the expected value. 299 | func PanicDeepEqual(t Fataler, expected interface{}, a ...interface{}) { 300 | if expected == nil { 301 | panic("can't pass nil to ensure.PanicDeepEqual") 302 | } 303 | actual := recover() 304 | if !reflect.DeepEqual(actual, expected) { 305 | fatal(cond{ 306 | Fataler: t, 307 | Format: "expected these to be equal:\nACTUAL:\n%s\nEXPECTED:\n%s", 308 | FormatArgs: []interface{}{spew.Sdump(actual), tsdump(expected)}, 309 | Extra: a, 310 | DisableDeleteSelf: true, 311 | }) 312 | } 313 | } 314 | 315 | // makes any slice into an []interface{} 316 | func toInterfaceSlice(v interface{}) []interface{} { 317 | rv := reflect.ValueOf(v) 318 | l := rv.Len() 319 | ret := make([]interface{}, l) 320 | for i := 0; i < l; i++ { 321 | ret[i] = rv.Index(i).Interface() 322 | } 323 | return ret 324 | } 325 | 326 | // tsdump is Sdump without the trailing newline. 327 | func tsdump(a ...interface{}) string { 328 | return strings.TrimSpace(spew.Sdump(a...)) 329 | } 330 | 331 | // pstack is the stack upto the Test function frame. 332 | func pstack(s stack.Stack, skipPrefix bool) string { 333 | first := s[0] 334 | if isTestFrame(first) { 335 | return fmt.Sprintf("%s:%d: ", filepath.Base(first.File), first.Line) 336 | } 337 | prefix := " " 338 | if skipPrefix { 339 | prefix = "" 340 | } 341 | var snew stack.Stack 342 | for _, f := range s { 343 | snew = append(snew, f) 344 | if isTestFrame(f) { 345 | return prefix + snew.String() + "\n" 346 | } 347 | } 348 | return prefix + s.String() + "\n" 349 | } 350 | 351 | func isTestFrame(f stack.Frame) bool { 352 | return strings.HasPrefix(f.Name, "Test") 353 | } 354 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/ensure/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For ensure software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/ensure/patents: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the ensure software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. 34 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/ensure/readme.md: -------------------------------------------------------------------------------- 1 | ensure [![Build Status](https://secure.travis-ci.org/facebookgo/ensure.png)](http://travis-ci.org/facebookgo/ensure) 2 | ====== 3 | 4 | Documentation: https://godoc.org/github.com/facebookgo/ensure 5 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.3 5 | 6 | matrix: 7 | fast_finish: true 8 | 9 | before_install: 10 | - if ! go get code.google.com/p/go.tools/cmd/vet; then go get golang.org/x/tools/cmd/vet; fi 11 | - go get -v github.com/golang/lint/golint 12 | - if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi 13 | 14 | install: 15 | - go install -race -v std 16 | - go get -race -t -v ./... 17 | - go install -race -v ./... 18 | 19 | script: 20 | - go vet ./... 21 | - $HOME/gopath/bin/golint . 22 | - go test -cpu=2 -race -v ./... 23 | - go test -cpu=2 -covermode=atomic ./... 24 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For stack software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/patents: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the stack software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. 34 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/readme.md: -------------------------------------------------------------------------------- 1 | # stack 2 | -- 3 | import "github.com/facebookgo/stack" 4 | 5 | Package stack provides utilities to capture and pass around stack traces. 6 | 7 | This is useful for building errors that know where they originated from, to 8 | track where a certain log event occured and so on. 9 | 10 | The package provides stack.Multi which represents a sequence of stack traces. 11 | Since in Go we return errors they don't necessarily end up with a single useful 12 | stack trace. For example an error may be going thru a channel across goroutines, 13 | in which case we may want to capture a stack trace in both (or many) goroutines. 14 | stack.Multi in turn is made up of stack.Stack, which is a set of stack.Frames. 15 | Each stack.Frame contains the File/Line/Name (function name). All these types 16 | implement a pretty human readable String() function. 17 | 18 | The GOPATH is stripped from the File location. Look at the StripGOPATH function 19 | on instructions for how to embed to GOPATH into the binary for when deploying to 20 | production and the GOPATH environment variable may not be set. The package name 21 | is stripped from the Name of the function since it included in the File 22 | location. 23 | 24 | ## Usage 25 | 26 | #### func StripGOPATH 27 | 28 | ```go 29 | func StripGOPATH(f string) string 30 | ``` 31 | StripGOPATH strips the GOPATH prefix from the file path f. In development, this 32 | will be done using the GOPATH environment variable. For production builds, where 33 | the GOPATH environment will not be set, the GOPATH can be included in the binary 34 | by passing ldflags, for example: 35 | 36 | GO_LDFLAGS="$GO_LDFLAGS -X github.com/facebookgo/stack.gopath $GOPATH" 37 | go install "-ldflags=$GO_LDFLAGS" my/pkg 38 | 39 | #### func StripPackage 40 | 41 | ```go 42 | func StripPackage(n string) string 43 | ``` 44 | StripPackage strips the package name from the given Func.Name. 45 | 46 | #### type Frame 47 | 48 | ```go 49 | type Frame struct { 50 | File string 51 | Line int 52 | Name string 53 | } 54 | ``` 55 | 56 | Frame identifies a file, line & function name in the stack. 57 | 58 | #### func Caller 59 | 60 | ```go 61 | func Caller(skip int) Frame 62 | ``` 63 | Caller returns a single Frame for the caller. The argument skip is the number of 64 | stack frames to ascend, with 0 identifying the caller of Callers. 65 | 66 | #### func (Frame) String 67 | 68 | ```go 69 | func (f Frame) String() string 70 | ``` 71 | String provides the standard file:line representation. 72 | 73 | #### type Multi 74 | 75 | ```go 76 | type Multi struct { 77 | } 78 | ``` 79 | 80 | Multi represents a number of Stacks. This is useful to allow tracking a value as 81 | it travels thru code. 82 | 83 | #### func CallersMulti 84 | 85 | ```go 86 | func CallersMulti(skip int) *Multi 87 | ``` 88 | CallersMulti returns a Multi which includes one Stack for the current callers. 89 | The argument skip is the number of stack frames to ascend, with 0 identifying 90 | the caller of CallersMulti. 91 | 92 | #### func (*Multi) Add 93 | 94 | ```go 95 | func (m *Multi) Add(s Stack) 96 | ``` 97 | Add the given Stack to this Multi. 98 | 99 | #### func (*Multi) AddCallers 100 | 101 | ```go 102 | func (m *Multi) AddCallers(skip int) 103 | ``` 104 | AddCallers adds the Callers Stack to this Multi. The argument skip is the number 105 | of stack frames to ascend, with 0 identifying the caller of Callers. 106 | 107 | #### func (*Multi) Stacks 108 | 109 | ```go 110 | func (m *Multi) Stacks() []Stack 111 | ``` 112 | Stacks returns the tracked Stacks. 113 | 114 | #### func (*Multi) String 115 | 116 | ```go 117 | func (m *Multi) String() string 118 | ``` 119 | String provides a human readable multi-line stack trace. 120 | 121 | #### type Stack 122 | 123 | ```go 124 | type Stack []Frame 125 | ``` 126 | 127 | Stack represents an ordered set of Frames. 128 | 129 | #### func Callers 130 | 131 | ```go 132 | func Callers(skip int) Stack 133 | ``` 134 | Callers returns a Stack of Frames for the callers. The argument skip is the 135 | number of stack frames to ascend, with 0 identifying the caller of Callers. 136 | 137 | #### func (Stack) String 138 | 139 | ```go 140 | func (s Stack) String() string 141 | ``` 142 | String provides the standard multi-line stack trace. 143 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/stack/stack.go: -------------------------------------------------------------------------------- 1 | // Package stack provides utilities to capture and pass around stack traces. 2 | // 3 | // This is useful for building errors that know where they originated from, to 4 | // track where a certain log event occured and so on. 5 | // 6 | // The package provides stack.Multi which represents a sequence of stack 7 | // traces. Since in Go we return errors they don't necessarily end up with a 8 | // single useful stack trace. For example an error may be going thru a channel 9 | // across goroutines, in which case we may want to capture a stack trace in 10 | // both (or many) goroutines. stack.Multi in turn is made up of stack.Stack, 11 | // which is a set of stack.Frames. Each stack.Frame contains the File/Line/Name 12 | // (function name). All these types implement a pretty human readable String() 13 | // function. 14 | // 15 | // The GOPATH is stripped from the File location. Look at the StripGOPATH 16 | // function on instructions for how to embed to GOPATH into the binary for when 17 | // deploying to production and the GOPATH environment variable may not be set. 18 | // The package name is stripped from the Name of the function since it included 19 | // in the File location. 20 | package stack 21 | 22 | import ( 23 | "bytes" 24 | "fmt" 25 | "os" 26 | "path/filepath" 27 | "runtime" 28 | "strings" 29 | ) 30 | 31 | const maxStackSize = 32 32 | 33 | // Frame identifies a file, line & function name in the stack. 34 | type Frame struct { 35 | File string 36 | Line int 37 | Name string 38 | } 39 | 40 | // String provides the standard file:line representation. 41 | func (f Frame) String() string { 42 | return fmt.Sprintf("%s:%d %s", f.File, f.Line, f.Name) 43 | } 44 | 45 | // Stack represents an ordered set of Frames. 46 | type Stack []Frame 47 | 48 | // String provides the standard multi-line stack trace. 49 | func (s Stack) String() string { 50 | var b bytes.Buffer 51 | writeStack(&b, s) 52 | return b.String() 53 | } 54 | 55 | // Multi represents a number of Stacks. This is useful to allow tracking a 56 | // value as it travels thru code. 57 | type Multi struct { 58 | stacks []Stack 59 | } 60 | 61 | // Stacks returns the tracked Stacks. 62 | func (m *Multi) Stacks() []Stack { 63 | return m.stacks 64 | } 65 | 66 | // Add the given Stack to this Multi. 67 | func (m *Multi) Add(s Stack) { 68 | m.stacks = append(m.stacks, s) 69 | } 70 | 71 | // AddCallers adds the Callers Stack to this Multi. The argument skip is 72 | // the number of stack frames to ascend, with 0 identifying the caller of 73 | // Callers. 74 | func (m *Multi) AddCallers(skip int) { 75 | m.Add(Callers(skip + 1)) 76 | } 77 | 78 | // String provides a human readable multi-line stack trace. 79 | func (m *Multi) String() string { 80 | var b bytes.Buffer 81 | for i, s := range m.stacks { 82 | if i != 0 { 83 | fmt.Fprintf(&b, "\n(Stack %d)\n", i+1) 84 | } 85 | writeStack(&b, s) 86 | } 87 | return b.String() 88 | } 89 | 90 | // Copy makes a copy of the stack which is safe to modify. 91 | func (m *Multi) Copy() *Multi { 92 | m2 := &Multi{ 93 | stacks: make([]Stack, len(m.stacks)), 94 | } 95 | copy(m2.stacks, m.stacks) 96 | return m2 97 | } 98 | 99 | // Caller returns a single Frame for the caller. The argument skip is the 100 | // number of stack frames to ascend, with 0 identifying the caller of Callers. 101 | func Caller(skip int) Frame { 102 | pc, file, line, _ := runtime.Caller(skip + 1) 103 | fun := runtime.FuncForPC(pc) 104 | return Frame{ 105 | File: StripGOPATH(file), 106 | Line: line, 107 | Name: StripPackage(fun.Name()), 108 | } 109 | } 110 | 111 | // Callers returns a Stack of Frames for the callers. The argument skip is the 112 | // number of stack frames to ascend, with 0 identifying the caller of Callers. 113 | func Callers(skip int) Stack { 114 | pcs := make([]uintptr, maxStackSize) 115 | num := runtime.Callers(skip+2, pcs) 116 | stack := make(Stack, num) 117 | for i, pc := range pcs[:num] { 118 | fun := runtime.FuncForPC(pc) 119 | file, line := fun.FileLine(pc - 1) 120 | stack[i].File = StripGOPATH(file) 121 | stack[i].Line = line 122 | stack[i].Name = StripPackage(fun.Name()) 123 | } 124 | return stack 125 | } 126 | 127 | // CallersMulti returns a Multi which includes one Stack for the 128 | // current callers. The argument skip is the number of stack frames to ascend, 129 | // with 0 identifying the caller of CallersMulti. 130 | func CallersMulti(skip int) *Multi { 131 | m := new(Multi) 132 | m.AddCallers(skip + 1) 133 | return m 134 | } 135 | 136 | func writeStack(b *bytes.Buffer, s Stack) { 137 | var width int 138 | for _, f := range s { 139 | if l := len(f.File) + numDigits(f.Line) + 1; l > width { 140 | width = l 141 | } 142 | } 143 | last := len(s) - 1 144 | for i, f := range s { 145 | b.WriteString(f.File) 146 | b.WriteRune(rune(':')) 147 | n, _ := fmt.Fprintf(b, "%d", f.Line) 148 | for i := width - len(f.File) - n; i != 0; i-- { 149 | b.WriteRune(rune(' ')) 150 | } 151 | b.WriteString(f.Name) 152 | if i != last { 153 | b.WriteRune(rune('\n')) 154 | } 155 | } 156 | } 157 | 158 | func numDigits(i int) int { 159 | var n int 160 | for { 161 | n++ 162 | i = i / 10 163 | if i == 0 { 164 | return n 165 | } 166 | } 167 | } 168 | 169 | var ( 170 | // This can be set by a build script. It will be the colon separated equivalent 171 | // of the environment variable. 172 | gopath string 173 | 174 | // This is the processed version based on either the above variable set by the 175 | // build or from the GOPATH environment variable. 176 | gopaths []string 177 | ) 178 | 179 | func init() { 180 | // prefer the variable set at build time, otherwise fallback to the 181 | // environment variable. 182 | if gopath == "" { 183 | gopath = os.Getenv("GOPATH") 184 | } 185 | SetGOPATH(gopath) 186 | } 187 | 188 | // StripGOPATH strips the GOPATH prefix from the file path f. 189 | // In development, this will be done using the GOPATH environment variable. 190 | // For production builds, where the GOPATH environment will not be set, the 191 | // GOPATH can be included in the binary by passing ldflags, for example: 192 | // 193 | // GO_LDFLAGS="$GO_LDFLAGS -X github.com/facebookgo/stack.gopath $GOPATH" 194 | // go install "-ldflags=$GO_LDFLAGS" my/pkg 195 | func StripGOPATH(f string) string { 196 | for _, p := range gopaths { 197 | if strings.HasPrefix(f, p) { 198 | return f[len(p):] 199 | } 200 | } 201 | return f 202 | } 203 | 204 | // SetGOPATH configures the GOPATH to enable relative paths in stack traces. 205 | func SetGOPATH(gp string) { 206 | gopath = gp 207 | gopaths = nil 208 | 209 | for _, p := range strings.Split(gopath, ":") { 210 | if p != "" { 211 | gopaths = append(gopaths, filepath.Join(p, "src")+"/") 212 | } 213 | } 214 | 215 | // Also strip GOROOT for maximum cleanliness 216 | gopaths = append(gopaths, filepath.Join(runtime.GOROOT(), "src", "pkg")+"/") 217 | } 218 | 219 | // StripPackage strips the package name from the given Func.Name. 220 | func StripPackage(n string) string { 221 | slashI := strings.LastIndex(n, "/") 222 | if slashI == -1 { 223 | slashI = 0 // for built-in packages 224 | } 225 | dotI := strings.Index(n[slashI:], ".") 226 | if dotI == -1 { 227 | return n 228 | } 229 | return n[slashI+dotI+1:] 230 | } 231 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/subset/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.2 5 | - 1.3 6 | 7 | matrix: 8 | fast_finish: true 9 | 10 | before_install: 11 | - go get -v code.google.com/p/go.tools/cmd/vet 12 | - go get -v github.com/golang/lint/golint 13 | - go get -v code.google.com/p/go.tools/cmd/cover 14 | 15 | install: 16 | - go install -race -v std 17 | - go get -race -t -v ./... 18 | - go install -race -v ./... 19 | 20 | script: 21 | - go vet ./... 22 | - $HOME/gopath/bin/golint . 23 | - go test -cpu=2 -race -v ./... 24 | - go test -cpu=2 -covermode=atomic ./... 25 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/subset/license: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | For subset software 4 | 5 | Copyright (c) 2015, Facebook, Inc. All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name Facebook nor the names of its contributors may be used to 18 | endorse or promote products derived from this software without specific 19 | prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 22 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 25 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 28 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/subset/patents: -------------------------------------------------------------------------------- 1 | Additional Grant of Patent Rights Version 2 2 | 3 | "Software" means the subset software distributed by Facebook, Inc. 4 | 5 | Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software 6 | ("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable 7 | (subject to the termination provision below) license under any Necessary 8 | Claims, to make, have made, use, sell, offer to sell, import, and otherwise 9 | transfer the Software. For avoidance of doubt, no license is granted under 10 | Facebook’s rights in any patent claims that are infringed by (i) modifications 11 | to the Software made by you or any third party or (ii) the Software in 12 | combination with any software or other technology. 13 | 14 | The license granted hereunder will terminate, automatically and without notice, 15 | if you (or any of your subsidiaries, corporate affiliates or agents) initiate 16 | directly or indirectly, or take a direct financial interest in, any Patent 17 | Assertion: (i) against Facebook or any of its subsidiaries or corporate 18 | affiliates, (ii) against any party if such Patent Assertion arises in whole or 19 | in part from any software, technology, product or service of Facebook or any of 20 | its subsidiaries or corporate affiliates, or (iii) against any party relating 21 | to the Software. Notwithstanding the foregoing, if Facebook or any of its 22 | subsidiaries or corporate affiliates files a lawsuit alleging patent 23 | infringement against you in the first instance, and you respond by filing a 24 | patent infringement counterclaim in that lawsuit against that party that is 25 | unrelated to the Software, the license granted hereunder will not terminate 26 | under section (i) of this paragraph due to such counterclaim. 27 | 28 | A "Necessary Claim" is a claim of a patent owned by Facebook that is 29 | necessarily infringed by the Software standing alone. 30 | 31 | A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, 32 | or contributory infringement or inducement to infringe any patent, including a 33 | cross-claim or counterclaim. 34 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/subset/readme.md: -------------------------------------------------------------------------------- 1 | subset [![Build Status](https://secure.travis-ci.org/facebookgo/subset.png)](http://travis-ci.org/facebookgo/subset) 2 | ====== 3 | 4 | Check if a value is a subset of another, based on reflect/deepequals.go. 5 | Documentation: http://godoc.org/github.com/facebookgo/subset 6 | -------------------------------------------------------------------------------- /vendor/github.com/facebookgo/subset/subset.go: -------------------------------------------------------------------------------- 1 | // Package subset implements logic to check if a value is a subset of 2 | // another using reflect. 3 | package subset 4 | 5 | import ( 6 | "reflect" 7 | ) 8 | 9 | // During checkSubset, must keep track of checks that are 10 | // in progress. The comparison algorithm assumes that all 11 | // checks in progress are true when it reencounters them. 12 | // Visited are stored in a map indexed by 17 * a1 + a2; 13 | type visit struct { 14 | a1 uintptr 15 | a2 uintptr 16 | typ reflect.Type 17 | next *visit 18 | } 19 | 20 | // Fatalf is how our assertion will fail. 21 | type Fatalf interface { 22 | Fatalf(format string, args ...interface{}) 23 | } 24 | 25 | // Ideally we'ed be able to use reflec.valueInterface(v, false) and 26 | // look at unexported fields, but for now we just ignore them. 27 | func safeInterface(v reflect.Value) (i interface{}) { 28 | defer func() { 29 | if err := recover(); err != nil { 30 | // fmt.Println("Recovered safeInterface:", err) 31 | i = nil 32 | } 33 | }() 34 | return v.Interface() 35 | } 36 | 37 | // Tests for deep equality using reflected types. The map argument tracks 38 | // comparisons that have already been seen, which allows short circuiting on 39 | // recursive types. 40 | func checkSubset(expected, target reflect.Value, visited map[uintptr]*visit, depth int) (b bool) { 41 | if !expected.IsValid() { 42 | // fmt.Println("!expected.IsValid()") 43 | return true 44 | } 45 | if !target.IsValid() { 46 | // fmt.Println("!target.IsValid()") 47 | return false 48 | } 49 | if expected.Type() != target.Type() { 50 | // fmt.Println("Type() differs") 51 | return false 52 | } 53 | 54 | // if depth > 10 { panic("checkSubset") } // for debugging 55 | 56 | if expected.CanAddr() && target.CanAddr() { 57 | addr1 := expected.UnsafeAddr() 58 | addr2 := target.UnsafeAddr() 59 | if addr1 > addr2 { 60 | // Canonicalize order to reduce number of entries in visited. 61 | addr1, addr2 = addr2, addr1 62 | } 63 | 64 | // Short circuit if references are identical ... 65 | if addr1 == addr2 { 66 | return true 67 | } 68 | 69 | // ... or already seen 70 | h := 17*addr1 + addr2 71 | seen := visited[h] 72 | typ := expected.Type() 73 | for p := seen; p != nil; p = p.next { 74 | if p.a1 == addr1 && p.a2 == addr2 && p.typ == typ { 75 | return true 76 | } 77 | } 78 | 79 | // Remember for later. 80 | visited[h] = &visit{addr1, addr2, typ, seen} 81 | } 82 | 83 | switch expected.Kind() { 84 | case reflect.Array: 85 | // fmt.Println("Kind: Array") 86 | if expected.Len() == 0 { 87 | return true 88 | } 89 | if expected.Len() != target.Len() { 90 | return false 91 | } 92 | for i := 0; i < expected.Len(); i++ { 93 | if !checkSubset(expected.Index(i), target.Index(i), visited, depth+1) { 94 | return false 95 | } 96 | } 97 | return true 98 | case reflect.Slice: 99 | // fmt.Println("Kind: Slice") 100 | if expected.IsNil() { 101 | return true 102 | } 103 | if expected.IsNil() != target.IsNil() { 104 | return false 105 | } 106 | if expected.Len() != target.Len() { 107 | return false 108 | } 109 | for i := 0; i < expected.Len(); i++ { 110 | if !checkSubset(expected.Index(i), target.Index(i), visited, depth+1) { 111 | return false 112 | } 113 | } 114 | return true 115 | case reflect.Interface: 116 | // fmt.Println("Kind: Interface") 117 | if expected.IsNil() { 118 | return true 119 | } 120 | if expected.IsNil() || target.IsNil() { 121 | return expected.IsNil() == target.IsNil() 122 | } 123 | return checkSubset(expected.Elem(), target.Elem(), visited, depth+1) 124 | case reflect.Ptr: 125 | // fmt.Println("Kind: Ptr") 126 | return checkSubset(expected.Elem(), target.Elem(), visited, depth+1) 127 | case reflect.Struct: 128 | // fmt.Println("Kind: Struct") 129 | for i, n := 0, expected.NumField(); i < n; i++ { 130 | if !checkSubset(expected.Field(i), target.Field(i), visited, depth+1) { 131 | return false 132 | } 133 | } 134 | return true 135 | case reflect.Map: 136 | // fmt.Println("Kind: Map") 137 | if expected.IsNil() { 138 | return true 139 | } 140 | if expected.IsNil() != target.IsNil() { 141 | return false 142 | } 143 | for _, k := range expected.MapKeys() { 144 | if !checkSubset(expected.MapIndex(k), target.MapIndex(k), visited, depth+1) { 145 | return false 146 | } 147 | } 148 | return true 149 | case reflect.Func: 150 | // fmt.Println("Kind: Func") 151 | if expected.IsNil() && target.IsNil() { 152 | return true 153 | } 154 | // Can't do better than this: 155 | return false 156 | default: 157 | expectedInterface := safeInterface(expected) 158 | if expectedInterface == nil { 159 | return true 160 | } 161 | targetInterface := target.Interface() // expect this to be safe now 162 | // fmt.Println("Kind: default", expectedInterface, targetInterface) 163 | // ignore zero value expectations 164 | zeroValue := reflect.Zero(expected.Type()) 165 | if reflect.DeepEqual(expectedInterface, zeroValue.Interface()) { 166 | // fmt.Println("Expecting zero value") 167 | return true 168 | } 169 | 170 | // Normal equality suffices 171 | return reflect.DeepEqual(expectedInterface, targetInterface) 172 | } 173 | } 174 | 175 | // Check tests for deep subset. It uses normal == equality where 176 | // possible but will scan members of arrays, slices, maps, and fields of 177 | // structs. It correctly handles recursive types. Functions are equal 178 | // only if they are both nil. 179 | func Check(expected, target interface{}) bool { 180 | if expected == nil { 181 | return true 182 | } 183 | if target == nil { 184 | return false 185 | } 186 | return checkSubset( 187 | reflect.ValueOf(expected), 188 | reflect.ValueOf(target), 189 | make(map[uintptr]*visit), 190 | 0) 191 | } 192 | 193 | // Assert will fatal if not a subset with a useful message. 194 | // TODO should pretty print and show a colored side-by-side diff? 195 | func Assert(t Fatalf, expected interface{}, actual interface{}) { 196 | if !Check(expected, actual) { 197 | t.Fatalf("Did not find expected subset:\n%+v\nInstead found:\n%+v", 198 | expected, actual) 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/davecgh/go-spew v1.1.0 2 | github.com/davecgh/go-spew/spew 3 | # github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 4 | github.com/facebookgo/ensure 5 | # github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 6 | github.com/facebookgo/stack 7 | # github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 8 | github.com/facebookgo/subset 9 | --------------------------------------------------------------------------------