mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-09-16 10:06:54 +00:00
Let's start caching some of the backlog data on the server
This commit is contained in:
parent
8918b9ac3a
commit
ae1306387e
4 changed files with 214 additions and 7 deletions
|
@ -74,14 +74,16 @@ func HBackendPublishRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
cmd := formData.Get("cmd")
|
cmd := formData.Get("cmd")
|
||||||
json := formData.Get("args")
|
json := formData.Get("args")
|
||||||
chat := formData.Get("chat")
|
channel := formData.Get("channel")
|
||||||
watchChannel := formData.Get("channel")
|
scope := formData.Get("scope")
|
||||||
cm := ClientMessage{MessageID: -1, Command: Command(cmd), origArguments: json}
|
cm := ClientMessage{MessageID: -1, Command: Command(cmd), origArguments: json}
|
||||||
var count int
|
var count int
|
||||||
if chat != "" {
|
if scope == "chat" {
|
||||||
count = PublishToChat(chat, cm)
|
count = PublishToChat(channel, cm)
|
||||||
} else if watchChannel != "" {
|
} else if scope == "channel" {
|
||||||
count = PublishToWatchers(watchChannel, cm)
|
count = PublishToWatchers(channel, cm)
|
||||||
|
} else if scope == "global" {
|
||||||
|
count = PublishToAll(cm)
|
||||||
} else {
|
} else {
|
||||||
w.WriteHeader(400)
|
w.WriteHeader(400)
|
||||||
fmt.Fprint(w, "Need to specify either chat or channel")
|
fmt.Fprint(w, "Need to specify either chat or channel")
|
||||||
|
|
|
@ -1 +1,89 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// this value is just docs right now
|
||||||
|
var ServerInitiatedCommands = []string{
|
||||||
|
/// Global updates & notices
|
||||||
|
"update_news", // timecache:global
|
||||||
|
"message", // timecache:global
|
||||||
|
"reload_ff", // timecache:global
|
||||||
|
|
||||||
|
/// Emote updates
|
||||||
|
"reload_badges", // timecache:global
|
||||||
|
"set_badge", // timecache:multichat
|
||||||
|
"reload_set", // timecache:multichat
|
||||||
|
"load_set", // TODO what are the semantics of this?
|
||||||
|
|
||||||
|
/// User auth
|
||||||
|
"do_authorize", // nocache:single
|
||||||
|
|
||||||
|
/// Channel data
|
||||||
|
// extra emote sets included in the chat
|
||||||
|
"follow_sets", // mustcache:chat
|
||||||
|
// extra follow buttons below the stream
|
||||||
|
"follow_buttons", // mustcache:watching
|
||||||
|
// SRL race data
|
||||||
|
"srl_race", // cachelast:watching
|
||||||
|
|
||||||
|
/// Chatter/viewer counts
|
||||||
|
"chatters", // cachelast:watching
|
||||||
|
"viewers", // cachelast:watching
|
||||||
|
}
|
||||||
|
var _ = ServerInitiatedCommands
|
||||||
|
|
||||||
|
type BacklogCacheType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// This is not a cache type.
|
||||||
|
CacheTypeInvalid BacklogCacheType = iota
|
||||||
|
// This message cannot be cached.
|
||||||
|
CacheTypeNever
|
||||||
|
// Save the last 24 hours of this message.
|
||||||
|
// If a client indicates that it has reconnected, replay the messages sent after the disconnect.
|
||||||
|
CacheTypeTimestamps
|
||||||
|
// Save only the last copy of this message, and always send it when the backlog is requested.
|
||||||
|
CacheTypeLastOnly
|
||||||
|
// Save this backlog data to disk with its timestamp.
|
||||||
|
// Send it when the backlog is requested, or after a reconnect if it was updated.
|
||||||
|
CacheTypePersistent
|
||||||
|
)
|
||||||
|
|
||||||
|
type MessageTargetType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// This is not a message target.
|
||||||
|
MsgTargetTypeInvalid MessageTargetType = iota
|
||||||
|
// This message is targeted to a single TODO(user or connection)
|
||||||
|
MsgTargetTypeSingle
|
||||||
|
// This message is targeted to all users in a chat
|
||||||
|
MsgTargetTypeChat
|
||||||
|
// This message is targeted to all users in multiple chats
|
||||||
|
MsgTargetTypeMultichat
|
||||||
|
// This message is targeted to all users watching a stream
|
||||||
|
MsgTargetTypeWatching
|
||||||
|
// This message is sent to all FFZ users.
|
||||||
|
MsgTargetTypeGlobal
|
||||||
|
)
|
||||||
|
|
||||||
|
// Returned by BacklogCacheType.UnmarshalJSON()
|
||||||
|
var ErrorUnrecognizedCacheType = errors.New("Invalid value for cachetype")
|
||||||
|
|
||||||
|
// Returned by MessageTargetType.UnmarshalJSON()
|
||||||
|
var ErrorUnrecognizedTargetType = errors.New("Invalid value for message target")
|
||||||
|
|
||||||
|
// note: see types.go for methods on these
|
||||||
|
|
||||||
|
func HBackendSaveBacklog(w http.ResponseWriter, r *http.Request) {
|
||||||
|
formData, err := UnsealRequest(r.Form)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(403)
|
||||||
|
fmt.Fprintf(w, "Error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -54,6 +54,8 @@ func HandleHello(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (r
|
||||||
client.ClientID = uuid.NewV4()
|
client.ClientID = uuid.NewV4()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SubscribeGlobal(client)
|
||||||
|
|
||||||
return ClientMessage{
|
return ClientMessage{
|
||||||
Arguments: client.ClientID.String(),
|
Arguments: client.ClientID.String(),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
|
@ -84,5 +84,120 @@ type ClientInfo struct {
|
||||||
|
|
||||||
// Server-initiated messages should be sent here
|
// Server-initiated messages should be sent here
|
||||||
// Never nil.
|
// Never nil.
|
||||||
MessageChannel chan <- ClientMessage
|
MessageChannel chan<- ClientMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bct BacklogCacheType) Name() string {
|
||||||
|
switch bct {
|
||||||
|
case CacheTypeInvalid:
|
||||||
|
return ""
|
||||||
|
case CacheTypeNever:
|
||||||
|
return "never"
|
||||||
|
case CacheTypeTimestamps:
|
||||||
|
return "timed"
|
||||||
|
case CacheTypeLastOnly:
|
||||||
|
return "last"
|
||||||
|
case CacheTypePersistent:
|
||||||
|
return "persist"
|
||||||
|
}
|
||||||
|
panic("Invalid BacklogCacheType value")
|
||||||
|
}
|
||||||
|
|
||||||
|
var CacheTypesByName = map[string]BacklogCacheType{
|
||||||
|
"never": CacheTypeNever,
|
||||||
|
"timed": CacheTypeTimestamps,
|
||||||
|
"last": CacheTypeLastOnly,
|
||||||
|
"persist": CacheTypePersistent,
|
||||||
|
}
|
||||||
|
|
||||||
|
func BacklogCacheTypeByName(name string) (bct BacklogCacheType) {
|
||||||
|
// CacheTypeInvalid is the zero value so it doesn't matter
|
||||||
|
bct, _ = CacheTypesByName[name]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Stringer
|
||||||
|
func (bct BacklogCacheType) String() string { return bct.Name() }
|
||||||
|
|
||||||
|
// Implements json.Marshaler
|
||||||
|
func (bct BacklogCacheType) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(bct.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements json.Unmarshaler
|
||||||
|
func (pbct *BacklogCacheType) UnmarshalJSON(data []byte) error {
|
||||||
|
var str string
|
||||||
|
err := json.Unmarshal(data, &str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if str == "" {
|
||||||
|
*pbct = CacheTypeInvalid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
val := BacklogCacheTypeByName(str)
|
||||||
|
if val != CacheTypeInvalid {
|
||||||
|
*pbct = val
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ErrorUnrecognizedCacheType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mtt MessageTargetType) Name() string {
|
||||||
|
switch mtt {
|
||||||
|
case MsgTargetTypeInvalid:
|
||||||
|
return ""
|
||||||
|
case MsgTargetTypeSingle:
|
||||||
|
return "single"
|
||||||
|
case MsgTargetTypeChat:
|
||||||
|
return "chat"
|
||||||
|
case MsgTargetTypeMultichat:
|
||||||
|
return "multichat"
|
||||||
|
case MsgTargetTypeWatching:
|
||||||
|
return "channel"
|
||||||
|
case MsgTargetTypeGlobal:
|
||||||
|
return "global"
|
||||||
|
}
|
||||||
|
panic("Invalid MessageTargetType value")
|
||||||
|
}
|
||||||
|
|
||||||
|
var TargetTypesByName = map[string]MessageTargetType{
|
||||||
|
"single": MsgTargetTypeSingle,
|
||||||
|
"chat": MsgTargetTypeChat,
|
||||||
|
"multichat": MsgTargetTypeMultichat,
|
||||||
|
"channel": MsgTargetTypeWatching,
|
||||||
|
"global": MsgTargetTypeGlobal,
|
||||||
|
}
|
||||||
|
|
||||||
|
func MessageTargetTypeByName(name string) (mtt MessageTargetType) {
|
||||||
|
// MsgTargetTypeInvalid is the zero value so it doesn't matter
|
||||||
|
mtt, _ = TargetTypesByName[name]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements Stringer
|
||||||
|
func (mtt MessageTargetType) String() string { return mtt.Name() }
|
||||||
|
|
||||||
|
// Implements json.Marshaler
|
||||||
|
func (mtt MessageTargetType) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(mtt.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements json.Unmarshaler
|
||||||
|
func (pmtt *MessageTargetType) UnmarshalJSON(data []byte) error {
|
||||||
|
var str string
|
||||||
|
err := json.Unmarshal(data, &str)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if str == "" {
|
||||||
|
*pmtt = MsgTargetTypeInvalid
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
mtt := MessageTargetTypeByName(str)
|
||||||
|
if mtt != MsgTargetTypeInvalid {
|
||||||
|
*pmtt = mtt
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ErrorUnrecognizedTargetType
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue