Skip to content

Commit

Permalink
Implemented Twilio Video Api
Browse files Browse the repository at this point in the history
  • Loading branch information
t-tomalak committed Jan 31, 2018
1 parent 9de033e commit 43cbb91
Show file tree
Hide file tree
Showing 9 changed files with 318 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ Maksym Pavlenko <[email protected]>
Marcus Westin <[email protected]>
Minko Gechev <[email protected]>
Scott Gose <[email protected]>
Tomasz Tomalak <[email protected]>
4 changes: 4 additions & 0 deletions BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ go_library(
"prices_voice.go",
"queue.go",
"recording.go",
"room.go",
"transcription.go",
"types.go",
"validation.go",
"video_recording.go",
"wireless.go",
"wireless_commands.go",
],
Expand Down Expand Up @@ -80,9 +82,11 @@ go_test(
"prices_voice_test.go",
"recording_test.go",
"responses_test.go",
"room_test.go",
"transcription_test.go",
"types_test.go",
"validation_test.go",
"video_recording_test.go",
"wireless_commands_test.go",
"wireless_test.go",
],
Expand Down
20 changes: 20 additions & 0 deletions http.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ const NotifyVersion = "v1"
const LookupBaseURL = "https://lookups.twilio.com"
const LookupVersion = "v1"

// Video service
var VideoBaseUrl = "https://video.twilio.com"

const VideoVersion = "v1"

