forked from emiago/sipgo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver_dialog.go
97 lines (78 loc) · 2.04 KB
/
server_dialog.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package sipgo
import (
"github.com/emiago/sipgo/sip"
)
// ServerDialog is extension of Server to support Dialog handling
type ServerDialog struct {
Server
onDialog func(d sip.Dialog)
}
func NewServerDialog(ua *UserAgent, options ...ServerOption) (*ServerDialog, error) {
base, err := newBaseServer(ua, options...)
if err != nil {
return nil, err
}
s := &ServerDialog{
Server: *base,
}
// s.tp = transport.NewLayer(s.dnsResolver)
// Handle our transaction layer requests
s.tx.OnRequest(s.onRequestDialog)
return s, nil
}
func (s *ServerDialog) onRequestDialog(r *sip.Request, tx sip.ServerTransaction) {
go s.handleRequestDialog(r, tx)
}
func (s *ServerDialog) handleRequestDialog(r *sip.Request, tx sip.ServerTransaction) {
switch r.Method {
// Early state
// case sip.INVITE:
case sip.ACK:
s.publish(r, sip.Dialog{
State: sip.DialogStateConfirmed,
})
case sip.BYE:
s.publish(r, sip.Dialog{
State: sip.DialogStateEnded,
})
}
// This makes allocation, but hard to override
// Maybe goign on transaction layer
wraptx := &dialogServerTx{tx, s}
s.Server.handleRequest(r, wraptx)
}
func (s *ServerDialog) publish(r sip.Message, d sip.Dialog) {
id, err := sip.MakeDialogIDFromMessage(r)
if err != nil {
s.log.Error().Err(err).Str("msg", sip.MessageShortString(r)).Msg("Failed to create dialog id")
return
}
d.ID = id
s.onDialog(d)
}
// OnDialog allows monitoring new dialogs
func (s *ServerDialog) OnDialog(f func(d sip.Dialog)) {
s.onDialog = f
}
// OnDialogChan same as onDialog but we channel instead callback func
func (s *ServerDialog) OnDialogChan(ch chan sip.Dialog) {
s.onDialog = func(d sip.Dialog) {
ch <- d
}
}
// this is just wrapper to allow listening response
type dialogServerTx struct {
sip.ServerTransaction
s *ServerDialog
}
func (tx *dialogServerTx) Respond(r *sip.Response) error {
switch {
// EARLY STATE NEEDS more definition
// case r.IsProvisional():
case r.IsSuccess():
tx.s.publish(r, sip.Dialog{
State: sip.DialogStateEstablished,
})
}
return tx.ServerTransaction.Respond(r)
}