Merge branch 'master' into room-access-restrictions
# Conflicts: # main.go
This commit is contained in:
commit
34d8fbf20c
35
chatroom.go
35
chatroom.go
|
@ -30,6 +30,8 @@ type ChatRoom struct {
|
||||||
|
|
||||||
modPasswords []string // single-use mod passwords
|
modPasswords []string // single-use mod passwords
|
||||||
modPasswordsMtx sync.Mutex
|
modPasswordsMtx sync.Mutex
|
||||||
|
|
||||||
|
isShutdown bool
|
||||||
}
|
}
|
||||||
|
|
||||||
//initializing the chatroom
|
//initializing the chatroom
|
||||||
|
@ -53,6 +55,11 @@ func newChatRoom() (*ChatRoom, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cr *ChatRoom) JoinTemp(conn *chatConnection) (string, error) {
|
func (cr *ChatRoom) JoinTemp(conn *chatConnection) (string, error) {
|
||||||
|
// Don't allow new joins when the server is closing.
|
||||||
|
if cr.isShutdown {
|
||||||
|
return "", fmt.Errorf("Server is shutting down")
|
||||||
|
}
|
||||||
|
|
||||||
defer cr.clientsMtx.Unlock()
|
defer cr.clientsMtx.Unlock()
|
||||||
cr.clientsMtx.Lock()
|
cr.clientsMtx.Lock()
|
||||||
|
|
||||||
|
@ -77,6 +84,11 @@ func (cr *ChatRoom) JoinTemp(conn *chatConnection) (string, error) {
|
||||||
//registering a new client
|
//registering a new client
|
||||||
//returns pointer to a Client, or Nil, if the name is already taken
|
//returns pointer to a Client, or Nil, if the name is already taken
|
||||||
func (cr *ChatRoom) Join(name, uid string) (*Client, error) {
|
func (cr *ChatRoom) Join(name, uid string) (*Client, error) {
|
||||||
|
// Don't allow new joins when the server is closing.
|
||||||
|
if cr.isShutdown {
|
||||||
|
return nil, fmt.Errorf("Server is shutting down")
|
||||||
|
}
|
||||||
|
|
||||||
defer cr.clientsMtx.Unlock()
|
defer cr.clientsMtx.Unlock()
|
||||||
cr.clientsMtx.Lock()
|
cr.clientsMtx.Lock()
|
||||||
|
|
||||||
|
@ -500,3 +512,26 @@ func (cr *ChatRoom) changeName(oldName, newName string, forced bool) error {
|
||||||
|
|
||||||
return fmt.Errorf("Client not found with name %q", oldName)
|
return fmt.Errorf("Client not found with name %q", oldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Shutdown the chatroom. First, dissallow new joins by setting
|
||||||
|
// isShutdown, then close each client connection. This would be
|
||||||
|
// a good place to put a final command that gets sent to the client.
|
||||||
|
func (cr *ChatRoom) Shutdown() {
|
||||||
|
cr.isShutdown = true
|
||||||
|
common.LogInfoln("ChatRoom is shutting down.")
|
||||||
|
|
||||||
|
cr.clientsMtx.Lock()
|
||||||
|
defer cr.clientsMtx.Unlock()
|
||||||
|
|
||||||
|
for uuid, client := range cr.clients {
|
||||||
|
common.LogDebugf("Closing connection for %s", uuid)
|
||||||
|
client.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
for uuid, conn := range cr.tempConn {
|
||||||
|
common.LogDebugf("Closing connection for temp %s", uuid)
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
common.LogInfoln("ChatRoom Shutdown() finished")
|
||||||
|
}
|
||||||
|
|
|
@ -7,39 +7,36 @@ import (
|
||||||
"github.com/lucasb-eyer/go-colorful"
|
"github.com/lucasb-eyer/go-colorful"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Colors holds all the valid html color names for MovieNight
|
||||||
// the values in colors must be lowercase so it matches with the color input
|
// the values in colors must be lowercase so it matches with the color input
|
||||||
// this saves from having to call strings.ToLower(color) every time to check
|
// this saves from having to call strings.ToLower(color) every time to check
|
||||||
var colors = []string{
|
var Colors = []string{
|
||||||
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
|
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
|
||||||
"beige", "bisque", "black", "blanchedalmond", "blue",
|
"beige", "bisque", "blanchedalmond", "blueviolet", "brown",
|
||||||
"blueviolet", "brown", "burlywood", "cadetblue", "chartreuse",
|
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
|
||||||
"chocolate", "coral", "cornflowerblue", "cornsilk", "crimson",
|
"cornflowerblue", "cornsilk", "crimson", "cyan", "darkcyan",
|
||||||
"cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
|
"darkgoldenrod", "darkgray", "darkkhaki", "darkmagenta", "darkolivegreen",
|
||||||
"darkgrey", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
|
"darkorange", "darkorchid", "darksalmon", "darkseagreen", "darkslateblue",
|
||||||
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
|
"darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue",
|
||||||
"darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet",
|
"dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen",
|
||||||
"deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
|
"fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod",
|
||||||
"firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro",
|
"gray", "greenyellow", "honeydew", "hotpink", "indigo",
|
||||||
"ghostwhite", "gold", "goldenrod", "gray", "grey",
|
"ivory", "khaki", "lavender", "lavenderblush", "lawngreen",
|
||||||
"green", "greenyellow", "honeydew", "hotpink", "indianred",
|
"lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow",
|
||||||
"indigo", "ivory", "khaki", "lavender", "lavenderblush",
|
"lightgrey", "lightgreen", "lightpink", "lightsalmon", "lightseagreen",
|
||||||
"lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan",
|
"lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime",
|
||||||
"lightgoldenrodyellow", "lightgray", "lightgrey", "lightgreen", "lightpink",
|
"limegreen", "linen", "magenta", "mediumaquamarine", "mediumorchid",
|
||||||
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey",
|
|
||||||
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen",
|
|
||||||
"magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid",
|
|
||||||
"mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
|
"mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
|
||||||
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
|
"mediumvioletred", "mintcream", "mistyrose", "moccasin", "navajowhite",
|
||||||
"navajowhite", "navy", "oldlace", "olive", "olivedrab",
|
"oldlace", "olive", "olivedrab", "orange", "orangered",
|
||||||
"orange", "orangered", "orchid", "palegoldenrod", "palegreen",
|
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
|
||||||
"paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru",
|
"papayawhip", "peachpuff", "peru", "pink", "plum",
|
||||||
"pink", "plum", "powderblue", "purple", "rebeccapurple",
|
"powderblue", "purple", "rebeccapurple", "red", "rosybrown",
|
||||||
"red", "rosybrown", "royalblue", "saddlebrown", "salmon",
|
"royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen",
|
||||||
"sandybrown", "seagreen", "seashell", "sienna", "silver",
|
"seashell", "sienna", "silver", "skyblue", "slateblue",
|
||||||
"skyblue", "slateblue", "slategray", "slategrey", "snow",
|
"slategray", "snow", "springgreen", "steelblue", "tan",
|
||||||
"springgreen", "steelblue", "tan", "teal", "thistle",
|
"teal", "thistle", "tomato", "turquoise", "violet",
|
||||||
"tomato", "turquoise", "violet", "wheat", "white",
|
"wheat", "white", "whitesmoke", "yellow", "yellowgreen",
|
||||||
"whitesmoke", "yellow", "yellowgreen",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -50,7 +47,7 @@ var (
|
||||||
// It also accepts hex codes in the form of #RGB and #RRGGBB
|
// It also accepts hex codes in the form of #RGB and #RRGGBB
|
||||||
func IsValidColor(s string) bool {
|
func IsValidColor(s string) bool {
|
||||||
s = strings.ToLower(s)
|
s = strings.ToLower(s)
|
||||||
for _, c := range colors {
|
for _, c := range Colors {
|
||||||
if s == c {
|
if s == c {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var data_good = map[string]string{
|
||||||
|
"one": `<img src="/emotes/one.png" height="28px" title="one" />`,
|
||||||
|
"two": `<img src="/emotes/two.png" height="28px" title="two" />`,
|
||||||
|
"three": `<img src="/emotes/three.gif" height="28px" title="three" />`,
|
||||||
|
|
||||||
|
":one:": `<img src="/emotes/one.png" height="28px" title="one" />`,
|
||||||
|
":two:": `<img src="/emotes/two.png" height="28px" title="two" />`,
|
||||||
|
":three:": `<img src="/emotes/three.gif" height="28px" title="three" />`,
|
||||||
|
|
||||||
|
"[one]": `<img src="/emotes/one.png" height="28px" title="one" />`,
|
||||||
|
"[two]": `<img src="/emotes/two.png" height="28px" title="two" />`,
|
||||||
|
"[three]": `<img src="/emotes/three.gif" height="28px" title="three" />`,
|
||||||
|
|
||||||
|
":one: two [three]": `<img src="/emotes/one.png" height="28px" title="one" /> <img src="/emotes/two.png" height="28px" title="two" /> <img src="/emotes/three.gif" height="28px" title="three" />`,
|
||||||
|
|
||||||
|
"nope one what": `nope <img src="/emotes/one.png" height="28px" title="one" /> what`,
|
||||||
|
"nope :two: what": `nope <img src="/emotes/two.png" height="28px" title="two" /> what`,
|
||||||
|
"nope [three] what": `nope <img src="/emotes/three.gif" height="28px" title="three" /> what`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
Emotes = map[string]string{
|
||||||
|
"one": "one.png",
|
||||||
|
"two": "two.png",
|
||||||
|
"three": "three.gif",
|
||||||
|
}
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmotes_ParseEmotes(t *testing.T) {
|
||||||
|
for input, expected := range data_good {
|
||||||
|
got := ParseEmotes(input)
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("%s failed to parse into %q. Received: %q", input, expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
136
main.go
136
main.go
|
@ -1,11 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/sessions"
|
"github.com/gorilla/sessions"
|
||||||
"github.com/nareix/joy4/format"
|
"github.com/nareix/joy4/format"
|
||||||
|
@ -14,9 +16,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
addr string
|
addr string
|
||||||
sKey string
|
sKey string
|
||||||
stats = newStreamStats()
|
stats = newStreamStats()
|
||||||
|
chatServer *http.Server
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupSettings() error {
|
func setupSettings() error {
|
||||||
|
@ -51,9 +54,6 @@ func main() {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
exit := make(chan bool)
|
|
||||||
go handleInterrupt(exit)
|
|
||||||
|
|
||||||
// Load emotes before starting server.
|
// Load emotes before starting server.
|
||||||
var err error
|
var err error
|
||||||
if chat, err = newChatRoom(); err != nil {
|
if chat, err = newChatRoom(); err != nil {
|
||||||
|
@ -77,54 +77,88 @@ func main() {
|
||||||
common.LogInfoln("RoomAccess: ", settings.RoomAccess)
|
common.LogInfoln("RoomAccess: ", settings.RoomAccess)
|
||||||
common.LogInfoln("RoomAccessPin: ", settings.RoomAccessPin)
|
common.LogInfoln("RoomAccessPin: ", settings.RoomAccessPin)
|
||||||
|
|
||||||
go startServer()
|
|
||||||
go startRmtpServer()
|
|
||||||
|
|
||||||
<-exit
|
|
||||||
}
|
|
||||||
|
|
||||||
func startRmtpServer() {
|
|
||||||
server := &rtmp.Server{
|
server := &rtmp.Server{
|
||||||
HandlePlay: handlePlay,
|
HandlePlay: handlePlay,
|
||||||
HandlePublish: handlePublish,
|
HandlePublish: handlePublish,
|
||||||
}
|
}
|
||||||
err := server.ListenAndServe()
|
|
||||||
if err != nil {
|
// Define this here so we can set some timeouts and things.
|
||||||
// If the server cannot start, don't pretend we can continue.
|
chatServer := &http.Server{
|
||||||
panic("Error trying to start rtmp server: " + err.Error())
|
Addr: addr,
|
||||||
|
ReadTimeout: 10 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
MaxHeaderBytes: 1 << 20,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
chatServer.RegisterOnShutdown(func() { chat.Shutdown() })
|
||||||
func startServer() {
|
// rtmp.Server does not implement .RegisterOnShutdown()
|
||||||
// Chat websocket
|
//server.RegisterOnShutdown(func() { common.LogDebugln("server shutdown callback called.") })
|
||||||
http.HandleFunc("/ws", wsHandler)
|
|
||||||
http.HandleFunc("/static/js/", wsStaticFiles)
|
// These have been moved back to annon functitons so I could use
|
||||||
http.HandleFunc("/static/css/", wsStaticFiles)
|
// `server`, `chatServer`, and `exit` in them without needing to
|
||||||
http.HandleFunc("/static/img/", wsImages)
|
// pass them as parameters.
|
||||||
http.HandleFunc("/static/main.wasm", wsWasmFile)
|
|
||||||
http.HandleFunc("/emotes/", wsEmotes)
|
// Signal handler
|
||||||
http.HandleFunc("/favicon.ico", wsStaticFiles)
|
exit := make(chan bool)
|
||||||
http.HandleFunc("/chat", handleIndexTemplate)
|
go func() {
|
||||||
http.HandleFunc("/video", handleIndexTemplate)
|
ch := make(chan os.Signal)
|
||||||
http.HandleFunc("/help", handleHelpTemplate)
|
signal.Notify(ch, os.Interrupt)
|
||||||
http.HandleFunc("/pin", handlePin)
|
<-ch
|
||||||
|
common.LogInfoln("Closing server")
|
||||||
http.HandleFunc("/", handleDefault)
|
if settings.StreamStats {
|
||||||
|
stats.Print()
|
||||||
err := http.ListenAndServe(addr, nil)
|
}
|
||||||
if err != nil {
|
|
||||||
// If the server cannot start, don't pretend we can continue.
|
if err := chatServer.Shutdown(context.Background()); err != nil {
|
||||||
panic("Error trying to start chat/http server: " + err.Error())
|
common.LogErrorf("Error shutting down chat server: %v", err)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
common.LogInfoln("Shutdown() sent. Sending exit.")
|
||||||
func handleInterrupt(exit chan bool) {
|
exit <- true
|
||||||
ch := make(chan os.Signal)
|
}()
|
||||||
signal.Notify(ch, os.Interrupt)
|
|
||||||
<-ch
|
// Chat and HTTP server
|
||||||
common.LogInfoln("Closing server")
|
go func() {
|
||||||
if settings.StreamStats {
|
// Use a ServeMux here instead of the default, global,
|
||||||
stats.Print()
|
// http handler. It's a good idea when we're starting more
|
||||||
}
|
// than one server.
|
||||||
exit <- true
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/ws", wsHandler)
|
||||||
|
mux.HandleFunc("/static/js/", wsStaticFiles)
|
||||||
|
mux.HandleFunc("/static/css/", wsStaticFiles)
|
||||||
|
mux.HandleFunc("/static/img/", wsImages)
|
||||||
|
mux.HandleFunc("/static/main.wasm", wsWasmFile)
|
||||||
|
mux.HandleFunc("/emotes/", wsEmotes)
|
||||||
|
mux.HandleFunc("/favicon.ico", wsStaticFiles)
|
||||||
|
mux.HandleFunc("/chat", handleIndexTemplate)
|
||||||
|
mux.HandleFunc("/video", handleIndexTemplate)
|
||||||
|
mux.HandleFunc("/help", handleHelpTemplate)
|
||||||
|
mux.HandleFunc("/pin", handlePin)
|
||||||
|
|
||||||
|
mux.HandleFunc("/", handleDefault)
|
||||||
|
|
||||||
|
chatServer.Handler = mux
|
||||||
|
err := chatServer.ListenAndServe()
|
||||||
|
// http.ErrServerClosed is returned when server.Shuddown()
|
||||||
|
// is called.
|
||||||
|
if err != http.ErrServerClosed {
|
||||||
|
// If the server cannot start, don't pretend we can continue.
|
||||||
|
panic("Error trying to start chat/http server: " + err.Error())
|
||||||
|
}
|
||||||
|
common.LogDebugln("ChatServer closed.")
|
||||||
|
}()
|
||||||
|
|
||||||
|
// RTMP server
|
||||||
|
go func() {
|
||||||
|
err := server.ListenAndServe()
|
||||||
|
// http.ErrServerClosed is returned when server.Shuddown()
|
||||||
|
// is called.
|
||||||
|
if err != http.ErrServerClosed {
|
||||||
|
// If the server cannot start, don't pretend we can continue.
|
||||||
|
panic("Error trying to start rtmp server: " + err.Error())
|
||||||
|
}
|
||||||
|
common.LogDebugln("RTMP server closed.")
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-exit
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,23 @@ span.svmsg {
|
||||||
color: #ea6260;
|
color: #ea6260;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=text] {
|
||||||
|
background: transparent;
|
||||||
|
border: var(--var-border);
|
||||||
|
border-radius: var(--var-border-radius);
|
||||||
|
color: var(--var-message-color);
|
||||||
|
padding: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#colorInputDiv {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#colorInput {
|
||||||
|
border: 2px solid var(--var-message-color);
|
||||||
|
}
|
||||||
|
|
||||||
.root {
|
.root {
|
||||||
max-width: var(--var-max-width);
|
max-width: var(--var-max-width);
|
||||||
max-height: var(--var-max-height);
|
max-height: var(--var-max-height);
|
||||||
|
@ -223,15 +240,6 @@ span.svmsg {
|
||||||
margin: 5px auto;
|
margin: 5px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#name {
|
|
||||||
background: transparent;
|
|
||||||
border: var(--var-border);
|
|
||||||
border-radius: var(--var-border-radius);
|
|
||||||
color: var(--var-message-color);
|
|
||||||
padding: 5px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
#chat {
|
#chat {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: 1.5em 2em 1fr 6em 2.5em 1em;
|
grid-template-rows: 1.5em 2em 1fr 6em 2.5em 1em;
|
||||||
|
@ -295,6 +303,12 @@ span.svmsg {
|
||||||
color: #b1b1b1;
|
color: #b1b1b1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#colorName {
|
||||||
|
font-weight: bold;
|
||||||
|
background: var(--var-background-color);
|
||||||
|
padding: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
#colorSubmit:disabled {
|
#colorSubmit:disabled {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,10 @@ function help() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showColors(show) {
|
function showColors(show) {
|
||||||
|
if (show === undefined) {
|
||||||
|
show = $("#hiddencolor").css("display") === "none";
|
||||||
|
}
|
||||||
|
|
||||||
$("#hiddencolor").css("display", show ? "block" : "");
|
$("#hiddencolor").css("display", show ? "block" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,11 +192,22 @@ function updateColor() {
|
||||||
|
|
||||||
function changeColor() {
|
function changeColor() {
|
||||||
if (isValidColor(colorAsHex())) {
|
if (isValidColor(colorAsHex())) {
|
||||||
sendMessage("/color " + colorAsHex());
|
sendColor(colorAsHex());
|
||||||
showColors(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function colorSelectChange() {
|
||||||
|
let val = $("#colorSelect").val()
|
||||||
|
if (val !== "") {
|
||||||
|
sendColor(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendColor(color) {
|
||||||
|
sendMessage("/color " + color);
|
||||||
|
showColors(false);
|
||||||
|
}
|
||||||
|
|
||||||
function setTimestamp(v) {
|
function setTimestamp(v) {
|
||||||
showTimestamp(v)
|
showTimestamp(v)
|
||||||
document.cookie = "timestamp=" + v
|
document.cookie = "timestamp=" + v
|
||||||
|
@ -268,37 +283,3 @@ window.addEventListener("load", () => {
|
||||||
// Make sure name is focused on start
|
// Make sure name is focused on start
|
||||||
$("#name").focus();
|
$("#name").focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
function pleaseremovethis() {
|
|
||||||
colors = ["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
|
|
||||||
"beige", "bisque", "black", "blanchedalmond", "blue",
|
|
||||||
"blueviolet", "brown", "burlywood", "cadetblue", "chartreuse",
|
|
||||||
"chocolate", "coral", "cornflowerblue", "cornsilk", "crimson",
|
|
||||||
"cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray",
|
|
||||||
"darkgrey", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
|
|
||||||
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
|
|
||||||
"darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet",
|
|
||||||
"deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
|
|
||||||
"firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro",
|
|
||||||
"ghostwhite", "gold", "goldenrod", "gray", "grey",
|
|
||||||
"green", "greenyellow", "honeydew", "hotpink", "indianred",
|
|
||||||
"indigo", "ivory", "khaki", "lavender", "lavenderblush",
|
|
||||||
"lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan",
|
|
||||||
"lightgoldenrodyellow", "lightgray", "lightgrey", "lightgreen", "lightpink",
|
|
||||||
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey",
|
|
||||||
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen",
|
|
||||||
"magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid",
|
|
||||||
"mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
|
|
||||||
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
|
|
||||||
"navajowhite", "navy", "oldlace", "olive", "olivedrab",
|
|
||||||
"orange", "orangered", "orchid", "palegoldenrod", "palegreen",
|
|
||||||
"paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru",
|
|
||||||
"pink", "plum", "powderblue", "purple", "rebeccapurple",
|
|
||||||
"red", "rosybrown", "royalblue", "saddlebrown", "salmon",
|
|
||||||
"sandybrown", "seagreen", "seashell", "sienna", "silver",
|
|
||||||
"skyblue", "slateblue", "slategray", "slategrey", "snow",
|
|
||||||
"springgreen", "steelblue", "tan", "teal", "thistle",
|
|
||||||
"tomato", "turquoise", "violet", "wheat", "white",
|
|
||||||
"whitesmoke", "yellow", "yellowgreen",]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
<div id="chatButtons">
|
<div id="chatButtons">
|
||||||
<input type="button" class="button pretty-button" onclick="auth();" value="Auth" />
|
<input type="button" class="button pretty-button" onclick="auth();" value="Auth" />
|
||||||
<input type="button" class="button pretty-button" onclick="help();" value="Help" />
|
<input type="button" class="button pretty-button" onclick="help();" value="Help" />
|
||||||
<input type="button" class="button pretty-button" onclick="showColors(true);" value="Color" />
|
<input type="button" class="button pretty-button" onclick="showColors();" value="Color" />
|
||||||
<input type="button" class="button pretty-button" onclick="nick();" value="Nick" />
|
<input type="button" class="button pretty-button" onclick="nick();" value="Nick" />
|
||||||
{{if .Video}}
|
{{if .Video}}
|
||||||
<input type="button" class="button pretty-button" onclick="initPlayer();" value="Reload Player" />
|
<input type="button" class="button pretty-button" onclick="initPlayer();" value="Reload Player" />
|
||||||
|
@ -75,7 +75,10 @@
|
||||||
<input id="colorBlue" type="range" min="0" max="255" value="0" oninput="updateColor();" />
|
<input id="colorBlue" type="range" min="0" max="255" value="0" oninput="updateColor();" />
|
||||||
<span id="colorBlueLabel"></span>
|
<span id="colorBlueLabel"></span>
|
||||||
</div>
|
</div>
|
||||||
<div id="colorName" class="range-div" style="font-weight: bold;">
|
<div class="range-div">
|
||||||
|
<select id="colorSelect" onchange="colorSelectChange();"></select>
|
||||||
|
</div>
|
||||||
|
<div id="colorName" class="range-div">
|
||||||
NAME
|
NAME
|
||||||
</div>
|
</div>
|
||||||
<div id="colorWarning" class="range-div contrast">
|
<div id="colorWarning" class="range-div contrast">
|
||||||
|
|
10
wasm/main.go
10
wasm/main.go
|
@ -189,6 +189,16 @@ func main() {
|
||||||
js.Set("debugValues", js.CallbackOf(debugValues))
|
js.Set("debugValues", js.CallbackOf(debugValues))
|
||||||
js.Set("showTimestamp", js.CallbackOf(showTimestamp))
|
js.Set("showTimestamp", js.CallbackOf(showTimestamp))
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
inner := `<option value=""></option>`
|
||||||
|
for _, c := range common.Colors {
|
||||||
|
inner += fmt.Sprintf(`<option value="%s">%s</option>\n`, c, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
js.Get("colorSelect").Set("innerHTML", inner)
|
||||||
|
}()
|
||||||
|
|
||||||
// This is needed so the goroutine does not end
|
// This is needed so the goroutine does not end
|
||||||
for {
|
for {
|
||||||
// heatbeat to keep connection alive to deal with nginx
|
// heatbeat to keep connection alive to deal with nginx
|
||||||
|
|
Loading…
Reference in New Issue