Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 133 additions & 44 deletions cmd/lk/sip.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,57 +227,19 @@ var (
Usage: "Create a SIP Dispatch Rule",
Action: createSIPDispatchRule,
ArgsUsage: RequestDesc[livekit.CreateSIPDispatchRuleRequest](),
Flags: []cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "Sets a new name for the dispatch rule",
},
&cli.StringSliceFlag{
Name: "trunks",
Usage: "Sets a list of trunks for the dispatch rule",
},
&cli.StringFlag{
Name: "direct",
Usage: "Sets a direct dispatch to a specified room",
},
&cli.StringFlag{
Name: "caller",
Aliases: []string{"individual"},
Usage: "Sets a individual caller dispatch to a new room with a specific prefix",
},
&cli.StringFlag{
Name: "callee",
Usage: "Sets a callee number dispatch to a new room with a specific prefix",
},
&cli.BoolFlag{
Name: "pin",
Usage: "PIN for a dispatch rule",
},
&cli.BoolFlag{
Name: "randomize",
Usage: "Randomize room name, only applies to callee dispatch",
},
},
Flags: sipDispatchRuleBaseFlags,
},
{
Name: "update",
Usage: "Update a SIP Dispatch Rule",
Action: updateSIPDispatchRule,
ArgsUsage: RequestDesc[livekit.UpdateSIPDispatchRuleRequest](),
Flags: []cli.Flag{
Flags: append([]cli.Flag{
&cli.StringFlag{
Name: "id",
Usage: "ID for the rule to update",
},
&cli.StringFlag{
Name: "name",
Usage: "Sets a new name for the rule",
},
&cli.StringSliceFlag{
Name: "trunks",
Usage: "Sets a new list of trunk IDs",
},
},
}, sipDispatchRuleBaseFlags...),
},
{
Name: "delete",
Expand Down Expand Up @@ -413,6 +375,47 @@ var (
},
},
}

// Define a shared base flag list for SIP Dispatch Rule create/update
sipDispatchRuleBaseFlags = []cli.Flag{
&cli.StringFlag{
Name: "name",
Usage: "Sets a name for the dispatch rule",
},
&cli.StringSliceFlag{
Name: "trunks",
Usage: "Sets a list of trunks for the dispatch rule",
},
&cli.StringFlag{
Name: "direct",
Usage: "Sets a direct dispatch to a specified room",
},
&cli.StringFlag{
Name: "caller",
Aliases: []string{"individual"},
Usage: "Sets an individual caller dispatch to a new room with a specific prefix",
},
&cli.StringFlag{
Name: "callee",
Usage: "Sets a callee number dispatch to a new room with a specific prefix",
},
&cli.BoolFlag{
Name: "pin",
Usage: "PIN for a dispatch rule",
},
&cli.BoolFlag{
Name: "randomize",
Usage: "Randomize room name, only applies to callee dispatch",
},
&cli.StringFlag{
Name: "dispatch-url",
Usage: "Sets a dynamic dispatch rule with webhook URL (uses POST method)",
},
&cli.StringFlag{
Name: "method",
Usage: "Sets the HTTP method for dynamic dispatch rule (default: POST)",
},
}
)

