Remove temp connections

Temp connections were removed to reduce some complexity.  Now a
connection is a full client, even before joining chat.  A name is
required to be set to join chat and receive messages.

This change also removes the need for UUIDs on connections and clients.
This commit is contained in:
Zorchenhimer 2019-04-13 15:56:49 -04:00
parent 0c3850d2f7
commit d513fe872d
6 changed files with 34 additions and 108 deletions

View File

@ -172,6 +172,12 @@ func (cl *Client) NewMsg(data common.ClientData) {
}
func (cl *Client) SendChatData(data common.ChatData) error {
// Don't send chat or event data to clients that have not fully joined the
// chatroom (ie, they have not set a name).
if cl.name == "" && (data.Type == common.DTChat || data.Type == common.DTEvent) {
return nil
}
// Colorize name on chat messages
if data.Type == common.DTChat {
var err error

View File

@ -491,13 +491,8 @@ var commands = &CommandControl{
Function: func(cl *Client, args []string) (string, error) {
cl.belongsTo.clientsMtx.Lock()
common.LogInfoln("Clients:")
for uuid, client := range cl.belongsTo.clients {
common.LogInfof(" [%s] %s %s\n", uuid, client.name, client.conn.Host())
}
common.LogInfoln("TmpConn:")
for uuid, conn := range cl.belongsTo.tempConn {
common.LogInfof(" [%s] %s\n", uuid, conn.Host())
for id, client := range cl.belongsTo.clients {
common.LogInfof(" [%d] %s %s\n", id, client.name, client.conn.Host())
}
cl.belongsTo.clientsMtx.Unlock()
return "see console for output", nil

View File

@ -1,11 +1,8 @@
package main
import (
"errors"
"fmt"
uuid "github.com/satori/go.uuid"
"strings"
"sync"
"time"
@ -18,9 +15,8 @@ const (
)
type ChatRoom struct {
clients map[string]*Client // this needs to be a pointer. key is suid.
clients []*Client // this needs to be a pointer. key is suid.
clientsMtx sync.Mutex
tempConn map[string]*chatConnection
queue chan common.ChatData
modqueue chan common.ChatData // mod and admin broadcast messages
@ -37,8 +33,7 @@ func newChatRoom() (*ChatRoom, error) {
cr := &ChatRoom{
queue: make(chan common.ChatData, 1000),
modqueue: make(chan common.ChatData, 1000),
clients: make(map[string]*Client),
tempConn: make(map[string]*chatConnection),
clients: []*Client{},
}
num, err := common.LoadEmotes()
@ -52,39 +47,11 @@ func newChatRoom() (*ChatRoom, error) {
return cr, nil
}
func (cr *ChatRoom) JoinTemp(conn *chatConnection) (string, error) {
// A new client joined
func (cr *ChatRoom) Join(conn *chatConnection, data common.JoinData) (*Client, error) {
defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock()
if conn == nil {
return "", errors.New("conn should not be nil")
}
uid, err := uuid.NewV4()
if err != nil {
return "", fmt.Errorf("could not create uuid: %v", err)
}
suid := uid.String()
if _, ok := cr.tempConn[suid]; ok {
return "", fmt.Errorf("%#v is already in the temp connections", suid)
}
cr.tempConn[suid] = conn
return suid, nil
}
//registering a new client
//returns pointer to a Client, or Nil, if the name is already taken
func (cr *ChatRoom) Join(uid string, data common.JoinData) (*Client, error) {
defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock()
conn, hasConn := cr.tempConn[uid]
if !hasConn {
return nil, errors.New("connection is missing from temp connections")
}
sendHiddenMessage := func(cd common.ClientDataType, i interface{}) {
// If the message cant be converted, then just don't send
if d, err := common.NewChatHiddenMessage(cd, i).ToJSON(); err == nil {
@ -128,8 +95,7 @@ func (cr *ChatRoom) Join(uid string, data common.JoinData) (*Client, error) {
return nil, newBannedUserError(host, data.Name, names)
}
cr.clients[uid] = client
delete(cr.tempConn, uid)
cr.clients = append(cr.clients, client)
common.LogChatf("[join] %s %s\n", host, data.Color)
playingCommand, err := common.NewChatCommand(common.CmdPlaying, []string{cr.playing, cr.playingLink}).ToJSON()
@ -152,7 +118,7 @@ func (cr *ChatRoom) Leave(name, color string) {
defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock() //preventing simultaneous access to the `clients` map
client, suid, err := cr.getClient(name)
client, id, err := cr.getClient(name)
if err != nil {
common.LogErrorf("[leave] Unable to get client suid %v\n", err)
return
@ -160,7 +126,7 @@ func (cr *ChatRoom) Leave(name, color string) {
host := client.Host()
name = client.name // grab the name from here for proper capitalization
client.conn.Close()
cr.delClient(suid)
cr.delClient(id)
cr.AddEventMsg(common.EvLeave, name, color)
common.LogChatf("[leave] %s %s\n", host, name)
@ -171,7 +137,7 @@ func (cr *ChatRoom) Kick(name string) error {
defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock() //preventing simultaneous access to the `clients` map
client, suid, err := cr.getClient(name)
client, id, err := cr.getClient(name)
if err != nil {
return fmt.Errorf("Unable to get client for name " + name)
}
@ -187,7 +153,7 @@ func (cr *ChatRoom) Kick(name string) error {
color := client.color
host := client.Host()
client.conn.Close()
cr.delClient(suid)
cr.delClient(id)
cr.AddEventMsg(common.EvKick, name, color)
common.LogInfof("[kick] %s %s has been kicked\n", host, name)
@ -198,7 +164,7 @@ func (cr *ChatRoom) Ban(name string) error {
defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock()
client, suid, err := cr.getClient(name)
client, id, err := cr.getClient(name)
if err != nil {
common.LogErrorf("[ban] Unable to get client for name %q\n", name)
return fmt.Errorf("Cannot find that name")
@ -212,14 +178,16 @@ func (cr *ChatRoom) Ban(name string) error {
host := client.Host()
color := client.color
// Remove the named client
client.conn.Close()
cr.delClient(suid)
cr.delClient(id)
for suid, c := range cr.clients {
// Remove additional clients on that IP address
for id, c := range cr.clients {
if c.Host() == host {
names = append(names, client.name)
client.conn.Close()
cr.delClient(suid)
cr.delClient(id)
}
}
@ -348,32 +316,6 @@ func (cr *ChatRoom) Broadcast() {
for _, client := range cr.clients {
go send(msg, client)
}
// Only send Chat and Event stuff to temp clients
if msg.Type != common.DTChat && msg.Type != common.DTEvent {
// Put this here instead of having two lock/unlock blocks. We want
// to avoid a case where a client is removed from the temp users
// and added to the clients between the two blocks.
cr.clientsMtx.Unlock()
break
}
data, err := msg.ToJSON()
if err != nil {
common.LogErrorf("Error converting ChatData to ChatDataJSON: %v\n", err)
cr.clientsMtx.Unlock()
break
}
for uuid, conn := range cr.tempConn {
go func(c *chatConnection, suid string) {
err = c.WriteData(data)
if err != nil {
common.LogErrorf("Error writing data to connection: %v\n", err)
delete(cr.tempConn, suid)
}
}(conn, uuid)
}
cr.clientsMtx.Unlock()
case msg := <-cr.modqueue:
cr.clientsMtx.Lock()
@ -416,18 +358,18 @@ func (cr *ChatRoom) GetNames() []string {
return names
}
func (cr *ChatRoom) delClient(suid string) {
delete(cr.clients, strings.ToLower(suid))
func (cr *ChatRoom) delClient(sliceId int) {
cr.clients = append(cr.clients[:sliceId], cr.clients[sliceId+1:]...)
}
func (cr *ChatRoom) getClient(name string) (*Client, string, error) {
for suid, client := range cr.clients {
func (cr *ChatRoom) getClient(name string) (*Client, int, error) {
for id, client := range cr.clients {
if client.name == name {
return client, suid, nil
return client, id, nil
}
}
return nil, "", fmt.Errorf("client with that name not found")
return nil, -1, fmt.Errorf("client with that name not found")
}
func (cr *ChatRoom) generateModPass() string {

3
go.mod
View File

@ -7,9 +7,6 @@ require (
github.com/dennwc/dom v0.3.0
github.com/gorilla/sessions v1.1.3
github.com/gorilla/websocket v1.4.0
github.com/kr/pretty v0.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.0.1
github.com/nareix/joy4 v0.0.0-20181022032202-3ddbc8f9d431
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)

9
go.sum
View File

@ -42,11 +42,6 @@ github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307 h1:vl4eIlySbjertFaNwiM
github.com/knq/sysutil v0.0.0-20181215143952-f05b59f0f307/go.mod h1:BjPj+aVjl9FW/cCGiF3nGh5v+9Gd3VCgBQbod/GlMaQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lucasb-eyer/go-colorful v1.0.1 h1:nKJRBvZWPzvkwB4sY8A3U4zgqLf2Y9c02yzPsbXu/5c=
@ -68,8 +63,6 @@ github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -88,7 +81,5 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

View File

@ -99,6 +99,8 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
return
}
common.LogDebugln("Connection has been upgraded to websocket")
chatConn := &chatConnection{
Conn: conn,
// If the server is behind a reverse proxy (eg, Nginx), look
@ -109,14 +111,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
go func() {
var client *Client
uid, err := chat.JoinTemp(chatConn)
if err != nil {
common.LogErrorf("[handler] could not do a temp join, %v\n", err)
conn.Close()
}
//first message has to be the name
// loop through name since websocket is opened once
// Get the client object
for client == nil {
var data common.ClientData
err := chatConn.ReadData(&data)
@ -134,7 +129,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
continue
}
client, err = chat.Join(uid, joinData)
client, err = chat.Join(chatConn, joinData)
if err != nil {
switch err.(type) {
case UserFormatError, UserTakenError:
@ -151,7 +146,7 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
}
}
//then watch for incoming messages
// Handle incomming messages
for {
var data common.ClientData
err := conn.ReadJSON(&data)