mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-01 23:48: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"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/pmylund/go-cache"
|
"github.com/pmylund/go-cache"
|
||||||
"golang.org/x/crypto/nacl/box"
|
"golang.org/x/crypto/nacl/box"
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const bPathAnnounceStartup = "/startup"
|
const bPathAnnounceStartup = "/startup"
|
||||||
|
@ -80,7 +81,7 @@ func getCacheKey(remoteCommand, data string) string {
|
||||||
// HTTPBackendUncachedPublish handles the /uncached_pub route.
|
// HTTPBackendUncachedPublish handles the /uncached_pub route.
|
||||||
// The backend can POST here to publish a message to clients with no caching.
|
// The backend can POST here to publish a message to clients with no caching.
|
||||||
// The POST arguments are `cmd`, `args`, `channel`, and `scope`.
|
// 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) {
|
func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
formData, err := Backend.UnsealRequest(r.Form)
|
formData, err := Backend.UnsealRequest(r.Form)
|
||||||
|
@ -95,14 +96,12 @@ func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
channel := formData.Get("channel")
|
channel := formData.Get("channel")
|
||||||
scope := formData.Get("scope")
|
scope := formData.Get("scope")
|
||||||
|
|
||||||
target := MessageTargetTypeByName(scope)
|
|
||||||
|
|
||||||
if cmd == "" {
|
if cmd == "" {
|
||||||
w.WriteHeader(422)
|
w.WriteHeader(422)
|
||||||
fmt.Fprintf(w, "Error: cmd cannot be blank")
|
fmt.Fprintf(w, "Error: cmd cannot be blank")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if channel == "" && (target == MsgTargetTypeChat || target == MsgTargetTypeMultichat) {
|
if channel == "" && scope != "global" {
|
||||||
w.WriteHeader(422)
|
w.WriteHeader(422)
|
||||||
fmt.Fprintf(w, "Error: channel must be specified")
|
fmt.Fprintf(w, "Error: channel must be specified")
|
||||||
return
|
return
|
||||||
|
@ -112,19 +111,11 @@ func HTTPBackendUncachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
cm.parseOrigArguments()
|
cm.parseOrigArguments()
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
switch target {
|
switch scope {
|
||||||
case MsgTargetTypeChat:
|
|
||||||
count = PublishToChannel(channel, cm)
|
|
||||||
case MsgTargetTypeMultichat:
|
|
||||||
count = PublishToMultiple(strings.Split(channel, ","), cm)
|
|
||||||
case MsgTargetTypeGlobal:
|
|
||||||
count = PublishToAll(cm)
|
|
||||||
case MsgTargetTypeInvalid:
|
|
||||||
fallthrough
|
|
||||||
default:
|
default:
|
||||||
w.WriteHeader(422)
|
count = PublishToMultiple(strings.Split(channel, ","), cm)
|
||||||
fmt.Fprint(w, "Invalid 'scope'. must be chat, multichat, channel, or global")
|
case "global":
|
||||||
return
|
count = PublishToAll(cm)
|
||||||
}
|
}
|
||||||
fmt.Fprint(w, count)
|
fmt.Fprint(w, count)
|
||||||
}
|
}
|
||||||
|
@ -294,7 +285,7 @@ func (backend *backendInfo) sendTopicNotice(topic string, added bool) error {
|
||||||
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
if resp.StatusCode < 200 || resp.StatusCode > 299 {
|
||||||
respBytes, err := ioutil.ReadAll(resp.Body)
|
respBytes, err := ioutil.ReadAll(resp.Body)
|
||||||
if err != nil {
|
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)}
|
return ErrBackendNotOK{Code: resp.StatusCode, Response: string(respBytes)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -10,64 +9,6 @@ import (
|
||||||
"time"
|
"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 {
|
type LastSavedMessage struct {
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
Data string
|
Data string
|
||||||
|
@ -80,19 +21,11 @@ type LastSavedMessage struct {
|
||||||
var CachedLastMessages = make(map[Command]map[string]LastSavedMessage)
|
var CachedLastMessages = make(map[Command]map[string]LastSavedMessage)
|
||||||
var CachedLSMLock sync.RWMutex
|
var CachedLSMLock sync.RWMutex
|
||||||
|
|
||||||
// PersistentLastMessages is of CacheTypePersistent. Never cleaned.
|
|
||||||
var PersistentLastMessages = CachedLastMessages
|
|
||||||
var PersistentLSMLock = CachedLSMLock
|
|
||||||
|
|
||||||
// DumpBacklogData drops all /cached_pub data.
|
// DumpBacklogData drops all /cached_pub data.
|
||||||
func DumpBacklogData() {
|
func DumpBacklogData() {
|
||||||
CachedLSMLock.Lock()
|
CachedLSMLock.Lock()
|
||||||
CachedLastMessages = make(map[Command]map[string]LastSavedMessage)
|
CachedLastMessages = make(map[Command]map[string]LastSavedMessage)
|
||||||
CachedLSMLock.Unlock()
|
CachedLSMLock.Unlock()
|
||||||
|
|
||||||
//PersistentLSMLock.Lock()
|
|
||||||
//PersistentLastMessages = make(map[Command]map[string]LastSavedMessage)
|
|
||||||
//PersistentLSMLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendBacklogForNewClient sends any backlog data relevant to a new client.
|
// SendBacklogForNewClient sends any backlog data relevant to a new client.
|
||||||
|
@ -104,26 +37,8 @@ func SendBacklogForNewClient(client *ClientInfo) {
|
||||||
copy(curChannels, client.CurrentChannels)
|
copy(curChannels, client.CurrentChannels)
|
||||||
client.Mutex.Unlock()
|
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()
|
CachedLSMLock.RLock()
|
||||||
for _, cmd := range GetCommandsOfType(CacheTypeLastOnly) {
|
for cmd, chanMap := range CachedLastMessages {
|
||||||
chanMap := CachedLastMessages[cmd]
|
|
||||||
if chanMap == nil {
|
if chanMap == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -140,23 +55,8 @@ func SendBacklogForNewClient(client *ClientInfo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendBacklogForChannel(client *ClientInfo, channel string) {
|
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()
|
CachedLSMLock.RLock()
|
||||||
for _, cmd := range GetCommandsOfType(CacheTypeLastOnly) {
|
for cmd, chanMap := range CachedLastMessages {
|
||||||
chanMap := CachedLastMessages[cmd]
|
|
||||||
if chanMap == nil {
|
if chanMap == nil {
|
||||||
continue
|
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) {
|
func HTTPBackendDropBacklog(w http.ResponseWriter, r *http.Request) {
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
formData, err := Backend.UnsealRequest(r.Form)
|
formData, err := Backend.UnsealRequest(r.Form)
|
||||||
|
@ -245,24 +135,10 @@ func HTTPBackendCachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
timestamp := time.Unix(timeNum, 0)
|
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
|
var count int
|
||||||
msg := ClientMessage{MessageID: -1, Command: cmd, origArguments: json}
|
msg := ClientMessage{MessageID: -1, Command: cmd, origArguments: json}
|
||||||
msg.parseOrigArguments()
|
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, ",")
|
channels := strings.Split(channel, ",")
|
||||||
var dummyLock sync.Mutex
|
var dummyLock sync.Mutex
|
||||||
CachedLSMLock.Lock()
|
CachedLSMLock.Lock()
|
||||||
|
@ -271,7 +147,6 @@ func HTTPBackendCachedPublish(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
CachedLSMLock.Unlock()
|
CachedLSMLock.Unlock()
|
||||||
count = PublishToMultiple(channels, msg)
|
count = PublishToMultiple(channels, msg)
|
||||||
}
|
|
||||||
|
|
||||||
w.Write([]byte(strconv.Itoa(count)))
|
w.Write([]byte(strconv.Itoa(count)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,7 @@ func TestSubscriptionAndPublish(t *testing.T) {
|
||||||
const TestData3 = false
|
const TestData3 = false
|
||||||
var TestData4 = []interface{}{"str1", "str2", "str3"}
|
var TestData4 = []interface{}{"str1", "str2", "str3"}
|
||||||
|
|
||||||
S2CCommandsCacheInfo[TestCommandChan] = PushCommandCacheInfo{Caching: CacheTypeLastOnly, Target: MsgTargetTypeChat}
|
t.Log("TestSubscriptionAndPublish")
|
||||||
S2CCommandsCacheInfo[TestCommandMulti] = PushCommandCacheInfo{Caching: CacheTypeLastOnly, Target: MsgTargetTypeMultichat}
|
|
||||||
S2CCommandsCacheInfo[TestCommandGlobal] = PushCommandCacheInfo{Caching: CacheTypeLastOnly, Target: MsgTargetTypeGlobal}
|
|
||||||
|
|
||||||
var server *httptest.Server
|
var server *httptest.Server
|
||||||
var urls TURLs
|
var urls TURLs
|
||||||
|
@ -195,7 +193,7 @@ func TestSubscriptionAndPublish(t *testing.T) {
|
||||||
|
|
||||||
// Publish message 4 - should go to clients 1, 2, 3
|
// 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 {
|
if err != nil {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
@ -254,6 +252,8 @@ func TestRestrictedCommands(t *testing.T) {
|
||||||
var server *httptest.Server
|
var server *httptest.Server
|
||||||
var urls TURLs
|
var urls TURLs
|
||||||
|
|
||||||
|
t.Log("TestRestrictedCommands")
|
||||||
|
|
||||||
var backendExpected = NewTBackendRequestChecker(t,
|
var backendExpected = NewTBackendRequestChecker(t,
|
||||||
TExpectedBackendRequest{200, bPathAnnounceStartup, &url.Values{"startup": []string{"1"}}, "", nil},
|
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},
|
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
|
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 := url.Values{}
|
||||||
form.Set("cmd", string(cmd))
|
form.Set("cmd", string(cmd))
|
||||||
argsBytes, err := json.Marshal(arguments)
|
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("delete", "1")
|
||||||
}
|
}
|
||||||
form.Set("time", time.Now().Format(time.UnixDate))
|
form.Set("time", time.Now().Format(time.UnixDate))
|
||||||
form.Set("scope", scope.String())
|
form.Set("scope", scope)
|
||||||
|
|
||||||
sealed, err := Backend.SealRequest(form)
|
sealed, err := Backend.SealRequest(form)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -152,109 +151,3 @@ func (cv *ClientVersion) After(cv2 *ClientVersion) bool {
|
||||||
func (cv *ClientVersion) Equal(cv2 *ClientVersion) bool {
|
func (cv *ClientVersion) Equal(cv2 *ClientVersion) bool {
|
||||||
return cv.Major == cv2.Major && cv.Minor == cv2.Minor && cv.Revision == cv2.Revision
|
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