func main() { http.HandleFunc("/", http.NotFound) http.HandleFunc("/ws", newConnection) logger.Info("Starting Tiberious on", config.Port) if err := http.ListenAndServe(config.Port, nil); err != nil { logger.Error(err) } }
// TODO move this into a separate handler of some form. func newConnection(w http.ResponseWriter, r *http.Request) { var upgrader = websocket.Upgrader{ ReadBufferSize: config.ReadBufferSize, WriteBufferSize: config.WriteBufferSize, } conn, err := upgrader.Upgrade(w, r, nil) if err != nil { logger.Error(err) return } go handlers.ClientHandler(conn) }
/* This seems extremely cumbersome but it's the best way I can think to handle * this without deleting the entire set and recreating it. */ func (r *rClient) updateSet(key string, new []string) { old, err := r.Client.SMembers(key).Result() if err != nil { logger.Error(err) } for _, o := range old { var rem = true for _, n := range new { if o == n { rem = false } } if rem { if err := r.Client.SRem(key, o).Err(); err != nil { logger.Error(err) } } } for _, n := range new { var add = true for _, o := range old { if n == o { add = false } } if add { if err := r.Client.SAdd(key, n).Err(); err != nil { logger.Error(err) } } } }
// ClientHandler handles all client interactions func ClientHandler(conn *websocket.Conn) { var err error client := types.NewClient() client.Conn = conn client.User = new(types.User) // Set the UUID and initialize a username of "guest" client.User.ID, err = getUniqueID() if err != nil { logger.Error(err) } guests, err := dbClient.GetKeySet("user-guest-*-*") if err != nil { logger.Error(err) } // TODO give guests a numeric suffix, allow disabling guest connections. client.User.Username = "******" + strconv.Itoa(len(guests)+1) client.User.LoginName = client.User.Username client.User.Type = "guest" client.User.Connected = true clients[client.User.ID.String()] = client if config.AllowGuests { defgroup, err := GetGroup("#default") if err != nil { logger.Error(err) } defgroup.Users[client.User.ID.String()] = client.User client.User.Groups = append(client.User.Groups, "#default") room, err := GetRoom("#default", "#general") if err != nil { logger.Error(err) } client.User.Rooms = append(client.User.Rooms, "#default/#general") room.Users[client.User.ID.String()] = client.User dbClient.WriteUserData(client.User) dbClient.WriteGroupData(defgroup) dbClient.WriteRoomData(room) logger.Info("guest", client.User.ID.String(), "connected") } else { logger.Info("new client connected") } if err := client.Alert(types.OK, ""); err != nil { logger.Error(err) } /* TODO we may want to remove this later it's just for easy testing. * to allow a client to get their UUID back from the server after * connecting. */ if config.AllowGuests { if err := client.Alert(types.GeneralNotice, string("Connected as guest with ID "+client.User.ID.String())); err != nil { logger.Error(err) } } else { if err := client.Alert(types.ImportantNotice, "No Guests Allowed : send authentication token to continue"); err != nil { logger.Error(err) } } /* Never return from this loop! * Never break from this loop unless intending to disconnect the client. */ for { _, rawmsg, err := client.Conn.ReadMessage() if err != nil { switch { case websocket.IsCloseError(err, websocket.CloseNormalClosure): if client.User != nil { logger.Info(client.User.Type, client.User.ID.String(), "disconnected") } else { logger.Info("client disconnected") } break // TODO handle these different cases appropriately. case websocket.IsCloseError(err, websocket.CloseGoingAway): case websocket.IsCloseError(err, websocket.CloseProtocolError, websocket.CloseUnsupportedData): // This should utilize the ban-score to combat possible spammers case websocket.IsCloseError(err, websocket.ClosePolicyViolation, websocket.CloseMessageTooBig): // These should also utilize the ban-score but with a higher ban default: logger.Info(err) } break } ban, err := ParseMessage(client, rawmsg) if err != nil { logger.Info(err) } if ban > 0 { // TODO handle ban-score break } } // We broke out of the loop so disconnect the client. client.Conn.Close() if client.User != nil { if client.User.Type == "guest" { if err := dbClient.DeleteUser(client.User); err != nil { logger.Error(err) } } else { client.User.Connected = false dbClient.WriteUserData(client.User) } } delete(clients, client.User.ID.String()) }