databag/net/server/internal/api_status.go

180 lines
3.6 KiB
Go
Raw Normal View History

2022-01-11 06:20:32 +00:00
package databag
import (
2022-03-11 23:14:06 +00:00
"time"
2022-01-19 19:36:53 +00:00
"errors"
2022-01-14 18:57:19 +00:00
"sync"
2022-01-11 06:20:32 +00:00
"net/http"
2022-01-14 21:36:02 +00:00
"encoding/json"
"github.com/gorilla/websocket"
2022-01-14 18:57:19 +00:00
"databag/internal/store"
2022-01-11 06:20:32 +00:00
)
2022-01-14 21:36:02 +00:00
var wsSync sync.Mutex
var wsExit = make(chan bool, 1)
2022-01-14 21:36:02 +00:00
var statusListener = make(map[uint][]chan<-[]byte)
var upgrader = websocket.Upgrader{}
2022-01-11 06:20:32 +00:00
func Status(w http.ResponseWriter, r *http.Request) {
2022-01-14 18:57:19 +00:00
// accept websocket connection
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
2022-01-19 19:36:53 +00:00
ErrMsg(err)
return
2022-01-14 18:57:19 +00:00
}
defer conn.Close()
conn.SetReadLimit(APP_BODYLIMIT)
2022-01-14 18:57:19 +00:00
2022-01-19 19:00:20 +00:00
// receive announce
2022-01-19 19:36:53 +00:00
t, m, res := conn.ReadMessage()
if res != nil {
ErrMsg(res)
return
}
if t != websocket.TextMessage {
ErrMsg(errors.New("invalid websocket message type"))
2022-01-19 19:00:20 +00:00
return
}
2022-01-19 19:36:53 +00:00
var a Announce
if err := json.Unmarshal(m, &a); err != nil {
ErrMsg(err)
2022-01-19 19:00:20 +00:00
return
}
2022-01-14 21:36:02 +00:00
2022-01-22 19:40:20 +00:00
// extract token target and access
target, access, ret := ParseToken(a.AppToken)
if ret != nil {
2022-03-11 23:14:06 +00:00
ErrMsg(ret)
2022-01-22 19:40:20 +00:00
return
}
2022-01-19 19:00:20 +00:00
// retrieve reference account
var app store.App
2022-01-22 19:40:20 +00:00
if err := store.DB.Preload("Account").Where("account_id = ? AND token = ?", target, access).First(&app).Error; err != nil {
2022-01-19 19:36:53 +00:00
ErrMsg(err)
2022-01-19 19:00:20 +00:00
return
2022-01-14 21:36:02 +00:00
}
// send current version
2022-01-20 23:19:26 +00:00
rev := getRevision(&app.Account)
2022-01-14 21:36:02 +00:00
var msg []byte
msg, err = json.Marshal(rev)
if err != nil {
2022-01-19 19:36:53 +00:00
ErrMsg(err)
2022-01-14 21:36:02 +00:00
return
}
2022-01-19 19:36:53 +00:00
if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
ErrMsg(err)
2022-01-14 21:36:02 +00:00
return
}
2022-01-14 18:57:19 +00:00
// open channel for revisions
2022-01-14 21:36:02 +00:00
c := make(chan []byte)
defer close(c)
// register channel for revisions
2022-01-19 19:00:20 +00:00
AddStatusListener(app.Account.ID, c)
defer RemoveStatusListener(app.Account.ID, c)
2022-01-14 21:36:02 +00:00
2022-03-11 23:14:06 +00:00
// start ping pong ticker
ticker := time.NewTicker(60 * time.Second)
defer ticker.Stop()
2022-01-14 21:36:02 +00:00
// send revision until channel is closed
for {
select {
case msg := <-c:
2022-01-19 19:36:53 +00:00
if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
ErrMsg(err)
return
}
2022-03-11 23:14:06 +00:00
case <-ticker.C:
2022-03-15 03:45:54 +00:00
conn.SetWriteDeadline(time.Now().Add(15 * time.Second))
2022-03-11 23:14:06 +00:00
if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
ErrMsg(err)
return
}
case <-wsExit:
2022-01-19 19:36:53 +00:00
LogMsg("exiting server")
wsExit<-true
return
}
}
2022-01-14 21:36:02 +00:00
}
2022-01-14 18:57:19 +00:00
2022-01-20 23:19:26 +00:00
func getRevision(account *store.Account) Revision {
2022-01-14 21:36:02 +00:00
var r Revision
2022-01-19 19:00:20 +00:00
r.Profile = account.ProfileRevision
2022-02-08 20:24:42 +00:00
r.Article = account.ArticleRevision
r.Channel = account.ChannelRevision
2022-01-19 19:00:20 +00:00
r.Group = account.GroupRevision
r.Card = account.CardRevision
2022-01-14 21:36:02 +00:00
return r
2022-01-14 18:57:19 +00:00
}
func ExitStatus() {
wsExit <- true
}
2022-01-20 23:19:26 +00:00
func SetStatus(account *store.Account) {
2022-01-14 18:57:19 +00:00
// get revisions for the account
2022-01-19 19:00:20 +00:00
rev := getRevision(account);
msg, err := json.Marshal(rev)
2022-01-14 18:57:19 +00:00
if err != nil {
2022-01-19 19:36:53 +00:00
ErrMsg(err)
2022-01-14 21:36:02 +00:00
return
2022-01-14 18:57:19 +00:00
}
// lock access to statusListener
wsSync.Lock()
2022-01-14 21:36:02 +00:00
defer wsSync.Unlock()
2022-01-14 18:57:19 +00:00
2022-01-14 21:36:02 +00:00
// notify all listeners
2022-01-19 19:00:20 +00:00
chs, ok := statusListener[account.ID]
2022-01-14 18:57:19 +00:00
if ok {
for _, ch := range chs {
2022-01-14 21:36:02 +00:00
ch <- msg
}
2022-01-14 18:57:19 +00:00
}
}
2022-01-14 21:36:02 +00:00
func AddStatusListener(act uint, ch chan<-[]byte) {
2022-01-14 18:57:19 +00:00
// lock access to statusListener
wsSync.Lock()
2022-01-14 21:36:02 +00:00
defer wsSync.Unlock()
2022-01-14 18:57:19 +00:00
2022-01-14 21:36:02 +00:00
// add new listener to map
2022-01-14 18:57:19 +00:00
chs, ok := statusListener[act]
if ok {
2022-02-20 08:15:04 +00:00
statusListener[act] = append(chs, ch)
2022-01-14 18:57:19 +00:00
} else {
2022-01-14 21:36:02 +00:00
statusListener[act] = []chan<-[]byte{ch}
2022-01-14 18:57:19 +00:00
}
}
2022-01-14 21:36:02 +00:00
func RemoveStatusListener(act uint, ch chan<-[]byte) {
2022-01-14 18:57:19 +00:00
// lock access to statusListener
wsSync.Lock()
2022-01-14 21:36:02 +00:00
defer wsSync.Unlock()
2022-01-14 18:57:19 +00:00
2022-01-14 21:36:02 +00:00
// remove channel from map
2022-01-14 18:57:19 +00:00
chs, ok := statusListener[act]
if ok {
for i, c := range chs {
if ch == c {
if len(chs) == 1 {
delete(statusListener, act)
} else {
chs[i] = chs[len(chs)-1]
statusListener[act] = chs[:len(chs)-1]
}
2022-01-14 18:57:19 +00:00
}
}
2022-01-14 18:57:19 +00:00
}
2022-01-11 06:20:32 +00:00
}
2022-01-14 18:57:19 +00:00