1
0
Fork 0
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:
Kane York 2016-07-08 12:46:16 -07:00
parent 3b3457af14
commit ec932b1c36
5 changed files with 24 additions and 265 deletions

View file

@ -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)}
}

View file

@ -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)))
}

View file

@ -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},

View file

@ -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 {

View file

@ -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
}