From ac036abe1535563b878b411c062c6523950980a8 Mon Sep 17 00:00:00 2001 From: Danielle Date: Fri, 22 Dec 2023 11:05:52 -0500 Subject: [PATCH] Replaces ws attribute with extension (#24) Co-authored-by: Benjamin Bengfort --- pkg/rtnl/rtnl.go | 2 +- pkg/rtnl/static/js/link-detail-chart.js | 54 +++++++++++++++++++++---- pkg/rtnl/static/styles/output.css | 12 +----- pkg/rtnl/templates/info.html | 2 +- pkg/rtnl/templates/layout/base.html | 5 ++- pkg/rtnl/web.go | 9 +++++ 6 files changed, 62 insertions(+), 22 deletions(-) diff --git a/pkg/rtnl/rtnl.go b/pkg/rtnl/rtnl.go index 1c9d37a..b0a1b4e 100644 --- a/pkg/rtnl/rtnl.go +++ b/pkg/rtnl/rtnl.go @@ -249,7 +249,7 @@ func (s *Server) Routes(router *gin.Engine) (err error) { // Heartbeat route (no authentication required) v1.GET("/status", s.Status) v1.POST("/shorten", s.Authenticate, s.ShortenURL) - v1.GET("/updates", s.Authenticate, s.Updates) + v1.GET("/updates", s.Updates) // TODO: add back authentication v1.GET("/links", s.Authenticate, s.ShortURLList) v1.POST("/links", s.Authenticate, s.ShortenURL) v1.GET("/links/:id", s.Authenticate, s.ShortURLInfo) diff --git a/pkg/rtnl/static/js/link-detail-chart.js b/pkg/rtnl/static/js/link-detail-chart.js index c41f4fd..268b555 100644 --- a/pkg/rtnl/static/js/link-detail-chart.js +++ b/pkg/rtnl/static/js/link-detail-chart.js @@ -1,14 +1,27 @@ -document.body.addEventListener('htmx:wsBeforeMessage', function(e) { - data = JSON.parse(e.detail.message); +function createWebSocket(url) { + var sock = new WebSocket(url); + sock.binaryType = "blob"; + sock.onerror = function(e) { + console.log(e); + } + + console.log(sock) + return sock; +} + +(function() { + // The chart labels are the data keys (hours) and the chart data is the values (number of clicks). + let data = {}; + + // Create the chart const ctx = document.getElementById('link-detail-chart'); - - new Chart(ctx, { + const chart = new Chart(ctx, { type: 'line', data: { - labels: data.Time, + labels: [], datasets: [{ label: 'URL Activity', - data: data.Views, + data: [], borderWidth: 1 }] }, @@ -20,5 +33,30 @@ document.body.addEventListener('htmx:wsBeforeMessage', function(e) { } } } -}); -}); + }); + + // Create a websocket connection + // TODO: get the link for the detail page. + const ws = createWebSocket("ws://localhost:8765/v1/updates"); + ws.onmessage = function(message) { + const click = JSON.parse(message.data); + if (data[click.time]) { + data[click.time] += click.views; + } else { + data[click.time] = click.views; + } + + let labels = []; + let values = []; + for (const key in data) { + labels.push(key); + values.push(data[key]); + } + + chart.labels = labels; + chart.data.datasets[0].data = data; + chart.update(); + }; + +})(); + diff --git a/pkg/rtnl/static/styles/output.css b/pkg/rtnl/static/styles/output.css index 995d83d..8dcdcdc 100644 --- a/pkg/rtnl/static/styles/output.css +++ b/pkg/rtnl/static/styles/output.css @@ -565,10 +565,6 @@ video { margin-bottom: 0.5rem; } -.mb-20 { - margin-bottom: 5rem; -} - .mb-6 { margin-bottom: 1.5rem; } @@ -585,18 +581,14 @@ video { margin-top: 3rem; } -.mt-20 { - margin-top: 5rem; +.mt-16 { + margin-top: 4rem; } .mt-4 { margin-top: 1rem; } -.mt-16 { - margin-top: 4rem; -} - .block { display: block; } diff --git a/pkg/rtnl/templates/info.html b/pkg/rtnl/templates/info.html index 033351e..2131be6 100644 --- a/pkg/rtnl/templates/info.html +++ b/pkg/rtnl/templates/info.html @@ -5,7 +5,7 @@ -
+
diff --git a/pkg/rtnl/templates/layout/base.html b/pkg/rtnl/templates/layout/base.html index 445bc92..534ceb2 100644 --- a/pkg/rtnl/templates/layout/base.html +++ b/pkg/rtnl/templates/layout/base.html @@ -10,7 +10,7 @@ - + {{ template "header" .}} @@ -22,7 +22,8 @@ {{ template "footer" .}} - + + {{ block "appcode" . }}{{ end }} diff --git a/pkg/rtnl/web.go b/pkg/rtnl/web.go index 95901d0..2cc4fe7 100644 --- a/pkg/rtnl/web.go +++ b/pkg/rtnl/web.go @@ -61,8 +61,17 @@ func (s *Server) Updates(c *gin.Context) { } defer sub.Close() + // TODO: write some initial data to the websocket to display the graph. + if err = conn.WriteJSON(api.Clicked(c)); err != nil { + log.Error().Err(err).Msg("could not send message to establish connection") + c.JSON(http.StatusInternalServerError, api.ErrorResponse(err)) + return + } + // In the meantime, just write data back to the server for event := range sub.C { + log.Debug().Msg("waiting for updates") + // Only publish click events to the updates stream if event.Type.Name != "Click" { continue