mirror of
https://github.com/jwetzell/showbridge-go.git
synced 2026-08-31 18:59:00 +00:00
remove SIP things
This commit is contained in:
@@ -1,269 +0,0 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/emiago/diago"
|
||||
"github.com/emiago/diago/media"
|
||||
"github.com/emiago/sipgo"
|
||||
"github.com/emiago/sipgo/sip"
|
||||
"github.com/google/jsonschema-go/jsonschema"
|
||||
"github.com/jwetzell/showbridge-go/internal/common"
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
"github.com/jwetzell/showbridge-go/internal/processor"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterModule(ModuleRegistration{
|
||||
Type: "sip.call.server",
|
||||
Title: "SIP Call Server",
|
||||
ParamsSchema: &jsonschema.Schema{
|
||||
Type: "object",
|
||||
Properties: map[string]*jsonschema.Schema{
|
||||
"ip": {
|
||||
Title: "IP",
|
||||
Description: "the IP address to bind the SIP server to",
|
||||
Type: "string",
|
||||
Default: json.RawMessage(`"0.0.0.0"`),
|
||||
},
|
||||
"port": {
|
||||
Title: "Port",
|
||||
Description: "the port for the SIP server to listen on",
|
||||
Type: "integer",
|
||||
Minimum: jsonschema.Ptr[float64](1024),
|
||||
Maximum: jsonschema.Ptr[float64](65535),
|
||||
Default: json.RawMessage(`5060`),
|
||||
},
|
||||
"transport": {
|
||||
Title: "Transport",
|
||||
Description: "the transport protocol to use for the SIP server",
|
||||
Type: "string",
|
||||
Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"},
|
||||
Default: json.RawMessage(`"udp"`),
|
||||
},
|
||||
"userAgent": {
|
||||
Title: "User Agent",
|
||||
Description: "the user agent string to use",
|
||||
Type: "string",
|
||||
Default: json.RawMessage(`"showbridge"`),
|
||||
},
|
||||
},
|
||||
Required: []string{},
|
||||
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
|
||||
},
|
||||
New: func(moduleConfig config.ModuleConfig) (common.Module, error) {
|
||||
params := moduleConfig.Params
|
||||
portNum, err := params.GetInt("port")
|
||||
if err != nil {
|
||||
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
portNum = 5060
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.call.server port error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ipString, err := params.GetString("ip")
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
ipString = "0.0.0.0"
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.call.server ip error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
transportString, err := params.GetString("transport")
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
transportString = "udp"
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.call.server transport error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
userAgentString, err := params.GetString("userAgent")
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
userAgentString = "showbridge"
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.call.server userAgent error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &SIPCallServer{config: moduleConfig, IP: ipString, Port: int(portNum), Transport: transportString, UserAgent: userAgentString, logger: CreateLogger(moduleConfig)}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type SIPCallServer struct {
|
||||
config config.ModuleConfig
|
||||
ctx context.Context
|
||||
inputHandler common.InputHandler
|
||||
IP string
|
||||
Port int
|
||||
Transport string
|
||||
UserAgent string
|
||||
logger *slog.Logger
|
||||
cancel context.CancelFunc
|
||||
ua *sipgo.UserAgent
|
||||
uaMu sync.Mutex
|
||||
}
|
||||
|
||||
type SIPCallMessage struct {
|
||||
To string
|
||||
}
|
||||
|
||||
type SIPCall struct {
|
||||
inDialog *diago.DialogServerSession
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
type sipCallContextKey string
|
||||
|
||||
func (scs *SIPCallServer) Id() string {
|
||||
return scs.config.Id
|
||||
}
|
||||
|
||||
func (scs *SIPCallServer) Type() string {
|
||||
return scs.config.Type
|
||||
}
|
||||
|
||||
func (scs *SIPCallServer) Start(ctx context.Context, inputHandler common.InputHandler) error {
|
||||
scs.logger.Debug("running")
|
||||
scs.inputHandler = inputHandler
|
||||
moduleContext, cancel := context.WithCancel(ctx)
|
||||
scs.ctx = moduleContext
|
||||
scs.cancel = cancel
|
||||
|
||||
diagoLogger := slog.New(slog.NewJSONHandler(io.Discard, nil))
|
||||
|
||||
ua, _ := sipgo.NewUA(
|
||||
sipgo.WithUserAgent(scs.UserAgent),
|
||||
sipgo.WithUserAgentTransportLayerOptions(sip.WithTransportLayerLogger(diagoLogger)),
|
||||
sipgo.WithUserAgentTransactionLayerOptions(sip.WithTransactionLayerLogger(diagoLogger)),
|
||||
)
|
||||
scs.uaMu.Lock()
|
||||
scs.ua = ua
|
||||
scs.uaMu.Unlock()
|
||||
|
||||
sip.SetDefaultLogger(diagoLogger)
|
||||
media.SetDefaultLogger(diagoLogger)
|
||||
dg := diago.NewDiago(ua, diago.WithLogger(diagoLogger), diago.WithTransport(
|
||||
diago.Transport{
|
||||
Transport: scs.Transport,
|
||||
BindHost: scs.IP,
|
||||
BindPort: scs.Port,
|
||||
},
|
||||
))
|
||||
|
||||
err := dg.Serve(scs.ctx, func(inDialog *diago.DialogServerSession) {
|
||||
scs.HandleCall(inDialog)
|
||||
})
|
||||
if err != nil {
|
||||
scs.logger.Error("diago serve error", "error", err)
|
||||
}
|
||||
|
||||
<-scs.ctx.Done()
|
||||
scs.logger.Debug("done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (scs *SIPCallServer) HandleCall(inDialog *diago.DialogServerSession) {
|
||||
inDialog.Trying()
|
||||
inDialog.Ringing()
|
||||
inDialog.Answer()
|
||||
|
||||
dialogContext := context.WithValue(scs.ctx, sipCallContextKey("call"), &SIPCall{
|
||||
inDialog: inDialog,
|
||||
})
|
||||
if scs.inputHandler != nil {
|
||||
scs.inputHandler(dialogContext, scs.Id(), SIPCallMessage{
|
||||
To: inDialog.ToUser(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (scs *SIPCallServer) Output(ctx context.Context, payload any) error {
|
||||
|
||||
call, ok := ctx.Value(sipCallContextKey("call")).(*SIPCall)
|
||||
|
||||
if !ok {
|
||||
return errors.New("sip.call.server output must originate from sip.call.server input")
|
||||
}
|
||||
|
||||
gotLock := call.lock.TryLock()
|
||||
|
||||
if !gotLock {
|
||||
return errors.New("sip.call.server call is already locked")
|
||||
}
|
||||
|
||||
if call.inDialog.LoadState() == sip.DialogStateEnded {
|
||||
return errors.New("sip.call.server inDialog already ended")
|
||||
}
|
||||
|
||||
payloadDTMFResponse, ok := common.GetAnyAs[processor.SipDTMFResponse](payload)
|
||||
|
||||
if ok {
|
||||
dtmfWriter, err := call.inDialog.AudioWriterDTMF()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PreWait))
|
||||
for i, dtmfRune := range payloadDTMFResponse.Digits {
|
||||
err := dtmfWriter.WriteDTMF(dtmfRune)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("sip.dtmf.server error output dtmf digit at index %d", i)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PostWait))
|
||||
return nil
|
||||
}
|
||||
|
||||
payloadAudioFileResponse, ok := common.GetAnyAs[processor.SipAudioFileResponse](payload)
|
||||
|
||||
if ok {
|
||||
audioFile, err := os.Open(payloadAudioFileResponse.AudioFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer audioFile.Close()
|
||||
|
||||
playback, err := call.inDialog.PlaybackCreate()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadAudioFileResponse.PreWait))
|
||||
|
||||
_, err = playback.Play(audioFile, "audio/wav")
|
||||
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadAudioFileResponse.PostWait))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("sip.dtmf.server can only output SipDTMFResponse or SipAudioFileResponse")
|
||||
}
|
||||
|
||||
func (scs *SIPCallServer) Stop() {
|
||||
if scs.cancel != nil {
|
||||
defer scs.cancel()
|
||||
}
|
||||
scs.uaMu.Lock()
|
||||
defer scs.uaMu.Unlock()
|
||||
if scs.ua != nil {
|
||||
scs.ua.Close()
|
||||
}
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
package module
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/emiago/diago"
|
||||
"github.com/emiago/diago/media"
|
||||
"github.com/emiago/sipgo"
|
||||
"github.com/emiago/sipgo/sip"
|
||||
"github.com/google/jsonschema-go/jsonschema"
|
||||
"github.com/jwetzell/showbridge-go/internal/common"
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
"github.com/jwetzell/showbridge-go/internal/processor"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterModule(ModuleRegistration{
|
||||
Type: "sip.dtmf.server",
|
||||
Title: "SIP DTMF Server",
|
||||
ParamsSchema: &jsonschema.Schema{
|
||||
Type: "object",
|
||||
Properties: map[string]*jsonschema.Schema{
|
||||
"ip": {
|
||||
Title: "IP",
|
||||
Description: "the IP address to bind the SIP server to",
|
||||
Type: "string",
|
||||
Default: json.RawMessage(`"0.0.0.0"`),
|
||||
},
|
||||
"port": {
|
||||
Title: "Port",
|
||||
Description: "the port for the SIP server to listen on",
|
||||
Type: "integer",
|
||||
Minimum: jsonschema.Ptr[float64](1024),
|
||||
Maximum: jsonschema.Ptr[float64](65535),
|
||||
Default: json.RawMessage(`5060`),
|
||||
},
|
||||
"transport": {
|
||||
Title: "Transport",
|
||||
Description: "the transport protocol to use for the SIP server",
|
||||
Type: "string",
|
||||
Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"},
|
||||
Default: json.RawMessage(`"udp"`),
|
||||
},
|
||||
"userAgent": {
|
||||
Title: "User Agent",
|
||||
Description: "the user agent string to use",
|
||||
Type: "string",
|
||||
Default: json.RawMessage(`"showbridge"`),
|
||||
},
|
||||
"separator": {
|
||||
Title: "DTMF Separator",
|
||||
Description: "the DTMF character to use as a separator between DTMF digit groups",
|
||||
Type: "string",
|
||||
MinLength: new(1),
|
||||
MaxLength: new(1),
|
||||
},
|
||||
},
|
||||
Required: []string{"separator"},
|
||||
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
|
||||
},
|
||||
New: func(moduleConfig config.ModuleConfig) (common.Module, error) {
|
||||
params := moduleConfig.Params
|
||||
|
||||
portNum, err := params.GetInt("port")
|
||||
if err != nil {
|
||||
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
portNum = 5060
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.dtmf.server port error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ipString, err := params.GetString("ip")
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
ipString = "0.0.0.0"
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.dtmf.server ip error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
transportString, err := params.GetString("transport")
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
transportString = "udp"
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.dtmf.server transport error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
userAgentString, err := params.GetString("userAgent")
|
||||
if err != nil {
|
||||
if errors.Is(err, config.ErrParamNotFound) {
|
||||
userAgentString = "showbridge"
|
||||
} else {
|
||||
return nil, fmt.Errorf("sip.dtmf.server userAgent error: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
separatorString, err := params.GetString("separator")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("sip.dtmf.server separator error: %w", err)
|
||||
}
|
||||
|
||||
if len(separatorString) != 1 {
|
||||
return nil, errors.New("sip.dtmf.server separator must be a single character")
|
||||
}
|
||||
|
||||
if !strings.ContainsRune("0123456789*#ABCD", rune(separatorString[0])) {
|
||||
return nil, errors.New("sip.dtmf.server separator must be a valid DTMF character")
|
||||
}
|
||||
return &SIPDTMFServer{config: moduleConfig, IP: ipString, Port: int(portNum), Transport: transportString, UserAgent: userAgentString, Separator: separatorString, logger: CreateLogger(moduleConfig)}, nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
type SIPDTMFServer struct {
|
||||
config config.ModuleConfig
|
||||
ctx context.Context
|
||||
inputHandler common.InputHandler
|
||||
IP string
|
||||
Port int
|
||||
Transport string
|
||||
UserAgent string
|
||||
Separator string
|
||||
logger *slog.Logger
|
||||
cancel context.CancelFunc
|
||||
ua *sipgo.UserAgent
|
||||
uaMu sync.Mutex
|
||||
}
|
||||
|
||||
type SIPDTMFMessage struct {
|
||||
To string
|
||||
Digits string
|
||||
}
|
||||
|
||||
type SIPDTMFCall struct {
|
||||
inDialog *diago.DialogServerSession
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func (sds *SIPDTMFServer) Id() string {
|
||||
return sds.config.Id
|
||||
}
|
||||
|
||||
func (sds *SIPDTMFServer) Type() string {
|
||||
return sds.config.Type
|
||||
}
|
||||
|
||||
func (sds *SIPDTMFServer) Start(ctx context.Context, inputHandler common.InputHandler) error {
|
||||
sds.logger.Debug("running")
|
||||
sds.inputHandler = inputHandler
|
||||
moduleContext, cancel := context.WithCancel(ctx)
|
||||
sds.ctx = moduleContext
|
||||
sds.cancel = cancel
|
||||
|
||||
diagoLogger := slog.New(slog.NewJSONHandler(io.Discard, nil))
|
||||
|
||||
ua, _ := sipgo.NewUA(
|
||||
sipgo.WithUserAgent(sds.UserAgent),
|
||||
sipgo.WithUserAgentTransportLayerOptions(sip.WithTransportLayerLogger(diagoLogger)),
|
||||
sipgo.WithUserAgentTransactionLayerOptions(sip.WithTransactionLayerLogger(diagoLogger)),
|
||||
)
|
||||
|
||||
sds.uaMu.Lock()
|
||||
sds.ua = ua
|
||||
sds.uaMu.Unlock()
|
||||
|
||||
sip.SetDefaultLogger(diagoLogger)
|
||||
media.SetDefaultLogger(diagoLogger)
|
||||
dg := diago.NewDiago(ua, diago.WithLogger(diagoLogger), diago.WithTransport(
|
||||
diago.Transport{
|
||||
Transport: sds.Transport,
|
||||
BindHost: sds.IP,
|
||||
BindPort: sds.Port,
|
||||
},
|
||||
))
|
||||
|
||||
err := dg.Serve(sds.ctx, func(inDialog *diago.DialogServerSession) {
|
||||
sds.HandleCall(inDialog)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
<-sds.ctx.Done()
|
||||
sds.logger.Debug("done")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sds *SIPDTMFServer) HandleCall(inDialog *diago.DialogServerSession) error {
|
||||
inDialog.Trying()
|
||||
inDialog.Ringing()
|
||||
inDialog.Answer()
|
||||
|
||||
reader, err := inDialog.AudioReaderDTMF()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userString := ""
|
||||
|
||||
return reader.Listen(func(dtmf rune) error {
|
||||
if dtmf == rune(sds.Separator[0]) {
|
||||
if sds.inputHandler != nil {
|
||||
dialogContext := context.WithValue(sds.ctx, sipCallContextKey("call"), &SIPDTMFCall{
|
||||
inDialog: inDialog,
|
||||
})
|
||||
sds.inputHandler(dialogContext, sds.Id(), SIPDTMFMessage{
|
||||
To: inDialog.ToUser(),
|
||||
Digits: userString,
|
||||
})
|
||||
}
|
||||
userString = ""
|
||||
} else {
|
||||
userString += string(dtmf)
|
||||
}
|
||||
return nil
|
||||
}, 5*time.Second)
|
||||
}
|
||||
|
||||
func (sds *SIPDTMFServer) Output(ctx context.Context, payload any) error {
|
||||
call, ok := ctx.Value(sipCallContextKey("call")).(*SIPDTMFCall)
|
||||
|
||||
if !ok {
|
||||
return errors.New("sip.dtmf.server output must originate from sip.dtmf.server input")
|
||||
}
|
||||
|
||||
gotLock := call.lock.TryLock()
|
||||
|
||||
if !gotLock {
|
||||
return errors.New("sip.dtmf.server call is already locked")
|
||||
}
|
||||
|
||||
if call.inDialog.LoadState() == sip.DialogStateEnded {
|
||||
return errors.New("sip.dtmf.server inDialog already ended")
|
||||
}
|
||||
|
||||
payloadDTMFResponse, ok := common.GetAnyAs[processor.SipDTMFResponse](payload)
|
||||
|
||||
if ok {
|
||||
dtmfWriter, err := call.inDialog.AudioWriterDTMF()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PreWait))
|
||||
for i, dtmfRune := range payloadDTMFResponse.Digits {
|
||||
err := dtmfWriter.WriteDTMF(dtmfRune)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("sip.dtmf.server error output dtmf digit at index %d", i)
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadDTMFResponse.PostWait))
|
||||
return nil
|
||||
}
|
||||
|
||||
payloadAudioFileResponse, ok := common.GetAnyAs[processor.SipAudioFileResponse](payload)
|
||||
|
||||
if ok {
|
||||
audioFile, err := os.Open(payloadAudioFileResponse.AudioFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer audioFile.Close()
|
||||
|
||||
playback, err := call.inDialog.PlaybackCreate()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadAudioFileResponse.PreWait))
|
||||
|
||||
_, err = playback.Play(audioFile, "audio/wav")
|
||||
|
||||
time.Sleep(time.Millisecond * time.Duration(payloadAudioFileResponse.PostWait))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return errors.New("sip.dtmf.server can only output SipDTMFResponse or SipAudioFileResponse")
|
||||
}
|
||||
|
||||
func (sds *SIPDTMFServer) Stop() {
|
||||
if sds.cancel != nil {
|
||||
defer sds.cancel()
|
||||
}
|
||||
sds.uaMu.Lock()
|
||||
defer sds.uaMu.Unlock()
|
||||
if sds.ua != nil {
|
||||
sds.ua.Close()
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package module_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
"github.com/jwetzell/showbridge-go/internal/module"
|
||||
)
|
||||
|
||||
func TestSIPCallServerFromRegistry(t *testing.T) {
|
||||
registration, ok := module.GetModuleRegistration("sip.call.server")
|
||||
if !ok {
|
||||
t.Fatalf("sip.call.server module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "sip.call.server",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create sip.call.server module: %s", err)
|
||||
}
|
||||
|
||||
if moduleInstance.Id() != "test" {
|
||||
t.Fatalf("sip.call.server module has wrong id: %s", moduleInstance.Id())
|
||||
}
|
||||
|
||||
if moduleInstance.Type() != "sip.call.server" {
|
||||
t.Fatalf("sip.call.server module has wrong type: %s", moduleInstance.Type())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadSIPCallServer(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
params map[string]any
|
||||
errorString string
|
||||
}{
|
||||
{
|
||||
name: "non-number port param",
|
||||
params: map[string]any{
|
||||
"port": "8000",
|
||||
},
|
||||
errorString: "sip.call.server port error: not a number",
|
||||
},
|
||||
{
|
||||
name: "non-string ip param",
|
||||
params: map[string]any{
|
||||
"ip": 123,
|
||||
},
|
||||
errorString: "sip.call.server ip error: not a string",
|
||||
},
|
||||
{
|
||||
name: "non-string transport param",
|
||||
params: map[string]any{
|
||||
"transport": 123,
|
||||
},
|
||||
errorString: "sip.call.server transport error: not a string",
|
||||
},
|
||||
{
|
||||
name: "non-string userAgent param",
|
||||
params: map[string]any{
|
||||
"userAgent": 123,
|
||||
},
|
||||
errorString: "sip.call.server userAgent error: not a string",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
registration, ok := module.GetModuleRegistration("sip.call.server")
|
||||
if !ok {
|
||||
t.Fatalf("sip.call.server module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "sip.call.server",
|
||||
Params: test.params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if test.errorString != err.Error() {
|
||||
t.Fatalf("sip.call.server got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = moduleInstance.Start(t.Context(), nil)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("sip.call.server expected to fail")
|
||||
}
|
||||
|
||||
if err.Error() != test.errorString {
|
||||
t.Fatalf("sip.call.server got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
package module_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/jwetzell/showbridge-go/internal/config"
|
||||
"github.com/jwetzell/showbridge-go/internal/module"
|
||||
)
|
||||
|
||||
func TestSIPDTMFServerFromRegistry(t *testing.T) {
|
||||
registration, ok := module.GetModuleRegistration("sip.dtmf.server")
|
||||
if !ok {
|
||||
t.Fatalf("sip.dtmf.server module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "sip.dtmf.server",
|
||||
Params: map[string]any{
|
||||
"separator": "#",
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create sip.dtmf.server module: %s", err)
|
||||
}
|
||||
|
||||
if moduleInstance.Id() != "test" {
|
||||
t.Fatalf("sip.dtmf.server module has wrong id: %s", moduleInstance.Id())
|
||||
}
|
||||
|
||||
if moduleInstance.Type() != "sip.dtmf.server" {
|
||||
t.Fatalf("sip.dtmf.server module has wrong type: %s", moduleInstance.Type())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadSIPDTMFServer(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
params map[string]any
|
||||
errorString string
|
||||
}{
|
||||
{
|
||||
name: "no separator param",
|
||||
params: map[string]any{},
|
||||
errorString: "sip.dtmf.server separator error: not found",
|
||||
},
|
||||
{
|
||||
name: "non-string separator param",
|
||||
params: map[string]any{
|
||||
"separator": 123,
|
||||
},
|
||||
errorString: "sip.dtmf.server separator error: not a string",
|
||||
},
|
||||
{
|
||||
name: "non-number port param",
|
||||
params: map[string]any{
|
||||
"separator": "#",
|
||||
"port": "8000",
|
||||
},
|
||||
errorString: "sip.dtmf.server port error: not a number",
|
||||
},
|
||||
{
|
||||
name: "non-string ip param",
|
||||
params: map[string]any{
|
||||
"separator": "#",
|
||||
"ip": 123,
|
||||
},
|
||||
errorString: "sip.dtmf.server ip error: not a string",
|
||||
},
|
||||
{
|
||||
name: "non-string transport param",
|
||||
params: map[string]any{
|
||||
"separator": "#",
|
||||
"transport": 123,
|
||||
},
|
||||
errorString: "sip.dtmf.server transport error: not a string",
|
||||
},
|
||||
{
|
||||
name: "non-string userAgent param",
|
||||
params: map[string]any{
|
||||
"separator": "#",
|
||||
"userAgent": 123,
|
||||
},
|
||||
errorString: "sip.dtmf.server userAgent error: not a string",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
|
||||
registration, ok := module.GetModuleRegistration("sip.dtmf.server")
|
||||
if !ok {
|
||||
t.Fatalf("sip.dtmf.server module not registered")
|
||||
}
|
||||
|
||||
moduleInstance, err := registration.New(config.ModuleConfig{
|
||||
Id: "test",
|
||||
Type: "sip.dtmf.server",
|
||||
Params: test.params,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if test.errorString != err.Error() {
|
||||
t.Fatalf("sip.dtmf.server got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = moduleInstance.Start(t.Context(), nil)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("sip.dtmf.server expected to fail")
|
||||
}
|
||||
|
||||
if err.Error() != test.errorString {
|
||||
t.Fatalf("sip.dtmf.server got error '%s', expected '%s'", err.Error(), test.errorString)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user