Skip to content

Commit cc28b7d

Browse files
committed
Pushing beta version for clients and servers :) It works haha. Tests are still very much required
1 parent 3d17bc2 commit cc28b7d

File tree

12 files changed

+229
-70
lines changed

12 files changed

+229
-70
lines changed

client.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,100 @@
55
// MIT License
66

77
package goesl
8+
9+
import (
10+
"bufio"
11+
"fmt"
12+
"time"
13+
)
14+
15+
// Client - In case you need to do inbound dialing against freeswitch server in order to originate call or see
16+
// sofia statuses or whatever else you came up with
17+
type Client struct {
18+
SocketConnection
19+
20+
Proto string `json:"freeswitch_protocol"`
21+
Addr string `json:"freeswitch_addr"`
22+
Passwd string `json:"freeswitch_password"`
23+
Timeout int `json:"freeswitch_connection_timeout"`
24+
}
25+
26+
// EstablishConnection - Will attempt to establish connection against freeswitch and create new SocketConnection
27+
func (c *Client) EstablishConnection() error {
28+
conn, err := c.Dial(c.Proto, c.Addr, time.Duration(c.Timeout*int(time.Second)))
29+
30+
c.SocketConnection = SocketConnection{
31+
Conn: conn,
32+
err: make(chan error),
33+
m: make(chan *Message),
34+
}
35+
36+
return err
37+
}
38+
39+
// Authenticate - Method used to authenticate client against freeswitch. In case of any errors durring so
40+
// we will return error.
41+
func (c *Client) Authenticate() error {
42+
43+
m, err := newMessage(bufio.NewReaderSize(c, ReadBufferSize), false)
44+
45+
if err != nil {
46+
Error(ECouldNotCreateMessage, err)
47+
return err
48+
}
49+
50+
cmr, err := m.tr.ReadMIMEHeader()
51+
52+
Debug("A: %v %v ", cmr, err)
53+
54+
if err != nil && err.Error() != "EOF" {
55+
c.Close()
56+
Error(ECouldNotReadMIMEHeaders, err)
57+
return err
58+
}
59+
60+
if cmr.Get("Content-Type") != "auth/request" {
61+
c.Close()
62+
Error(EUnexpectedAuthHeader, cmr.Get("Content-Type"))
63+
return fmt.Errorf(EUnexpectedAuthHeader, cmr.Get("Content-Type"))
64+
}
65+
66+
fmt.Fprintf(c, "auth %s\r\n\r\n", c.Passwd)
67+
68+
am, err := m.tr.ReadMIMEHeader()
69+
70+
if err != nil && err.Error() != "EOF" {
71+
c.Close()
72+
Error(ECouldNotReadMIMEHeaders, err)
73+
return err
74+
}
75+
76+
if am.Get("Reply-Text") != "+OK accepted" {
77+
c.Close()
78+
Error(EInvalidPassword, c.Passwd)
79+
return fmt.Errorf(EInvalidPassword, c.Passwd)
80+
}
81+
82+
return nil
83+
}
84+
85+
// NewClient - Will initiate new client that will establish connection and attempt to authenticate
86+
// against connected freeswitch server
87+
func NewClient(host string, port uint, passwd string, timeout int) (Client, error) {
88+
client := Client{
89+
Proto: "tcp", // Let me know if you ever need this open up lol
90+
Addr: fmt.Sprintf("%s:%d", host, port),
91+
Passwd: passwd,
92+
Timeout: timeout,
93+
}
94+
95+
if err := client.EstablishConnection(); err != nil {
96+
return client, err
97+
}
98+
99+
if err := client.Authenticate(); err != nil {
100+
return client, err
101+
}
102+
103+
return client, nil
104+
}

config.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

connection.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"net"
1414
"strconv"
1515
"strings"
16+
"time"
1617
)
1718

1819
// Main connection against ESL - Gotta add more description here
@@ -22,6 +23,11 @@ type SocketConnection struct {
2223
m chan *Message
2324
}
2425

