diff --git a/go.mod b/go.mod index 968c0663e00d2..24164f3680336 100644 --- a/go.mod +++ b/go.mod @@ -82,6 +82,7 @@ require ( github.com/msteinert/pam v1.1.0 github.com/nektos/act v0.2.48 github.com/niklasfasching/go-org v1.7.0 + github.com/olahol/melody v1.1.4 github.com/olivere/elastic/v7 v7.0.32 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc4 @@ -208,6 +209,7 @@ require ( github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/securecookie v1.1.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect diff --git a/go.sum b/go.sum index 4b92b1ee637d1..7e7baa15e4186 100644 --- a/go.sum +++ b/go.sum @@ -575,6 +575,8 @@ github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -824,6 +826,8 @@ github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olahol/melody v1.1.4 h1:RQHfKZkQmDxI0+SLZRNBCn4LiXdqxLKRGSkT8Dyoe/E= +github.com/olahol/melody v1.1.4/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E= diff --git a/routers/web/web.go b/routers/web/web.go index bbab9b37b5973..d944c4774a7f8 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -37,6 +37,7 @@ import ( "code.gitea.io/gitea/routers/web/user" user_setting "code.gitea.io/gitea/routers/web/user/setting" "code.gitea.io/gitea/routers/web/user/setting/security" + "code.gitea.io/gitea/routers/web/websocket" auth_service "code.gitea.io/gitea/services/auth" context_service "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" @@ -414,6 +415,8 @@ func registerRoutes(m *web.Route) { m.Any("/user/events", routing.MarkLongPolling, events.Events) + websocket.Init(m) + m.Group("/login/oauth", func() { m.Get("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) m.Post("/grant", web.Bind(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth) diff --git a/routers/web/websocket/websocket.go b/routers/web/websocket/websocket.go new file mode 100644 index 0000000000000..b03245786cc93 --- /dev/null +++ b/routers/web/websocket/websocket.go @@ -0,0 +1,27 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package websocket + +import ( + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/web" + + "github.com/olahol/melody" +) + +var m *melody.Melody + +func Init(r *web.Route) { + m = melody.New() + r.Any("/ws", WebSocket) + m.HandleMessage(HandleMessage) +} + +func WebSocket(ctx *context.Context) { + m.HandleRequest(ctx.Resp, ctx.Req) +} + +func HandleMessage(s *melody.Session, msg []byte) { + m.Broadcast(msg) +} diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 4dcf02d2dca90..fabe6dc283da0 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -7,6 +7,13 @@ export function initNotificationsTable() { const table = document.getElementById('notification_table'); if (!table) return; + const url = 'ws://' + window.location.host + '/ws'; + const ws = new WebSocket(url); + ws.addEventListener('message', (msg) => { + const line = now() + ' ' + msg.data + '\n'; + console.info(line); + }); + // when page restores from bfcache, delete previously clicked items window.addEventListener('pageshow', (e) => { if (e.persisted) { // page was restored from bfcache