forked from wasabee-project/Wasabee-Server
-
Notifications
You must be signed in to change notification settings - Fork 0
/
firebase.go
269 lines (232 loc) · 5.8 KB
/
firebase.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
package wasabee
import (
"database/sql"
)
var fb struct {
running bool
c chan FirebaseCmd
}
// FirebaseCommandCode is the command codes used for communicating with the Firebase module
type FirebaseCommandCode int
// FbccQuit et al. are the friendly names for the FirebaseCommandCode
const (
FbccQuit FirebaseCommandCode = iota
FbccGenericMessage
FbccAgentLocationChange
FbccMapChange
FbccMarkerStatusChange
FbccMarkerAssignmentChange
FbccLinkStatusChange
FbccLinkAssignmentChange
FbccSubscribeTeam
)
// FirebaseCmd is the struct passed to the Firebase module to take actions -- required params depend on the FBCC
type FirebaseCmd struct {
Cmd FirebaseCommandCode
TeamID TeamID
OpID OperationID
ObjID string // either LinkID, MarkerID ... XXX define ObjectID type?
Gid GoogleID
Msg string
}
// FirebaseInit creates the channel used to pass messages to the Firebase subsystem
func FirebaseInit() <-chan FirebaseCmd {
out := make(chan FirebaseCmd, 3)
fb.c = out
fb.running = true
return out
}
// FirebaseClose shuts down the channel when done
func FirebaseClose() {
if fb.running {
Log.Debug("shutting down firebase")
fb.running = false
close(fb.c)
}
}
func (cc FirebaseCommandCode) String() string {
return [...]string{"Quit", "Generic Message", "Agent Location Change", "Map Change", "Marker Status Change", "Marker Assignment Change", "Link Status Change", "Link Assignment Change", "Subscribe"}[cc]
}
// Functions called from Wasabee to message the firebase subsystem
func fbPush(fbc FirebaseCmd) {
if !fb.running {
Log.Debug("Firebase is not running, not sending msg")
return
}
fb.c <- fbc
}
// notifiy all subscribers to the agent's teams that they have moved
// do not share the location since it is possible to subscribe to firebase topics without being on the team
func (gid GoogleID) firebaseAgentLocation() {
if !fb.running {
return
}
for _, tid := range gid.teamList() {
fbPush(FirebaseCmd{
Cmd: FbccAgentLocationChange,
TeamID: tid,
Gid: gid,
Msg: tid.String(),
})
}
}
// notifiy the agent that they have a new assigned marker in a given op
func (opID OperationID) firebaseAssignMarker(gid GoogleID, markerID MarkerID) {
if !fb.running {
return
}
fbPush(FirebaseCmd{
Cmd: FbccMarkerAssignmentChange,
OpID: opID,
ObjID: string(markerID),
Gid: gid,
Msg: "assigned",
})
}
// notify a team that a marker's status has changed
func (o *Operation) firebaseMarkerStatus(markerID MarkerID, status string) {
if !fb.running {
return
}
if len(o.Teams) == 0 {
_ = o.PopulateTeams()
}
for _, t := range o.Teams {
fbPush(FirebaseCmd{
Cmd: FbccMarkerStatusChange,
TeamID: t.TeamID,
OpID: o.ID,
ObjID: string(markerID),
Msg: status,
})
}
}
// notifiy the agent that they have a new assigned marker in a given op
func (opID OperationID) firebaseAssignLink(gid GoogleID, linkID LinkID) {
if !fb.running {
return
}
fbPush(FirebaseCmd{
Cmd: FbccLinkAssignmentChange,
OpID: opID,
ObjID: string(linkID),
Gid: gid,
Msg: "assigned",
})
}
func (o *Operation) firebaseLinkStatus(linkID LinkID, completed bool) {
if !fb.running {
return
}
msg := "complete"
if !completed {
msg = "incomplete"
}
if len(o.Teams) == 0 {
_ = o.PopulateTeams()
}
for _, t := range o.Teams {
fbPush(FirebaseCmd{
Cmd: FbccLinkStatusChange,
TeamID: t.TeamID,
OpID: o.ID,
ObjID: string(linkID),
Msg: msg,
})
}
}
func (o *Operation) firebaseMapChange() {
if !fb.running {
return
}
if len(o.Teams) == 0 {
_ = o.PopulateTeams()
}
for _, t := range o.Teams {
fbPush(FirebaseCmd{
Cmd: FbccMapChange,
TeamID: t.TeamID,
OpID: o.ID,
Msg: "changed",
})
}
}
func (gid GoogleID) firebaseSubscribeTeam(teamID TeamID) {
if !fb.running {
return
}
fbPush(FirebaseCmd{
Cmd: FbccSubscribeTeam,
Gid: gid,
TeamID: teamID,
Msg: "subscribe",
})
}
func (gid GoogleID) firebaseUnsubscribeTeam(teamID TeamID) {
if !fb.running {
return
}
fbPush(FirebaseCmd{
Cmd: FbccSubscribeTeam,
Gid: gid,
TeamID: teamID,
Msg: "unsubscribe",
})
}
// Functions called from Firebase to use Wasabee resources
// FirebaseTokens gets an agents FirebaseToken from the database
// token may be "" if it has not been set for a user
func (gid GoogleID) FirebaseTokens() ([]string, error) {
var token string
var toks []string
rows, err := db.Query("SELECT DISTINCT token FROM firebase WHERE gid = ?", gid)
if err != nil && err != sql.ErrNoRows {
Log.Error(err)
return toks, err
}
// this is technically redundant with the main return, but be explicit about what we want
if err != nil && err == sql.ErrNoRows {
return toks, nil
}
for rows.Next() {
err := rows.Scan(&token)
if err != nil {
Log.Error(err)
continue
}
toks = append(toks, token)
}
return toks, nil
}
// FirebaseInsertToken updates a token in the database for an agent
// gid is not unique, an agent may have any number of tokens (e.g. multiple devices/browsers) -- need a cleaning mechanism
func (gid GoogleID) FirebaseInsertToken(token string) error {
// XXX ensure the token is unique, maybe add a unique key for it?
_, err := db.Exec("INSERT INTO firebase (gid, token) VALUES (?, ?)", gid, token)
if err != nil {
Log.Error(err)
return err
}
tl := gid.teamList()
for _, teamID := range tl {
gid.firebaseSubscribeTeam(teamID)
}
return nil
}
// FirebaseRemoveToken removes known token for a given user
func (gid GoogleID) FirebaseRemoveToken(token string) error {
_, err := db.Exec("DELETE FROM firebase WHERE gid = ? AND token = ?", gid, token)
if err != nil {
Log.Error(err)
return err
}
return nil
}
func (gid GoogleID) FirebaseRemoveAllTokens() error {
_, err := db.Exec("DELETE FROM firebase WHERE gid = ?", gid)
if err != nil {
Log.Error(err)
return err
}
return nil
}