mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-30 14:38:31 +00:00
remove MsgTargetType and CacheType
This commit is contained in:
parent
3b3457af14
commit
ec932b1c36
5 changed files with 24 additions and 265 deletions
|
@ -14,9 +14,10 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"sync"
|
||||
|
||||
"github.com/pmylund/go-cache"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const bPathAnnounceStartup = "/startup"
|
||||
|
@ -80,7 +81,7 @@ func getCacheKey(remoteCommand, data string) string {
|
|||
// HTTPBackendUncachedPublish handles the /uncached_pub route.
|
||||
// The backend can POST here to publish a message to clients with no caching.
|
||||
// The POST arguments are `cmd`, `args`, `channel`, and `scope`.
|
||||
// The `scope` argument is required because no attempt is made to infer the scope from the command, unlike /cached_pub.
|
||||
// If "scope" is "global", then "channel" is not used.
|
||||
func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
formData, err := Backend.UnsealRequest(r.Form)
|
||||
|
@ -95,14 +96,12 @@ func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
|||
channel := formData.Get("channel")
|
||||
scope := formData.Get("scope")
|
||||
|
||||
target := MessageTargetTypeByName(scope)
|
||||
|
||||
if cmd == "" {
|
||||
w.WriteHeader(422)
|
||||
fmt.Fprintf(w, "Error: cmd cannot be blank")
|
||||
return
|
||||
}
|
||||
if channel == "" && (target == MsgTargetTypeChat || target == MsgTargetTypeMultichat) {
|
||||
if channel == "" && scope != "global" {
|
||||
w.WriteHeader(422)
|
||||
fmt.Fprintf(w, "Error: channel must be specified")
|
||||
return
|
||||
|
@ -112,19 +111,11 @@ func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
|||
cm.parseOrigArguments()
|
||||
var count int
|
||||
|
||||
switch target {
|
||||
case MsgTargetTypeChat:
|
||||
count = PublishToChannel(channel, cm)
|
||||
case MsgTargetTypeMultichat:
|
||||
count = PublishToMultiple(strings.Split(channel, ","), cm)
|
||||
case MsgTargetTypeGlobal:
|
||||
count = PublishToAll(cm)
|
||||
case MsgTargetTypeInvalid:
|
||||
fallthrough
|
||||
switch scope {
|
||||
default:
|
||||
w.WriteHeader(422)
|
||||
fmt.Fprint(w, "Invalid 'scope'. must be chat, multichat, channel, or global")
|
||||
return
|
||||
count = PublishToMultiple(strings.Split(channel, ","), cm)
|
||||
case "global":
|
||||
count = PublishToAll(cm)
|
||||
}
|
||||
fmt.Fprint(w, count)
|
||||
}
|
||||
|
@ -294,7 +285,7 @@ func (backend *backendInfo) sendTopicNotice(topic string, added bool) error {
|
|||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||
respBytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return ErrBackendNotOK{Code: resp.StatusCode, Response: fmt.Sprintf("(error reading non-2xx response): %s", err.Error()}
|
||||
return ErrBackendNotOK{Code: resp.StatusCode, Response: fmt.Sprintf("(error reading non-2xx response): %s", err.Error())}
|
||||
}
|
||||
return ErrBackendNotOK{Code: resp.StatusCode, Response: string(respBytes)}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
@ -10,64 +9,6 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
type PushCommandCacheInfo struct {
|
||||
Caching BacklogCacheType
|
||||
Target MessageTargetType
|
||||
}
|
||||
|
||||
// S2CCommandsCacheInfo details what the behavior is of each command that can be sent to /cached_pub.
|
||||
var S2CCommandsCacheInfo = map[Command]PushCommandCacheInfo{
|
||||
/// Channel data
|
||||
// follow_sets: extra emote sets included in the chat
|
||||
// follow_buttons: extra follow buttons below the stream
|
||||
"follow_sets": {CacheTypePersistent, MsgTargetTypeChat},
|
||||
"follow_buttons": {CacheTypePersistent, MsgTargetTypeChat},
|
||||
"srl_race": {CacheTypeLastOnly, MsgTargetTypeMultichat},
|
||||
|
||||
/// Chatter/viewer counts
|
||||
"chatters": {CacheTypeLastOnly, MsgTargetTypeChat},
|
||||
"viewers": {CacheTypeLastOnly, MsgTargetTypeChat},
|
||||
}
|
||||
|
||||
var PersistentCachingCommands = []Command{"follow_sets", "follow_buttons"}
|
||||
var HourlyCachingCommands = []Command{"chatters", "viewers"} /* srl_race */
|
||||
|
||||
type BacklogCacheType int
|
||||
|
||||
const (
|
||||
// CacheTypeInvalid is the sentinel value.
|
||||
CacheTypeInvalid BacklogCacheType = iota
|
||||
// CacheTypeNever is a message that cannot be cached.
|
||||
CacheTypeNever
|
||||
// CacheTypeLastOnly means to save only the last copy of this message,
|
||||
// and always send it when the backlog is requested.
|
||||
CacheTypeLastOnly
|
||||
// CacheTypePersistent means to save the last copy of this message,
|
||||
// and always send it when the backlog is requested, but do not clean it periodically.
|
||||
CacheTypePersistent
|
||||
)
|
||||
|
||||
type MessageTargetType int
|
||||
|
||||
const (
|
||||
// MsgTargetTypeInvalid is the sentinel value.
|
||||
MsgTargetTypeInvalid MessageTargetType = iota
|
||||
// MsgTargetTypeChat is a message is targeted to all users in a particular chat.
|
||||
MsgTargetTypeChat
|
||||
// MsgTargetTypeMultichat is a message is targeted to all users in multiple chats.
|
||||
MsgTargetTypeMultichat
|
||||
// MsgTargetTypeGlobal is a message sent to all FFZ users.
|
||||
MsgTargetTypeGlobal
|
||||
)
|
||||
|
||||
// note: see types.go for methods on these
|
||||
|
||||
// ErrorUnrecognizedCacheType is returned by BacklogCacheType.UnmarshalJSON()
|
||||
var ErrorUnrecognizedCacheType = errors.New("Invalid value for cachetype")
|
||||
|
||||
// ErrorUnrecognizedTargetType is returned by MessageTargetType.UnmarshalJSON()
|
||||
var ErrorUnrecognizedTargetType = errors.New("Invalid value for message target")
|
||||
|
||||
type LastSavedMessage struct {
|
||||
Timestamp time.Time
|
||||
Data string
|
||||
|
@ -80,19 +21,11 @@ type LastSavedMessage struct {
|
|||
var CachedLastMessages = make(map[Command]map[string]LastSavedMessage)
|
||||
var CachedLSMLock sync.RWMutex
|
||||
|
||||
// PersistentLastMessages is of CacheTypePersistent. Never cleaned.
|
||||
var PersistentLastMessages = CachedLastMessages
|
||||
var PersistentLSMLock = CachedLSMLock
|
||||
|
||||
// DumpBacklogData drops all /cached_pub data.
|
||||
func DumpBacklogData() {
|
||||
CachedLSMLock.Lock()
|
||||
CachedLastMessages = make(map[Command]map[string]LastSavedMessage)
|
||||
CachedLSMLock.Unlock()
|
||||
|
||||
//PersistentLSMLock.Lock()
|
||||
//PersistentLastMessages = make(map[Command]map[string]LastSavedMessage)
|
||||
//PersistentLSMLock.Unlock()
|
||||
}
|
||||
|
||||
// SendBacklogForNewClient sends any backlog data relevant to a new client.
|
||||
|
@ -104,26 +37,8 @@ func SendBacklogForNewClient(client *ClientInfo) {
|
|||
copy(curChannels, client.CurrentChannels)
|
||||
client.Mutex.Unlock()
|
||||
|
||||
PersistentLSMLock.RLock()
|
||||
for _, cmd := range GetCommandsOfType(CacheTypePersistent) {
|
||||
chanMap := PersistentLastMessages[cmd]
|
||||
if chanMap == nil {
|
||||
continue
|
||||
}
|
||||
for _, channel := range curChannels {
|
||||
msg, ok := chanMap[channel]
|
||||
if ok {
|
||||
msg := ClientMessage{MessageID: -1, Command: cmd, origArguments: msg.Data}
|
||||
msg.parseOrigArguments()
|
||||
client.MessageChannel <- msg
|
||||
}
|
||||
}
|
||||
}
|
||||
PersistentLSMLock.RUnlock()
|
||||
|
||||
CachedLSMLock.RLock()
|
||||
for _, cmd := range GetCommandsOfType(CacheTypeLastOnly) {
|
||||
chanMap := CachedLastMessages[cmd]
|
||||
for cmd, chanMap := range CachedLastMessages {
|
||||
if chanMap == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -140,23 +55,8 @@ func SendBacklogForNewClient(client *ClientInfo) {
|
|||
}
|
||||
|
||||
func SendBacklogForChannel(client *ClientInfo, channel string) {
|
||||
PersistentLSMLock.RLock()
|
||||
for _, cmd := range GetCommandsOfType(CacheTypePersistent) {
|
||||
chanMap := PersistentLastMessages[cmd]
|
||||
if chanMap == nil {
|
||||
continue
|
||||
}
|
||||
if msg, ok := chanMap[channel]; ok {
|
||||
msg := ClientMessage{MessageID: -1, Command: cmd, origArguments: msg.Data}
|
||||
msg.parseOrigArguments()
|
||||
client.MessageChannel <- msg
|
||||
}
|
||||
}
|
||||
PersistentLSMLock.RUnlock()
|
||||
|
||||
CachedLSMLock.RLock()
|
||||
for _, cmd := range GetCommandsOfType(CacheTypeLastOnly) {
|
||||
chanMap := CachedLastMessages[cmd]
|
||||
for cmd, chanMap := range CachedLastMessages {
|
||||
if chanMap == nil {
|
||||
continue
|
||||
}
|
||||
|
@ -194,16 +94,6 @@ func SaveLastMessage(which map[Command]map[string]LastSavedMessage, locker sync.
|
|||
}
|
||||
}
|
||||
|
||||
func GetCommandsOfType(match BacklogCacheType) []Command {
|
||||
var ret []Command
|
||||
for cmd, info := range S2CCommandsCacheInfo {
|
||||
if info.Caching == match {
|
||||
ret = append(ret, cmd)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func HTTPBackendDropBacklog(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
formData, err := Backend.UnsealRequest(r.Form)
|
||||
|
@ -245,33 +135,18 @@ func HTTPBackendCachedPublish(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
timestamp := time.Unix(timeNum, 0)
|
||||
|
||||
cacheinfo, ok := S2CCommandsCacheInfo[cmd]
|
||||
if !ok {
|
||||
w.WriteHeader(422)
|
||||
fmt.Fprintf(w, "Caching semantics unknown for command '%s'. Post to /addcachedcommand first.", cmd)
|
||||
return
|
||||
}
|
||||
|
||||
var count int
|
||||
msg := ClientMessage{MessageID: -1, Command: cmd, origArguments: json}
|
||||
msg.parseOrigArguments()
|
||||
|
||||
if cacheinfo.Caching == CacheTypeLastOnly && cacheinfo.Target == MsgTargetTypeChat {
|
||||
SaveLastMessage(CachedLastMessages, &CachedLSMLock, cmd, channel, timestamp, json, deleteMode)
|
||||
count = PublishToChannel(channel, msg)
|
||||
} else if cacheinfo.Caching == CacheTypePersistent && cacheinfo.Target == MsgTargetTypeChat {
|
||||
SaveLastMessage(PersistentLastMessages, &PersistentLSMLock, cmd, channel, timestamp, json, deleteMode)
|
||||
count = PublishToChannel(channel, msg)
|
||||
} else if cacheinfo.Caching == CacheTypeLastOnly && cacheinfo.Target == MsgTargetTypeMultichat {
|
||||
channels := strings.Split(channel, ",")
|
||||
var dummyLock sync.Mutex
|
||||
CachedLSMLock.Lock()
|
||||
for _, channel := range channels {
|
||||
SaveLastMessage(CachedLastMessages, &dummyLock, cmd, channel, timestamp, json, deleteMode)
|
||||
}
|
||||
CachedLSMLock.Unlock()
|
||||
count = PublishToMultiple(channels, msg)
|
||||
channels := strings.Split(channel, ",")
|
||||
var dummyLock sync.Mutex
|
||||
CachedLSMLock.Lock()
|
||||
for _, channel := range channels {
|
||||
SaveLastMessage(CachedLastMessages, &dummyLock, cmd, channel, timestamp, json, deleteMode)
|
||||
}
|
||||
CachedLSMLock.Unlock()
|
||||
count = PublishToMultiple(channels, msg)
|
||||
|
||||
w.Write([]byte(strconv.Itoa(count)))
|
||||
}
|
||||
|
|
|
@ -33,9 +33,7 @@ func TestSubscriptionAndPublish(t *testing.T) {
|
|||
const TestData3 = false
|
||||
var TestData4 = []interface{}{"str1", "str2", "str3"}
|
||||
|
||||
S2CCommandsCacheInfo[TestCommandChan] = PushCommandCacheInfo{Caching: CacheTypeLastOnly, Target: MsgTargetTypeChat}
|
||||
S2CCommandsCacheInfo[TestCommandMulti] = PushCommandCacheInfo{Caching: CacheTypeLastOnly, Target: MsgTargetTypeMultichat}
|
||||
S2CCommandsCacheInfo[TestCommandGlobal] = PushCommandCacheInfo{Caching: CacheTypeLastOnly, Target: MsgTargetTypeGlobal}
|
||||
t.Log("TestSubscriptionAndPublish")
|
||||
|
||||
var server *httptest.Server
|
||||
var urls TURLs
|
||||
|
@ -195,7 +193,7 @@ func TestSubscriptionAndPublish(t *testing.T) {
|
|||
|
||||
// Publish message 4 - should go to clients 1, 2, 3
|
||||
|
||||
form, err = TSealForUncachedPubMsg(t, TestCommandGlobal, "", TestData4, MsgTargetTypeGlobal, false)
|
||||
form, err = TSealForUncachedPubMsg(t, TestCommandGlobal, "", TestData4, "global", false)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
|
@ -254,6 +252,8 @@ func TestRestrictedCommands(t *testing.T) {
|
|||
var server *httptest.Server
|
||||
var urls TURLs
|
||||
|
||||
t.Log("TestRestrictedCommands")
|
||||
|
||||
var backendExpected = NewTBackendRequestChecker(t,
|
||||
TExpectedBackendRequest{200, bPathAnnounceStartup, &url.Values{"startup": []string{"1"}}, "", nil},
|
||||
TExpectedBackendRequest{401, fmt.Sprintf("%s%s", bPathOtherCommand, TestCommandNeedsAuth), &url.Values{"authenticated": []string{"0"}, "username": []string{""}, "clientData": []string{TestRequestDataJSON}}, "", nil},
|
||||
|
|
|
@ -284,7 +284,7 @@ func TSealForSavePubMsg(tb testing.TB, cmd Command, channel string, arguments in
|
|||
return sealed, nil
|
||||
}
|
||||
|
||||
func TSealForUncachedPubMsg(tb testing.TB, cmd Command, channel string, arguments interface{}, scope MessageTargetType, deleteMode bool) (url.Values, error) {
|
||||
func TSealForUncachedPubMsg(tb testing.TB, cmd Command, channel string, arguments interface{}, scope string, deleteMode bool) (url.Values, error) {
|
||||
form := url.Values{}
|
||||
form.Set("cmd", string(cmd))
|
||||
argsBytes, err := json.Marshal(arguments)
|
||||
|
@ -298,7 +298,7 @@ func TSealForUncachedPubMsg(tb testing.TB, cmd Command, channel string, argument
|
|||
form.Set("delete", "1")
|
||||
}
|
||||
form.Set("time", time.Now().Format(time.UnixDate))
|
||||
form.Set("scope", scope.String())
|
||||
form.Set("scope", scope)
|
||||
|
||||
sealed, err := Backend.SealRequest(form)
|
||||
if err != nil {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
@ -152,109 +151,3 @@ func (cv *ClientVersion) After(cv2 *ClientVersion) bool {
|
|||
func (cv *ClientVersion) Equal(cv2 *ClientVersion) bool {
|
||||
return cv.Major == cv2.Major && cv.Minor == cv2.Minor && cv.Revision == cv2.Revision
|
||||
}
|
||||
|
||||
func (bct BacklogCacheType) Name() string {
|
||||
switch bct {
|
||||
case CacheTypeInvalid:
|
||||
return ""
|
||||
case CacheTypeNever:
|
||||
return "never"
|
||||
case CacheTypeLastOnly:
|
||||
return "last"
|
||||
case CacheTypePersistent:
|
||||
return "persist"
|
||||
}
|
||||
panic("Invalid BacklogCacheType value")
|
||||
}
|
||||
|
||||
var CacheTypesByName = map[string]BacklogCacheType{
|
||||
"never": CacheTypeNever,
|
||||
"last": CacheTypeLastOnly,
|
||||
"persist": CacheTypePersistent,
|
||||
}
|
||||
|
||||
func BacklogCacheTypeByName(name string) (bct BacklogCacheType) {
|
||||
// CacheTypeInvalid is the zero value so it doesn't matter
|
||||
bct, _ = CacheTypesByName[name]
|
||||
return
|
||||
}
|
||||
|
||||
// String implements Stringer
|
||||
func (bct BacklogCacheType) String() string { return bct.Name() }
|
||||
|
||||
// MarshalJSON implements json.Marshaler
|
||||
func (bct BacklogCacheType) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(bct.Name())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler
|
||||
func (bct *BacklogCacheType) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
err := json.Unmarshal(data, &str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if str == "" {
|
||||
*bct = CacheTypeInvalid
|
||||
return nil
|
||||
}
|
||||
newBct := BacklogCacheTypeByName(str)
|
||||
if newBct != CacheTypeInvalid {
|
||||
*bct = newBct
|
||||
return nil
|
||||
}
|
||||
return ErrorUnrecognizedCacheType
|
||||
}
|
||||
|
||||
func (mtt MessageTargetType) Name() string {
|
||||
switch mtt {
|
||||
case MsgTargetTypeInvalid:
|
||||
return ""
|
||||
case MsgTargetTypeChat:
|
||||
return "chat"
|
||||
case MsgTargetTypeMultichat:
|
||||
return "multichat"
|
||||
case MsgTargetTypeGlobal:
|
||||
return "global"
|
||||
}
|
||||
panic("Invalid MessageTargetType value")
|
||||
}
|
||||
|
||||
var TargetTypesByName = map[string]MessageTargetType{
|
||||
"chat": MsgTargetTypeChat,
|
||||
"multichat": MsgTargetTypeMultichat,
|
||||
"global": MsgTargetTypeGlobal,
|
||||
}
|
||||
|
||||
func MessageTargetTypeByName(name string) (mtt MessageTargetType) {
|
||||
// MsgTargetTypeInvalid is the zero value so it doesn't matter
|
||||
mtt, _ = TargetTypesByName[name]
|
||||
return
|
||||
}
|
||||
|
||||
// String implements Stringer
|
||||
func (mtt MessageTargetType) String() string { return mtt.Name() }
|
||||
|
||||
// MarshalJSON implements json.Marshaler
|
||||
func (mtt MessageTargetType) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(mtt.Name())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler
|
||||
func (mtt *MessageTargetType) UnmarshalJSON(data []byte) error {
|
||||
var str string
|
||||
err := json.Unmarshal(data, &str)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if str == "" {
|
||||
*mtt = MsgTargetTypeInvalid
|
||||
return nil
|
||||
}
|
||||
newMtt := MessageTargetTypeByName(str)
|
||||
if newMtt != MsgTargetTypeInvalid {
|
||||
*mtt = newMtt
|
||||
return nil
|
||||
}
|
||||
return ErrorUnrecognizedTargetType
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue