Write the /help command
This still needs a bunch of work, but this should be OK until the UI is rewritten. The command injects a <script> tag to open up a new window. Mod and admin commands are only shown to mods and admins (no authentication happens for this). Resolves #8 for now.
This commit is contained in:
parent
02400b667c
commit
86ba07b4f7
453
chatcommands.go
453
chatcommands.go
|
@ -11,158 +11,213 @@ var commands *CommandControl
|
|||
var colorRegex *regexp.Regexp = regexp.MustCompile(`^#[0-9A-Fa-f]{6}$`)
|
||||
|
||||
type CommandControl struct {
|
||||
user map[string]CommandFunction
|
||||
mod map[string]CommandFunction
|
||||
admin map[string]CommandFunction
|
||||
user map[string]Command
|
||||
mod map[string]Command
|
||||
admin map[string]Command
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
HelpText string
|
||||
Function CommandFunction
|
||||
}
|
||||
|
||||
type CommandFunction func(client *Client, args []string) string
|
||||
|
||||
//type HelpFunction func(client *Client) string
|
||||
|
||||
func init() {
|
||||
commands = &CommandControl{
|
||||
user: map[string]CommandFunction{
|
||||
"me": func(client *Client, args []string) string {
|
||||
client.Me(strings.Join(args, " "))
|
||||
return ""
|
||||
user: map[string]Command{
|
||||
"me": Command{
|
||||
HelpText: "Display an action message.",
|
||||
Function: func(client *Client, args []string) string {
|
||||
client.Me(strings.Join(args, " "))
|
||||
return ""
|
||||
},
|
||||
},
|
||||
"help": func(client *Client, args []string) string {
|
||||
return "I haven't written this yet LUL"
|
||||
|
||||
"help": Command{
|
||||
HelpText: "This help text.",
|
||||
Function: cmdHelp,
|
||||
},
|
||||
"count": func(client *Client, args []string) string {
|
||||
return fmt.Sprintf("Users in chat: %d", client.belongsTo.UserCount())
|
||||
|
||||
"count": Command{
|
||||
HelpText: "Display number of users in chat.",
|
||||
Function: func(client *Client, args []string) string {
|
||||
return fmt.Sprintf("Users in chat: %d", client.belongsTo.UserCount())
|
||||
},
|
||||
},
|
||||
|
||||
"color": cmdColor,
|
||||
"colour": cmdColor,
|
||||
"w": func(cl *Client, args []string) string {
|
||||
return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t", cl.name, cl.IsMod, cl.IsAdmin)
|
||||
},
|
||||
"whoami": func(cl *Client, args []string) string {
|
||||
return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t", cl.name, cl.IsMod, cl.IsAdmin)
|
||||
},
|
||||
"auth": func(cl *Client, args []string) string {
|
||||
if cl.IsAdmin {
|
||||
return "You are already authenticated."
|
||||
}
|
||||
|
||||
pw := html.UnescapeString(strings.Join(args, " "))
|
||||
"w": cmdWhoAmI,
|
||||
"whoami": cmdWhoAmI,
|
||||
|
||||
//fmt.Printf("/auth from %s. expecting %q [%X], received %q [%X]\n", cl.name, settings.AdminPassword, settings.AdminPassword, pw, pw)
|
||||
if settings.AdminPassword == pw {
|
||||
cl.IsMod = true
|
||||
cl.IsAdmin = true
|
||||
return "Admin rights granted."
|
||||
}
|
||||
|
||||
// Don't let on that this command exists. Not the most secure, but should be "good enough" LUL.
|
||||
return "Invalid command."
|
||||
},
|
||||
"users": func(cl *Client, args []string) string {
|
||||
names := cl.belongsTo.GetNames()
|
||||
return strings.Join(names, " ")
|
||||
},
|
||||
},
|
||||
|
||||
mod: map[string]CommandFunction{
|
||||
"sv": func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "Missing message"
|
||||
}
|
||||
svmsg := formatLinks(ParseEmotes(strings.Join(args, " ")))
|
||||
cl.belongsTo.AddCmdMsg(fmt.Sprintf(`<div class="announcement">%s</div>`, svmsg))
|
||||
return ""
|
||||
},
|
||||
"playing": func(cl *Client, args []string) string {
|
||||
// Clear/hide title if sent with no arguments.
|
||||
if len(args) == 1 {
|
||||
cl.belongsTo.ClearPlaying()
|
||||
//cl.belongsTo.AddMsg(`<script>setPlaying("","");</script>`)
|
||||
return ""
|
||||
}
|
||||
link := ""
|
||||
title := ""
|
||||
|
||||
// pickout the link (can be anywhere, as long as there are no spaces).
|
||||
for _, word := range args {
|
||||
word = html.UnescapeString(word)
|
||||
if strings.HasPrefix(word, "http://") || strings.HasPrefix(word, "https://") {
|
||||
link = word
|
||||
} else {
|
||||
title = title + " " + word
|
||||
"auth": Command{
|
||||
HelpText: "Authenticate to admin",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if cl.IsAdmin {
|
||||
return "You are already authenticated."
|
||||
}
|
||||
}
|
||||
|
||||
cl.belongsTo.SetPlaying(title, link)
|
||||
//cl.belongsTo.AddMsg(fmt.Sprintf(`<script>setPlaying("%s","%s");</script>`, title, link))
|
||||
return ""
|
||||
pw := html.UnescapeString(strings.Join(args, " "))
|
||||
|
||||
//fmt.Printf("/auth from %s. expecting %q [%X], received %q [%X]\n", cl.name, settings.AdminPassword, settings.AdminPassword, pw, pw)
|
||||
if settings.AdminPassword == pw {
|
||||
cl.IsMod = true
|
||||
cl.IsAdmin = true
|
||||
return "Admin rights granted."
|
||||
}
|
||||
|
||||
// Don't let on that this command exists. Not the most secure, but should be "good enough" LUL.
|
||||
return "Invalid command."
|
||||
},
|
||||
},
|
||||
"unmod": func(cl *Client, args []string) string {
|
||||
if len(args) > 0 && !cl.IsAdmin {
|
||||
return "You can only unmod yourself, not others."
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
cl.Unmod()
|
||||
return "You have unmodded yourself."
|
||||
}
|
||||
|
||||
if err := cl.belongsTo.Unmod(args[0]); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`%s has been unmodded.`, args[0])
|
||||
},
|
||||
"kick": func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "Missing name to kick."
|
||||
}
|
||||
return cl.belongsTo.Kick(args[0])
|
||||
},
|
||||
"ban": func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "missing name to ban."
|
||||
}
|
||||
fmt.Printf("[ban] Attempting to ban %s\n", strings.Join(args, ""))
|
||||
return cl.belongsTo.Ban(args[0])
|
||||
},
|
||||
"unban": func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "missing name to unban."
|
||||
}
|
||||
fmt.Printf("[ban] Attempting to unban %s\n", strings.Join(args, ""))
|
||||
|
||||
err := settings.RemoveBan(args[0])
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return ""
|
||||
"users": Command{
|
||||
HelpText: "Show a list of users in chat",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
names := cl.belongsTo.GetNames()
|
||||
return strings.Join(names, " ")
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
admin: map[string]CommandFunction{
|
||||
"mod": func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "Missing user to mod."
|
||||
}
|
||||
if err := cl.belongsTo.Mod(args[0]); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf(`%s has been modded.`, args[0])
|
||||
mod: map[string]Command{
|
||||
"sv": Command{
|
||||
HelpText: "Send a server announcement message. It will show up red with a border in chat.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "Missing message"
|
||||
}
|
||||
svmsg := formatLinks(ParseEmotes(strings.Join(args, " ")))
|
||||
cl.belongsTo.AddCmdMsg(fmt.Sprintf(`<div class="announcement">%s</div>`, svmsg))
|
||||
return ""
|
||||
},
|
||||
},
|
||||
"reloadplayer": func(cl *Client, args []string) string {
|
||||
cl.belongsTo.AddCmdMsg(`<span class="svmsg">[SERVER] Video player reload forced.</span><script>initPlayer();</script><br />`)
|
||||
return "Reloading player for all chatters."
|
||||
},
|
||||
"reloademotes": func(cl *Client, args []string) string {
|
||||
cl.ServerMessage("Reloading emotes")
|
||||
num, err := LoadEmotes()
|
||||
if err != nil {
|
||||
fmt.Printf("Unbale to reload emotes: %s\n", err)
|
||||
return fmt.Sprintf("ERROR: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Loaded %d emotes\n", num)
|
||||
return fmt.Sprintf("Emotes loaded: %d", num)
|
||||
"playing": Command{
|
||||
HelpText: "Set the title text and info link.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
// Clear/hide title if sent with no arguments.
|
||||
if len(args) == 1 {
|
||||
cl.belongsTo.ClearPlaying()
|
||||
return ""
|
||||
}
|
||||
link := ""
|
||||
title := ""
|
||||
|
||||
// pickout the link (can be anywhere, as long as there are no spaces).
|
||||
for _, word := range args {
|
||||
word = html.UnescapeString(word)
|
||||
if strings.HasPrefix(word, "http://") || strings.HasPrefix(word, "https://") {
|
||||
link = word
|
||||
} else {
|
||||
title = title + " " + word
|
||||
}
|
||||
}
|
||||
|
||||
cl.belongsTo.SetPlaying(title, link)
|
||||
return ""
|
||||
},
|
||||
},
|
||||
|
||||
"unmod": Command{
|
||||
HelpText: "Revoke a user's moderator privilages. Moderators can only unmod themselves.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if len(args) > 0 && !cl.IsAdmin {
|
||||
return "You can only unmod yourself, not others."
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
cl.Unmod()
|
||||
return "You have unmodded yourself."
|
||||
}
|
||||
|
||||
if err := cl.belongsTo.Unmod(args[0]); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`%s has been unmodded.`, args[0])
|
||||
},
|
||||
},
|
||||
|
||||
"kick": Command{
|
||||
HelpText: "Kick a user from chat.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "Missing name to kick."
|
||||
}
|
||||
return cl.belongsTo.Kick(args[0])
|
||||
},
|
||||
},
|
||||
|
||||
"ban": 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.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "missing name to ban."
|
||||
}
|
||||
fmt.Printf("[ban] Attempting to ban %s\n", strings.Join(args, ""))
|
||||
return cl.belongsTo.Ban(args[0])
|
||||
},
|
||||
},
|
||||
|
||||
"unban": Command{
|
||||
HelpText: "Remove a ban on a user.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "missing name to unban."
|
||||
}
|
||||
fmt.Printf("[ban] Attempting to unban %s\n", strings.Join(args, ""))
|
||||
|
||||
err := settings.RemoveBan(args[0])
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return ""
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
admin: map[string]Command{
|
||||
"mod": Command{
|
||||
HelpText: "Grant moderator privilages to a user.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if len(args) == 0 {
|
||||
return "Missing user to mod."
|
||||
}
|
||||
if err := cl.belongsTo.Mod(args[0]); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf(`%s has been modded.`, args[0])
|
||||
},
|
||||
},
|
||||
|
||||
"reloadplayer": Command{
|
||||
HelpText: "Reload the stream player for everybody in chat.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
cl.belongsTo.AddCmdMsg(`<span class="svmsg">[SERVER] Video player reload forced.</span><script>initPlayer();</script><br />`)
|
||||
return "Reloading player for all chatters."
|
||||
},
|
||||
},
|
||||
|
||||
"reloademotes": Command{
|
||||
HelpText: "Reload the emotes on the server.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
cl.ServerMessage("Reloading emotes")
|
||||
num, err := LoadEmotes()
|
||||
if err != nil {
|
||||
fmt.Printf("Unbale to reload emotes: %s\n", err)
|
||||
return fmt.Sprintf("ERROR: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Loaded %d emotes\n", num)
|
||||
return fmt.Sprintf("Emotes loaded: %d", num)
|
||||
},
|
||||
},
|
||||
|
||||
//"reloadsettings": func(cl *Client, args []string) string {
|
||||
// return ""
|
||||
//},
|
||||
|
@ -174,14 +229,14 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
|
|||
// Look for user command
|
||||
if userCmd, ok := cc.user[command]; ok {
|
||||
fmt.Printf("[user] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
||||
return userCmd(sender, args)
|
||||
return userCmd.Function(sender, args)
|
||||
}
|
||||
|
||||
// Look for mod command
|
||||
if modCmd, ok := cc.mod[command]; ok {
|
||||
if sender.IsMod || sender.IsAdmin {
|
||||
fmt.Printf("[mod] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
||||
return modCmd(sender, args)
|
||||
return modCmd.Function(sender, args)
|
||||
}
|
||||
|
||||
fmt.Printf("[mod REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
||||
|
@ -192,7 +247,7 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
|
|||
if adminCmd, ok := cc.admin[command]; ok {
|
||||
if sender.IsAdmin {
|
||||
fmt.Printf("[admin] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
||||
return adminCmd(sender, args)
|
||||
return adminCmd.Function(sender, args)
|
||||
}
|
||||
fmt.Printf("[admin REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
||||
return "You are not the admin Jebaited"
|
||||
|
@ -203,48 +258,102 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
|
|||
return "Invalid command."
|
||||
}
|
||||
|
||||
func cmdColor(cl *Client, args []string) string {
|
||||
// If the caller is priviledged enough, they can change the color of another user
|
||||
if len(args) == 2 && (cl.IsMod || cl.IsAdmin) {
|
||||
color := ""
|
||||
name := ""
|
||||
for _, s := range args {
|
||||
if strings.HasPrefix(s, "#") {
|
||||
color = s
|
||||
} else {
|
||||
name = s
|
||||
}
|
||||
}
|
||||
if color == "" {
|
||||
|
||||
fmt.Printf("[color:mod] %s missing color\n", cl.name)
|
||||
return "Missing color"
|
||||
}
|
||||
|
||||
if err := cl.belongsTo.ForceColorChange(name, color); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("Color changed for user %s to %s\n", name, color)
|
||||
func cmdHelp(cl *Client, args []string) string {
|
||||
url := "/help"
|
||||
if cl.IsMod {
|
||||
url = "/modhelp"
|
||||
}
|
||||
|
||||
// Don't allow an unprivilaged user to change their color if
|
||||
// it was changed by a mod
|
||||
if cl.IsColorForced {
|
||||
fmt.Printf("[color] %s tried to change a forced color\n", cl.name)
|
||||
return "You are not allowed to change your color."
|
||||
if cl.IsAdmin {
|
||||
url = "/adminhelp"
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
cl.color = randomColor()
|
||||
return "Random color chosen: " + cl.color
|
||||
}
|
||||
|
||||
// Change the color of the user
|
||||
if !colorRegex.MatchString(args[0]) {
|
||||
return "To choose a specific color use the format <i>/color #c029ce</i>. Hex values expected."
|
||||
}
|
||||
|
||||
cl.color = args[0]
|
||||
fmt.Printf("[color] %s new color: %s\n", cl.name, cl.color)
|
||||
return "Color changed successfully."
|
||||
return `Opening help in new window.<script>window.open("` + url + `", "_blank", "menubar=0,status=0,toolbar=0,width=300,height=600")</script>`
|
||||
}
|
||||
|
||||
var hlpTemplate = `<dl class="helptext"><dt>%s</dt><dd>%s</dd></dl>`
|
||||
|
||||
// Return a full HTML page for the help text. This should probably be rewritten with templates.
|
||||
func helpPage(ismod, isadmin bool) string {
|
||||
if commands == nil {
|
||||
return "No commands loaded Jebaited"
|
||||
}
|
||||
|
||||
text := []string{}
|
||||
for key, cmd := range commands.user {
|
||||
text = append(text, fmt.Sprintf(hlpTemplate, key, cmd.HelpText))
|
||||
}
|
||||
|
||||
if ismod {
|
||||
for key, cmd := range commands.mod {
|
||||
text = append(text, fmt.Sprintf(hlpTemplate, key, cmd.HelpText))
|
||||
}
|
||||
}
|
||||
|
||||
if isadmin {
|
||||
for key, cmd := range commands.mod {
|
||||
text = append(text, fmt.Sprintf(hlpTemplate, key, cmd.HelpText))
|
||||
}
|
||||
}
|
||||
|
||||
// This is ugly
|
||||
return `<html><head><title>Help</title><link rel="stylesheet" type="text/css" href="/static/site.css"></head><body>` + strings.Join(text, "") + `</body></html>`
|
||||
}
|
||||
|
||||
// Commands below have more than one invoking command (aliases).
|
||||
|
||||
var cmdColor = Command{
|
||||
HelpText: "Change user color.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
// If the caller is priviledged enough, they can change the color of another user
|
||||
if len(args) == 2 && (cl.IsMod || cl.IsAdmin) {
|
||||
color := ""
|
||||
name := ""
|
||||
for _, s := range args {
|
||||
if strings.HasPrefix(s, "#") {
|
||||
color = s
|
||||
} else {
|
||||
name = s
|
||||
}
|
||||
}
|
||||
if color == "" {
|
||||
|
||||
fmt.Printf("[color:mod] %s missing color\n", cl.name)
|
||||
return "Missing color"
|
||||
}
|
||||
|
||||
if err := cl.belongsTo.ForceColorChange(name, color); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return fmt.Sprintf("Color changed for user %s to %s\n", name, color)
|
||||
}
|
||||
|
||||
// Don't allow an unprivilaged user to change their color if
|
||||
// it was changed by a mod
|
||||
if cl.IsColorForced {
|
||||
fmt.Printf("[color] %s tried to change a forced color\n", cl.name)
|
||||
return "You are not allowed to change your color."
|
||||
}
|
||||
|
||||
if len(args) == 0 {
|
||||
cl.color = randomColor()
|
||||
return "Random color chosen: " + cl.color
|
||||
}
|
||||
|
||||
// Change the color of the user
|
||||
if !colorRegex.MatchString(args[0]) {
|
||||
return "To choose a specific color use the format <i>/color #c029ce</i>. Hex values expected."
|
||||
}
|
||||
|
||||
cl.color = args[0]
|
||||
fmt.Printf("[color] %s new color: %s\n", cl.name, cl.color)
|
||||
return "Color changed successfully."
|
||||
},
|
||||
}
|
||||
|
||||
var cmdWhoAmI = Command{
|
||||
HelpText: "Shows debug user info",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t", cl.name, cl.IsMod, cl.IsAdmin)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -24,6 +24,17 @@ func wsStaticFiles(w http.ResponseWriter, r *http.Request) {
|
|||
case "/justvideo":
|
||||
http.ServeFile(w, r, "./static/justvideo.html")
|
||||
return
|
||||
|
||||
// TODO: use a template for this, lol.
|
||||
case "/help":
|
||||
w.Write([]byte(helpPage(false, false)))
|
||||
return
|
||||
case "/modhelp":
|
||||
w.Write([]byte(helpPage(true, false)))
|
||||
return
|
||||
case "/adminhelp":
|
||||
w.Write([]byte(helpPage(true, true)))
|
||||
return
|
||||
}
|
||||
|
||||
goodPath := r.URL.Path[8:len(r.URL.Path)]
|
||||
|
|
3
main.go
3
main.go
|
@ -96,6 +96,9 @@ func main() {
|
|||
http.HandleFunc("/favicon.ico", wsStaticFiles)
|
||||
http.HandleFunc("/justchat", wsStaticFiles)
|
||||
http.HandleFunc("/justvideo", wsStaticFiles)
|
||||
http.HandleFunc("/help", wsStaticFiles)
|
||||
http.HandleFunc("/modhelp", wsStaticFiles)
|
||||
http.HandleFunc("/adminhelp", wsStaticFiles)
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
l.RLock()
|
||||
|
|
|
@ -84,3 +84,11 @@ span.svmsg {
|
|||
#playing {
|
||||
font-size: x-Large;
|
||||
}
|
||||
|
||||
.helptext {
|
||||
color: white;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue