Skip to content

Commit 0cf7daa

Browse files
Incorporating changes in the list phone number api (#734)
* Incorporating changes in the list phone number api * Doing away with the now deprecated SipDispatchRuleId field and also directly using SipDispatchRuleIds instead of constructing it locally
1 parent 63dc9fc commit 0cf7daa

File tree

3 files changed

+59
-256
lines changed

3 files changed

+59
-256
lines changed

cmd/lk/phone_number.go

Lines changed: 53 additions & 250 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,17 @@ var (
7676
Flags: []cli.Flag{
7777
&cli.IntFlag{
7878
Name: "limit",
79-
Usage: "Maximum number of results (default: 50)",
79+
Usage: "Maximum number of results per page (default: 50)",
8080
Value: 50,
8181
},
82+
&cli.IntFlag{
83+
Name: "offset",
84+
Usage: "Offset for pagination (default: 0)",
85+
Value: 0,
86+
},
8287
&cli.StringSliceFlag{
8388
Name: "status",
84-
Usage: "Filter by status(es) (active, pending, released). Multiple values can be specified.",
89+
Usage: "Filter by status(es) (active, pending, released, offline). Multiple values can be specified.",
8590
},
8691
&cli.StringFlag{
8792
Name: "sip-dispatch-rule-id",
@@ -161,36 +166,6 @@ func createPhoneNumberClient(ctx context.Context, cmd *cli.Command) (*lksdk.Phon
161166
return lksdk.NewPhoneNumberClient(project.URL, project.APIKey, project.APISecret, withDefaultClientOpts(project)...), nil
162167
}
163168

164-
// getPhoneNumberToDispatchRulesMap fetches all dispatch rules and maps phone number IDs to their associated dispatch rule IDs
165-
// Returns a map where key is phone number ID and value is a slice of dispatch rule IDs
166-
func getPhoneNumberToDispatchRulesMap(ctx context.Context, cmd *cli.Command) (map[string][]string, error) {
167-
_, err := requireProject(ctx, cmd)
168-
if err != nil {
169-
return nil, fmt.Errorf("failed to get project: %w", err)
170-
}
171-
172-
sipClient := lksdk.NewSIPClient(project.URL, project.APIKey, project.APISecret, withDefaultClientOpts(project)...)
173-
174-
// List all dispatch rules
175-
resp, err := sipClient.ListSIPDispatchRule(ctx, &livekit.ListSIPDispatchRuleRequest{})
176-
if err != nil {
177-
return nil, fmt.Errorf("failed to list dispatch rules: %w", err)
178-
}
179-
180-
// Build map: phone number ID -> []dispatch rule IDs
181-
phoneNumberToRules := make(map[string][]string)
182-
for _, rule := range resp.Items {
183-
for _, trunkID := range rule.TrunkIds {
184-
// Check if trunkID is a phone number ID (starts with PN_PPN_)
185-
if strings.HasPrefix(trunkID, "PN_PPN_") {
186-
phoneNumberToRules[trunkID] = append(phoneNumberToRules[trunkID], rule.SipDispatchRuleId)
187-
}
188-
}
189-
}
190-
191-
return phoneNumberToRules, nil
192-
}
193-
194169
func searchPhoneNumbers(ctx context.Context, cmd *cli.Command) error {
195170
client, err := createPhoneNumberClient(ctx, cmd)
196171
if err != nil {
@@ -265,65 +240,9 @@ func purchasePhoneNumbers(ctx context.Context, cmd *cli.Command) error {
265240
req.SipDispatchRuleId = &dispatchRuleID
266241
}
267242

268-
// Call purchase and get dispatch rules in parallel
269-
type purchaseResult struct {
270-
resp *livekit.PurchasePhoneNumberResponse
271-
err error
272-
}
273-
type dispatchRulesResult struct {
274-
rules map[string][]string
275-
err error
276-
}
277-
278-
purchaseChan := make(chan purchaseResult, 1)
279-
dispatchRulesChan := make(chan dispatchRulesResult, 1)
280-
281-
// Purchase phone numbers
282-
go func() {
283-
resp, err := client.PurchasePhoneNumber(ctx, req)
284-
purchaseChan <- purchaseResult{resp: resp, err: err}
285-
}()
286-
287-
// Get dispatch rules mapping in parallel
288-
go func() {
289-
rules, err := getPhoneNumberToDispatchRulesMap(ctx, cmd)
290-
dispatchRulesChan <- dispatchRulesResult{rules: rules, err: err}
291-
}()
292-
293-
// Wait for purchase to complete
294-
purchaseRes := <-purchaseChan
295-
if purchaseRes.err != nil {
296-
return purchaseRes.err
297-
}
298-
resp := purchaseRes.resp
299-
300-
// Wait for dispatch rules (ignore errors, we'll just not show them)
301-
dispatchRulesRes := <-dispatchRulesChan
302-
phoneNumberToRules := dispatchRulesRes.rules
303-
if dispatchRulesRes.err != nil {
304-
// Log but don't fail
305-
if cmd.Bool("verbose") {
306-
fmt.Fprintf(cmd.ErrWriter, "Warning: failed to get dispatch rules: %v\n", dispatchRulesRes.err)
307-
}
308-
phoneNumberToRules = make(map[string][]string)
309-
}
310-
311-
// If dispatch rule ID was provided, add it to the mapping for display
312-
// (The actual update is now handled by cloud-io)
313-
if dispatchRuleID != "" {
314-
for _, phoneNumber := range resp.PhoneNumbers {
315-
// Check if dispatchRuleID is already in the list
316-
found := false
317-
for _, ruleID := range phoneNumberToRules[phoneNumber.Id] {
318-
if ruleID == dispatchRuleID {
319-
found = true
320-
break
321-
}
322-
}
323-
if !found {
324-
phoneNumberToRules[phoneNumber.Id] = append(phoneNumberToRules[phoneNumber.Id], dispatchRuleID)
325-
}
326-
}
243+
resp, err := client.PurchasePhoneNumber(ctx, req)
244+
if err != nil {
245+
return err
327246
}
328247

329248
if cmd.Bool("json") {
@@ -334,9 +253,8 @@ func purchasePhoneNumbers(ctx context.Context, cmd *cli.Command) error {
334253
fmt.Printf("Successfully purchased %d phone numbers:\n", len(resp.PhoneNumbers))
335254
for _, phoneNumber := range resp.PhoneNumbers {
336255
ruleInfo := ""
337-
rules := phoneNumberToRules[phoneNumber.Id]
338-
if len(rules) > 0 {
339-
ruleInfo = fmt.Sprintf(" (SIP Dispatch Rules: %s)", strings.Join(rules, ", "))
256+
if len(phoneNumber.SipDispatchRuleIds) > 0 {
257+
ruleInfo = fmt.Sprintf(" (SIP Dispatch Rules: %s)", strings.Join(phoneNumber.SipDispatchRuleIds, ", "))
340258
}
341259
fmt.Printf(" %s (%s) - %s%s\n", phoneNumber.E164Format, phoneNumber.Id, strings.TrimPrefix(phoneNumber.Status.String(), "PHONE_NUMBER_STATUS_"), ruleInfo)
342260
}
@@ -351,10 +269,17 @@ func listPhoneNumbers(ctx context.Context, cmd *cli.Command) error {
351269
}
352270

353271
req := &livekit.ListPhoneNumbersRequest{}
354-
if val := cmd.Int("limit"); val != 0 {
355-
limit := int32(val)
356-
req.Limit = &limit
272+
limit := int32(cmd.Int("limit"))
273+
offset := int32(cmd.Int("offset"))
274+
275+
// Encode offset and limit into a page token for pagination
276+
// Even if offset is 0, we encode it to include the limit in the token
277+
pageToken, err := livekit.EncodeTokenPagination(offset, limit)
278+
if err != nil {
279+
return fmt.Errorf("failed to encode pagination token: %w", err)
357280
}
281+
req.PageToken = pageToken
282+
358283
if statuses := cmd.StringSlice("status"); len(statuses) > 0 {
359284
var phoneNumberStatuses []livekit.PhoneNumberStatus
360285
for _, status := range statuses {
@@ -370,66 +295,41 @@ func listPhoneNumbers(ctx context.Context, cmd *cli.Command) error {
370295
req.SipDispatchRuleId = &val
371296
}
372297

373-
// Call list and get dispatch rules in parallel
374-
type listResult struct {
375-
resp *livekit.ListPhoneNumbersResponse
376-
err error
377-
}
378-
type dispatchRulesResult struct {
379-
rules map[string][]string
380-
err error
298+
resp, err := client.ListPhoneNumbers(ctx, req)
299+
if err != nil {
300+
return err
381301
}
382302

383-
listChan := make(chan listResult, 1)
384-
dispatchRulesChan := make(chan dispatchRulesResult, 1)
385-
386-
// List phone numbers
387-
go func() {
388-
resp, err := client.ListPhoneNumbers(ctx, req)
389-
listChan <- listResult{resp: resp, err: err}
390-
}()
391-
392-
// Get dispatch rules mapping in parallel
393-
go func() {
394-
rules, err := getPhoneNumberToDispatchRulesMap(ctx, cmd)
395-
dispatchRulesChan <- dispatchRulesResult{rules: rules, err: err}
396-
}()
397-
398-
// Wait for list to complete
399-
listRes := <-listChan
400-
if listRes.err != nil {
401-
return listRes.err
303+
if cmd.Bool("json") {
304+
util.PrintJSON(resp)
305+
return nil
402306
}
403-
resp := listRes.resp
404307

405-
// Wait for dispatch rules (ignore errors, we'll just not show them)
406-
dispatchRulesRes := <-dispatchRulesChan
407-
phoneNumberToRules := dispatchRulesRes.rules
408-
if dispatchRulesRes.err != nil {
409-
// Log but don't fail
410-
if cmd.Bool("verbose") {
411-
fmt.Fprintf(cmd.ErrWriter, "Warning: failed to get dispatch rules: %v\n", dispatchRulesRes.err)
412-
}
413-
phoneNumberToRules = make(map[string][]string)
308+
fmt.Printf("Total phone numbers: %d", resp.TotalCount)
309+
if resp.OfflineCount > 0 {
310+
fmt.Printf(" (%d offline)", resp.OfflineCount)
414311
}
312+
fmt.Printf("\n")
415313

416-
if cmd.Bool("json") {
417-
util.PrintJSON(resp)
418-
return nil
314+
// Show pagination info
315+
if offset > 0 {
316+
fmt.Printf("Showing results from offset %d\n", offset)
317+
}
318+
if resp.NextPageToken != nil {
319+
nextOffset, _, err := livekit.DecodeTokenPagination(resp.NextPageToken)
320+
if err == nil {
321+
fmt.Printf("More results available. Use --offset %d to see the next page.\n", nextOffset)
322+
}
419323
}
420324

421-
fmt.Printf("Total phone numbers: %d\n", resp.TotalCount)
422325
return listAndPrint(ctx, cmd, func(ctx context.Context, req *livekit.ListPhoneNumbersRequest) (*livekit.ListPhoneNumbersResponse, error) {
423326
return client.ListPhoneNumbers(ctx, req)
424327
}, req, []string{
425328
"ID", "E164", "Country", "Area Code", "Type", "Locality", "Region", "Capabilities", "Status", "SIP Dispatch Rules",
426329
}, func(item *livekit.PhoneNumber) []string {
427-
rules := phoneNumberToRules[item.Id]
428330
dispatchRulesStr := ""
429-
if len(rules) > 0 {
430-
dispatchRulesStr = strings.Join(rules, ", ")
431-
} else if item.SipDispatchRuleId != "" {
432-
dispatchRulesStr = item.SipDispatchRuleId
331+
if len(item.SipDispatchRuleIds) > 0 {
332+
dispatchRulesStr = strings.Join(item.SipDispatchRuleIds, ", ")
433333
} else {
434334
dispatchRulesStr = "-"
435335
}
@@ -471,47 +371,9 @@ func getPhoneNumber(ctx context.Context, cmd *cli.Command) error {
471371
req.PhoneNumber = &phoneNumber
472372
}
473373

474-
// Call get and get dispatch rules in parallel
475-
type getResult struct {
476-
resp *livekit.GetPhoneNumberResponse
477-
err error
478-
}
479-
type dispatchRulesResult struct {
480-
rules map[string][]string
481-
err error
482-
}
483-
484-
getChan := make(chan getResult, 1)
485-
dispatchRulesChan := make(chan dispatchRulesResult, 1)
486-
487-
// Get phone number
488-
go func() {
489-
resp, err := client.GetPhoneNumber(ctx, req)
490-
getChan <- getResult{resp: resp, err: err}
491-
}()
492-
493-
// Get dispatch rules mapping in parallel
494-
go func() {
495-
rules, err := getPhoneNumberToDispatchRulesMap(ctx, cmd)
496-
dispatchRulesChan <- dispatchRulesResult{rules: rules, err: err}
497-
}()
498-
499-
// Wait for get to complete
500-
getRes := <-getChan
501-
if getRes.err != nil {
502-
return getRes.err
503-
}
504-
resp := getRes.resp
505-
506-
// Wait for dispatch rules (ignore errors, we'll just not show them)
507-
dispatchRulesRes := <-dispatchRulesChan
508-
phoneNumberToRules := dispatchRulesRes.rules
509-
if dispatchRulesRes.err != nil {
510-
// Log but don't fail
511-
if cmd.Bool("verbose") {
512-
fmt.Fprintf(cmd.ErrWriter, "Warning: failed to get dispatch rules: %v\n", dispatchRulesRes.err)
513-
}
514-
phoneNumberToRules = make(map[string][]string)
374+
resp, err := client.GetPhoneNumber(ctx, req)
375+
if err != nil {
376+
return err
515377
}
516378

517379
if cmd.Bool("json") {
@@ -520,12 +382,9 @@ func getPhoneNumber(ctx context.Context, cmd *cli.Command) error {
520382
}
521383

522384
item := resp.PhoneNumber
523-
rules := phoneNumberToRules[item.Id]
524385
dispatchRulesStr := ""
525-
if len(rules) > 0 {
526-
dispatchRulesStr = strings.Join(rules, ", ")
527-
} else if item.SipDispatchRuleId != "" {
528-
dispatchRulesStr = item.SipDispatchRuleId
386+
if len(item.SipDispatchRuleIds) > 0 {
387+
dispatchRulesStr = strings.Join(item.SipDispatchRuleIds, ", ")
529388
} else {
530389
dispatchRulesStr = "-"
531390
}
@@ -576,64 +435,9 @@ func updatePhoneNumber(ctx context.Context, cmd *cli.Command) error {
576435
req.SipDispatchRuleId = &dispatchRuleID
577436
}
578437

579-
// Call update and get dispatch rules in parallel
580-
type updateResult struct {
581-
resp *livekit.UpdatePhoneNumberResponse
582-
err error
583-
}
584-
type dispatchRulesResult struct {
585-
rules map[string][]string
586-
err error
587-
}
588-
589-
updateChan := make(chan updateResult, 1)
590-
dispatchRulesChan := make(chan dispatchRulesResult, 1)
591-
592-
// Update phone number
593-
go func() {
594-
resp, err := client.UpdatePhoneNumber(ctx, req)
595-
updateChan <- updateResult{resp: resp, err: err}
596-
}()
597-
598-
// Get dispatch rules mapping in parallel
599-
go func() {
600-
rules, err := getPhoneNumberToDispatchRulesMap(ctx, cmd)
601-
dispatchRulesChan <- dispatchRulesResult{rules: rules, err: err}
602-
}()
603-
604-
// Wait for update to complete
605-
updateRes := <-updateChan
606-
if updateRes.err != nil {
607-
return updateRes.err
608-
}
609-
resp := updateRes.resp
610-
611-
// Wait for dispatch rules (ignore errors, we'll just not show them)
612-
dispatchRulesRes := <-dispatchRulesChan
613-
phoneNumberToRules := dispatchRulesRes.rules
614-
if dispatchRulesRes.err != nil {
615-
// Log but don't fail
616-
if cmd.Bool("verbose") {
617-
fmt.Fprintf(cmd.ErrWriter, "Warning: failed to get dispatch rules: %v\n", dispatchRulesRes.err)
618-
}
619-
phoneNumberToRules = make(map[string][]string)
620-
}
621-
622-
// If dispatch rule ID was provided, add it to the mapping for display
623-
// (The actual update is now handled by cloud-io)
624-
if dispatchRuleID != "" {
625-
phoneNumberID := resp.PhoneNumber.Id
626-
// Check if dispatchRuleID is already in the list
627-
found := false
628-
for _, ruleID := range phoneNumberToRules[phoneNumberID] {
629-
if ruleID == dispatchRuleID {
630-
found = true
631-
break
632-
}
633-
}
634-
if !found {
635-
phoneNumberToRules[phoneNumberID] = append(phoneNumberToRules[phoneNumberID], dispatchRuleID)
636-
}
438+
resp, err := client.UpdatePhoneNumber(ctx, req)
439+
if err != nil {
440+
return err
637441
}
638442

639443
if cmd.Bool("json") {
@@ -642,10 +446,9 @@ func updatePhoneNumber(ctx context.Context, cmd *cli.Command) error {
642446
}
643447

644448
item := resp.PhoneNumber
645-
rules := phoneNumberToRules[item.Id]
646449
dispatchRulesStr := ""
647-
if len(rules) > 0 {
648-
dispatchRulesStr = strings.Join(rules, ", ")
450+
if len(item.SipDispatchRuleIds) > 0 {
451+
dispatchRulesStr = strings.Join(item.SipDispatchRuleIds, ", ")
649452
} else {
650453
dispatchRulesStr = "-"
651454
}

0 commit comments

Comments
 (0)