mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-07 06:40:54 +00:00
client: Move room/channel distinction into name (room.trihex)
Also, have the client send a "ready" message when it has sent all its initial requests.
This commit is contained in:
parent
69676bf287
commit
85d261afb3
10 changed files with 62 additions and 162 deletions
|
@ -87,7 +87,7 @@ func HBackendPublishRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Fprintf(w, "Error: cmd cannot be blank")
|
fmt.Fprintf(w, "Error: cmd cannot be blank")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if channel == "" && (target == MsgTargetTypeChat || target == MsgTargetTypeMultichat || target == MsgTargetTypeWatching) {
|
if channel == "" && (target == MsgTargetTypeChat || target == MsgTargetTypeMultichat) {
|
||||||
w.WriteHeader(422)
|
w.WriteHeader(422)
|
||||||
fmt.Fprintf(w, "Error: channel must be specified")
|
fmt.Fprintf(w, "Error: channel must be specified")
|
||||||
return
|
return
|
||||||
|
@ -104,8 +104,6 @@ func HBackendPublishRequest(w http.ResponseWriter, r *http.Request) {
|
||||||
count = PublishToChat(channel, cm)
|
count = PublishToChat(channel, cm)
|
||||||
case MsgTargetTypeMultichat:
|
case MsgTargetTypeMultichat:
|
||||||
// TODO
|
// TODO
|
||||||
case MsgTargetTypeWatching:
|
|
||||||
count = PublishToWatchers(channel, cm)
|
|
||||||
case MsgTargetTypeGlobal:
|
case MsgTargetTypeGlobal:
|
||||||
count = PublishToAll(cm)
|
count = PublishToAll(cm)
|
||||||
case MsgTargetTypeInvalid:
|
case MsgTargetTypeInvalid:
|
||||||
|
@ -169,10 +167,9 @@ func RequestRemoteData(remoteCommand, data string, auth AuthInfo) (responseStr s
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchBacklogData(chatSubs, channelSubs []string) ([]ClientMessage, error) {
|
func FetchBacklogData(chatSubs []string) ([]ClientMessage, error) {
|
||||||
formData := url.Values{
|
formData := url.Values{
|
||||||
"chatSubs": chatSubs,
|
"subs": chatSubs,
|
||||||
"channelSubs": channelSubs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealedForm, err := SealRequest(formData)
|
sealedForm, err := SealRequest(formData)
|
||||||
|
|
|
@ -22,7 +22,7 @@ var ServerInitiatedCommands = map[string]PushCommandCacheInfo{
|
||||||
/// Emote updates
|
/// Emote updates
|
||||||
"reload_badges": {CacheTypeTimestamps, MsgTargetTypeGlobal}, // timecache:global
|
"reload_badges": {CacheTypeTimestamps, MsgTargetTypeGlobal}, // timecache:global
|
||||||
"set_badge": {CacheTypeTimestamps, MsgTargetTypeMultichat}, // timecache:multichat
|
"set_badge": {CacheTypeTimestamps, MsgTargetTypeMultichat}, // timecache:multichat
|
||||||
"reload_set": {CacheTypeTimestamps, MsgTargetTypeMultichat}, // timecache:multichat
|
"reload_set": {}, // timecache:multichat
|
||||||
"load_set": {}, // TODO what are the semantics of this?
|
"load_set": {}, // TODO what are the semantics of this?
|
||||||
|
|
||||||
/// User auth
|
/// User auth
|
||||||
|
@ -32,12 +32,12 @@ var ServerInitiatedCommands = map[string]PushCommandCacheInfo{
|
||||||
// follow_sets: extra emote sets included in the chat
|
// follow_sets: extra emote sets included in the chat
|
||||||
// follow_buttons: extra follow buttons below the stream
|
// follow_buttons: extra follow buttons below the stream
|
||||||
"follow_sets": {CacheTypePersistent, MsgTargetTypeChat}, // mustcache:chat
|
"follow_sets": {CacheTypePersistent, MsgTargetTypeChat}, // mustcache:chat
|
||||||
"follow_buttons": {CacheTypePersistent, MsgTargetTypeWatching}, // mustcache:watching
|
"follow_buttons": {CacheTypePersistent, MsgTargetTypeChat}, // mustcache:watching
|
||||||
"srl_race": {CacheTypeLastOnly, MsgTargetTypeWatching}, // cachelast:watching
|
"srl_race": {CacheTypeLastOnly, MsgTargetTypeChat}, // cachelast:watching
|
||||||
|
|
||||||
/// Chatter/viewer counts
|
/// Chatter/viewer counts
|
||||||
"chatters": {CacheTypeLastOnly, MsgTargetTypeWatching}, // cachelast:watching
|
"chatters": {CacheTypeLastOnly, MsgTargetTypeChat}, // cachelast:watching
|
||||||
"viewers": {CacheTypeLastOnly, MsgTargetTypeWatching}, // cachelast:watching
|
"viewers": {CacheTypeLastOnly, MsgTargetTypeChat}, // cachelast:watching
|
||||||
}
|
}
|
||||||
|
|
||||||
type BacklogCacheType int
|
type BacklogCacheType int
|
||||||
|
@ -69,8 +69,6 @@ const (
|
||||||
MsgTargetTypeChat
|
MsgTargetTypeChat
|
||||||
// This message is targeted to all users in multiple chats
|
// This message is targeted to all users in multiple chats
|
||||||
MsgTargetTypeMultichat
|
MsgTargetTypeMultichat
|
||||||
// This message is targeted to all users watching a stream
|
|
||||||
MsgTargetTypeWatching
|
|
||||||
// This message is sent to all FFZ users.
|
// This message is sent to all FFZ users.
|
||||||
MsgTargetTypeGlobal
|
MsgTargetTypeGlobal
|
||||||
)
|
)
|
||||||
|
|
|
@ -85,7 +85,7 @@ func HandleSub(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rms
|
||||||
client.Mutex.Lock()
|
client.Mutex.Lock()
|
||||||
|
|
||||||
AddToSliceS(&client.CurrentChannels, channel)
|
AddToSliceS(&client.CurrentChannels, channel)
|
||||||
client.PendingChatBacklogs = append(client.PendingChatBacklogs, channel)
|
client.PendingSubscriptionsBacklog = append(client.PendingSubscriptionsBacklog, channel)
|
||||||
|
|
||||||
if client.MakePendingRequests == nil {
|
if client.MakePendingRequests == nil {
|
||||||
client.MakePendingRequests = time.AfterFunc(ChannelInfoDelay, GetSubscriptionBacklogFor(conn, client))
|
client.MakePendingRequests = time.AfterFunc(ChannelInfoDelay, GetSubscriptionBacklogFor(conn, client))
|
||||||
|
@ -118,49 +118,6 @@ func HandleUnsub(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (r
|
||||||
return ResponseSuccess, nil
|
return ResponseSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleSubChannel(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg ClientMessage, err error) {
|
|
||||||
channel, err := msg.ArgumentsAsString()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
client.Mutex.Lock()
|
|
||||||
|
|
||||||
AddToSliceS(&client.WatchingChannels, channel)
|
|
||||||
client.PendingStreamBacklogs = append(client.PendingStreamBacklogs, channel)
|
|
||||||
|
|
||||||
if client.MakePendingRequests == nil {
|
|
||||||
client.MakePendingRequests = time.AfterFunc(ChannelInfoDelay, GetSubscriptionBacklogFor(conn, client))
|
|
||||||
} else {
|
|
||||||
if !client.MakePendingRequests.Reset(ChannelInfoDelay) {
|
|
||||||
client.MakePendingRequests = time.AfterFunc(ChannelInfoDelay, GetSubscriptionBacklogFor(conn, client))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
client.Mutex.Unlock()
|
|
||||||
|
|
||||||
SubscribeWatching(client, channel)
|
|
||||||
|
|
||||||
return ResponseSuccess, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func HandleUnsubChannel(conn *websocket.Conn, client *ClientInfo, msg ClientMessage) (rmsg ClientMessage, err error) {
|
|
||||||
channel, err := msg.ArgumentsAsString()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
client.Mutex.Lock()
|
|
||||||
RemoveFromSliceS(&client.WatchingChannels, channel)
|
|
||||||
client.Mutex.Unlock()
|
|
||||||
|
|
||||||
UnsubscribeSingleChannel(client, channel)
|
|
||||||
|
|
||||||
return ResponseSuccess, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSubscriptionBacklogFor(conn *websocket.Conn, client *ClientInfo) func() {
|
func GetSubscriptionBacklogFor(conn *websocket.Conn, client *ClientInfo) func() {
|
||||||
return func() {
|
return func() {
|
||||||
GetSubscriptionBacklog(conn, client)
|
GetSubscriptionBacklog(conn, client)
|
||||||
|
@ -169,25 +126,23 @@ func GetSubscriptionBacklogFor(conn *websocket.Conn, client *ClientInfo) func()
|
||||||
|
|
||||||
// On goroutine
|
// On goroutine
|
||||||
func GetSubscriptionBacklog(conn *websocket.Conn, client *ClientInfo) {
|
func GetSubscriptionBacklog(conn *websocket.Conn, client *ClientInfo) {
|
||||||
var chatSubs, channelSubs []string
|
var subs []string
|
||||||
|
|
||||||
// Lock, grab the data, and reset it
|
// Lock, grab the data, and reset it
|
||||||
client.Mutex.Lock()
|
client.Mutex.Lock()
|
||||||
chatSubs = client.PendingChatBacklogs
|
subs = client.PendingSubscriptionsBacklog
|
||||||
channelSubs = client.PendingStreamBacklogs
|
client.PendingSubscriptionsBacklog = nil
|
||||||
client.PendingChatBacklogs = nil
|
|
||||||
client.PendingStreamBacklogs = nil
|
|
||||||
client.MakePendingRequests = nil
|
client.MakePendingRequests = nil
|
||||||
client.Mutex.Unlock()
|
client.Mutex.Unlock()
|
||||||
|
|
||||||
if len(chatSubs) == 0 && len(channelSubs) == 0 {
|
if len(subs) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if backendUrl == "" {
|
if backendUrl == "" {
|
||||||
return // for testing runs
|
return // for testing runs
|
||||||
}
|
}
|
||||||
messages, err := FetchBacklogData(chatSubs, channelSubs)
|
messages, err := FetchBacklogData(subs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Oh well.
|
// Oh well.
|
||||||
|
|
|
@ -42,8 +42,6 @@ var CommandHandlers = map[Command]CommandHandler{
|
||||||
|
|
||||||
"sub": HandleSub,
|
"sub": HandleSub,
|
||||||
"unsub": HandleUnsub,
|
"unsub": HandleUnsub,
|
||||||
"sub_channel": HandleSubChannel,
|
|
||||||
"unsub_channel": HandleUnsubChannel,
|
|
||||||
|
|
||||||
"track_follow": HandleTrackFollow,
|
"track_follow": HandleTrackFollow,
|
||||||
"emoticon_uses": HandleEmoticonUses,
|
"emoticon_uses": HandleEmoticonUses,
|
||||||
|
|
|
@ -15,8 +15,6 @@ type SubscriberList struct {
|
||||||
|
|
||||||
var ChatSubscriptionInfo map[string]*SubscriberList = make(map[string]*SubscriberList)
|
var ChatSubscriptionInfo map[string]*SubscriberList = make(map[string]*SubscriberList)
|
||||||
var ChatSubscriptionLock sync.RWMutex
|
var ChatSubscriptionLock sync.RWMutex
|
||||||
var WatchingSubscriptionInfo map[string]*SubscriberList = make(map[string]*SubscriberList)
|
|
||||||
var WatchingSubscriptionLock sync.RWMutex
|
|
||||||
var GlobalSubscriptionInfo SubscriberList
|
var GlobalSubscriptionInfo SubscriberList
|
||||||
|
|
||||||
func PublishToChat(channel string, msg ClientMessage) (count int) {
|
func PublishToChat(channel string, msg ClientMessage) (count int) {
|
||||||
|
@ -34,21 +32,6 @@ func PublishToChat(channel string, msg ClientMessage) (count int) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func PublishToWatchers(channel string, msg ClientMessage) (count int) {
|
|
||||||
WatchingSubscriptionLock.RLock()
|
|
||||||
list := WatchingSubscriptionInfo[channel]
|
|
||||||
if list != nil {
|
|
||||||
list.RLock()
|
|
||||||
for _, msgChan := range list.Members {
|
|
||||||
msgChan <- msg
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
list.RUnlock()
|
|
||||||
}
|
|
||||||
WatchingSubscriptionLock.RUnlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func PublishToAll(msg ClientMessage) (count int) {
|
func PublishToAll(msg ClientMessage) (count int) {
|
||||||
GlobalSubscriptionInfo.RLock()
|
GlobalSubscriptionInfo.RLock()
|
||||||
for _, msgChan := range GlobalSubscriptionInfo.Members {
|
for _, msgChan := range GlobalSubscriptionInfo.Members {
|
||||||
|
@ -64,17 +47,17 @@ func PublishToAll(msg ClientMessage) (count int) {
|
||||||
// - ALREADY HOLDING a read-lock to the 'which' top-level map via the rlocker object
|
// - ALREADY HOLDING a read-lock to the 'which' top-level map via the rlocker object
|
||||||
// - possible write lock to the 'which' top-level map via the wlocker object
|
// - possible write lock to the 'which' top-level map via the wlocker object
|
||||||
// - write lock to SubscriptionInfo (if not creating new)
|
// - write lock to SubscriptionInfo (if not creating new)
|
||||||
func _subscribeWhileRlocked(which map[string]*SubscriberList, channelName string, value chan<- ClientMessage, rlocker sync.Locker, wlocker sync.Locker) {
|
func _subscribeWhileRlocked(channelName string, value chan<- ClientMessage) {
|
||||||
list := which[channelName]
|
list := ChatSubscriptionInfo[channelName]
|
||||||
if list == nil {
|
if list == nil {
|
||||||
// Not found, so create it
|
// Not found, so create it
|
||||||
rlocker.Unlock()
|
ChatSubscriptionLock.RUnlock()
|
||||||
wlocker.Lock()
|
ChatSubscriptionLock.Lock()
|
||||||
list = &SubscriberList{}
|
list = &SubscriberList{}
|
||||||
list.Members = []chan<- ClientMessage{value} // Create it populated, to avoid reaper
|
list.Members = []chan<- ClientMessage{value} // Create it populated, to avoid reaper
|
||||||
which[channelName] = list
|
ChatSubscriptionInfo[channelName] = list
|
||||||
wlocker.Unlock()
|
ChatSubscriptionLock.Unlock()
|
||||||
rlocker.Lock()
|
ChatSubscriptionLock.RLock()
|
||||||
} else {
|
} else {
|
||||||
list.Lock()
|
list.Lock()
|
||||||
AddToSliceC(&list.Members, value)
|
AddToSliceC(&list.Members, value)
|
||||||
|
@ -90,16 +73,10 @@ func SubscribeGlobal(client *ClientInfo) {
|
||||||
|
|
||||||
func SubscribeChat(client *ClientInfo, channelName string) {
|
func SubscribeChat(client *ClientInfo, channelName string) {
|
||||||
ChatSubscriptionLock.RLock()
|
ChatSubscriptionLock.RLock()
|
||||||
_subscribeWhileRlocked(ChatSubscriptionInfo, channelName, client.MessageChannel, ChatSubscriptionLock.RLocker(), &ChatSubscriptionLock)
|
_subscribeWhileRlocked(channelName, client.MessageChannel)
|
||||||
ChatSubscriptionLock.RUnlock()
|
ChatSubscriptionLock.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubscribeWatching(client *ClientInfo, channelName string) {
|
|
||||||
WatchingSubscriptionLock.RLock()
|
|
||||||
_subscribeWhileRlocked(WatchingSubscriptionInfo, channelName, client.MessageChannel, WatchingSubscriptionLock.RLocker(), &WatchingSubscriptionLock)
|
|
||||||
WatchingSubscriptionLock.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func unsubscribeAllClients() {
|
func unsubscribeAllClients() {
|
||||||
GlobalSubscriptionInfo.Lock()
|
GlobalSubscriptionInfo.Lock()
|
||||||
GlobalSubscriptionInfo.Members = nil
|
GlobalSubscriptionInfo.Members = nil
|
||||||
|
@ -107,9 +84,6 @@ func unsubscribeAllClients() {
|
||||||
ChatSubscriptionLock.Lock()
|
ChatSubscriptionLock.Lock()
|
||||||
ChatSubscriptionInfo = make(map[string]*SubscriberList)
|
ChatSubscriptionInfo = make(map[string]*SubscriberList)
|
||||||
ChatSubscriptionLock.Unlock()
|
ChatSubscriptionLock.Unlock()
|
||||||
WatchingSubscriptionLock.Lock()
|
|
||||||
WatchingSubscriptionInfo = make(map[string]*SubscriberList)
|
|
||||||
WatchingSubscriptionLock.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsubscribe the client from all channels, AND clear the CurrentChannels / WatchingChannels fields.
|
// Unsubscribe the client from all channels, AND clear the CurrentChannels / WatchingChannels fields.
|
||||||
|
@ -119,8 +93,8 @@ func unsubscribeAllClients() {
|
||||||
// - write lock to ClientInfo
|
// - write lock to ClientInfo
|
||||||
func UnsubscribeAll(client *ClientInfo) {
|
func UnsubscribeAll(client *ClientInfo) {
|
||||||
client.Mutex.Lock()
|
client.Mutex.Lock()
|
||||||
client.PendingChatBacklogs = nil
|
client.PendingSubscriptionsBacklog = nil
|
||||||
client.PendingStreamBacklogs = nil
|
client.PendingSubscriptionsBacklog = nil
|
||||||
client.Mutex.Unlock()
|
client.Mutex.Unlock()
|
||||||
|
|
||||||
GlobalSubscriptionInfo.Lock()
|
GlobalSubscriptionInfo.Lock()
|
||||||
|
@ -140,20 +114,6 @@ func UnsubscribeAll(client *ClientInfo) {
|
||||||
client.CurrentChannels = nil
|
client.CurrentChannels = nil
|
||||||
client.Mutex.Unlock()
|
client.Mutex.Unlock()
|
||||||
ChatSubscriptionLock.RUnlock()
|
ChatSubscriptionLock.RUnlock()
|
||||||
|
|
||||||
WatchingSubscriptionLock.RLock()
|
|
||||||
client.Mutex.Lock()
|
|
||||||
for _, v := range client.WatchingChannels {
|
|
||||||
list := WatchingSubscriptionInfo[v]
|
|
||||||
if list != nil {
|
|
||||||
list.Lock()
|
|
||||||
RemoveFromSliceC(&list.Members, client.MessageChannel)
|
|
||||||
list.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
client.WatchingChannels = nil
|
|
||||||
client.Mutex.Unlock()
|
|
||||||
WatchingSubscriptionLock.RUnlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnsubscribeSingleChat(client *ClientInfo, channelName string) {
|
func UnsubscribeSingleChat(client *ClientInfo, channelName string) {
|
||||||
|
@ -165,23 +125,13 @@ func UnsubscribeSingleChat(client *ClientInfo, channelName string) {
|
||||||
ChatSubscriptionLock.RUnlock()
|
ChatSubscriptionLock.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnsubscribeSingleChannel(client *ClientInfo, channelName string) {
|
|
||||||
WatchingSubscriptionLock.RLock()
|
|
||||||
list := WatchingSubscriptionInfo[channelName]
|
|
||||||
list.Lock()
|
|
||||||
RemoveFromSliceC(&list.Members, client.MessageChannel)
|
|
||||||
list.Unlock()
|
|
||||||
WatchingSubscriptionLock.RUnlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
const ReapingDelay = 120 * time.Minute
|
const ReapingDelay = 120 * time.Minute
|
||||||
|
|
||||||
// Checks each of ChatSubscriptionInfo / WatchingSubscriptionInfo
|
// Checks ChatSubscriptionInfo for entries with no subscribers every ReapingDelay.
|
||||||
// for entries with no subscribers every ReapingDelay.
|
|
||||||
// Started from SetupServer().
|
// Started from SetupServer().
|
||||||
func deadChannelReaper() {
|
func deadChannelReaper() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(ReapingDelay / 2)
|
time.Sleep(ReapingDelay)
|
||||||
ChatSubscriptionLock.Lock()
|
ChatSubscriptionLock.Lock()
|
||||||
for key, val := range ChatSubscriptionInfo {
|
for key, val := range ChatSubscriptionInfo {
|
||||||
if len(val.Members) == 0 {
|
if len(val.Members) == 0 {
|
||||||
|
@ -189,12 +139,5 @@ func deadChannelReaper() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChatSubscriptionLock.Unlock()
|
ChatSubscriptionLock.Unlock()
|
||||||
time.Sleep(ReapingDelay / 2)
|
|
||||||
WatchingSubscriptionLock.Lock()
|
|
||||||
for key, val := range WatchingSubscriptionInfo {
|
|
||||||
if len(val.Members) == 0 {
|
|
||||||
WatchingSubscriptionInfo[key] = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ func TestSubscriptionAndPublish(t *testing.T) {
|
||||||
var doneWg sync.WaitGroup
|
var doneWg sync.WaitGroup
|
||||||
var readyWg sync.WaitGroup
|
var readyWg sync.WaitGroup
|
||||||
|
|
||||||
const TestChannelName = "testchannel"
|
const TestChannelName = "room.testchannel"
|
||||||
const TestCommand = "testdata"
|
const TestCommand = "testdata"
|
||||||
const TestData = "123456789"
|
const TestData = "123456789"
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ func BenchmarkUserSubscriptionSinglePublish(b *testing.B) {
|
||||||
var doneWg sync.WaitGroup
|
var doneWg sync.WaitGroup
|
||||||
var readyWg sync.WaitGroup
|
var readyWg sync.WaitGroup
|
||||||
|
|
||||||
const TestChannelName = "testchannel"
|
const TestChannelName = "room.testchannel"
|
||||||
const TestCommand = "testdata"
|
const TestCommand = "testdata"
|
||||||
const TestData = "123456789"
|
const TestData = "123456789"
|
||||||
|
|
||||||
|
|
|
@ -62,19 +62,10 @@ type ClientInfo struct {
|
||||||
// Protected by Mutex.
|
// Protected by Mutex.
|
||||||
CurrentChannels []string
|
CurrentChannels []string
|
||||||
|
|
||||||
// This list of channels this client needs UI updates for.
|
|
||||||
// Protected by Mutex.
|
|
||||||
WatchingChannels []string
|
|
||||||
|
|
||||||
// List of channels that we have not yet checked current chat-related channel info for.
|
// List of channels that we have not yet checked current chat-related channel info for.
|
||||||
// This lets us batch the backlog requests.
|
// This lets us batch the backlog requests.
|
||||||
// Protected by Mutex.
|
// Protected by Mutex.
|
||||||
PendingChatBacklogs []string
|
PendingSubscriptionsBacklog []string
|
||||||
|
|
||||||
// List of channels that we have not yet checked current stream-related channel info for.
|
|
||||||
// This lets us batch the backlog requests.
|
|
||||||
// Protected by Mutex.
|
|
||||||
PendingStreamBacklogs []string
|
|
||||||
|
|
||||||
// A timer that, when fired, will make the pending backlog requests.
|
// A timer that, when fired, will make the pending backlog requests.
|
||||||
// Usually nil. Protected by Mutex.
|
// Usually nil. Protected by Mutex.
|
||||||
|
@ -151,8 +142,6 @@ func (mtt MessageTargetType) Name() string {
|
||||||
return "chat"
|
return "chat"
|
||||||
case MsgTargetTypeMultichat:
|
case MsgTargetTypeMultichat:
|
||||||
return "multichat"
|
return "multichat"
|
||||||
case MsgTargetTypeWatching:
|
|
||||||
return "channel"
|
|
||||||
case MsgTargetTypeGlobal:
|
case MsgTargetTypeGlobal:
|
||||||
return "global"
|
return "global"
|
||||||
}
|
}
|
||||||
|
@ -163,7 +152,6 @@ var TargetTypesByName = map[string]MessageTargetType{
|
||||||
"single": MsgTargetTypeSingle,
|
"single": MsgTargetTypeSingle,
|
||||||
"chat": MsgTargetTypeChat,
|
"chat": MsgTargetTypeChat,
|
||||||
"multichat": MsgTargetTypeMultichat,
|
"multichat": MsgTargetTypeMultichat,
|
||||||
"channel": MsgTargetTypeWatching,
|
|
||||||
"global": MsgTargetTypeGlobal,
|
"global": MsgTargetTypeGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,10 +153,10 @@ FFZ.prototype.setup_channel = function() {
|
||||||
|
|
||||||
if ( id !== f.__old_host_target ) {
|
if ( id !== f.__old_host_target ) {
|
||||||
if ( f.__old_host_target )
|
if ( f.__old_host_target )
|
||||||
f.ws_send("unsub_channel", f.__old_host_target);
|
f.ws_send("unsub", "channel." + f.__old_host_target);
|
||||||
|
|
||||||
if ( id ) {
|
if ( id ) {
|
||||||
f.ws_send("sub_channel", id);
|
f.ws_send("sub", "channel." + id);
|
||||||
f.__old_host_target = id;
|
f.__old_host_target = id;
|
||||||
} else
|
} else
|
||||||
delete f.__old_host_target;
|
delete f.__old_host_target;
|
||||||
|
@ -208,7 +208,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
el = this.get('element');
|
el = this.get('element');
|
||||||
|
|
||||||
f._cindex = this;
|
f._cindex = this;
|
||||||
f.ws_send("sub_channel", id);
|
f.ws_send("sub", "channel." + id);
|
||||||
|
|
||||||
el.setAttribute('data-channel', id);
|
el.setAttribute('data-channel', id);
|
||||||
el.classList.add('ffz-channel');
|
el.classList.add('ffz-channel');
|
||||||
|
@ -621,7 +621,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
ffzTeardown: function() {
|
ffzTeardown: function() {
|
||||||
var id = this.get('controller.id');
|
var id = this.get('controller.id');
|
||||||
if ( id )
|
if ( id )
|
||||||
f.ws_send("unsub_channel", id);
|
f.ws_send("unsub", "channel." + id);
|
||||||
|
|
||||||
this.get('element').setAttribute('data-channel', '');
|
this.get('element').setAttribute('data-channel', '');
|
||||||
f._cindex = undefined;
|
f._cindex = undefined;
|
||||||
|
|
|
@ -591,7 +591,7 @@ FFZ.prototype.add_room = function(id, room) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let the server know where we are.
|
// Let the server know where we are.
|
||||||
this.ws_send("sub", id);
|
this.ws_send("sub", "room." + id);
|
||||||
|
|
||||||
// See if we need history?
|
// See if we need history?
|
||||||
if ( ! this.has_bttv && this.settings.chat_history && room && (room.get('messages.length') || 0) < 10 ) {
|
if ( ! this.has_bttv && this.settings.chat_history && room && (room.get('messages.length') || 0) < 10 ) {
|
||||||
|
@ -619,7 +619,7 @@ FFZ.prototype.remove_room = function(id) {
|
||||||
utils.update_css(this._room_style, id, null);
|
utils.update_css(this._room_style, id, null);
|
||||||
|
|
||||||
// Let the server know we're gone and delete our data for this room.
|
// Let the server know we're gone and delete our data for this room.
|
||||||
this.ws_send("unsub", id);
|
this.ws_send("unsub", "room." + id);
|
||||||
delete this.rooms[id];
|
delete this.rooms[id];
|
||||||
|
|
||||||
// Clean up sets we aren't using any longer.
|
// Clean up sets we aren't using any longer.
|
||||||
|
|
|
@ -64,8 +64,8 @@ FFZ.prototype.ws_create = function() {
|
||||||
if ( f.is_dashboard ) {
|
if ( f.is_dashboard ) {
|
||||||
var match = location.pathname.match(/\/([^\/]+)/);
|
var match = location.pathname.match(/\/([^\/]+)/);
|
||||||
if ( match ) {
|
if ( match ) {
|
||||||
f.ws_send("sub", match[1]);
|
f.ws_send("sub", "room." + match[1]);
|
||||||
f.ws_send("sub_channel", match[1]);
|
f.ws_send("sub", "channel." + match[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ FFZ.prototype.ws_create = function() {
|
||||||
if ( ! f.rooms.hasOwnProperty(room_id) || ! f.rooms[room_id] )
|
if ( ! f.rooms.hasOwnProperty(room_id) || ! f.rooms[room_id] )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
f.ws_send("sub", room_id);
|
f.ws_send("sub", "room." + room_id);
|
||||||
|
|
||||||
if ( f.rooms[room_id].needs_history ) {
|
if ( f.rooms[room_id].needs_history ) {
|
||||||
f.rooms[room_id].needs_history = false;
|
f.rooms[room_id].needs_history = false;
|
||||||
|
@ -89,10 +89,10 @@ FFZ.prototype.ws_create = function() {
|
||||||
hosted_id = f._cindex.get('controller.hostModeTarget.id');
|
hosted_id = f._cindex.get('controller.hostModeTarget.id');
|
||||||
|
|
||||||
if ( channel_id )
|
if ( channel_id )
|
||||||
f.ws_send("sub_channel", channel_id);
|
f.ws_send("sub", "channel." + channel_id);
|
||||||
|
|
||||||
if ( hosted_id )
|
if ( hosted_id )
|
||||||
f.ws_send("sub_channel", hosted_id);
|
f.ws_send("sub", "channel." + hosted_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send any pending commands.
|
// Send any pending commands.
|
||||||
|
@ -103,11 +103,32 @@ FFZ.prototype.ws_create = function() {
|
||||||
var d = pending[i];
|
var d = pending[i];
|
||||||
f.ws_send(d[0], d[1], d[2]);
|
f.ws_send(d[0], d[1], d[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If reconnecting, get the backlog that we missed.
|
||||||
|
if ( f._ws_offline_time ) {
|
||||||
|
var timestamp = f._ws_offline_time;
|
||||||
|
delete f._ws_offline_time;
|
||||||
|
f.ws_send("ready", timestamp);
|
||||||
|
} else {
|
||||||
|
f.ws_send("ready", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onerror = function() {
|
||||||
|
if ( ! f._ws_offline_time ) {
|
||||||
|
f._ws_offline_time = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cycle selected server
|
||||||
|
f._ws_host_idx = (f._ws_host_idx + 1) % constants.WS_SERVERS.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.onclose = function(e) {
|
ws.onclose = function(e) {
|
||||||
f.log("Socket closed. (Code: " + e.code + ", Reason: " + e.reason + ")");
|
f.log("Socket closed. (Code: " + e.code + ", Reason: " + e.reason + ")");
|
||||||
f._ws_open = false;
|
f._ws_open = false;
|
||||||
|
if ( ! f._ws_offline_time ) {
|
||||||
|
f._ws_offline_time = new Date().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
// When the connection closes, run our callbacks.
|
// When the connection closes, run our callbacks.
|
||||||
for (var i=0; i < FFZ.ws_on_close.length; i++) {
|
for (var i=0; i < FFZ.ws_on_close.length; i++) {
|
||||||
|
@ -118,7 +139,7 @@ FFZ.prototype.ws_create = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to cycle to backup server
|
// Cycle selected server
|
||||||
f._ws_host_idx = (f._ws_host_idx + 1) % constants.WS_SERVERS.length;
|
f._ws_host_idx = (f._ws_host_idx + 1) % constants.WS_SERVERS.length;
|
||||||
|
|
||||||
if ( f._ws_delay > 10000 ) {
|
if ( f._ws_delay > 10000 ) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue