diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1f333fc..0000000 --- a/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go - -go: - - 1.3 - - 1.4 - - 1.5 - - tip - -install: - - go get -v "github.com/smartystreets/goconvey" - - go get -v "github.com/op/go-logging" - -script: - - go test -run="TestJustToTest" diff --git a/LICENSE b/LICENSE index 2ee90d9..9e6e8ef 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -The MIT License (MIT) - -Copyright (c) 2015 Nevio Vesic - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2023] [GoESL Community] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index c706a9d..6c8371d 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,18 @@ -[![License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/0x19/goesl/tree/master/LICENSE) -[![Build Status](https://travis-ci.org/0x19/goesl.svg)](https://travis-ci.org/0x19/goesl) -[![Go 1.3 Ready](https://img.shields.io/badge/Go%201.3-Ready-green.svg?style=flat)]() -[![Go 1.4 Ready](https://img.shields.io/badge/Go%201.4-Ready-green.svg?style=flat)]() -[![Go 1.5 Ready](https://img.shields.io/badge/Go%201.5-Ready-green.svg?style=flat)]() + ##FreeSWITCH Event Socket Library Wrapper for Go GoESL is a small wrapper around [FreeSWITCH](https://freeswitch.org/) [Event Socket Library](https://wiki.freeswitch.org/wiki/Event_Socket_Library) written in [Go](http://golang.org). -Point of this library is to fully implement FreeSWITCH ESL and bring outbound server as inbound client to you, fellow Go developer :) - - -### TODO? - -You can find what still needs to be done at [GoESL TODO](https://github.com/0x19/goesl/blob/master/TODO.md) - - -### Examples - -There are few different types of examples that can be found at [GoESL Examples](https://github.com/0x19/goesl/tree/master/examples). - -Feel free to suggest more examples :) - - -### Contributions / Issues? - -Please reach me over nevio.vesic@gmail.com or visit my [website](http://www.neviovesic.com/) or submit new [issue](https://github.com/0x19/goesl/issues/new). I'd prefer tho if you would submit [issue](https://github.com/0x19/goesl/issues/new). - +## REWRITE.... -### License +To be defined... -The MIT License (MIT) +## Contributing -Copyright (c) 2015 Nevio Vesic +Contributions to SolGo are always welcome! If you have a feature request, bug report, or proposal for improvement, please open an issue. If you wish to contribute code, please fork the repository, make your changes, and submit a pull request. -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +## License -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +SolGo is licensed under the Apache 2.0. See [LICENSE](LICENSE) for the full license text. diff --git a/TODO.md b/TODO.md deleted file mode 100644 index d8ee232..0000000 --- a/TODO.md +++ /dev/null @@ -1,8 +0,0 @@ -## Still needs to be done - -List of things that I still need to do in order to make GoESL completed - -[x] Better documentation -[x] FreeSWITCH WIKI Golang page (proposal) -[] Unit testing -[] More examples \ No newline at end of file diff --git a/client.go b/client.go deleted file mode 100644 index 70abc38..0000000 --- a/client.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -import ( - "bufio" - "fmt" - "time" -) - -// Client - In case you need to do inbound dialing against freeswitch server in order to originate call or see -// sofia statuses or whatever else you came up with -type Client struct { - SocketConnection - - Proto string `json:"freeswitch_protocol"` - Addr string `json:"freeswitch_addr"` - Passwd string `json:"freeswitch_password"` - Timeout int `json:"freeswitch_connection_timeout"` -} - -// EstablishConnection - Will attempt to establish connection against freeswitch and create new SocketConnection -func (c *Client) EstablishConnection() error { - conn, err := c.Dial(c.Proto, c.Addr, time.Duration(c.Timeout*int(time.Second))) - - c.SocketConnection = SocketConnection{ - Conn: conn, - err: make(chan error), - m: make(chan *Message), - } - - return err -} - -// Authenticate - Method used to authenticate client against freeswitch. In case of any errors durring so -// we will return error. -func (c *Client) Authenticate() error { - - m, err := newMessage(bufio.NewReaderSize(c, ReadBufferSize), false) - - if err != nil { - Error(ECouldNotCreateMessage, err) - return err - } - - cmr, err := m.tr.ReadMIMEHeader() - - Debug("A: %v %v ", cmr, err) - - if err != nil && err.Error() != "EOF" { - Error(ECouldNotReadMIMEHeaders, err) - return err - } - - if cmr.Get("Content-Type") != "auth/request" { - Error(EUnexpectedAuthHeader, cmr.Get("Content-Type")) - return fmt.Errorf(EUnexpectedAuthHeader, cmr.Get("Content-Type")) - } - - fmt.Fprintf(c, "auth %s\r\n\r\n", c.Passwd) - - am, err := m.tr.ReadMIMEHeader() - - if err != nil && err.Error() != "EOF" { - Error(ECouldNotReadMIMEHeaders, err) - return err - } - - if am.Get("Reply-Text") != "+OK accepted" { - Error(EInvalidPassword, c.Passwd) - return fmt.Errorf(EInvalidPassword, c.Passwd) - } - - return nil -} - -// NewClient - Will initiate new client that will establish connection and attempt to authenticate -// against connected freeswitch server -func NewClient(host string, port uint, passwd string, timeout int) (Client, error) { - client := Client{ - Proto: "tcp", // Let me know if you ever need this open up lol - Addr: fmt.Sprintf("%s:%d", host, port), - Passwd: passwd, - Timeout: timeout, - } - - if err := client.EstablishConnection(); err != nil { - return client, err - } - - if err := client.Authenticate(); err != nil { - client.Close() - return client, err - } - - return client, nil -} diff --git a/connection.go b/connection.go deleted file mode 100644 index 1966c47..0000000 --- a/connection.go +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -import ( - "bufio" - "bytes" - "fmt" - "net" - "strconv" - "strings" - "time" -) - -// Main connection against ESL - Gotta add more description here -type SocketConnection struct { - net.Conn - err chan error - m chan *Message -} - -// Dial - Will establish timedout dial against specified address. In this case, it will be freeswitch server -func (c *SocketConnection) Dial(network string, addr string, timeout time.Duration) (net.Conn, error) { - return net.DialTimeout(network, addr, timeout) -} - -// Send - Will send raw message to open net connection -func (c *SocketConnection) Send(cmd string) error { - - if strings.Contains(cmd, "\r\n") { - fmt.Errorf(EInvalidCommandProvided, cmd) - } - - fmt.Fprintf(c, "%s\r\n\r\n", cmd) - - return nil -} - -// SendMany - Will loop against passed commands and return 1st error if error happens -func (c *SocketConnection) SendMany(cmds []string) error { - - for _, cmd := range cmds { - if err := c.Send(cmd); err != nil { - return err - } - } - - return nil -} - -// Execute - Helper fuck to execute commands with its args and sync/async mode -func (c *SocketConnection) Execute(command, args string, sync bool) (m *Message, err error) { - return c.SendMsg(map[string]string{ - "call-command": "execute", - "execute-app-name": command, - "execute-app-arg": args, - "event-lock": strconv.FormatBool(sync), - }, "", "") -} - -// ExecuteUUID - Helper fuck to execute uuid specific commands with its args and sync/async mode -func (c *SocketConnection) ExecuteUUID(uuid string, command string, args string, sync bool) (m *Message, err error) { - return c.SendMsg(map[string]string{ - "call-command": "execute", - "execute-app-name": command, - "execute-app-arg": args, - "event-lock": strconv.FormatBool(sync), - }, uuid, "") -} - -// SendMsg - Basically this func will send message to the opened connection -func (c *SocketConnection) SendMsg(msg map[string]string, uuid, data string) (m *Message, err error) { - - b := bytes.NewBufferString("sendmsg") - - if uuid != "" { - if strings.Contains(uuid, "\r\n") { - return nil, fmt.Errorf(EInvalidCommandProvided, msg) - } - - b.WriteString(" " + uuid) - } - - b.WriteString("\n") - - for k, v := range msg { - if strings.Contains(k, "\r\n") { - return nil, fmt.Errorf(EInvalidCommandProvided, msg) - } - - if v != "" { - if strings.Contains(v, "\r\n") { - return nil, fmt.Errorf(EInvalidCommandProvided, msg) - } - - b.WriteString(fmt.Sprintf("%s: %s\n", k, v)) - } - } - - b.WriteString("\n") - - if msg["content-length"] != "" && data != "" { - b.WriteString(data) - } - - if _, err := b.WriteTo(c); err != nil { - return nil, err - } - - select { - case err := <-c.err: - return nil, err - case m := <-c.m: - return m, nil - } -} - -// OriginatorAdd - Will return originator address known as net.RemoteAddr() -// This will actually be a freeswitch address -func (c *SocketConnection) OriginatorAddr() net.Addr { - return c.RemoteAddr() -} - -// ReadMessage - Will read message from channels and return them back accordingy. -// If error is received, error will be returned. If not, message will be returned back! -func (c *SocketConnection) ReadMessage() (*Message, error) { - Debug("Waiting for connection message to be received ...") - - select { - case err := <-c.err: - return nil, err - case msg := <-c.m: - return msg, nil - } -} - -// Handle - Will handle new messages and close connection when there are no messages left to process -func (c *SocketConnection) Handle() { - - done := make(chan bool) - - go func() { - for { - msg, err := newMessage(bufio.NewReaderSize(c, ReadBufferSize), true) - - if err != nil { - c.err <- err - done <- true - break - } - - c.m <- msg - } - }() - - <-done - - // Closing the connection now as there's nothing left to do ... - c.Close() -} - -// Close - Will close down net connection and return error if error happen -func (c *SocketConnection) Close() error { - if err := c.Conn.Close(); err != nil { - return err - } - - return nil -} diff --git a/errors.go b/errors.go deleted file mode 100644 index 959c702..0000000 --- a/errors.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -var ( - EInvalidCommandProvided = "Invalid command provided. Command cannot contain \\r and/or \\n. Provided command is: %s" - ECouldNotReadMIMEHeaders = "Error while reading MIME headers: %s" - EInvalidContentLength = "Unable to get size of content-length: %s" - EUnsuccessfulReply = "Got error while reading from reply command: %s" - ECouldNotReadyBody = "Got error while reading reader body: %s" - EUnsupportedMessageType = "Unsupported message type! We got '%s'. Supported types are: %v " - ECouldNotDecode = "Could not decode/unescape message: %s" - ECouldNotStartListener = "Got error while attempting to start listener: %s" - EListenerConnection = "Listener connection error: %s" - EInvalidServerAddr = "Please make sure to pass along valid address. You've passed: \"%s\"" - EUnexpectedAuthHeader = "Expected auth/request content type. Got %s" - EInvalidPassword = "Could not authenticate against freeswitch with provided password: %s" - ECouldNotCreateMessage = "Error while creating new message: %s" -) diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index d478a56..0000000 --- a/examples/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -server -server_playback -server_tts -client \ No newline at end of file diff --git a/examples/client.go b/examples/client.go deleted file mode 100644 index f299f0b..0000000 --- a/examples/client.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package examples - -import ( - "flag" - "fmt" - . "github.com/0x19/goesl" - "runtime" - "strings" -) - -var ( - fshost = flag.String("fshost", "localhost", "Freeswitch hostname. Default: localhost") - fsport = flag.Uint("fsport", 8021, "Freeswitch port. Default: 8021") - password = flag.String("pass", "ClueCon", "Freeswitch password. Default: ClueCon") - timeout = flag.Int("timeout", 10, "Freeswitch conneciton timeout in seconds. Default: 10") -) - -// Small client that will first make sure all events are returned as JSON and second, will originate -func main() { - - // Boost it as much as it can go ... - runtime.GOMAXPROCS(runtime.NumCPU()) - - client, err := NewClient(*fshost, *fsport, *password, *timeout) - - if err != nil { - Error("Error while creating new client: %s", err) - return - } - - Debug("Yuhu! New client: %q", client) - - // Apparently all is good... Let us now handle connection :) - // We don't want this to be inside of new connection as who knows where it my lead us. - // Remember that this is crutial part in handling incoming messages :) - go client.Handle() - - client.Send("events json ALL") - - client.BgApi(fmt.Sprintf("originate %s %s", "sofia/internal/1001@127.0.0.1", "&socket(192.168.1.2:8084 async full)")) - - for { - msg, err := client.ReadMessage() - - if err != nil { - - // If it contains EOF, we really dont care... - if !strings.Contains(err.Error(), "EOF") && err.Error() != "unexpected end of JSON input" { - Error("Error while reading Freeswitch message: %s", err) - } - break - } - - Debug("%s", msg) - } -} diff --git a/examples/media/welcome.wav b/examples/media/welcome.wav deleted file mode 100644 index 060ba7a..0000000 Binary files a/examples/media/welcome.wav and /dev/null differ diff --git a/examples/server_playback.go b/examples/server_playback.go deleted file mode 100644 index 1d7bb21..0000000 --- a/examples/server_playback.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package examples - -import ( - "fmt" - . "github.com/0x19/goesl" - "os" - "runtime" - "strings" -) - -var welcomeFile = "%s/media/welcome.wav" - -func main() { - - defer func() { - if r := recover(); r != nil { - Error("Recovered in f", r) - } - }() - - // Boost it as much as it can go ... - runtime.GOMAXPROCS(runtime.NumCPU()) - - wd, err := os.Getwd() - - if err != nil { - Error("Error while attempt to get WD: %s", wd) - os.Exit(1) - } - - welcomeFile = fmt.Sprintf(welcomeFile, wd) - - if s, err := NewOutboundServer(":8084"); err != nil { - Error("Got error while starting Freeswitch outbound server: %s", err) - } else { - go handle(s) - s.Start() - } - -} - -// handle - Running under goroutine here to explain how to handle playback ( play to the caller ) -func handle(s *OutboundServer) { - - for { - - select { - - case conn := <-s.Conns: - Notice("New incomming connection: %v", conn) - - if err := conn.Connect(); err != nil { - Error("Got error while accepting connection: %s", err) - break - } - - answer, err := conn.ExecuteAnswer("", false) - - if err != nil { - Error("Got error while executing answer: %s", err) - break - } - - Debug("Answer Message: %s", answer) - Debug("Caller UUID: %s", answer.GetHeader("Caller-Unique-Id")) - - cUUID := answer.GetCallUUID() - - if sm, err := conn.Execute("playback", welcomeFile, true); err != nil { - Error("Got error while executing playback: %s", err) - break - } else { - Debug("Playback Message: %s", sm) - } - - if hm, err := conn.ExecuteHangup(cUUID, "", false); err != nil { - Error("Got error while executing hangup: %s", err) - break - } else { - Debug("Hangup Message: %s", hm) - } - - go func() { - for { - msg, err := conn.ReadMessage() - - if err != nil { - - // If it contains EOF, we really dont care... - if !strings.Contains(err.Error(), "EOF") { - Error("Error while reading Freeswitch message: %s", err) - } - break - } - - Debug("%s", msg) - } - }() - - default: - // YabbaDabbaDooooo! - //Flintstones. Meet the Flintstones. They're the modern stone age family. From the town of Bedrock, - // They're a page right out of history. La la,lalalalala la :D - } - } - -} diff --git a/examples/server_tts.go b/examples/server_tts.go deleted file mode 100644 index b60e4fc..0000000 --- a/examples/server_tts.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package examples - -import ( - . "github.com/0x19/goesl" - "runtime" - "strings" -) - -var ( - goeslMessage = "Hello from GoESL. Open source freeswitch event socket wrapper written in Golang!" -) - -func main() { - - defer func() { - if r := recover(); r != nil { - Error("Recovered in: ", r) - } - }() - - // Boost it as much as it can go ... - runtime.GOMAXPROCS(runtime.NumCPU()) - - if s, err := NewOutboundServer(":8084"); err != nil { - Error("Got error while starting Freeswitch outbound server: %s", err) - } else { - go handle(s) - s.Start() - } - -} - -// handle - Running under goroutine here to explain how to run tts outbound server -func handle(s *OutboundServer) { - - for { - - select { - - case conn := <-s.Conns: - Notice("New incomming connection: %v", conn) - - if err := conn.Connect(); err != nil { - Error("Got error while accepting connection: %s", err) - break - } - - answer, err := conn.ExecuteAnswer("", false) - - if err != nil { - Error("Got error while executing answer: %s", err) - break - } - - Debug("Answer Message: %s", answer) - Debug("Caller UUID: %s", answer.GetHeader("Caller-Unique-Id")) - - cUUID := answer.GetCallUUID() - - if te, err := conn.ExecuteSet("tts_engine", "flite", false); err != nil { - Error("Got error while attempting to set tts_engine: %s", err) - } else { - Debug("TTS Engine Msg: %s", te) - } - - if tv, err := conn.ExecuteSet("tts_voice", "slt", false); err != nil { - Error("Got error while attempting to set tts_voice: %s", err) - } else { - Debug("TTS Voice Msg: %s", tv) - } - - if sm, err := conn.Execute("speak", goeslMessage, true); err != nil { - Error("Got error while executing speak: %s", err) - break - } else { - Debug("Speak Message: %s", sm) - } - - if hm, err := conn.ExecuteHangup(cUUID, "", false); err != nil { - Error("Got error while executing hangup: %s", err) - break - } else { - Debug("Hangup Message: %s", hm) - } - - go func() { - for { - msg, err := conn.ReadMessage() - - if err != nil { - - // If it contains EOF, we really dont care... - if !strings.Contains(err.Error(), "EOF") { - Error("Error while reading Freeswitch message: %s", err) - } - break - } - - Debug("%s", msg) - } - }() - - default: - // YabbaDabbaDooooo! - //Flintstones. Meet the Flintstones. They're the modern stone age family. From the town of Bedrock, - // They're a page right out of history. La la,lalalalala la :D - } - } - -} diff --git a/helpers.go b/helpers.go deleted file mode 100644 index 178c1de..0000000 --- a/helpers.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -import "fmt" - -// Set - Helper that you can use to execute SET application against active ESL session -func (sc *SocketConnection) ExecuteSet(key string, value string, sync bool) (m *Message, err error) { - return sc.Execute("set", fmt.Sprintf("%s=%s", key, value), sync) -} - -// ExecuteHangup - Helper desgned to help with executing Answer against active ESL session -func (sc *SocketConnection) ExecuteAnswer(args string, sync bool) (m *Message, err error) { - return sc.Execute("answer", args, sync) -} - -// ExecuteHangup - Helper desgned to help with executing Hangup against active ESL session -func (sc *SocketConnection) ExecuteHangup(uuid string, args string, sync bool) (m *Message, err error) { - if uuid != "" { - return sc.ExecuteUUID(uuid, "hangup", args, sync) - } - - return sc.Execute("hangup", args, sync) -} - -// BgApi - Helper designed to attach api in front of the command so that you do not need to write it -func (sc *SocketConnection) Api(command string) error { - return sc.Send(fmt.Sprintf("api %s", command)) -} - -// BgApi - Helper designed to attach bgapi in front of the command so that you do not need to write it -func (sc *SocketConnection) BgApi(command string) error { - return sc.Send(fmt.Sprintf("bgapi %s", command)) -} - -// Connect - Helper designed to help you handle connection. Each outbound server when handling needs to connect e.g. accept -// connection in order for you to do answer, hangup or do whatever else you wish to do -func (sc *SocketConnection) Connect() error { - return sc.Send("connect") -} - -// Exit - Used to send exit signal to ESL. It will basically hangup call and close connection -func (sc *SocketConnection) Exit() error { - return sc.Send("exit") -} diff --git a/logger.go b/logger.go deleted file mode 100644 index b1de6d2..0000000 --- a/logger.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -import ( - "github.com/op/go-logging" - "os" -) - -var ( - log = logging.MustGetLogger("goes") - - // Example format string. Everything except the message has a custom color - // which is dependent on the log level. Many fields have a custom output - // formatting too, eg. the time returns the hour down to the milli second. - format = logging.MustStringFormatter( - "%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.8s}%{color:reset} %{message}", - ) -) - -func Debug(message string, args ...interface{}) { - log.Debug(message, args...) -} - -func Error(message string, args ...interface{}) { - log.Error(message, args...) -} - -func Notice(message string, args ...interface{}) { - log.Notice(message, args...) -} - -func Info(message string, args ...interface{}) { - log.Info(message, args...) -} - -func Warning(message string, args ...interface{}) { - log.Warning(message, args...) -} - -func init() { - backend := logging.NewLogBackend(os.Stderr, "", 0) - formatter := logging.NewBackendFormatter(backend, format) - logging.SetBackend(formatter) -} diff --git a/message.go b/message.go deleted file mode 100644 index 7d2a60e..0000000 --- a/message.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "net/textproto" - "net/url" - "sort" - "strconv" - "strings" -) - -// Message - Freeswitch Message that is received by GoESL. Message struct is here to help with parsing message -// and dumping its contents. In addition to that it's here to make sure received message is in fact message we wish/can support -type Message struct { - Headers map[string]string - Body []byte - - r *bufio.Reader - tr *textproto.Reader -} - -// String - Will return message representation as string -func (m *Message) String() string { - return fmt.Sprintf("%v body=%s", m.Headers, m.Body) -} - -// GetCallUUID - Will return Caller-Unique-Id -func (m *Message) GetCallUUID() string { - return m.GetHeader("Caller-Unique-Id") -} - -// GetHeader - Will return message header value, or "" if the key is not set. -func (m *Message) GetHeader(key string) string { - return m.Headers[key] -} - -// Parse - Will parse out message received from Freeswitch and basically build it accordingly for later use. -// However, in case of any issues func will return error. -func (m *Message) Parse() error { - - cmr, err := m.tr.ReadMIMEHeader() - - if err != nil && err.Error() != "EOF" { - Error(ECouldNotReadMIMEHeaders, err) - return err - } - - if cmr.Get("Content-Type") == "" { - Debug("Not accepting message because of empty content type. Just whatever with it ...") - return fmt.Errorf("Parse EOF") - } - - // Will handle content length by checking if appropriate lenght is here and if it is than - // we are going to read it into body - if lv := cmr.Get("Content-Length"); lv != "" { - l, err := strconv.Atoi(lv) - - if err != nil { - Error(EInvalidContentLength, err) - return err - } - - m.Body = make([]byte, l) - - if _, err := io.ReadFull(m.r, m.Body); err != nil { - Error(ECouldNotReadyBody, err) - return err - } - } - - msgType := cmr.Get("Content-Type") - - Debug("Got message content (type: %s). Searching if we can handle it ...", msgType) - - if !StringInSlice(msgType, AvailableMessageTypes) { - return fmt.Errorf(EUnsupportedMessageType, msgType, AvailableMessageTypes) - } - - // Assing message headers IF message is not type of event-json - if msgType != "text/event-json" { - for k, v := range cmr { - - m.Headers[k] = v[0] - - // Will attempt to decode if % is discovered within the string itself - if strings.Contains(v[0], "%") { - m.Headers[k], err = url.QueryUnescape(v[0]) - - if err != nil { - Error(ECouldNotDecode, err) - continue - } - } - } - } - - switch msgType { - case "text/disconnect-notice": - for k, v := range cmr { - Debug("Message (header: %s) -> (value: %v)", k, v) - } - case "command/reply": - reply := cmr.Get("Reply-Text") - - if strings.Contains(reply, "-ERR") { - return fmt.Errorf(EUnsuccessfulReply, reply[5:]) - } - case "api/response": - if strings.Contains(string(m.Body), "-ERR") { - return fmt.Errorf(EUnsuccessfulReply, string(m.Body)[5:]) - } - case "text/event-json": - if err := json.Unmarshal(m.Body, &m.Headers); err != nil { - return err - } - - if v, _ := m.Headers["_body"]; v != "" { - m.Body = []byte(v) - delete(m.Headers, "_body") - } else { - m.Body = []byte("") - } - - case "text/event-plain": - r := bufio.NewReader(bytes.NewReader(m.Body)) - - tr := textproto.NewReader(r) - - emh, err := tr.ReadMIMEHeader() - - if err != nil { - return fmt.Errorf(ECouldNotReadMIMEHeaders, err) - } - - if vl := emh.Get("Content-Length"); vl != "" { - length, err := strconv.Atoi(vl) - - if err != nil { - Error(EInvalidContentLength, err) - return err - } - - m.Body = make([]byte, length) - - if _, err = io.ReadFull(r, m.Body); err != nil { - Error(ECouldNotReadyBody, err) - return err - } - } - } - - return nil -} - -// Dump - Will return message prepared to be dumped out. It's like prettify message for output -func (m *Message) Dump() (resp string) { - var keys []string - - for k := range m.Headers { - keys = append(keys, k) - } - - sort.Strings(keys) - - for _, k := range keys { - resp += fmt.Sprintf("%s: %s\r\n", k, m.Headers[k]) - } - - resp += fmt.Sprintf("BODY: %v\r\n", string(m.Body)) - - return -} - -// newMessage - Will build and execute parsing against received freeswitch message. -// As return will give brand new Message{} for you to use it. -func newMessage(r *bufio.Reader, autoParse bool) (*Message, error) { - - msg := Message{ - r: r, - tr: textproto.NewReader(r), - Headers: make(map[string]string), - } - - if autoParse { - if err := msg.Parse(); err != nil { - return &msg, err - } - } - - return &msg, nil -} diff --git a/protos/.gitkeep b/protos/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server.go b/server.go deleted file mode 100644 index 1e296ec..0000000 --- a/server.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -import ( - "fmt" - "net" - "os" - "os/signal" - "syscall" -) - -// OutboundServer - In case you need to start server, this Struct have it covered -type OutboundServer struct { - net.Listener - - Addr string `json:"address"` - Proto string - - Conns chan SocketConnection -} - -// Start - Will start new outbound server -func (s *OutboundServer) Start() error { - Notice("Starting Freeswitch Outbound Server @ (address: %s) ...", s.Addr) - - var err error - - s.Listener, err = net.Listen(s.Proto, s.Addr) - - if err != nil { - Error(ECouldNotStartListener, err) - return err - } - - quit := make(chan bool) - - go func() { - for { - Warning("Waiting for incoming connections ...") - - c, err := s.Accept() - - if err != nil { - Error(EListenerConnection, err) - quit <- true - break - } - - conn := SocketConnection{ - Conn: c, - err: make(chan error), - m: make(chan *Message), - } - - Notice("Got new connection from: %s", conn.OriginatorAddr()) - - go conn.Handle() - - s.Conns <- conn - } - }() - - <-quit - - // Stopping server itself ... - s.Stop() - - return err -} - -// Stop - Will close server connection once SIGTERM/Interrupt is received -func (s *OutboundServer) Stop() { - Warning("Stopping Outbound Server ...") - s.Close() -} - -// NewOutboundServer - Will instanciate new outbound server -func NewOutboundServer(addr string) (*OutboundServer, error) { - if len(addr) < 2 { - addr = os.Getenv("GOESL_OUTBOUND_SERVER_ADDR") - - if addr == "" { - return nil, fmt.Errorf(EInvalidServerAddr, addr) - } - } - - server := OutboundServer{ - Addr: addr, - Proto: "tcp", - Conns: make(chan SocketConnection), - } - - sig := make(chan os.Signal, 1) - - signal.Notify(sig, os.Interrupt) - signal.Notify(sig, syscall.SIGTERM) - - go func() { - <-sig - server.Stop() - os.Exit(1) - }() - - return &server, nil -} diff --git a/utils.go b/utils.go deleted file mode 100644 index 7bdae4d..0000000 --- a/utils.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -// StringInSlice - Will check if string in list. This is equivalent to python if x in [] -func StringInSlice(str string, list []string) bool { - for _, value := range list { - if value == str { - return true - } - } - return false -} diff --git a/vars.go b/vars.go deleted file mode 100644 index 74247d1..0000000 --- a/vars.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2015 Nevio Vesic -// Please check out LICENSE file for more information about what you CAN and what you CANNOT do! -// Basically in short this is a free software for you to do whatever you want to do BUT copyright must be included! -// I didn't write all of this code so you could say it's yours. -// MIT License - -package goesl - -var ( - - // Size of buffer when we read from connection. - // 1024 << 6 == 65536 - ReadBufferSize = 1024 << 6 - - // Freeswitch events that we can handle (have logic for it) - AvailableMessageTypes = []string{"auth/request", "text/disconnect-notice", "text/event-json", "text/event-plain", "api/response", "command/reply"} -) diff --git a/wiki/proposal.md b/wiki/proposal.md deleted file mode 100644 index 13b664b..0000000 --- a/wiki/proposal.md +++ /dev/null @@ -1,229 +0,0 @@ -Go ESL -==== - -###Introduction - -[GoESL](https://github.com/0x19/goesl) is a very simple and straight forward [Go](http://golang.org/) package designed to interact with FreeSWITCH [ESL](https://freeswitch.org/confluence/display/FREESWITCH/Event+Socket+Library). GoESL supports both client and server. Server is used to bind and listen for incoming FreeSWITCH messages where client is used for sending commands. GoESL package contains few helpers which can be found in helpers.go so you can easily answer, hangup or send api events. - - -###Installation - -[GoESL](https://github.com/0x19/goesl) is a package as-is. Standard go get will get you going :) Make sure to have go properly setup based on your operating system. - -If you're unsure how to do it [Go Getting Started](http://golang.org/doc/install) will help you out. - -```go -go get github.com/0x19/goesl -``` - - -###How To / Examples - -Following code is the only thing you need to do in order to import GoESL - -```go -import ( - . "github.com/0x19/goesl" -) -``` - -All available examples can be found at [GoESL Examples](https://github.com/0x19/goesl/tree/master/examples) - - -####Client Example - -Following example will connect to FreeSWITCH event socket interface and send originate api command - -```go -package examples - -import ( - "flag" - "fmt" - . "github.com/0x19/goesl" - "runtime" - "strings" -) - -var ( - fshost = flag.String("fshost", "localhost", "Freeswitch hostname. Default: localhost") - fsport = flag.Uint("fsport", 8021, "Freeswitch port. Default: 8021") - password = flag.String("pass", "ClueCon", "Freeswitch password. Default: ClueCon") - timeout = flag.Int("timeout", 10, "Freeswitch conneciton timeout in seconds. Default: 10") -) - -func main() { - - // Boost it as much as it can go ... - runtime.GOMAXPROCS(runtime.NumCPU()) - - client, err := NewClient(*fshost, *fsport, *password, *timeout) - - if err != nil { - Error("Error while creating new client: %s", err) - return - } - - // Apparently all is good... Let us now handle connection :) - // We don't want this to be inside of new connection as who knows where it my lead us. - // Remember that this is crutial part in handling incoming messages. This is a must! - go client.Handle() - - client.Send("events json ALL") - - client.BgApi(fmt.Sprintf("originate %s %s", "sofia/internal/1001@127.0.0.1", "&socket(192.168.1.2:8084 async full)")) - - for { - msg, err := client.ReadMessage() - - if err != nil { - - // If it contains EOF, we really dont care... - if !strings.Contains(err.Error(), "EOF") && err.Error() != "unexpected end of JSON input" { - Error("Error while reading Freeswitch message: %s", err) - } - - break - } - - Debug("Got new message: %s", msg) - } -} - -``` - -You can run this code by saving it as client.go and than running - -```bash -go build client.go && ./client -``` - -#### Server Example (TTS) - -Following example will start server and listen for incoming messages. Once received speak (TTS) will be initiated to the originator. - -```go -package examples - -import ( - . "github.com/0x19/goesl" - "runtime" - "strings" -) - -var ( - goeslMessage = "Hello from GoESL. Open source FreeSWITCH event socket wrapper written in Go!" -) - -func main() { - - defer func() { - if r := recover(); r != nil { - Error("Recovered in: ", r) - } - }() - - // Boost it as much as it can go ... - runtime.GOMAXPROCS(runtime.NumCPU()) - - if s, err := NewOutboundServer(":8084"); err != nil { - Error("Got error while starting FreeSWITCH outbound server: %s", err) - } else { - go handle(s) - s.Start() - } - -} - -// handle - Running under goroutine here to explain how to run tts outbound server -func handle(s *OutboundServer) { - - for { - - select { - - case conn := <-s.Conns: - Notice("New incomming connection: %v", conn) - - if err := conn.Connect(); err != nil { - Error("Got error while accepting connection: %s", err) - break - } - - answer, err := conn.ExecuteAnswer("", false) - - if err != nil { - Error("Got error while executing answer: %s", err) - break - } - - Debug("Answer Message: %s", answer) - Debug("Caller UUID: %s", answer.GetHeader("Caller-Unique-Id")) - - cUUID := answer.GetCallUUID() - - if te, err := conn.ExecuteSet("tts_engine", "flite", false); err != nil { - Error("Got error while attempting to set tts_engine: %s", err) - } else { - Debug("TTS Engine Msg: %s", te) - } - - if tv, err := conn.ExecuteSet("tts_voice", "slt", false); err != nil { - Error("Got error while attempting to set tts_voice: %s", err) - } else { - Debug("TTS Voice Msg: %s", tv) - } - - if sm, err := conn.Execute("speak", goeslMessage, true); err != nil { - Error("Got error while executing speak: %s", err) - break - } else { - Debug("Speak Message: %s", sm) - } - - if hm, err := conn.ExecuteHangup(cUUID, "", false); err != nil { - Error("Got error while executing hangup: %s", err) - break - } else { - Debug("Hangup Message: %s", hm) - } - - go func() { - for { - msg, err := conn.ReadMessage() - - if err != nil { - - // If it contains EOF, we really dont care... - if !strings.Contains(err.Error(), "EOF") { - Error("Error while reading Freeswitch message: %s", err) - } - break - } - - Debug("Got message: %s", msg) - } - }() - - default: - } - } - -} -``` - -You can run this code by saving it as tts_server.go and than running - -```bash -go build tts_server.go && ./tts_server -``` - - - - - - - - - -