type Client struct {
*rest.Client
Monitor *Client
Expand All @@ -62,6 +67,7 @@ type Client struct {
Wireless *Client
Notify *Client
Lookup *Client
Video *Client

// FullPath takes a path part (e.g. "Messages") and
// returns the full API path, including the version (e.g.
Expand Down Expand Up @@ -108,6 +114,10 @@ type Client struct {

// NewLookupClient initializes these services
LookupPhoneNumbers *LookupPhoneNumbersService

// NewVideoClient initializes these services
Rooms *RoomService
VideoRecordings *VideoRecordingService
}

const defaultTimeout = 30*time.Second + 500*time.Millisecond
Expand Down Expand Up @@ -245,6 +255,15 @@ func NewLookupClient(accountSid string, authToken string, httpClient *http.Clien
return c
}

// NewVideoClient returns a new Client to use the video API
func NewVideoClient(accountSid string, authToken string, httpClient *http.Client) *Client {
c := newNewClient(accountSid, authToken, VideoBaseUrl, httpClient)
c.APIVersion = VideoVersion
c.Rooms = &RoomService{client: c}
c.VideoRecordings = &VideoRecordingService{client: c}
return c
}

// NewClient creates a Client for interacting with the Twilio API. This is the
// main entrypoint for API interactions; view the methods on the subresources
// for more information.
Expand All @@ -269,6 +288,7 @@ func NewClient(accountSid string, authToken string, httpClient *http.Client) *Cl
c.Wireless = NewWirelessClient(accountSid, authToken, httpClient)
c.Notify = NewNotifyClient(accountSid, authToken, httpClient)
c.Lookup = NewLookupClient(accountSid, authToken, httpClient)
c.Video = NewVideoClient(accountSid, authToken, httpClient)

c.Accounts = &AccountService{client: c}
c.Applications = &ApplicationService{client: c}
Expand Down
47 changes: 47 additions & 0 deletions responses_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func getServer(response []byte) (*Client, *Server) {
client.Wireless.Base = s.URL
client.Notify.Base = s.URL
client.Lookup.Base = s.URL
client.Video.Base = s.URL
return client, s
}

Expand All @@ -83,6 +84,7 @@ func getServerCode(response []byte, code int) (*Client, *Server) {
client.Wireless.Base = s.URL
client.Notify.Base = s.URL
client.Lookup.Base = s.URL
client.Video.Base = s.URL
return client, s
}

Expand Down Expand Up @@ -2730,5 +2732,50 @@ var phoneLookupResponse = []byte(`
}
`)

var roomResponse = []byte(`
{
"api_key_sid": "AC58f1e8f2b1c6b88ca90a012a4be0c279",
"date_created": "2015-07-30T20:00:00Z",
"date_updated": "2015-07-30T20:00:00Z",
"status": "in-progress",
"type": "peer-to-peer",
"sid": "RMca86cf94c7d4f89e0bd45bfa7d9b9e7d",
"enable_turn": false,
"unique_name": "DailyStandup",
"max_participants": 10,
"duration": 0,
"status_callback_method": "POST",
"status_callback": "",
"record_participants_on_connect": false,
"end_time": "2015-07-30T20:00:00Z",
"url": "https://video.twilio.com/v1/Rooms/RMca86cf94c7d4f89e0bd45bfa7d9b9e7d",
"links": {
"recordings": "https://video.twilio.com/v1/Rooms/RMca86cf94c7d4f89e0bd45bfa7d9b9e7d/Recordings"
}
}
`)

var videoRecordingResponse = []byte(`
{
"api_key_sid": "AC58f1e8f2b1c6b88ca90a012a4be0c279",
"status": "processing",
"date_created": "2015-07-30T20:00:00Z",
"sid": "RT63868a235fc1cf3987e6a2b67346273f",
"source_sid": "MT58f1e8f2b1c6b88ca90a012a4be0c279",
"size": 0,
"url": "https://video.twilio.com/v1/Recordings/RT58f1e8f2b1c6b88ca90a012a4be0c279",
"type": "audio",
"duration": 20,
"container_format": "mka",
"codec": "OPUS",
"grouping_sids": {
"room_sid" : "RM58f1e8f2b1c6b88ca90a012a4be0c279"
},
"links": {
"media": "https://video.twilio.com/v1/Recordings/RT58f1e8f2b1c6b88ca90a012a4be0c279/Media"
}
}
`)

const from = "+19253920364"
const to = "+19253920364"
92 changes: 92 additions & 0 deletions room.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package twilio

import (
"context"
"net/url"
)

const roomPathPart = "Rooms"

type RoomService struct {
client *Client
}

type Room struct {
Sid string `json:"sid"`
AccountSid string `json:"account_sid"`
Type string `json:"type"`
EnableTurn bool `json:"enable_turn"`
UniqueName string `json:"unique_name"`
StatusCallback string `json:"status_callback"`
StatusCallbackMethod string `json:"status_callback_method"`
MaxParticipants uint `json:"max_participants"`
RecordParticipantsOnConnect bool `json:"record_participants_on_connect"`
Duration uint `json:"duration"`
MediaRegion string `json:"media_region"`
Status Status `json:"status"`
DateCreated TwilioTime `json:"date_created"`
DateUpdated TwilioTime `json:"date_updated"`
EndTime TwilioTime `json:"end_time"`
URL string `json:"url"`
Links map[string]string `json:"links"`
}

type RoomPage struct {
Meta Meta `json:"meta"`
Rooms []*Room `json:"rooms"`
}

type RoomPageIterator struct {
p *PageIterator
}

// Get finds a single Room resource by its sid or unique name, or returns an error.
func (r *RoomService) Get(ctx context.Context, sidOrUniqueName string) (*Room, error) {
room := new(Room)
err := r.client.GetResource(ctx, roomPathPart, sidOrUniqueName, room)
return room, err
}

// Complete an in-progress Room with the given sid. All connected
// Participants will be immediately disconnected from the Room.
func (r *RoomService) Complete(sid string) (*Room, error) {
room := new(Room)
v := url.Values{}
v.Set("Status", string(StatusCompleted))
err := r.client.UpdateResource(context.Background(), roomPathPart, sid, v, room)
return room, err
}

// Create a room with the given url.Values. For more information on valid values,
// see https://www.twilio.com/docs/api/video/rooms-resource#post-parameters or use the
func (r *RoomService) Create(ctx context.Context, data url.Values) (*Room, error) {
room := new(Room)
err := r.client.CreateResource(ctx, roomPathPart, data, room)
return room, err
}

// Returns a list of rooms. For more information on valid values,
// see https://www.twilio.com/docs/api/video/rooms-resource#get-list-resource
func (r *RoomService) GetPage(ctx context.Context, data url.Values) (*RoomPage, error) {
return r.GetPageIterator(data).Next(ctx)
}

// GetPageIterator returns an iterator which can be used to retrieve pages.
func (r *RoomService) GetPageIterator(data url.Values) *RoomPageIterator {
iter := NewPageIterator(r.client, data, roomPathPart)
return &RoomPageIterator{
p: iter,
}
}

// Next returns the next page of resources. If there are no more resources,
// NoMoreResults is returned.
func (r *RoomPageIterator) Next(ctx context.Context) (*RoomPage, error) {
rp := new(RoomPage)
err := r.p.Next(ctx, rp)
if err != nil {
return nil, err
}
r.p.SetNextPageURI(rp.Meta.NextPageURL)
return rp, nil
}
25 changes: 25 additions & 0 deletions room_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package twilio

import (
"context"
"testing"
)

func TestGetRoom(t *testing.T) {
t.Parallel()
client, server := getServer(roomResponse)
defer server.Close()
room, err := client.Video.Rooms.Get(context.Background(), "RMca86cf94c7d4f89e0bd45bfa7d9b9e7d")
if err != nil {
t.Fatal(err)
}
if room.Sid != "RMca86cf94c7d4f89e0bd45bfa7d9b9e7d" {
t.Errorf("room: got sid %q, want %q", room.Sid, "RMca86cf94c7d4f89e0bd45bfa7d9b9e7d")
}
if room.Status != StatusInProgress {
t.Errorf("room: got status %q, want %q", room.Status, StatusInProgress)
}
if room.Type != RoomTypePeerToPeer {
t.Errorf("room: got type %q, want %q", room.Type, RoomTypePeerToPeer)
}
}
4 changes: 4 additions & 0 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,7 @@ func capitalize(s string) string {
utf8.EncodeRune(b, unicode.ToTitle(r))
return strings.Join([]string{string(b), s[l:]}, "")
}

// types of video room
const RoomType = "group"
const RoomTypePeerToPeer = "peer-to-peer"
95 changes: 95 additions & 0 deletions video_recording.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package twilio

import (
"context"
"net/url"
"strings"
)

type VideoRecordingService struct {
client *Client
}

const videoRecordingsPathPart = "Recordings"

func videoMediaPathPart(recordingSid string) string {
return strings.Join([]string{videoRecordingsPathPart, recordingSid, "Media"}, "/")
}

type VideoRecording struct {
Sid string `json:"sid"`
Duration uint `json:"duration"`
Status Status `json:"status"`
DateCreated TwilioTime `json:"date_created"`
SourceSid string `json:"source_sid"`
URI string `json:"uri"`
Size uint `json:"size"`
Type string `json:"type"`
ContainerFormat string `json:"container_format"`
Codec string `json:"codec"`
GroupingSids map[string]string `json:"grouping_sids"`
Links map[string]string `json:"links"`
}

type VideoMedia struct {
Location string `json:"location"`
}

type VideoRecordingPage struct {
Meta Meta `json:"meta"`
Recordings []*VideoRecording `json:"recordings"`
}

type VideoRecordingPageIterator struct {
p *PageIterator
}

// When you make a request to this URL, Twilio will generate a temporary URL for accessing
// this binary data, and issue an HTTP 302 redirect response to your request. The Recording
// will be returned in the format as described in the metadata.
func (vr *VideoRecordingService) Media(ctx context.Context, sid string) (*VideoMedia, error) {
media := new(VideoMedia)
path := videoMediaPathPart(sid)
err := vr.client.ListResource(ctx, path, nil, media)
return media, err
}

// Returns the VideoRecording with the given sid.
func (vr *VideoRecordingService) Get(ctx context.Context, sid string) (*VideoRecording, error) {
recording := new(VideoRecording)
err := vr.client.GetResource(ctx, videoRecordingsPathPart, sid, recording)
return recording, err
}

// Delete the VideoRecording with the given sid. If the VideoRecording has already been
// deleted, or does not exist, Delete returns nil. If another error or a
// timeout occurs, the error is returned.
func (vr *VideoRecordingService) Delete(ctx context.Context, sid string) error {
return vr.client.DeleteResource(ctx, videoRecordingsPathPart, sid)
}

// Returns a list of recordings. For more information on valid values,
// see https://www.twilio.com/docs/api/video/recordings-resource#recordings-list-resource
func (vr *VideoRecordingService) GetPage(ctx context.Context, data url.Values) (*VideoRecordingPage, error) {
return vr.GetPageIterator(data).Next(ctx)
}

// GetPageIterator returns an iterator which can be used to retrieve pages.
func (vr *VideoRecordingService) GetPageIterator(data url.Values) *VideoRecordingPageIterator {
iter := NewPageIterator(vr.client, data, videoRecordingsPathPart)
return &VideoRecordingPageIterator{
p: iter,
}
}

// Next returns the next page of resources. If there are no more resources,
// NoMoreResults is returned.
func (vr *VideoRecordingPageIterator) Next(ctx context.Context) (*VideoRecordingPage, error) {
vrp := new(VideoRecordingPage)
err := vr.p.Next(ctx, vrp)
if err != nil {
return nil, err
}
vr.p.SetNextPageURI(vrp.Meta.NextPageURL)
return vrp, nil
}
Loading

0 comments on commit 43cbb91

Please sign in to comment.