]> code.octet-stream.net Git - broadcaster/blob - internal/protocol/protocol.go
Handle timestamps with no seconds cleanly
[broadcaster] / internal / protocol / protocol.go
1 package protocol
2
3 import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 )
8
9 const (
10 StartTimeFormat = "2006-01-02T15:04"
11 StartTimeFormatSecs = "2006-01-02T15:04:05"
12 LocalTimeFormat = "Mon _2 Jan 2006 15:04:05"
13
14 // Radio to server
15
16 AuthenticateType = "authenticate"
17 StatusType = "status"
18
19 // Server to radio
20
21 FilesType = "files"
22 PlaylistsType = "playlists"
23 StopType = "stop"
24
25 // Status values
26
27 StatusIdle = "idle"
28 StatusDelay = "delay"
29 StatusChannelInUse = "channel_in_use"
30 StatusPlaying = "playing"
31 )
32
33 // Base message type to determine what type of payload is expected.
34 type Message struct {
35 T string
36 }
37
38 // Initial message from Radio to authenticate itself with a token string.
39 type AuthenticateMessage struct {
40 T string
41 Token string
42 }
43
44 // Server updates the radio with the list of files that currently exist.
45 // This will be provided on connect and when there are any changes.
46 // The radio is expected to obtain all these files and cache them locally.
47 type FilesMessage struct {
48 T string
49 Files []FileSpec
50 }
51
52 type PlaylistsMessage struct {
53 T string
54 Playlists []PlaylistSpec
55 }
56
57 // Any playlist currently being played should be stopped and PTT disengaged.
58 type StopMessage struct {
59 T string
60 }
61
62 type StatusMessage struct {
63 T string
64
65 // Status w.r.t. playing a playlist
66 Status string
67
68 // File being played or about to be played - empty string in idle status
69 Filename string
70
71 // Name of playlist being played - empty string in idle status
72 Playlist string
73
74 // Seconds until playback begins - never mind latency
75 DelaySecondsRemaining int
76
77 // Number of seconds file has been actually playing
78 PlaybackSecondsElapsed int
79
80 // Number of seconds waiting for channel to clear
81 WaitingForChannelSeconds int
82
83 PTT bool
84 COS bool
85 FilesInSync bool
86
87 // Timestamp of the current time on this radio, using LocalTimeFormat
88 LocalTime string
89
90 // Time zone in use, e.g. "Australia/Hobart"
91 TimeZone string
92 }
93
94 // Description of an individual file available in the broadcasting system.
95 type FileSpec struct {
96 // Filename, e.g. "broadcast.wav"
97 Name string
98 // SHA-256 hash of the file's contents
99 Hash string
100 }
101
102 type PlaylistSpec struct {
103 Id int
104 Name string
105 StartTime string
106 Entries []EntrySpec
107 }
108
109 type EntrySpec struct {
110 Filename string
111 DelaySeconds int
112 IsRelative bool
113 }
114
115 func ParseMessage(data []byte) (string, interface{}, error) {
116 var t Message
117 err := json.Unmarshal(data, &t)
118 if err != nil {
119 return "", nil, err
120 }
121
122 if t.T == AuthenticateType {
123 var auth AuthenticateMessage
124 err = json.Unmarshal(data, &auth)
125 if err != nil {
126 return "", nil, err
127 }
128 return t.T, auth, nil
129 }
130
131 if t.T == FilesType {
132 var files FilesMessage
133 err = json.Unmarshal(data, &files)
134 if err != nil {
135 return "", nil, err
136 }
137 return t.T, files, nil
138 }
139
140 if t.T == PlaylistsType {
141 var playlists PlaylistsMessage
142 err = json.Unmarshal(data, &playlists)
143 if err != nil {
144 return "", nil, err
145 }
146 return t.T, playlists, nil
147 }
148
149 if t.T == StatusType {
150 var status StatusMessage
151 err = json.Unmarshal(data, &status)
152 if err != nil {
153 return "", nil, err
154 }
155 return t.T, status, nil
156 }
157
158 if t.T == StopType {
159 var stop StopMessage
160 err = json.Unmarshal(data, &stop)
161 if err != nil {
162 return "", nil, err
163 }
164 return t.T, stop, nil
165 }
166
167 return "", nil, errors.New(fmt.Sprintf("unknown message type %v", t.T))
168 }