Return errors from commands

Change the function signature for commands to return a string as well as
an error.  Currently, errors are handled no differently than normal
response messages.

Also removed the redundant `/setpin` command.
This commit is contained in:
Zorchenhimer 2019-04-11 21:06:55 -04:00
parent 293c818eb2
commit 5508dc3f1c
4 changed files with 114 additions and 127 deletions

View File

@ -103,10 +103,15 @@ func (cl *Client) NewMsg(data common.ClientData) {
cmd := strings.ToLower(fullcmd[0]) cmd := strings.ToLower(fullcmd[0])
args := fullcmd[1:len(fullcmd)] args := fullcmd[1:len(fullcmd)]
response := commands.RunCommand(cmd, args, cl) response, err := commands.RunCommand(cmd, args, cl)
if response != "" { if response != "" || err != nil {
respText := response
if err != nil {
respText = err.Error()
}
err := cl.SendChatData(common.NewChatMessage("", "", err := cl.SendChatData(common.NewChatMessage("", "",
common.ParseEmotes(response), common.ParseEmotes(respText),
common.CmdlUser, common.CmdlUser,
common.MsgCommandResponse)) common.MsgCommandResponse))
if err != nil { if err != nil {

View File

@ -20,17 +20,17 @@ type Command struct {
Function CommandFunction Function CommandFunction
} }
type CommandFunction func(client *Client, args []string) string type CommandFunction func(client *Client, args []string) (string, error)
var commands = &CommandControl{ var commands = &CommandControl{
user: map[string]Command{ user: map[string]Command{
common.CNMe.String(): Command{ common.CNMe.String(): Command{
HelpText: "Display an action message.", HelpText: "Display an action message.",
Function: func(client *Client, args []string) string { Function: func(client *Client, args []string) (string, error) {
if len(args) != 0 { if len(args) != 0 {
client.Me(strings.Join(args, " ")) client.Me(strings.Join(args, " "))
} }
return "" return "", fmt.Errorf("Missing a message")
}, },
}, },
@ -41,29 +41,29 @@ var commands = &CommandControl{
common.CNCount.String(): Command{ common.CNCount.String(): Command{
HelpText: "Display number of users in chat.", HelpText: "Display number of users in chat.",
Function: func(client *Client, args []string) string { Function: func(client *Client, args []string) (string, error) {
return fmt.Sprintf("Users in chat: %d", client.belongsTo.UserCount()) return fmt.Sprintf("Users in chat: %d", client.belongsTo.UserCount()), nil
}, },
}, },
common.CNColor.String(): Command{ common.CNColor.String(): Command{
HelpText: "Change user color.", HelpText: "Change user color.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) > 2 { if len(args) > 2 {
return "Too many arguments!" return "", fmt.Errorf("Too many arguments!")
} }
// If the caller is priviledged enough, they can change the color of another user // If the caller is priviledged enough, they can change the color of another user
if len(args) == 2 { if len(args) == 2 {
if cl.CmdLevel == common.CmdlUser { if cl.CmdLevel == common.CmdlUser {
return "You cannot change someone else's color. PeepoSus" return "", fmt.Errorf("You cannot change someone else's color. PeepoSus")
} }
name, color := "", "" name, color := "", ""
if strings.ToLower(args[0]) == strings.ToLower(args[1]) || if strings.ToLower(args[0]) == strings.ToLower(args[1]) ||
(common.IsValidColor(args[0]) && common.IsValidColor(args[1])) { (common.IsValidColor(args[0]) && common.IsValidColor(args[1])) {
return "Name and color are ambiguous. Prefix the name with '@' or color with '#'" return "", fmt.Errorf("Name and color are ambiguous. Prefix the name with '@' or color with '#'")
} }
// Check for explicit name // Check for explicit name
@ -98,47 +98,47 @@ var commands = &CommandControl{
} }
if name == "" { if name == "" {
return "Cannot determine name. Prefix name with @." return "", fmt.Errorf("Cannot determine name. Prefix name with @.")
} }
if color == "" { if color == "" {
return "Cannot determine color. Prefix name with @." return "", fmt.Errorf("Cannot determine color. Prefix name with @.")
} }
if color == "" { if color == "" {
common.LogInfof("[color:mod] %s missing color\n", cl.name) common.LogInfof("[color:mod] %s missing color\n", cl.name)
return "Missing color" return "", fmt.Errorf("Missing color")
} }
if name == "" { if name == "" {
common.LogInfof("[color:mod] %s missing name\n", cl.name) common.LogInfof("[color:mod] %s missing name\n", cl.name)
return "Missing name" return "", fmt.Errorf("Missing name")
} }
if err := cl.belongsTo.ForceColorChange(name, color); err != nil { if err := cl.belongsTo.ForceColorChange(name, color); err != nil {
return err.Error() return "", err
} }
return fmt.Sprintf("Color changed for user %s to %s\n", name, color) return fmt.Sprintf("Color changed for user %s to %s\n", name, color), nil
} }
// Don't allow an unprivilaged user to change their color if // Don't allow an unprivileged user to change their color if
// it was changed by a mod // it was changed by a mod
if cl.IsColorForced { if cl.IsColorForced {
common.LogInfof("[color] %s tried to change a forced color\n", cl.name) common.LogInfof("[color] %s tried to change a forced color\n", cl.name)
return "You are not allowed to change your color." return "", fmt.Errorf("You are not allowed to change your color.")
} }
if time.Now().Before(cl.nextColor) && cl.CmdLevel == common.CmdlUser { if time.Now().Before(cl.nextColor) && cl.CmdLevel == common.CmdlUser {
return fmt.Sprintf("Slow down. You can change your color in %0.0f seconds.", time.Until(cl.nextColor).Seconds()) return "", fmt.Errorf("Slow down. You can change your color in %0.0f seconds.", time.Until(cl.nextColor).Seconds())
} }
if len(args) == 0 { if len(args) == 0 {
cl.setColor(common.RandomColor()) cl.setColor(common.RandomColor())
return "Random color chosen: " + cl.color return "Random color chosen: " + cl.color, nil
} }
// Change the color of the user // Change the color of the user
if !common.IsValidColor(args[0]) { if !common.IsValidColor(args[0]) {
return "To choose a specific color use the format <i>/color #c029ce</i>. Hex values expected." return "", fmt.Errorf("To choose a specific color use the format <i>/color #c029ce</i>. Hex values expected.")
} }
cl.nextColor = time.Now().Add(time.Second * settings.RateLimitColor) cl.nextColor = time.Now().Add(time.Second * settings.RateLimitColor)
@ -149,31 +149,31 @@ var commands = &CommandControl{
} }
common.LogInfof("[color] %s new color: %s\n", cl.name, cl.color) common.LogInfof("[color] %s new color: %s\n", cl.name, cl.color)
return "Color changed successfully." return "Color changed successfully.", nil
}, },
}, },
common.CNWhoAmI.String(): Command{ common.CNWhoAmI.String(): Command{
HelpText: "Shows debug user info", HelpText: "Shows debug user info",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t", return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t",
cl.name, cl.name,
cl.CmdLevel >= common.CmdlMod, cl.CmdLevel >= common.CmdlMod,
cl.CmdLevel == common.CmdlAdmin) cl.CmdLevel == common.CmdlAdmin), nil
}, },
}, },
common.CNAuth.String(): Command{ common.CNAuth.String(): Command{
HelpText: "Authenticate to admin", HelpText: "Authenticate to admin",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if cl.CmdLevel == common.CmdlAdmin { if cl.CmdLevel == common.CmdlAdmin {
return "You are already authenticated." return "", fmt.Errorf("You are already authenticated.")
} }
// TODO: handle backoff policy // TODO: handle back off policy
if time.Now().Before(cl.nextAuth) { if time.Now().Before(cl.nextAuth) {
cl.nextAuth = time.Now().Add(time.Second * settings.RateLimitAuth) cl.nextAuth = time.Now().Add(time.Second * settings.RateLimitAuth)
return "Slow down." return "", fmt.Errorf("Slow down.")
} }
cl.authTries += 1 // this isn't used yet cl.authTries += 1 // this isn't used yet
cl.nextAuth = time.Now().Add(time.Second * settings.RateLimitAuth) cl.nextAuth = time.Now().Add(time.Second * settings.RateLimitAuth)
@ -184,41 +184,41 @@ var commands = &CommandControl{
cl.CmdLevel = common.CmdlAdmin cl.CmdLevel = common.CmdlAdmin
cl.belongsTo.AddModNotice(cl.name + " used the admin password") cl.belongsTo.AddModNotice(cl.name + " used the admin password")
common.LogInfof("[auth] %s used the admin password\n", cl.name) common.LogInfof("[auth] %s used the admin password\n", cl.name)
return "Admin rights granted." return "Admin rights granted.", nil
} }
if cl.belongsTo.redeemModPass(pw) { if cl.belongsTo.redeemModPass(pw) {
cl.CmdLevel = common.CmdlMod cl.CmdLevel = common.CmdlMod
cl.belongsTo.AddModNotice(cl.name + " used a mod password") cl.belongsTo.AddModNotice(cl.name + " used a mod password")
common.LogInfof("[auth] %s used a mod password\n", cl.name) common.LogInfof("[auth] %s used a mod password\n", cl.name)
return "Moderator privileges granted." return "Moderator privileges granted.", nil
} }
cl.belongsTo.AddModNotice(cl.name + " attempted to auth without success") cl.belongsTo.AddModNotice(cl.name + " attempted to auth without success")
common.LogInfof("[auth] %s gave an invalid password\n", cl.name) common.LogInfof("[auth] %s gave an invalid password\n", cl.name)
return "Invalid password." return "", fmt.Errorf("Invalid password.")
}, },
}, },
common.CNUsers.String(): Command{ common.CNUsers.String(): Command{
HelpText: "Show a list of users in chat", HelpText: "Show a list of users in chat",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
names := cl.belongsTo.GetNames() names := cl.belongsTo.GetNames()
return strings.Join(names, " ") return strings.Join(names, " "), nil
}, },
}, },
common.CNNick.String(): Command{ common.CNNick.String(): Command{
HelpText: "Change display name", HelpText: "Change display name",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if time.Now().Before(cl.nextNick) { if time.Now().Before(cl.nextNick) {
//cl.nextNick = time.Now().Add(time.Second * settings.RateLimitNick) //cl.nextNick = time.Now().Add(time.Second * settings.RateLimitNick)
return fmt.Sprintf("Slow down. You can change your nick in %0.0f seconds.", time.Until(cl.nextNick).Seconds()) return "", fmt.Errorf("Slow down. You can change your nick in %0.0f seconds.", time.Until(cl.nextNick).Seconds())
} }
cl.nextNick = time.Now().Add(time.Second * settings.RateLimitNick) cl.nextNick = time.Now().Add(time.Second * settings.RateLimitNick)
if len(args) == 0 { if len(args) == 0 {
return "Missing name to change to." return "", fmt.Errorf("Missing name to change to.")
} }
newName := strings.TrimLeft(args[0], "@") newName := strings.TrimLeft(args[0], "@")
@ -228,7 +228,7 @@ var commands = &CommandControl{
// Two arguments to force a name change on another user: `/nick OldName NewName` // Two arguments to force a name change on another user: `/nick OldName NewName`
if len(args) == 2 { if len(args) == 2 {
if cl.CmdLevel != common.CmdlAdmin { if cl.CmdLevel != common.CmdlAdmin {
return "Only admins can do that PeepoSus" return "", fmt.Errorf("Only admins can do that PeepoSus")
} }
oldName = strings.TrimLeft(args[0], "@") oldName = strings.TrimLeft(args[0], "@")
@ -237,15 +237,15 @@ var commands = &CommandControl{
} }
if len(args) == 1 && cl.IsNameForced && cl.CmdLevel != common.CmdlAdmin { if len(args) == 1 && cl.IsNameForced && cl.CmdLevel != common.CmdlAdmin {
return "You cannot change your name once it has been changed by an admin." return "", fmt.Errorf("You cannot change your name once it has been changed by an admin.")
} }
err := cl.belongsTo.changeName(oldName, newName, forced) err := cl.belongsTo.changeName(oldName, newName, forced)
if err != nil { if err != nil {
return "Unable to change name: " + err.Error() return "", fmt.Errorf("Unable to change name: " + err.Error())
} }
return "" return "", nil
}, },
}, },
}, },
@ -253,29 +253,29 @@ var commands = &CommandControl{
mod: map[string]Command{ mod: map[string]Command{
common.CNSv.String(): Command{ common.CNSv.String(): Command{
HelpText: "Send a server announcement message. It will show up red with a border in chat.", HelpText: "Send a server announcement message. It will show up red with a border in chat.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) == 0 { if len(args) == 0 {
return "Missing message" return "", fmt.Errorf("Missing message")
} }
svmsg := formatLinks(strings.Join(common.ParseEmotesArray(args), " ")) svmsg := formatLinks(strings.Join(common.ParseEmotesArray(args), " "))
cl.belongsTo.AddModNotice("Server message from " + cl.name) cl.belongsTo.AddModNotice("Server message from " + cl.name)
cl.belongsTo.AddMsg(cl, false, true, svmsg) cl.belongsTo.AddMsg(cl, false, true, svmsg)
return "" return "", nil
}, },
}, },
common.CNPlaying.String(): Command{ common.CNPlaying.String(): Command{
HelpText: "Set the title text and info link.", HelpText: "Set the title text and info link.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
// Clear/hide title if sent with no arguments. // Clear/hide title if sent with no arguments.
if len(args) == 0 { if len(args) == 0 {
cl.belongsTo.ClearPlaying() cl.belongsTo.ClearPlaying()
return "Title cleared" return "Title cleared", nil
} }
link := "" link := ""
title := "" title := ""
// pickout the link (can be anywhere, as long as there are no spaces). // pick out the link (can be anywhere, as long as there are no spaces).
for _, word := range args { for _, word := range args {
word = html.UnescapeString(word) word = html.UnescapeString(word)
if strings.HasPrefix(word, "http://") || strings.HasPrefix(word, "https://") { if strings.HasPrefix(word, "http://") || strings.HasPrefix(word, "https://") {
@ -289,7 +289,7 @@ var commands = &CommandControl{
link = strings.TrimSpace(link) link = strings.TrimSpace(link)
if len(title) > settings.TitleLength { if len(title) > settings.TitleLength {
return fmt.Sprintf("Title too long (%d/%d)", len(title), settings.TitleLength) return "", fmt.Errorf("Title too long (%d/%d)", len(title), settings.TitleLength)
} }
// Send a notice to the mods and admins // Send a notice to the mods and admins
@ -300,93 +300,93 @@ var commands = &CommandControl{
} }
cl.belongsTo.SetPlaying(title, link) cl.belongsTo.SetPlaying(title, link)
return "" return "", nil
}, },
}, },
common.CNUnmod.String(): Command{ common.CNUnmod.String(): Command{
HelpText: "Revoke a user's moderator privilages. Moderators can only unmod themselves.", HelpText: "Revoke a user's moderator privilages. Moderators can only unmod themselves.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) > 0 && cl.CmdLevel != common.CmdlAdmin && cl.name != args[0] { if len(args) > 0 && cl.CmdLevel != common.CmdlAdmin && cl.name != args[0] {
return "You can only unmod yourself, not others." return "", fmt.Errorf("You can only unmod yourself, not others.")
} }
if len(args) == 0 || (len(args) == 1 && strings.TrimLeft(args[0], "@") == cl.name) { if len(args) == 0 || (len(args) == 1 && strings.TrimLeft(args[0], "@") == cl.name) {
cl.Unmod() cl.Unmod()
cl.belongsTo.AddModNotice(cl.name + " has unmodded themselves") cl.belongsTo.AddModNotice(cl.name + " has unmodded themselves")
return "You have unmodded yourself." return "You have unmodded yourself.", nil
} }
name := strings.TrimLeft(args[0], "@") name := strings.TrimLeft(args[0], "@")
if err := cl.belongsTo.Unmod(name); err != nil { if err := cl.belongsTo.Unmod(name); err != nil {
return err.Error() return "", err
} }
cl.belongsTo.AddModNotice(cl.name + " has unmodded " + name) cl.belongsTo.AddModNotice(cl.name + " has unmodded " + name)
return "" return "", nil
}, },
}, },
common.CNKick.String(): Command{ common.CNKick.String(): Command{
HelpText: "Kick a user from chat.", HelpText: "Kick a user from chat.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) == 0 { if len(args) == 0 {
return "Missing name to kick." return "", fmt.Errorf("Missing name to kick.")
} }
return cl.belongsTo.Kick(strings.TrimLeft(args[0], "@")) return "", cl.belongsTo.Kick(strings.TrimLeft(args[0], "@"))
}, },
}, },
common.CNBan.String(): Command{ common.CNBan.String(): Command{
HelpText: "Ban a user from chat. They will not be able to re-join chat, but will still be able to view the stream.", HelpText: "Ban a user from chat. They will not be able to re-join chat, but will still be able to view the stream.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) == 0 { if len(args) == 0 {
return "missing name to ban." return "", fmt.Errorf("missing name to ban.")
} }
name := strings.TrimLeft(args[0], "@") name := strings.TrimLeft(args[0], "@")
common.LogInfof("[ban] Attempting to ban %s\n", name) common.LogInfof("[ban] Attempting to ban %s\n", name)
return cl.belongsTo.Ban(name) return "", cl.belongsTo.Ban(name)
}, },
}, },
common.CNUnban.String(): Command{ common.CNUnban.String(): Command{
HelpText: "Remove a ban on a user.", HelpText: "Remove a ban on a user.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) == 0 { if len(args) == 0 {
return "missing name to unban." return "", fmt.Errorf("missing name to unban.")
} }
name := strings.TrimLeft(args[0], "@") name := strings.TrimLeft(args[0], "@")
common.LogInfof("[ban] Attempting to unban %s\n", name) common.LogInfof("[ban] Attempting to unban %s\n", name)
err := settings.RemoveBan(name) err := settings.RemoveBan(name)
if err != nil { if err != nil {
return err.Error() return "", err
} }
cl.belongsTo.AddModNotice(cl.name + " has unbanned " + name) cl.belongsTo.AddModNotice(cl.name + " has unbanned " + name)
return "" return "", nil
}, },
}, },
common.CNPurge.String(): Command{ common.CNPurge.String(): Command{
HelpText: "Purge the chat.", HelpText: "Purge the chat.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
common.LogInfoln("[purge] clearing chat") common.LogInfoln("[purge] clearing chat")
cl.belongsTo.AddCmdMsg(common.CmdPurgeChat, nil) cl.belongsTo.AddCmdMsg(common.CmdPurgeChat, nil)
return "" return "", nil
}, },
}, },
common.CNPin.String(): Command{ common.CNPin.String(): Command{
HelpText: "Display the current room access type and pin/password (if applicable).", HelpText: "Display the current room access type and pin/password (if applicable).",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
switch settings.RoomAccess { switch settings.RoomAccess {
case AccessPin: case AccessPin:
return "Room is secured via PIN. Current PIN: " + settings.RoomAccessPin return "Room is secured via PIN. Current PIN: " + settings.RoomAccessPin, nil
case AccessRequest: case AccessRequest:
return "Room is secured via access requests. Users must request to be granted access." return "Room is secured via access requests. Users must request to be granted access.", nil
} }
return "Room is open access. Anybody can join." return "Room is open access. Anybody can join.", nil
}, },
}, },
}, },
@ -394,85 +394,68 @@ var commands = &CommandControl{
admin: map[string]Command{ admin: map[string]Command{
common.CNMod.String(): Command{ common.CNMod.String(): Command{
HelpText: "Grant moderator privilages to a user.", HelpText: "Grant moderator privilages to a user.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
if len(args) == 0 { if len(args) == 0 {
return "Missing user to mod." return "", fmt.Errorf("Missing user to mod.")
} }
name := strings.TrimLeft(args[0], "@") name := strings.TrimLeft(args[0], "@")
if err := cl.belongsTo.Mod(name); err != nil { if err := cl.belongsTo.Mod(name); err != nil {
return err.Error() return "", err
} }
cl.belongsTo.AddModNotice(cl.name + " has modded " + name) cl.belongsTo.AddModNotice(cl.name + " has modded " + name)
return "" return "", nil
}, },
}, },
common.CNReloadPlayer.String(): Command{ common.CNReloadPlayer.String(): Command{
HelpText: "Reload the stream player for everybody in chat.", HelpText: "Reload the stream player for everybody in chat.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
cl.belongsTo.AddModNotice(cl.name + " has modded forced a player reload") cl.belongsTo.AddModNotice(cl.name + " has modded forced a player reload")
cl.belongsTo.AddCmdMsg(common.CmdRefreshPlayer, nil) cl.belongsTo.AddCmdMsg(common.CmdRefreshPlayer, nil)
return "Reloading player for all chatters." return "Reloading player for all chatters.", nil
}, },
}, },
common.CNReloadEmotes.String(): Command{ common.CNReloadEmotes.String(): Command{
HelpText: "Reload the emotes on the server.", HelpText: "Reload the emotes on the server.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
cl.SendServerMessage("Reloading emotes") cl.SendServerMessage("Reloading emotes")
num, err := common.LoadEmotes() num, err := common.LoadEmotes()
if err != nil { if err != nil {
common.LogErrorf("Unbale to reload emotes: %s\n", err) common.LogErrorf("Unbale to reload emotes: %s\n", err)
return fmt.Sprintf("ERROR: %s", err) return "", err
} }
cl.belongsTo.AddChatMsg(common.NewChatHiddenMessage(common.CdEmote, common.Emotes)) cl.belongsTo.AddChatMsg(common.NewChatHiddenMessage(common.CdEmote, common.Emotes))
cl.belongsTo.AddModNotice(cl.name + " has reloaded emotes") cl.belongsTo.AddModNotice(cl.name + " has reloaded emotes")
common.LogInfof("Loaded %d emotes\n", num) common.LogInfof("Loaded %d emotes\n", num)
return fmt.Sprintf("Emotes loaded: %d", num) return fmt.Sprintf("Emotes loaded: %d", num), nil
}, },
}, },
common.CNModpass.String(): Command{ common.CNModpass.String(): Command{
HelpText: "Generate a single-use mod password.", HelpText: "Generate a single-use mod password.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
cl.belongsTo.AddModNotice(cl.name + " generated a mod password") cl.belongsTo.AddModNotice(cl.name + " generated a mod password")
password := cl.belongsTo.generateModPass() password := cl.belongsTo.generateModPass()
return "Single use password: " + password return "Single use password: " + password, nil
},
},
common.CNNewPin.String(): Command{
HelpText: "Generate a room acces new pin",
Function: func(cl *Client, args []string) string {
if settings.RoomAccess != AccessPin {
return "Room is not restricted by Pin. (" + string(settings.RoomAccess) + ")"
}
pin, err := settings.generateNewPin()
if err != nil {
return "Unable to generate new pin: " + err.Error()
}
common.LogInfoln("New room access pin: ", pin)
return "New access pin: " + pin
}, },
}, },
common.CNRoomAccess.String(): Command{ common.CNRoomAccess.String(): Command{
HelpText: "Change the room access type.", HelpText: "Change the room access type.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
// Print current access type if no arguments given // Print current access type if no arguments given
if len(args) == 0 { if len(args) == 0 {
return "Current room access type: " + string(settings.RoomAccess) return "Current room access type: " + string(settings.RoomAccess), nil
} }
switch AccessMode(strings.ToLower(args[0])) { switch AccessMode(strings.ToLower(args[0])) {
case AccessOpen: case AccessOpen:
settings.RoomAccess = AccessOpen settings.RoomAccess = AccessOpen
common.LogInfoln("[access] Room set to open") common.LogInfoln("[access] Room set to open")
return "Room access set to open" return "Room access set to open", nil
case AccessPin: case AccessPin:
// A pin/password was provided, use it. // A pin/password was provided, use it.
@ -484,27 +467,27 @@ var commands = &CommandControl{
_, err := settings.generateNewPin() _, err := settings.generateNewPin()
if err != nil { if err != nil {
common.LogErrorln("Error generating new access pin: ", err.Error()) common.LogErrorln("Error generating new access pin: ", err.Error())
return "Unable to generate a new pin, access unchanged: " + err.Error() return "", fmt.Errorf("Unable to generate a new pin, access unchanged: " + err.Error())
} }
} }
settings.RoomAccess = AccessPin settings.RoomAccess = AccessPin
common.LogInfoln("[access] Room set to pin: " + settings.RoomAccessPin) common.LogInfoln("[access] Room set to pin: " + settings.RoomAccessPin)
return "Room access set to Pin: " + settings.RoomAccessPin return "Room access set to Pin: " + settings.RoomAccessPin, nil
case AccessRequest: case AccessRequest:
settings.RoomAccess = AccessRequest settings.RoomAccess = AccessRequest
common.LogInfoln("[access] Room set to request") common.LogInfoln("[access] Room set to request")
return "Room access set to request. WARNING: this isn't implemented yet." return "Room access set to request. WARNING: this isn't implemented yet.", nil
default: default:
return "Invalid access mode" return "", fmt.Errorf("Invalid access mode")
} }
}, },
}, },
common.CNIP.String(): Command{ common.CNIP.String(): Command{
HelpText: "List users and IP in the server console. Requires logging level to be set to info or above.", HelpText: "List users and IP in the server console. Requires logging level to be set to info or above.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
cl.belongsTo.clientsMtx.Lock() cl.belongsTo.clientsMtx.Lock()
common.LogInfoln("Clients:") common.LogInfoln("Clients:")
for uuid, client := range cl.belongsTo.clients { for uuid, client := range cl.belongsTo.clients {
@ -516,18 +499,18 @@ var commands = &CommandControl{
common.LogInfof(" [%s] %s\n", uuid, conn.Host()) common.LogInfof(" [%s] %s\n", uuid, conn.Host())
} }
cl.belongsTo.clientsMtx.Unlock() cl.belongsTo.clientsMtx.Unlock()
return "see console for output" return "see console for output", nil
}, },
}, },
common.CNAddEmotes.String(): Command{ common.CNAddEmotes.String(): Command{
HelpText: "Add emotes from a given twitch channel.", HelpText: "Add emotes from a given twitch channel.",
Function: func(cl *Client, args []string) string { Function: func(cl *Client, args []string) (string, error) {
// Fire this off in it's own goroutine so the client doesn't // Fire this off in it's own goroutine so the client doesn't
// block waiting for the emote download to finish. // block waiting for the emote download to finish.
go func() { go func() {
// Pretty sure this breaks on partial downloads (eg, one good channel and one non-existant) // Pretty sure this breaks on partial downloads (eg, one good channel and one non-existent)
_, err := GetEmotes(args) _, err := GetEmotes(args)
if err != nil { if err != nil {
cl.SendChatData(common.NewChatMessage("", "", cl.SendChatData(common.NewChatMessage("", "",
@ -547,13 +530,13 @@ var commands = &CommandControl{
cl.belongsTo.AddModNotice(cl.name + " has added emotes from the following channels: " + strings.Join(args, ", ")) cl.belongsTo.AddModNotice(cl.name + " has added emotes from the following channels: " + strings.Join(args, ", "))
}() }()
return "Emote download initiated for the following channels: " + strings.Join(args, ", ") return "Emote download initiated for the following channels: " + strings.Join(args, ", "), nil
}, },
}, },
}, },
} }
func (cc *CommandControl) RunCommand(command string, args []string, sender *Client) string { func (cc *CommandControl) RunCommand(command string, args []string, sender *Client) (string, error) {
// get correct command from combined commands // get correct command from combined commands
cmd := common.GetFullChatCommand(command) cmd := common.GetFullChatCommand(command)
@ -571,7 +554,7 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
} }
common.LogInfof("[mod REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " ")) common.LogInfof("[mod REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
return "You are not a mod Jebaited" return "", fmt.Errorf("You are not a mod Jebaited")
} }
// Look for admin command // Look for admin command
@ -581,15 +564,15 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
return adminCmd.Function(sender, args) return adminCmd.Function(sender, args)
} }
common.LogInfof("[admin REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " ")) common.LogInfof("[admin REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
return "You are not the admin Jebaited" return "", fmt.Errorf("You are not the admin Jebaited")
} }
// Command not found // Command not found
common.LogInfof("[cmd] %s /%s %s\n", sender.name, command, strings.Join(args, " ")) common.LogInfof("[cmd] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
return "Invalid command." return "", fmt.Errorf("Invalid command.")
} }
func cmdHelp(cl *Client, args []string) string { func cmdHelp(cl *Client, args []string) (string, error) {
url := "/help" url := "/help"
if cl.CmdLevel >= common.CmdlMod { if cl.CmdLevel >= common.CmdlMod {
@ -601,7 +584,7 @@ func cmdHelp(cl *Client, args []string) string {
} }
cl.SendChatData(common.NewChatCommand(common.CmdHelp, []string{url})) cl.SendChatData(common.NewChatCommand(common.CmdHelp, []string{url}))
return `Opening help in new window.` return `Opening help in new window.`, nil
} }
func getHelp(lvl common.CommandLevel) map[string]string { func getHelp(lvl common.CommandLevel) map[string]string {

View File

@ -145,21 +145,21 @@ func (cr *ChatRoom) Leave(name, color string) {
} }
// kicked from the chatroom // kicked from the chatroom
func (cr *ChatRoom) Kick(name string) string { func (cr *ChatRoom) Kick(name string) error {
defer cr.clientsMtx.Unlock() defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock() //preventing simultaneous access to the `clients` map cr.clientsMtx.Lock() //preventing simultaneous access to the `clients` map
client, suid, err := cr.getClient(name) client, suid, err := cr.getClient(name)
if err != nil { if err != nil {
return "Unable to get client for name " + name return fmt.Errorf("Unable to get client for name " + name)
} }
if client.CmdLevel == common.CmdlMod { if client.CmdLevel == common.CmdlMod {
return "You cannot kick another mod." return fmt.Errorf("You cannot kick another mod.")
} }
if client.CmdLevel == common.CmdlAdmin { if client.CmdLevel == common.CmdlAdmin {
return "Jebaited No." return fmt.Errorf("Jebaited No.")
} }
color := client.color color := client.color
@ -169,21 +169,21 @@ func (cr *ChatRoom) Kick(name string) string {
cr.AddEventMsg(common.EvKick, name, color) cr.AddEventMsg(common.EvKick, name, color)
common.LogInfof("[kick] %s %s has been kicked\n", host, name) common.LogInfof("[kick] %s %s has been kicked\n", host, name)
return "" return nil
} }
func (cr *ChatRoom) Ban(name string) string { func (cr *ChatRoom) Ban(name string) error {
defer cr.clientsMtx.Unlock() defer cr.clientsMtx.Unlock()
cr.clientsMtx.Lock() cr.clientsMtx.Lock()
client, suid, err := cr.getClient(name) client, suid, err := cr.getClient(name)
if err != nil { if err != nil {
common.LogErrorf("[ban] Unable to get client for name %q\n", name) common.LogErrorf("[ban] Unable to get client for name %q\n", name)
return "Cannot find that name" return fmt.Errorf("Cannot find that name")
} }
if client.CmdLevel == common.CmdlAdmin { if client.CmdLevel == common.CmdlAdmin {
return "You cannot ban an admin Jebaited" return fmt.Errorf("You cannot ban an admin Jebaited")
} }
names := []string{} names := []string{}
@ -211,7 +211,7 @@ func (cr *ChatRoom) Ban(name string) string {
} else { } else {
cr.AddEventMsg(common.EvBan, name, color) cr.AddEventMsg(common.EvBan, name, color)
} }
return "" return nil
} }
// Add a chat message from a viewer // Add a chat message from a viewer

View File

@ -37,7 +37,6 @@ var (
CNModpass ChatCommandNames = []string{"modpass"} CNModpass ChatCommandNames = []string{"modpass"}
CNIP ChatCommandNames = []string{"iplist"} CNIP ChatCommandNames = []string{"iplist"}
CNAddEmotes ChatCommandNames = []string{"addemotes"} CNAddEmotes ChatCommandNames = []string{"addemotes"}
CNNewPin ChatCommandNames = []string{"newpin", "newpassword"}
CNRoomAccess ChatCommandNames = []string{"changeaccess", "hodor"} CNRoomAccess ChatCommandNames = []string{"changeaccess", "hodor"}
) )