func listUpdateFlag(cmd *cli.Command, setName string) *livekit.ListUpdate {
Expand Down Expand Up @@ -895,6 +898,23 @@ func createSIPDispatchRule(ctx context.Context, cmd *cli.Command) error {
},
}
}
if val := cmd.String("dispatch-url"); val != "" {
if p.Rule != nil {
return fmt.Errorf("only one dispatch rule type is allowed")
}
method := cmd.String("method")
if method == "" {
method = "POST"
}
p.Rule = &livekit.SIPDispatchRule{
Rule: &livekit.SIPDispatchRule_DispatchRuleDynamic{
DispatchRuleDynamic: &livekit.SIPDispatchRuleDynamic{
Url: val,
Method: method,
},
},
}
}
return nil
}, cli.CreateSIPDispatchRule, printSIPDispatchRuleID)
}
Expand Down Expand Up @@ -945,6 +965,71 @@ func updateSIPDispatchRule(ctx context.Context, cmd *cli.Command) error {
if id == "" {
return errors.New("no ID specified")
}

// Check if any dispatch rule flags are set
hasDispatchRuleFlags := cmd.IsSet("direct") || cmd.IsSet("caller") || cmd.IsSet("callee") || cmd.IsSet("dispatch-url")

if hasDispatchRuleFlags {
// Create a new dispatch rule from flags (similar to create function)
rule := &livekit.SIPDispatchRule{}

if val := cmd.String("direct"); val != "" {
rule.Rule = &livekit.SIPDispatchRule_DispatchRuleDirect{
DispatchRuleDirect: &livekit.SIPDispatchRuleDirect{
RoomName: val,
Pin: cmd.String("pin"),
},
}
} else if val := cmd.String("caller"); val != "" {
rule.Rule = &livekit.SIPDispatchRule_DispatchRuleIndividual{
DispatchRuleIndividual: &livekit.SIPDispatchRuleIndividual{
RoomPrefix: val,
Pin: cmd.String("pin"),
},
}
} else if val := cmd.String("callee"); val != "" {
rule.Rule = &livekit.SIPDispatchRule_DispatchRuleCallee{
DispatchRuleCallee: &livekit.SIPDispatchRuleCallee{
RoomPrefix: val,
Randomize: cmd.Bool("randomize"),
Pin: cmd.String("pin"),
},
}
} else if val := cmd.String("dispatch-url"); val != "" {
method := cmd.String("method")
if method == "" {
method = "POST"
}
rule.Rule = &livekit.SIPDispatchRule_DispatchRuleDynamic{
DispatchRuleDynamic: &livekit.SIPDispatchRuleDynamic{
Url: val,
Method: method,
},
}
}

// Use Update action with the rule field populated
req := &livekit.SIPDispatchRuleUpdate{
Rule: rule,
}
if val := cmd.String("name"); val != "" {
req.Name = &val
}
req.TrunkIds = listUpdateFlag(cmd, "trunks")

info, err := cli.UpdateSIPDispatchRule(ctx, &livekit.UpdateSIPDispatchRuleRequest{
SipDispatchRuleId: id,
Action: &livekit.UpdateSIPDispatchRuleRequest_Update{
Update: req,
},
})
if err != nil {
return err
}
printSIPDispatchRuleID(info)
return err
}

req := &livekit.SIPDispatchRuleUpdate{}
if val := cmd.String("name"); val != "" {
req.Name = &val
Expand All @@ -969,10 +1054,10 @@ func listSipDispatchRule(ctx context.Context, cmd *cli.Command) error {
return err
}
return listAndPrint(ctx, cmd, cli.ListSIPDispatchRule, &livekit.ListSIPDispatchRuleRequest{}, []string{
"SipDispatchRuleID", "Name", "SipTrunks", "Type", "RoomName", "Pin",
"SipDispatchRuleID", "Name", "SipTrunks", "Type", "RoomName", "Pin", "DispatchURL",
"Attributes", "Agents",
}, func(item *livekit.SIPDispatchRuleInfo) []string {
var room, typ, pin string
var room, typ, pin, dispatchUrl string
switch r := item.GetRule().GetRule().(type) {
case *livekit.SIPDispatchRule_DispatchRuleDirect:
room = r.DispatchRuleDirect.RoomName
Expand All @@ -989,6 +1074,10 @@ func listSipDispatchRule(ctx context.Context, cmd *cli.Command) error {
}
pin = r.DispatchRuleCallee.Pin
typ = "Callee"
case *livekit.SIPDispatchRule_DispatchRuleDynamic:
room = ""
dispatchUrl = r.DispatchRuleDynamic.Url
typ = "Dynamic"
}
trunks := strings.Join(item.TrunkIds, ",")
if trunks == "" {
Expand All @@ -1001,7 +1090,7 @@ func listSipDispatchRule(ctx context.Context, cmd *cli.Command) error {
}
}
return []string{
item.SipDispatchRuleId, item.Name, trunks, typ, room, pin,
item.SipDispatchRuleId, item.Name, trunks, typ, room, pin, dispatchUrl,
fmt.Sprintf("%v", item.Attributes), strings.Join(agents, ","),
}
})
Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/go-logr/logr v1.4.3
github.com/go-task/task/v3 v3.43.3
github.com/joho/godotenv v1.5.1
github.com/livekit/protocol v1.39.3-0.20250620210232-022f52ebc520
github.com/livekit/protocol v1.39.4-0.20250630060303-c71f9553b08a
github.com/livekit/server-sdk-go/v2 v2.9.2-0.20250612220331-fb6301c37033
github.com/moby/buildkit v0.22.0
github.com/pion/rtcp v1.2.15
Expand Down Expand Up @@ -47,7 +47,6 @@ require (
github.com/alecthomas/chroma/v2 v2.16.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aws/smithy-go v1.22.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
Expand Down Expand Up @@ -278,8 +276,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT
github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ=
github.com/livekit/mediatransportutil v0.0.0-20250519131108-fb90f5acfded h1:ylZPdnlX1RW9Z15SD4mp87vT2D2shsk0hpLJwSPcq3g=
github.com/livekit/mediatransportutil v0.0.0-20250519131108-fb90f5acfded/go.mod h1:mSNtYzSf6iY9xM3UX42VEI+STHvMgHmrYzEHPcdhB8A=
github.com/livekit/protocol v1.39.3-0.20250620210232-022f52ebc520 h1:PDL0srf3NH7B6XnAHyRZkvcZq808R0rBTAvPr9W0NiQ=
github.com/livekit/protocol v1.39.3-0.20250620210232-022f52ebc520/go.mod h1:W1zjNtf9w2EVlVfdfXjRp+K9Ng51KWKsBG7Sghk9x3Y=
github.com/livekit/protocol v1.39.4-0.20250630060303-c71f9553b08a h1:8W+OwGRRPwVu2rFefuYq6i4dR5Yw1obqF1F9Nh7pYEs=
github.com/livekit/protocol v1.39.4-0.20250630060303-c71f9553b08a/go.mod h1:6HPISM0bkTXTk9RIaQTCe0IDbomBPz7Jwp+N3w5sqL0=
github.com/livekit/psrpc v0.6.1-0.20250511053145-465289d72c3c h1:WwEr0YBejYbKzk8LSaO9h8h0G9MnE7shyDu8yXQWmEc=
github.com/livekit/psrpc v0.6.1-0.20250511053145-465289d72c3c/go.mod h1:kmD+AZPkWu0MaXIMv57jhNlbiSZZ/Jx4bzlxBDVmJes=
github.com/livekit/server-sdk-go/v2 v2.9.2-0.20250612220331-fb6301c37033 h1:5znH+FcwNGJMVfLVqrTcVMeurZGTcVnH+4l4o1wfU5k=
Expand Down