2015-10-25 00:44:25 -07:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2015-11-16 20:35:03 -08:00
|
|
|
"fmt"
|
2015-11-01 13:17:35 -08:00
|
|
|
"net"
|
2015-10-25 00:44:25 -07:00
|
|
|
"sync"
|
2016-04-28 14:36:59 -07:00
|
|
|
|
|
|
|
"github.com/satori/go.uuid"
|
2015-10-25 00:44:25 -07:00
|
|
|
)
|
|
|
|
|
2015-12-16 11:15:17 -08:00
|
|
|
const NegativeOne = ^uint64(0)
|
|
|
|
|
2016-05-21 11:35:32 -07:00
|
|
|
var AnonymousClientID = uuid.FromStringOrNil("683b45e4-f853-4c45-bf96-7d799cc93e34")
|
|
|
|
|
2015-10-26 22:16:03 -07:00
|
|
|
type ConfigFile struct {
|
|
|
|
// Numeric server id known to the backend
|
2016-04-28 14:36:59 -07:00
|
|
|
ServerID int
|
2016-01-15 20:59:33 -08:00
|
|
|
// Address to bind the HTTP server to on startup.
|
2016-04-28 14:36:59 -07:00
|
|
|
ListenAddr string
|
2016-01-15 20:59:33 -08:00
|
|
|
// Address to bind the TLS server to on startup.
|
2015-11-23 16:08:22 -08:00
|
|
|
SSLListenAddr string
|
2015-10-26 22:16:03 -07:00
|
|
|
// URL to the backend server
|
2015-11-15 18:43:34 -08:00
|
|
|
BackendURL string
|
2015-10-26 22:16:03 -07:00
|
|
|
|
2015-11-17 11:01:42 -08:00
|
|
|
// Minimum memory to accept a new connection
|
2015-11-17 11:11:14 -08:00
|
|
|
MinMemoryKBytes uint64
|
2016-01-15 20:59:33 -08:00
|
|
|
// Maximum # of clients that can be connected. 0 to disable.
|
2016-04-28 14:36:59 -07:00
|
|
|
MaxClientCount uint64
|
2015-11-17 11:01:42 -08:00
|
|
|
|
2015-10-26 22:16:03 -07:00
|
|
|
// SSL/TLS
|
2016-01-15 20:59:33 -08:00
|
|
|
// Enable the use of SSL.
|
2016-04-28 14:36:59 -07:00
|
|
|
UseSSL bool
|
2016-01-15 20:59:33 -08:00
|
|
|
// Path to certificate file.
|
2015-10-26 22:16:03 -07:00
|
|
|
SSLCertificateFile string
|
2016-01-15 20:59:33 -08:00
|
|
|
// Path to key file.
|
2016-04-28 14:36:59 -07:00
|
|
|
SSLKeyFile string
|
2015-10-26 22:16:03 -07:00
|
|
|
|
2015-12-16 11:48:37 -08:00
|
|
|
UseESLogStashing bool
|
2015-11-17 19:53:58 -08:00
|
|
|
ESServer string
|
|
|
|
ESIndexPrefix string
|
|
|
|
ESHostName string
|
|
|
|
|
2015-10-26 22:16:03 -07:00
|
|
|
// Nacl keys
|
|
|
|
OurPrivateKey []byte
|
|
|
|
OurPublicKey []byte
|
|
|
|
BackendPublicKey []byte
|
2015-11-08 16:44:16 -08:00
|
|
|
|
2016-01-15 20:59:33 -08:00
|
|
|
// Request username validation from all new clients.
|
2015-11-08 16:44:16 -08:00
|
|
|
SendAuthToNewClients bool
|
2015-10-25 12:40:07 -07:00
|
|
|
}
|
|
|
|
|
2015-10-25 00:44:25 -07:00
|
|
|
type ClientMessage struct {
|
|
|
|
// Message ID. Increments by 1 for each message sent from the client.
|
|
|
|
// When replying to a command, the message ID must be echoed.
|
|
|
|
// When sending a server-initiated message, this is -1.
|
2015-11-05 23:24:35 -08:00
|
|
|
MessageID int `json:"m"`
|
2015-10-25 00:44:25 -07:00
|
|
|
// The command that the client wants from the server.
|
|
|
|
// When sent from the server, the literal string 'True' indicates success.
|
|
|
|
// Before sending, a blank Command will be converted into SuccessCommand.
|
2015-11-05 23:24:35 -08:00
|
|
|
Command Command `json:"c"`
|
2015-10-25 00:44:25 -07:00
|
|
|
// Result of json.Unmarshal on the third field send from the client
|
2015-11-05 23:24:35 -08:00
|
|
|
Arguments interface{} `json:"a"`
|
2015-10-25 00:44:25 -07:00
|
|
|
|
|
|
|
origArguments string
|
|
|
|
}
|
|
|
|
|
2017-09-15 16:25:52 -07:00
|
|
|
func (cm ClientMessage) Reply(cmd string, args interface{}) ClientMessage {
|
|
|
|
return ClientMessage{
|
|
|
|
MessageID: cm.MessageID,
|
2017-09-15 16:26:44 -07:00
|
|
|
Command: cmd,
|
2017-09-15 16:25:52 -07:00
|
|
|
Arguments: args,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cm ClientMessage) ReplyJSON(cmd string, argsJSON string) ClientMessage {
|
|
|
|
n := ClientMessage{
|
2017-09-15 16:26:44 -07:00
|
|
|
MessageID: cm.MessageID,
|
|
|
|
Command: cmd,
|
2017-09-15 16:25:52 -07:00
|
|
|
origArguments: argsJSON,
|
|
|
|
}
|
|
|
|
n.parseOrigArguments()
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
2015-10-25 00:44:25 -07:00
|
|
|
type AuthInfo struct {
|
|
|
|
// The client's claimed username on Twitch.
|
2015-10-26 10:06:45 -07:00
|
|
|
TwitchUsername string
|
2015-10-25 00:44:25 -07:00
|
|
|
|
|
|
|
// Whether or not the server has validated the client's claimed username.
|
|
|
|
UsernameValidated bool
|
|
|
|
}
|
|
|
|
|
2015-11-16 14:30:09 -08:00
|
|
|
type ClientVersion struct {
|
2015-11-16 20:35:03 -08:00
|
|
|
Major int
|
|
|
|
Minor int
|
2015-11-16 14:30:09 -08:00
|
|
|
Revision int
|
|
|
|
}
|
|
|
|
|
2015-10-25 00:44:25 -07:00
|
|
|
type ClientInfo struct {
|
|
|
|
// The client ID.
|
|
|
|
// This must be written once by the owning goroutine before the struct is passed off to any other goroutines.
|
2015-10-26 10:06:45 -07:00
|
|
|
ClientID uuid.UUID
|
2015-10-25 00:44:25 -07:00
|
|
|
|
2015-11-16 14:30:09 -08:00
|
|
|
// The client's literal version string.
|
2015-10-25 00:44:25 -07:00
|
|
|
// This must be written once by the owning goroutine before the struct is passed off to any other goroutines.
|
2015-11-16 14:30:09 -08:00
|
|
|
VersionString string
|
|
|
|
|
|
|
|
Version ClientVersion
|
2015-10-25 00:44:25 -07:00
|
|
|
|
2017-09-15 13:07:41 -07:00
|
|
|
// Set after a successful hello message.
|
|
|
|
HelloOK bool
|
|
|
|
|
2015-10-25 00:44:25 -07:00
|
|
|
// This mutex protects writable data in this struct.
|
|
|
|
// If it seems to be a performance problem, we can split this.
|
2015-10-26 10:06:45 -07:00
|
|
|
Mutex sync.Mutex
|
2015-10-25 00:44:25 -07:00
|
|
|
|
2016-01-17 18:01:21 -08:00
|
|
|
// Info about the client's username and whether or not we have verified it.
|
2015-10-25 00:44:25 -07:00
|
|
|
AuthInfo
|
|
|
|
|
2015-11-01 13:17:35 -08:00
|
|
|
RemoteAddr net.Addr
|
|
|
|
|
2015-10-25 00:44:25 -07:00
|
|
|
// Username validation nonce.
|
2015-10-26 10:06:45 -07:00
|
|
|
ValidationNonce string
|
2015-10-25 00:44:25 -07:00
|
|
|
|
|
|
|
// The list of chats this client is currently in.
|
2015-10-25 03:21:50 -07:00
|
|
|
// Protected by Mutex.
|
2015-10-26 10:06:45 -07:00
|
|
|
CurrentChannels []string
|
2015-10-25 00:44:25 -07:00
|
|
|
|
2016-04-28 14:39:20 -07:00
|
|
|
// True if the client has already sent the 'ready' command
|
|
|
|
ReadyComplete bool
|
2015-10-25 03:21:50 -07:00
|
|
|
|
2017-02-02 23:20:10 -08:00
|
|
|
// Server-initiated messages should be sent via the Send() method.
|
2015-10-26 10:07:15 -07:00
|
|
|
MessageChannel chan<- ClientMessage
|
2015-10-28 22:59:27 -07:00
|
|
|
|
2017-02-02 22:59:17 -08:00
|
|
|
// Closed when the client is shutting down.
|
2015-11-03 16:44:42 -08:00
|
|
|
MsgChannelIsDone <-chan struct{}
|
|
|
|
|
2015-11-02 22:54:53 -08:00
|
|
|
// Take out an Add() on this during a command if you need to use the MessageChannel later.
|
|
|
|
MsgChannelKeepalive sync.WaitGroup
|
2015-10-29 01:23:58 -07:00
|
|
|
|
2015-11-16 12:50:00 -08:00
|
|
|
// The number of pings sent without a response.
|
|
|
|
// Protected by Mutex
|
2015-10-28 22:59:27 -07:00
|
|
|
pingCount int
|
2015-10-26 10:07:15 -07:00
|
|
|
}
|
|
|
|
|
2015-11-16 14:30:09 -08:00
|
|
|
func VersionFromString(v string) ClientVersion {
|
|
|
|
var cv ClientVersion
|
|
|
|
fmt.Sscanf(v, "ffz_%d.%d.%d", &cv.Major, &cv.Minor, &cv.Revision)
|
|
|
|
return cv
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cv *ClientVersion) After(cv2 *ClientVersion) bool {
|
|
|
|
if cv.Major > cv2.Major {
|
|
|
|
return true
|
|
|
|
} else if cv.Major < cv2.Major {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if cv.Minor > cv2.Minor {
|
|
|
|
return true
|
|
|
|
} else if cv.Minor < cv2.Minor {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if cv.Revision > cv2.Revision {
|
|
|
|
return true
|
|
|
|
} else if cv.Revision < cv2.Revision {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return false // equal
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cv *ClientVersion) Equal(cv2 *ClientVersion) bool {
|
|
|
|
return cv.Major == cv2.Major && cv.Minor == cv2.Minor && cv.Revision == cv2.Revision
|
|
|
|
}
|