summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chat/messages.go2
-rw-r--r--pages.go6
-rw-r--r--static/chat.js100
-rw-r--r--static/style.css26
-rw-r--r--tpls/chat.html16
-rw-r--r--websock.go15
6 files changed, 156 insertions, 9 deletions
diff --git a/chat/messages.go b/chat/messages.go
index dbcd150..eed62fa 100644
--- a/chat/messages.go
+++ b/chat/messages.go
@@ -26,7 +26,7 @@ func (mt MsgType) String() string {
return "???"
}
-func (mt *MsgType) MarshalJSON() ([]byte, error) {
+func (mt MsgType) MarshalJSON() ([]byte, error) {
return json.Marshal(mt.String())
}
diff --git a/pages.go b/pages.go
index 40c2c21..886f1d6 100644
--- a/pages.go
+++ b/pages.go
@@ -1,6 +1,7 @@
package main
import (
+ "github.com/gorilla/mux"
"html/template"
"net/http"
"path"
@@ -11,7 +12,7 @@ var (
)
type ChatpageData struct {
- Websock string
+ Websock, Roomname string
}
func PrepTemplates() {
@@ -24,5 +25,6 @@ func Home(rw http.ResponseWriter, req *http.Request) {
}
func Chatpage(rw http.ResponseWriter, req *http.Request) {
- TplChat.Execute(rw, ChatpageData{"ws://" + req.Host + req.URL.Path + "socket"})
+ vars := mux.Vars(req)
+ TplChat.Execute(rw, ChatpageData{"ws://" + req.Host + req.URL.Path + "socket", vars["chatroom"]})
}
diff --git a/static/chat.js b/static/chat.js
new file mode 100644
index 0000000..d9c89fe
--- /dev/null
+++ b/static/chat.js
@@ -0,0 +1,100 @@
+function askTryAgain(reason, ws_url) {
+ if(confirm("Could not join chat (Reason: "+ reason +"). Try again?")) {
+ window.setTimeout(RunChat, 1, ws_url); // We use a timeout, so we don't accidentally fill up the call stack.
+ }
+}
+
+function addBuddy(nick) {
+ var found = false;
+ $("#buddies li").each(function(index) {
+ if($(this).text() == nick) {
+ found = true;
+ }
+ });
+ if(!found) {
+ $("#buddies").append($("<li/>").text(nick));
+ }
+}
+
+function removeBuddy(nick) {
+ $("#buddies li").each(function(index) {
+ var self = $(this);
+ if(self.text() == nick) {
+ self.remove();
+ }
+ });
+}
+
+function chatlogWriter(event) {
+ var data = JSON.parse(event.data);
+ var msgtext = "";
+ switch(data.type) {
+ case "chat":
+ msgtext = data.text;
+ break;
+ case "join":
+ msgtext = "joined the room";
+ addBuddy(data.user);
+ break;
+ case "leave":
+ msgtext = "left the room";
+ removeBuddy(data.user);
+ break;
+ }
+
+ var elemNick = $("<span/>").addClass("nick").text(data.user);
+ var elemText = $("<span/>").addClass("msg").text(msgtext);
+ var logentry = $("<li/>").addClass(data.type).append(elemNick).append(elemText);
+ $("#chatlog").append(logentry);
+ window.scrollTo(0, logentry.offset().top);
+}
+
+function initChatSender(ws) {
+ var send = function() {
+ var ct = $("#chattext")
+ ws.send(ct.prop("value"));
+ ct.prop("value","");
+ ct.focus();
+ };
+
+ $("#sendbtn").click(send);
+ $("#chattext").keyup(function(event) {
+ if(event.keyCode==13) {
+ send();
+ }
+ });
+}
+
+function Join(ws_url, nick) {
+ var ws = new WebSocket(ws_url, "chat");
+ ws.onopen = function(_) {
+ ws.send(nick);
+ ws.onmessage = function(event) {
+ var data = JSON.parse(event.data);
+ if(data.ok) {
+ ws.onmessage = chatlogWriter;
+ for(i in data.buddies) {
+ addBuddy(data.buddies[i]);
+ }
+ initChatSender(ws);
+ ws.onclose = function(_) {
+ alert("Connection lost. Try refreshing the page.");
+ };
+ } else {
+ ws.close();
+ askTryAgain(data.error, ws_url);
+ }
+ };
+ };
+}
+
+function RunChat(ws_url) {
+ var nick = "";
+ while(nick == "") {
+ nick = prompt("Choose a nickname");
+ if(nick === null) {
+ return;
+ }
+ }
+ Join(ws_url, nick);
+}
diff --git a/static/style.css b/static/style.css
new file mode 100644
index 0000000..00fe4a4
--- /dev/null
+++ b/static/style.css
@@ -0,0 +1,26 @@
+* {
+ font-family: sans-serif;
+}
+
+#chatlog {
+ display: table;
+ list-style: none;
+ margin: 0;
+ padding: 0
+}
+
+#chatlog li {
+ display: table-row;
+ margin: 0;
+ padding: 0;
+}
+
+#chatlog li .nick {
+ display: table-cell;
+ padding-right: 1ex;
+ font-weight: bold;
+}
+
+#chatlog li .msg {
+ display: table-cell;
+} \ No newline at end of file
diff --git a/tpls/chat.html b/tpls/chat.html
index c107b49..27ad69f 100644
--- a/tpls/chat.html
+++ b/tpls/chat.html
@@ -1,9 +1,19 @@
<!DOCTYPE html>
<html>
<head>
- <title></title>
+ <title>{{.Roomname}}</title>
+ <script type="text/javascript" src="/static/jquery.min.js"></script>
+ <script type="text/javascript" src="/static/chat.js"></script>
+ <script type="text/javascript">$("document").ready(function(){RunChat("{{.Websock}}");});</script>
+ <link rel="stylesheet" type="text/css" href="/static/style.css" />
</head>
<body>
-{{ .Websock }}
+ <h1>{{.Roomname}}</h1>
+ <ul id="buddies"></ul>
+ <ul id="chatlog"></ul>
+ <div id="chatinput">
+ <input type="text" name="chattext" id="chattext"/>
+ <button id="sendbtn">Chat</button>
+ </div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/websock.go b/websock.go
index bf4fabd..9734e65 100644
--- a/websock.go
+++ b/websock.go
@@ -43,11 +43,13 @@ func AcceptWebSock(rw http.ResponseWriter, req *http.Request) {
return
}
+ exit := make(chan struct{})
+
go func() {
var s string
for {
if websocket.Message.Receive(ws, &s) != nil {
- return
+ break
}
if s == "" {
@@ -56,11 +58,18 @@ func AcceptWebSock(rw http.ResponseWriter, req *http.Request) {
buddy.Say(s)
}
+
+ exit <- struct{}{}
}()
- for m := range buddy.Receive {
- if send(m) != nil {
+ for {
+ select {
+ case <-exit:
return
+ case m := <-buddy.Receive:
+ if send(m) != nil {
+ return
+ }
}
}
}).ServeHTTP(rw, req)