Skip to content

Commit 8a1e15b

Browse files
committed
Add support for call legs
1 parent dab548b commit 8a1e15b

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

voice/call.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,8 @@ func InitiateCall(client *messagebird.Client, source, destination string, callfl
143143
func (call *Call) Delete(client *messagebird.Client) error {
144144
return client.Request(nil, "DELETE", "calls/"+call.ID, nil)
145145
}
146+
147+
// Legs returns a paginator over all Legs associated with a call.
148+
func (call *Call) Legs(client *messagebird.Client) *Paginator {
149+
return newPaginator(client, fmt.Sprintf("calls/%s/legs", call.ID), reflect.TypeOf(Leg{}))
150+
}

voice/leg.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
package voice
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"time"
7+
)
8+
9+
// LegStatus enumerates all valid values for a leg status.
10+
type LegStatus string
11+
12+
const (
13+
// LegStatusStarting indicates that a leg is currently starting.
14+
LegStatusStarting LegStatus = "starting"
15+
// LegStatusRinging indicates that a leg is connected and ringing.
16+
LegStatusRinging LegStatus = "ringing"
17+
// LegStatusOngoing indicates a healthy leg that is currently participating
18+
// in a call.
19+
LegStatusOngoing LegStatus = "ongoing"
20+
// LegStatusBusy indicates that a leg could not be established because the
21+
// other side is busy.
22+
LegStatusBusy LegStatus = "busy"
23+
// LegStatusNoAnswer indicates that a leg could not be established because
24+
// the other side did not pick up.
25+
LegStatusNoAnswer LegStatus = "no_answer"
26+
// LegStatusFailed indicates some kind of failure of a leg.
27+
LegStatusFailed LegStatus = "failed"
28+
// LegStatusHangup indicates that a leg has been hung up.
29+
LegStatusHangup LegStatus = "hangup"
30+
)
31+
32+
// LegDirection indicates the direction of some leg in a call.
33+
type LegDirection string
34+
35+
const (
36+
// LegDirectionOutgoing is the direction of a leg that are created when a
37+
// call is transferred.
38+
LegDirectionOutgoing LegDirection = "outgoing"
39+
// LegDirectionIncoming is the direction of a leg that is created when a
40+
// number is called.
41+
LegDirectionIncoming LegDirection = "incoming"
42+
)
43+
44+
// A Leg describes a leg object (inbound or outbound) that belongs to a call.
45+
//
46+
// At least one leg exists per call. Inbound legs are being created when an
47+
// incoming call to a Number is being initiated. Outgoing legs are created when
48+
// a call is transferred or when a call is being originated from the API.
49+
type Leg struct {
50+
// The unique ID of the leg.
51+
ID string
52+
// The unique ID of the call that this leg belongs to.
53+
CallID string
54+
// The number/SIP URL that is making the connection.
55+
Source string
56+
// The number/SIP URL that a connection is made to.
57+
Destination string
58+
// The status of the leg. Possible values: starting, ringing, ongoing,
59+
// busy, no_answer, failed and hangup.
60+
Status LegStatus
61+
// The direction of the leg, indicating if it's an incoming connection or
62+
// outgoing (e.g. for transferring a call). Possible values: incoming,
63+
// outgoing.
64+
Direction LegDirection
65+
// The cost of the leg. The amount relates to the currency parameter.
66+
Cost float64
67+
// The three-letter currency code (ISO 4217) related to the cost of the
68+
// leg.
69+
Currency string
70+
// The duration of the leg.
71+
//
72+
// Truncated to seconds.
73+
Duration time.Duration
74+
// The date-time the leg was created.
75+
CreatedAt time.Time
76+
// The date-time the leg was last updated.
77+
UpdatedAt time.Time
78+
// The date-time the leg was answered.
79+
AnsweredAt *time.Time
80+
// The date-time the leg ended.
81+
EndedAt *time.Time
82+
}
83+
84+
type jsonLeg struct {
85+
ID string `json:"id"`
86+
CallID string `json:"callID"`
87+
Source string `json:"source"`
88+
Destination string `json:"destination"`
89+
Status string `json:"status"`
90+
Direction string `json:"direction"`
91+
Cost float64 `json:"cost"`
92+
Currency string `json:"currency"`
93+
Duration int `json:"duration"`
94+
CreatedAt string `json:"createdAt"`
95+
UpdatedAt string `json:"updatedAt"`
96+
AnsweredAt string `json:"answeredAt,omitempty"`
97+
EndedAt string `json:"endedAt,omitempty"`
98+
}
99+
100+
// UnmarshalJSON implements the json.Unmarshaler interface.
101+
func (leg *Leg) UnmarshalJSON(data []byte) error {
102+
var raw jsonLeg
103+
if err := json.Unmarshal(data, &raw); err != nil {
104+
return err
105+
}
106+
createdAt, err := time.Parse(time.RFC3339, raw.CreatedAt)
107+
if err != nil {
108+
return fmt.Errorf("unable to parse Leg CreatedAt: %v", err)
109+
}
110+
updatedAt, err := time.Parse(time.RFC3339, raw.UpdatedAt)
111+
if err != nil {
112+
return fmt.Errorf("unable to parse Leg UpdatedAt: %v", err)
113+
}
114+
var answeredAt *time.Time
115+
if raw.EndedAt != "" {
116+
aat, err := time.Parse(time.RFC3339, raw.EndedAt)
117+
if err != nil {
118+
return fmt.Errorf("unable to parse Leg AnsweredAt: %v", err)
119+
}
120+
answeredAt = &aat
121+
}
122+
var endedAt *time.Time
123+
if raw.EndedAt != "" {
124+
eat, err := time.Parse(time.RFC3339, raw.EndedAt)
125+
if err != nil {
126+
return fmt.Errorf("unable to parse Leg EndedAt: %v", err)
127+
}
128+
endedAt = &eat
129+
}
130+
*leg = Leg{
131+
ID: raw.ID,
132+
CallID: raw.CallID,
133+
Source: raw.Source,
134+
Destination: raw.Destination,
135+
Status: LegStatus(raw.Status),
136+
Direction: LegDirection(raw.Direction),
137+
Cost: raw.Cost,
138+
Currency: raw.Currency,
139+
Duration: time.Second * time.Duration(raw.Duration),
140+
CreatedAt: createdAt,
141+
UpdatedAt: updatedAt,
142+
AnsweredAt: answeredAt,
143+
EndedAt: endedAt,
144+
}
145+
return nil
146+
}

0 commit comments

Comments
 (0)