Skip to content

Commit

Permalink
Use SIP statuses as Go and gRPC errors. (#960)
Browse files Browse the repository at this point in the history
  • Loading branch information
dennwc authored Feb 4, 2025
1 parent bdefe90 commit e6dce57
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/healthy-turtles-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"github.com/livekit/protocol": minor
---

Use SIP statuses as Go and gRPC errors.
59 changes: 58 additions & 1 deletion livekit/sip.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,67 @@ import (
"strconv"
"strings"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/livekit/protocol/utils/xtwirp"
)

var _ xtwirp.ErrorMeta = (*SIPStatus)(nil)
var (
_ xtwirp.ErrorMeta = (*SIPStatus)(nil)
_ error = (*SIPStatus)(nil)
)

func (p SIPStatusCode) ShortName() string {
return strings.TrimPrefix(p.String(), "SIP_STATUS_")
}

func (p *SIPStatus) Error() string {
if p.Status != "" {
return fmt.Sprintf("sip status: %d: %s", p.Code, p.Status)
}
return fmt.Sprintf("sip status: %d (%s)", p.Code, p.Code.ShortName())
}

func (p *SIPStatus) GRPCStatus() *status.Status {
msg := p.Status
if msg == "" {
msg = p.Code.ShortName()
}
var code = codes.Internal
switch p.Code {
case SIPStatusCode_SIP_STATUS_OK:
return status.New(codes.OK, "OK")
case SIPStatusCode_SIP_STATUS_REQUEST_TERMINATED:
code = codes.Aborted
case SIPStatusCode_SIP_STATUS_BAD_REQUEST,
SIPStatusCode_SIP_STATUS_NOTFOUND,
SIPStatusCode_SIP_STATUS_ADDRESS_INCOMPLETE,
SIPStatusCode_SIP_STATUS_AMBIGUOUS,
SIPStatusCode_SIP_STATUS_BAD_EXTENSION,
SIPStatusCode_SIP_STATUS_EXTENSION_REQUIRED:
code = codes.InvalidArgument
case SIPStatusCode_SIP_STATUS_REQUEST_TIMEOUT,
SIPStatusCode_SIP_STATUS_GATEWAY_TIMEOUT:
code = codes.DeadlineExceeded
case SIPStatusCode_SIP_STATUS_SERVICE_UNAVAILABLE,
SIPStatusCode_SIP_STATUS_TEMPORARILY_UNAVAILABLE,
SIPStatusCode_SIP_STATUS_BUSY_HERE,
SIPStatusCode_SIP_STATUS_GLOBAL_BUSY_EVERYWHERE,
SIPStatusCode_SIP_STATUS_NOT_IMPLEMENTED,
SIPStatusCode_SIP_STATUS_GLOBAL_DECLINE:
code = codes.Unavailable
case SIPStatusCode_SIP_STATUS_PROXY_AUTH_REQUIRED,
SIPStatusCode_SIP_STATUS_UNAUTHORIZED,
SIPStatusCode_SIP_STATUS_FORBIDDEN:
code = codes.PermissionDenied
}
st := status.New(code, fmt.Sprintf("sip status %d: %s", p.Code, msg))
if st2, err := st.WithDetails(p); err == nil {
return st2
}
return st
}

func (p *SIPStatus) TwirpErrorMeta() map[string]string {
status := p.Status
Expand Down
16 changes: 16 additions & 0 deletions livekit/sip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import (
"testing"

"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)

func TestSIPTrunkAs(t *testing.T) {
Expand Down Expand Up @@ -358,3 +361,16 @@ func TestSIPDispatchRuleFilter(t *testing.T) {
})
}
}

func TestGRPCStatus(t *testing.T) {
e := &SIPStatus{Code: SIPStatusCode_SIP_STATUS_BUSY_HERE}
st, ok := status.FromError(e)
require.True(t, ok)
require.Equal(t, codes.Unavailable, st.Code())
require.Equal(t, "sip status 486: BUSY_HERE", st.Message())
details := st.Details()
require.Len(t, details, 1)
e2, ok := details[0].(*SIPStatus)
require.True(t, ok)
require.True(t, proto.Equal(e, e2))
}

0 comments on commit e6dce57

Please sign in to comment.