From dfd11c94c1ad5261caa43128a39fcce550edf61d Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Thu, 27 Mar 2014 12:28:05 +0100 Subject: Chat now works on the client side --- chat/messages.go | 2 +- pages.go | 6 ++-- static/chat.js | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ static/style.css | 26 +++++++++++++++ tpls/chat.html | 16 +++++++-- websock.go | 15 +++++++-- 6 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 static/chat.js create mode 100644 static/style.css 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($("
  • ").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 = $("").addClass("nick").text(data.user); + var elemText = $("").addClass("msg").text(msgtext); + var logentry = $("
  • ").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 @@ - + {{.Roomname}} + + + + -{{ .Websock }} +

    {{.Roomname}}

    + + +
    + + +
    - \ No newline at end of file + 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) -- cgit v1.2.3-70-g09d2