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"
|
2022-01-14 07:22:02 +00:00
|
|
|
"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
|
2022-01-14 22:14:51 +00:00
|
|
|
var wsExit = make(chan bool, 1)
|
2022-01-14 21:36:02 +00:00
|
|
|
var statusListener = make(map[uint][]chan<-[]byte)
|
2022-01-14 07:22:02 +00:00
|
|
|
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()
|
2022-01-23 04:46:58 +00:00
|
|
|
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
|
2022-01-14 22:14:51 +00:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case msg := <-c:
|
2022-01-19 19:36:53 +00:00
|
|
|
if err := conn.WriteMessage(websocket.TextMessage, msg); err != nil {
|
|
|
|
ErrMsg(err)
|
2022-01-14 22:14:51 +00:00
|
|
|
return
|
|
|
|
}
|
2022-03-11 23:14:06 +00:00
|
|
|
case <-ticker.C:
|
|
|
|
if err := conn.WriteMessage(websocket.PingMessage, nil); err != nil {
|
|
|
|
ErrMsg(err)
|
|
|
|
return
|
|
|
|
}
|
2022-01-14 22:14:51 +00:00
|
|
|
case <-wsExit:
|
2022-01-19 19:36:53 +00:00
|
|
|
LogMsg("exiting server")
|
2022-01-14 22:14:51 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2022-01-14 22:14:51 +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 07:22:02 +00:00
|
|
|
}
|
2022-01-14 18:57:19 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-14 07:22:02 +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 07:22:02 +00:00
|
|
|
}
|
2022-01-14 18:57:19 +00:00
|
|
|
}
|
2022-01-14 07:22:02 +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
|
|
|
|