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
175
chatcommands.go
175
chatcommands.go
|
@ -11,35 +11,52 @@ var commands *CommandControl
|
||||||
var colorRegex *regexp.Regexp = regexp.MustCompile(`^#[0-9A-Fa-f]{6}$`)
|
var colorRegex *regexp.Regexp = regexp.MustCompile(`^#[0-9A-Fa-f]{6}$`)
|
||||||
|
|
||||||
type CommandControl struct {
|
type CommandControl struct {
|
||||||
user map[string]CommandFunction
|
user map[string]Command
|
||||||
mod map[string]CommandFunction
|
mod map[string]Command
|
||||||
admin map[string]CommandFunction
|
admin map[string]Command
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
HelpText string
|
||||||
|
Function CommandFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandFunction func(client *Client, args []string) string
|
type CommandFunction func(client *Client, args []string) string
|
||||||
|
|
||||||
|
//type HelpFunction func(client *Client) string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
commands = &CommandControl{
|
commands = &CommandControl{
|
||||||
user: map[string]CommandFunction{
|
user: map[string]Command{
|
||||||
"me": func(client *Client, args []string) string {
|
"me": Command{
|
||||||
|
HelpText: "Display an action message.",
|
||||||
|
Function: func(client *Client, args []string) string {
|
||||||
client.Me(strings.Join(args, " "))
|
client.Me(strings.Join(args, " "))
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
"help": func(client *Client, args []string) string {
|
|
||||||
return "I haven't written this yet LUL"
|
|
||||||
},
|
},
|
||||||
"count": func(client *Client, args []string) string {
|
|
||||||
|
"help": Command{
|
||||||
|
HelpText: "This help text.",
|
||||||
|
Function: cmdHelp,
|
||||||
|
},
|
||||||
|
|
||||||
|
"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())
|
return fmt.Sprintf("Users in chat: %d", client.belongsTo.UserCount())
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
"color": cmdColor,
|
"color": cmdColor,
|
||||||
"colour": 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)
|
"w": cmdWhoAmI,
|
||||||
},
|
"whoami": cmdWhoAmI,
|
||||||
"whoami": func(cl *Client, args []string) string {
|
|
||||||
return fmt.Sprintf("Name: %s IsMod: %t IsAdmin: %t", cl.name, cl.IsMod, cl.IsAdmin)
|
"auth": Command{
|
||||||
},
|
HelpText: "Authenticate to admin",
|
||||||
"auth": func(cl *Client, args []string) string {
|
Function: func(cl *Client, args []string) string {
|
||||||
if cl.IsAdmin {
|
if cl.IsAdmin {
|
||||||
return "You are already authenticated."
|
return "You are already authenticated."
|
||||||
}
|
}
|
||||||
|
@ -56,14 +73,21 @@ func init() {
|
||||||
// Don't let on that this command exists. Not the most secure, but should be "good enough" LUL.
|
// Don't let on that this command exists. Not the most secure, but should be "good enough" LUL.
|
||||||
return "Invalid command."
|
return "Invalid command."
|
||||||
},
|
},
|
||||||
"users": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"users": Command{
|
||||||
|
HelpText: "Show a list of users in chat",
|
||||||
|
Function: func(cl *Client, args []string) string {
|
||||||
names := cl.belongsTo.GetNames()
|
names := cl.belongsTo.GetNames()
|
||||||
return strings.Join(names, " ")
|
return strings.Join(names, " ")
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
mod: map[string]CommandFunction{
|
mod: map[string]Command{
|
||||||
"sv": func(cl *Client, args []string) string {
|
"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 {
|
if len(args) == 0 {
|
||||||
return "Missing message"
|
return "Missing message"
|
||||||
}
|
}
|
||||||
|
@ -71,11 +95,14 @@ func init() {
|
||||||
cl.belongsTo.AddCmdMsg(fmt.Sprintf(`<div class="announcement">%s</div>`, svmsg))
|
cl.belongsTo.AddCmdMsg(fmt.Sprintf(`<div class="announcement">%s</div>`, svmsg))
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
"playing": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"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.
|
// Clear/hide title if sent with no arguments.
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
cl.belongsTo.ClearPlaying()
|
cl.belongsTo.ClearPlaying()
|
||||||
//cl.belongsTo.AddMsg(`<script>setPlaying("","");</script>`)
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
link := ""
|
link := ""
|
||||||
|
@ -92,10 +119,13 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
cl.belongsTo.SetPlaying(title, link)
|
cl.belongsTo.SetPlaying(title, link)
|
||||||
//cl.belongsTo.AddMsg(fmt.Sprintf(`<script>setPlaying("%s","%s");</script>`, title, link))
|
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
"unmod": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"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 {
|
if len(args) > 0 && !cl.IsAdmin {
|
||||||
return "You can only unmod yourself, not others."
|
return "You can only unmod yourself, not others."
|
||||||
}
|
}
|
||||||
|
@ -111,20 +141,32 @@ func init() {
|
||||||
|
|
||||||
return fmt.Sprintf(`%s has been unmodded.`, args[0])
|
return fmt.Sprintf(`%s has been unmodded.`, args[0])
|
||||||
},
|
},
|
||||||
"kick": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"kick": Command{
|
||||||
|
HelpText: "Kick a user from chat.",
|
||||||
|
Function: func(cl *Client, args []string) string {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return "Missing name to kick."
|
return "Missing name to kick."
|
||||||
}
|
}
|
||||||
return cl.belongsTo.Kick(args[0])
|
return cl.belongsTo.Kick(args[0])
|
||||||
},
|
},
|
||||||
"ban": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"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 {
|
if len(args) == 0 {
|
||||||
return "missing name to ban."
|
return "missing name to ban."
|
||||||
}
|
}
|
||||||
fmt.Printf("[ban] Attempting to ban %s\n", strings.Join(args, ""))
|
fmt.Printf("[ban] Attempting to ban %s\n", strings.Join(args, ""))
|
||||||
return cl.belongsTo.Ban(args[0])
|
return cl.belongsTo.Ban(args[0])
|
||||||
},
|
},
|
||||||
"unban": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"unban": Command{
|
||||||
|
HelpText: "Remove a ban on a user.",
|
||||||
|
Function: func(cl *Client, args []string) string {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return "missing name to unban."
|
return "missing name to unban."
|
||||||
}
|
}
|
||||||
|
@ -137,9 +179,12 @@ func init() {
|
||||||
return ""
|
return ""
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
admin: map[string]CommandFunction{
|
admin: map[string]Command{
|
||||||
"mod": func(cl *Client, args []string) string {
|
"mod": Command{
|
||||||
|
HelpText: "Grant moderator privilages to a user.",
|
||||||
|
Function: func(cl *Client, args []string) string {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return "Missing user to mod."
|
return "Missing user to mod."
|
||||||
}
|
}
|
||||||
|
@ -148,11 +193,19 @@ func init() {
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`%s has been modded.`, args[0])
|
return fmt.Sprintf(`%s has been modded.`, args[0])
|
||||||
},
|
},
|
||||||
"reloadplayer": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"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 />`)
|
cl.belongsTo.AddCmdMsg(`<span class="svmsg">[SERVER] Video player reload forced.</span><script>initPlayer();</script><br />`)
|
||||||
return "Reloading player for all chatters."
|
return "Reloading player for all chatters."
|
||||||
},
|
},
|
||||||
"reloademotes": func(cl *Client, args []string) string {
|
},
|
||||||
|
|
||||||
|
"reloademotes": Command{
|
||||||
|
HelpText: "Reload the emotes on the server.",
|
||||||
|
Function: func(cl *Client, args []string) string {
|
||||||
cl.ServerMessage("Reloading emotes")
|
cl.ServerMessage("Reloading emotes")
|
||||||
num, err := LoadEmotes()
|
num, err := LoadEmotes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -163,6 +216,8 @@ func init() {
|
||||||
fmt.Printf("Loaded %d emotes\n", num)
|
fmt.Printf("Loaded %d emotes\n", num)
|
||||||
return fmt.Sprintf("Emotes loaded: %d", num)
|
return fmt.Sprintf("Emotes loaded: %d", num)
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
|
||||||
//"reloadsettings": func(cl *Client, args []string) string {
|
//"reloadsettings": func(cl *Client, args []string) string {
|
||||||
// return ""
|
// return ""
|
||||||
//},
|
//},
|
||||||
|
@ -174,14 +229,14 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
|
||||||
// Look for user command
|
// Look for user command
|
||||||
if userCmd, ok := cc.user[command]; ok {
|
if userCmd, ok := cc.user[command]; ok {
|
||||||
fmt.Printf("[user] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
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
|
// Look for mod command
|
||||||
if modCmd, ok := cc.mod[command]; ok {
|
if modCmd, ok := cc.mod[command]; ok {
|
||||||
if sender.IsMod || sender.IsAdmin {
|
if sender.IsMod || sender.IsAdmin {
|
||||||
fmt.Printf("[mod] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
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, " "))
|
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 adminCmd, ok := cc.admin[command]; ok {
|
||||||
if sender.IsAdmin {
|
if sender.IsAdmin {
|
||||||
fmt.Printf("[admin] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
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, " "))
|
fmt.Printf("[admin REJECTED] %s /%s %s\n", sender.name, command, strings.Join(args, " "))
|
||||||
return "You are not the admin Jebaited"
|
return "You are not the admin Jebaited"
|
||||||
|
@ -203,7 +258,53 @@ func (cc *CommandControl) RunCommand(command string, args []string, sender *Clie
|
||||||
return "Invalid command."
|
return "Invalid command."
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdColor(cl *Client, args []string) string {
|
func cmdHelp(cl *Client, args []string) string {
|
||||||
|
url := "/help"
|
||||||
|
if cl.IsMod {
|
||||||
|
url = "/modhelp"
|
||||||
|
}
|
||||||
|
|
||||||
|
if cl.IsAdmin {
|
||||||
|
url = "/adminhelp"
|
||||||
|
}
|
||||||
|
|
||||||
|
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 the caller is priviledged enough, they can change the color of another user
|
||||||
if len(args) == 2 && (cl.IsMod || cl.IsAdmin) {
|
if len(args) == 2 && (cl.IsMod || cl.IsAdmin) {
|
||||||
color := ""
|
color := ""
|
||||||
|
@ -247,4 +348,12 @@ func cmdColor(cl *Client, args []string) string {
|
||||||
cl.color = args[0]
|
cl.color = args[0]
|
||||||
fmt.Printf("[color] %s new color: %s\n", cl.name, cl.color)
|
fmt.Printf("[color] %s new color: %s\n", cl.name, cl.color)
|
||||||
return "Color changed successfully."
|
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":
|
case "/justvideo":
|
||||||
http.ServeFile(w, r, "./static/justvideo.html")
|
http.ServeFile(w, r, "./static/justvideo.html")
|
||||||
return
|
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)]
|
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("/favicon.ico", wsStaticFiles)
|
||||||
http.HandleFunc("/justchat", wsStaticFiles)
|
http.HandleFunc("/justchat", wsStaticFiles)
|
||||||
http.HandleFunc("/justvideo", 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) {
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
l.RLock()
|
l.RLock()
|
||||||
|
|
|
@ -84,3 +84,11 @@ span.svmsg {
|
||||||
#playing {
|
#playing {
|
||||||
font-size: x-Large;
|
font-size: x-Large;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.helptext {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
dt {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue