diff --git a/go.mod b/go.mod index 558c3b98dca468ec6647358600550ffe7c3ebfbb..94943d2332b9f03b9b413a8edb43428cc4a09e4d 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/gorilla/mux v1.7.3 github.com/gorilla/securecookie v1.1.1 github.com/gorilla/sessions v1.2.0 + github.com/gorilla/websocket v1.4.1 github.com/mattn/go-sqlite3 v1.11.0 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 xorm.io/core v0.7.0 diff --git a/go.sum b/go.sum index 85948584b1819909d1baeb0bda258829d5c75ae8..69b293090b12d38202b8416c0425d31a8871e796 100644 --- a/go.sum +++ b/go.sum @@ -54,6 +54,8 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= diff --git a/html/leaderboard.html b/html/leaderboard.html index 2855405a656373ac919092ac14b30701cdd50311..cb18d17c4dd7b9463534dfbb7a1408ba45a03c7e 100644 --- a/html/leaderboard.html +++ b/html/leaderboard.html @@ -1,7 +1,8 @@ {{ template "header" . }} <main class="flexcell gridcontainer-leader"> - <div id="table" class="col-0" style="width: 20%;"> + <div id="table" class="col-0 row-0" style="width: 20%;"> <table> + <tbody> <tr> <th>Name</th> <th>Points</th> @@ -12,22 +13,27 @@ <td>{{ .Points }}</td> </tr> {{ end }} + </tbody> </table> </div> - <div class="col-1" style="height: 100%;"> + <div class="col-1 row-0"> <canvas id="graph"></canvas> </div> <script src="static/Chart.bundle.min.js" type="text/javascript"></script> <script> + var score = {name: [{{ range .AllUsers }}{{ .DisplayName }},{{end}}], points: [ { label: "Points", data: [{{ range .AllUsers }}{{ .Points }},{{end}}]}] }; + var chart; + (function(){ var c = document.getElementById("graph").getContext('2d'); c.height = 800; - var chart = new Chart(c, { + + chart = new Chart(c, { type: 'horizontalBar', data: { - labels: [{{ range .AllUsers }}{{ .DisplayName }},{{end}}], - datasets: [ { label: "Points", data: [{{ range .AllUsers }}{{ .Points }},{{end}}]}] + labels: score.name, + datasets: score.points }, options: { scales: { @@ -45,6 +51,38 @@ responsive: true, }, }); + + ws = new WebSocket("ws://"+window.location.host+"/ws"); +ws.onopen = function() { + + // Web Socket is connected, send data uting send() + console.log("ws connected"); +}; +ws.onclose = function() { + alert("WS Disconnected, reload the page") +}; + +ws.onmessage = (evt)=>{ + var rec = evt.data; + console.log(evt.data); + score = JSON.parse(rec); + chart.data = { + labels: score.name, + datasets: [{data: score.points, label: "Solved Challenges" }] + }; + chart.update(); + table = document.getElementsByTagName("tbody")[0]; + table.innerHTML = "<tr><th>Name</th><th>Points</th></tr>"; + for(i=0; i < score.name.length; i++){ + row = table.insertRow(); + namecell = row.insertCell(); + namecell.innerHTML = score.name[i]; + pointcell = row.insertCell(); + pointcell.innerHTML = score.points[i]; + + } + +}; })(); </script> </main> diff --git a/internal/liveScoreboard.go b/internal/liveScoreboard.go new file mode 100644 index 0000000000000000000000000000000000000000..c281441bbb9f3d5b8c7ea245fa7991552c09e9c6 --- /dev/null +++ b/internal/liveScoreboard.go @@ -0,0 +1,94 @@ +package wtfd + +import ( + "encoding/json" + "github.com/gorilla/websocket" + "log" + "net/http" +) + +var ( + serverChan = make(chan chan string, 4) + messageChan = make(chan string, 1) + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } +) + +func leaderboardMessageServer(serverChan chan chan string) { + var clients []chan string + // And now we listen to new clients and new messages: + for { + select { + case client, _ := <-serverChan: + clients = append(clients, client) + case msg, _ := <-messageChan: + // Send the uptime to all connected clients: + for _, c := range clients { + c <- msg + } + } + } +} + +func leaderboardServer(serverChan chan chan string) { + var clients []chan string + for { + select { + case client, _ := <-serverChan: + clients = append(clients, client) + } + } +} + +func leaderboardWS(w http.ResponseWriter, r *http.Request) { + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + log.Println(err) + } + return + } + client := make(chan string, 1) + serverChan <- client // i have no idea what this go magic is + + for { + select { + case text, _ := <-client: + writer, _ := ws.NextWriter(websocket.TextMessage) + writer.Write([]byte(text)) + writer.Close() + } + } + +} + +func updateScoreboard() error { + log.Printf("Scoreboard Update\n") + type userNamePoints struct { + Name []string `json:"name"` + Points []int `json:"points"` + } + var name []string + var points []int + allu, err := ormAllUsersSortedByPoints() + if err != nil { + log.Printf("Scoreboard Update Error: %v\n", err) + return err + } + for _, u := range allu { + name = append(name, u.DisplayName) + points = append(points, u.Points) + } + + json, err := json.Marshal(&userNamePoints{Name: name, Points: points}) + if err != nil { + log.Printf("Scoreboard Update Error: %v\n", err) + return err + } + messageChan <- string(json) + log.Printf("Scoreboard Update String: %s\n", string(json)) + + return nil +} diff --git a/internal/server.go b/internal/server.go index c52a0ea4df28a9f0913eff2fe89e2435689dad5d..a410c59409bfd881dc4e67a7d3d570bca9ac33d0 100644 --- a/internal/server.go +++ b/internal/server.go @@ -1,15 +1,15 @@ package wtfd import ( + "encoding/base64" "encoding/gob" "encoding/json" - "encoding/base64" "errors" "fmt" "github.com/gomarkdown/markdown" "github.com/gorilla/mux" - "github.com/gorilla/sessions" "github.com/gorilla/securecookie" + "github.com/gorilla/sessions" "golang.org/x/crypto/bcrypt" "html/template" "io/ioutil" @@ -497,6 +497,7 @@ func submitFlag(w http.ResponseWriter, r *http.Request) { } _, _ = fmt.Fprintf(w, "correct") + _ = updateScoreboard() } else { _, _ = fmt.Fprintf(w, "not correct") @@ -533,7 +534,8 @@ func register(w http.ResponseWriter, r *http.Request) { _, _ = fmt.Fprintf(w, "Server Error: %v", err) } else { _ = ormNewUser(u) - login(w,r) + login(w, r) + _ = updateScoreboard() } @@ -732,6 +734,7 @@ func Server() error { if err != nil { return err } + go leaderboardMessageServer(serverChan) // Http sturf r := mux.NewRouter() r.HandleFunc("/", mainpage) @@ -741,6 +744,7 @@ func Server() error { r.HandleFunc("/logout", logout) r.HandleFunc("/register", register) r.HandleFunc("/submitflag", submitFlag) + r.HandleFunc("/ws", leaderboardWS) r.HandleFunc("/{chall}", mainpage) r.HandleFunc("/detailview/{chall}", detailview) r.HandleFunc("/solutionview/{chall}", solutionview)