percipia / eslgo Goto Github PK
View Code? Open in Web Editor NEWA GoLang FreeSWITCH ESL Library
License: Mozilla Public License 2.0
A GoLang FreeSWITCH ESL Library
License: Mozilla Public License 2.0
Hi, thanks for sharing this neat library with the community.
I've used it to create a small PoC that generates IVR menu dynamically instead of using fixed XML files, but when I got to the part where I needed to capture callers menu response I ran into an issue with the underlying TCP connection:
time="2022-07-14T07:14:32Z" level=info msg="[1] Answer the call"
time="2022-07-14T07:14:32Z" level=info msg="[2] Start DTMF listener"
time="2022-07-14T07:14:32Z" level=info msg="[3] Play IVR menu"
time="2022-07-14T07:14:32Z" level=info msg="[5] Capture DTMF events"
time="2022-07-14T07:14:48Z" level=info msg="Received digit: 2"
time="2022-07-14T07:14:48Z" level=error msg="Error transferring the call!"
time="2022-07-14T07:14:48Z" level=error msg="write tcp 10.22.1.201:8084->10.22.1.200:52490: i/o timeout"
Here is how DTMF digit is captured:
func (ch *CallHandler) captureDTMF(ctx context.Context, conn *eslgo.Conn) (byte, error) {
digit, err := conn.WaitForDTMF(ctx, ch.uuid)
if err != nil {
ch.logger.Error("Error waiting for DTMF signal")
return 0, err
}
ch.logger.Info("Received digit: " + string(digit))
return digit, nil
}
Timeout happens on the next ESL command I try to executed after receiving the digit. Not sure if it matters, but the next command is this:
func (ch *CallHandler) transferCall(ctx context.Context, conn *eslgo.Conn, digit byte) error {
_, err := conn.SendCommand(ctx, &call.Execute{UUID: ch.uuid, AppName: "deflect", AppArgs: "sip:eureka@" + ch.outboundDestIp, Sync: true, SyncPri: true})
if err != nil {
ch.logger.Error("Error transferring the call!")
ch.logger.Error(err)
return err
}
return nil
}
The deflect
commmand works as expected if I comment out the "capture DTMF digits" logic, which makes me think that capturing the DTMF digit somehow affects the connection.
Any ideas what might be going wrong here or if I'm missing something important?
Connections made with esl.Dial
cannot send commands using c.SendCommand
after five seconds of life.
This is because we set a global deadline on the connection.
I had a much longer issue written, with some additional data, but my machine inexplicably rebooted...
I am grateful for this package! These are small things that can (maybe) be improved iteratively, and they are only my opinions.
context
docs - Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it.
Conn
would be helpful for developers - specifically the newConnection
constructor.
receiveLoop
on a context.Err()
with only an internal logger.Warn
can make it difficult to track down what's happening when things inevitably go wrong.
panic
? I'm not normally a fan but the entire system is down at this point, right?error
.Conn
struct in favor of passing context around?Disable the deadline checker/setter here (remove or comment out). Replace with another timeout enforcement method, or just allow the caller to manage their own timeouts.
/*
* This code snippet shows a long-running ESL connection that
* fails to deliver commands after five seconds of life.
*
* Note that we are limited by an artificial Go deadline, not
* any FreeSWITCH limitation.
*/
package main
import (
"context"
"log"
"time"
"github.com/percipia/eslgo"
"github.com/percipia/eslgo/command"
)
func main() {
// Connect to FreeSWITCH
conn, err := eslgo.Dial("127.0.0.1:8021", "ClueCon", func() {
log.Println("Inbound Connection Disconnected")
})
if err != nil {
log.Println("Error connecting", err)
return
}
defer conn.ExitAndClose()
// Create a basic context
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
go func() {
i := 0
for {
log.Printf("sending ping %v\n", i)
if _, err := conn.SendCommand(ctx, command.API{
Command: "echo",
Arguments: log.Sprintf("ping %v", i),
Background: false,
}); err != nil {
log.Println(err)
}
i++
time.Sleep(time.Second * 1)
}
}()
time.Sleep(30)
}
Hello!
Thanks for the library, @winsock ! It's so useful and helpful!
I've encountered this behavior: when I set an incorrect ESL password the library replies like the following:
$ ~/go/bin/go run ~/main.go
2021/02/16 13:43:36 Failed to auth &{%!e(string=failed to auth Content-Type: []string{"command/reply"}
Reply-Text: []string{"-ERR invalid"}
)}
2021/02/16 13:43:41 No one to handle response Content-Type: []string{"text/disconnect-notice"}
Content-Length: []string{"67"}
Disconnected, goodbye.
See you at ClueCon! http://www.cluecon.com/
and it never exits.
In my opinion, the program must exit after sending "exit" command to FreeSWITCH instance.
There are some debug log messages printed out by the library. As brought up in a side discussion of #5 we should allow setting a customer logger to allow users of the library to decide how to save/print these messages rather than printing to stdout using GoLang's default logging interface.
Logger
with the following definition since it seems to be what most third party libraries usetype Logger interface {
Debug(format string, args ...interface{})
Info(format string, args ...interface{})
Warn(format string, args ...interface{})
Error(format string, args ...interface{})
}
Problem
Outbound connection setting "linger" is invalid, the connection is immediately disconnected after hanging up, resulting in no event received.
As a result, the agent status cannot be properly monitored through "esl"
Hey percipia Team,
It will be really helpful if you guys will make built in support for N number of freeswitches.
When FreeSwitch returns a "text/rude-rejection" Response the opts.Dial function keeps waiting a message from channel forever in:
<-connection.responseChannels[TypeAuthRequest]
I created a temporary fix adding a new response and an anonymous go routine before the line of the mentioned above
go func () {
<-connection.responseChannels[TypeRude]
connection.ExitAndClose()
}()
// First auth
<-connection.responseChannels[TypeAuthRequest]
Tell me if you want me to make a pull request or to find another cleaner solution (I'm sure there's a better way)
Regards.
Hello!
I would like to see this feature in the library :)
I think, it is possible to implement with the OnDisconnect
callback and global variables. Am I right?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.