26+
// Dial - Will establish timedout dial against specified address. In this case, it will be freeswitch server
27+
func (c *SocketConnection) Dial(network string, addr string, timeout time.Duration) (net.Conn, error) {
28+
return net.DialTimeout(network, addr, timeout)
29+
}
30+
2531
// Send - Will send raw message to open net connection
2632
func (c *SocketConnection) Send(cmd string) error {
2733

@@ -139,7 +145,7 @@ func (c *SocketConnection) Handle() {
139145

140146
go func() {
141147
for {
142-
msg, err := newMessage(bufio.NewReaderSize(c, ReadBufferSize))
148+
msg, err := newMessage(bufio.NewReaderSize(c, ReadBufferSize), true)
143149

144150
if err != nil {
145151
c.err <- err

errors.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ var (
1717
ECouldNotStartListener = "Got error while attempting to start listener: %s"
1818
EListenerConnection = "Listener connection error: %s"
1919
EInvalidServerAddr = "Please make sure to pass along valid address. You've passed: \"%s\""
20+
EUnexpectedAuthHeader = "Expected auth/request content type. Got %s"
21+
EInvalidPassword = "Could not authenticate against freeswitch with provided password: %s"
22+
ECouldNotCreateMessage = "Error while creating new message: %s"
2023
)

examples/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
server
22
server_playback
3-
server_tts
3+
server_tts
4+
client

examples/client.go

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,56 @@
77
package main
88

99
import (
10+
"flag"
11+
"fmt"
1012
. "github.com/0x19/goesl"
1113
"runtime"
14+
"strings"
1215
)
1316

17+
var (
18+
fshost = flag.String("fshost", "localhost", "Freeswitch hostname. Default: localhost")
19+
fsport = flag.Uint("fsport", 8021, "Freeswitch port. Default: 8021")
20+
password = flag.String("pass", "ClueCon", "Freeswitch password. Default: ClueCon")
21+
timeout = flag.Int("timeout", 10, "Freeswitch conneciton timeout in seconds. Default: 10")
22+
)
23+
24+
// Small client that will first make sure all events are returned as JSON and second, will originate
1425
func main() {
1526

1627
// Boost it as much as it can go ...
1728
runtime.GOMAXPROCS(runtime.NumCPU())
1829

19-
Debug("While thinking what to do, this is how many CPU threads we got: %d", runtime.NumCPU())
30+
client, err := NewClient(*fshost, *fsport, *password, *timeout)
31+
32+
if err != nil {
33+
Error("Error while creating new client: %s", err)
34+
return
35+
}
36+
37+
Debug("Yuhu! New client: %q", client)
38+
39+
// Apparently all is good... Let us now handle connection :)
40+
// We don't want this to be inside of new connection as who knows where it my lead us.
41+
// Remember that this is crutial part in handling incoming messages :)
42+
go client.Handle()
43+
44+
client.Send("events json ALL")
45+
46+
client.BgApi(fmt.Sprintf("originate %s %s", "sofia/internal/[email protected]", "&socket(192.168.1.2:8084 async full)"))
47+
48+
for {
49+
msg, err := client.ReadMessage()
50+
51+
if err != nil {
52+
53+
// If it contains EOF, we really dont care...
54+
if !strings.Contains(err.Error(), "EOF") && err.Error() != "unexpected end of JSON input" {
55+
Error("Error while reading Freeswitch message: %s", err)
56+
}
57+
break
58+
}
2059

60+
Debug("%s", msg)
61+
}
2162
}

examples/server_playback.go

Lines changed: 45 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ import (
1414
"strings"
1515
)
1616

17-
var (
18-
welcomeFile = "%s/media/welcome.wav"
19-
)
17+
var welcomeFile = "%s/media/welcome.wav"
2018

2119
func main() {
2220

@@ -47,69 +45,69 @@ func main() {
4745

4846
}
4947

50-
// handle - Running under goroutine here to explain how to send message, receive message and in general dump stuff out
48+
// handle - Running under goroutine here to explain how to handle playback ( play to the caller )
5149
func handle(s *OutboundServer) {
5250

5351
for {
5452

55-
conn := <-s.Conns
56-
57-
Notice("New incomming connection: %v", conn)
58-
59-
conn.Send("connect")
60-
61-
aMsg, err := conn.Execute("answer", "", false)
53+
select {
6254

63-
if err != nil {
64-
Error("Got error while executing answer against call: %s", err)
65-
break
66-
}
67-
68-
Debug("Answer Message: %s", aMsg)
69-
Debug("Caller UUID: %s", aMsg.GetHeader("Caller-Unique-Id"))
55+
case conn := <-s.Conns:
56+
Notice("New incomming connection: %v", conn)
7057

71-
cUUID := aMsg.GetHeader("Caller-Unique-Id")
72-
73-
pMsg, err := conn.Execute("playback", welcomeFile, true)
58+
if err := conn.Connect(); err != nil {
59+
Error("Got error while accepting connection: %s", err)
60+
break
61+
}
7462

75-
if err != nil {
76-
Error("Got error while executing answer against call: %s", err)
77-
break
78-
}
63+
answer, err := conn.ExecuteAnswer("", false)
7964

80-
Debug("Playback Message: %s", pMsg)
65+
if err != nil {
66+
Error("Got error while executing answer: %s", err)
67+
break
68+
}
8169

82-
hMsg, err := conn.ExecuteUUID(cUUID, "hangup", "", false)
70+
Debug("Answer Message: %s", answer)
71+
Debug("Caller UUID: %s", answer.GetHeader("Caller-Unique-Id"))
8372

84-
if err != nil {
85-
Error("Got error while executing hangup against call: %s", err)
86-
break
87-
}
73+
cUUID := answer.GetCallUUID()
8874

89-
Debug("Hangup Message: %s", hMsg)
75+
if sm, err := conn.Execute("playback", welcomeFile, true); err != nil {
76+
Error("Got error while executing playback: %s", err)
77+
break
78+
} else {
79+
Debug("Playback Message: %s", sm)
80+
}
9081

91-
done := make(chan bool)
82+
if hm, err := conn.ExecuteHangup(cUUID, "", false); err != nil {
83+
Error("Got error while executing hangup: %s", err)
84+
break
85+
} else {
86+
Debug("Hangup Message: %s", hm)
87+
}
9288

93-
go func() {
94-
for {
95-
msg, err := conn.ReadMessage()
89+
go func() {
90+
for {
91+
msg, err := conn.ReadMessage()
9692

97-
if err != nil {
93+
if err != nil {
9894

99-
// If it contains EOF, we really dont care...
100-
if !strings.Contains(err.Error(), "EOF") {
101-
Error("Error while reading Freeswitch message: %s", err)
95+
// If it contains EOF, we really dont care...
96+
if !strings.Contains(err.Error(), "EOF") {
97+
Error("Error while reading Freeswitch message: %s", err)
98+
}
99+
break
102100
}
103101

104-
done <- true
105-
break
102+
Debug("%s", msg)
106103
}
104+
}()
107105

108-
Info("%s", msg.Dump())
109-
}
110-
}()
111-
112-
<-done
106+
default:
107+
// YabbaDabbaDooooo!
108+
//Flintstones. Meet the Flintstones. They're the modern stone age family. From the town of Bedrock,
109+
// They're a page right out of history. La la,lalalalala la :D
110+
}
113111
}
114112

115113
}

examples/server_tts.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ func handle(s *OutboundServer) {
102102
break
103103
}
104104

105-
Debug("%s", msg.Dump())
105+
Debug("%s", msg)
106106
}
107107
}()
108108

helpers.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
// I didn't write all of this code so you could say it's yours.
55
// MIT License
66

7-
// This package is used to set helpers for common applications/send that we may use such as set variable against dialplan or accepting connection
8-
97
package goesl
108

119
import "fmt"
@@ -29,6 +27,16 @@ func (sc *SocketConnection) ExecuteHangup(uuid string, args string, sync bool) (
2927
return sc.Execute("hangup", args, sync)
3028
}
3129

30+
// BgApi - Helper designed to attach api in front of the command so that you do not need to write it
31+
func (sc *SocketConnection) Api(command string) error {
32+
return sc.Send(fmt.Sprintf("api %s", command))
33+
}
34+
35+
// BgApi - Helper designed to attach bgapi in front of the command so that you do not need to write it
36+
func (sc *SocketConnection) BgApi(command string) error {
37+
return sc.Send(fmt.Sprintf("bgapi %s", command))
38+
}
39+
3240
// Connect - Helper designed to help you handle connection. Each outbound server when handling needs to connect e.g. accept
3341
// connection in order for you to do answer, hangup or do whatever else you wish to do
3442
func (sc *SocketConnection) Connect() error {

0 commit comments

Comments
 (0)