snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
137
server/pkg/websocket/server.go
Normal file
137
server/pkg/websocket/server.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/auth"
|
||||
"github.com/cortezaproject/corteza/server/pkg/errors"
|
||||
"github.com/cortezaproject/corteza/server/pkg/options"
|
||||
"github.com/cortezaproject/corteza/server/pkg/slice"
|
||||
"github.com/gorilla/websocket"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type (
|
||||
tokenValidator func(context.Context, string) (auth.Identifiable, error)
|
||||
|
||||
server struct {
|
||||
config options.WebsocketOpt
|
||||
logger *zap.Logger
|
||||
|
||||
// user id => session id => session
|
||||
sessions map[uint64]map[uint64]io.Writer
|
||||
|
||||
// keep lock on session map changes
|
||||
l sync.RWMutex
|
||||
|
||||
tokenValidator tokenValidator
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// upgrader handles websocket requests from peers
|
||||
upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
|
||||
// Allow connections from any Origin
|
||||
CheckOrigin: func(r *http.Request) bool { return true },
|
||||
}
|
||||
)
|
||||
|
||||
func Server(logger *zap.Logger, config options.WebsocketOpt, tv tokenValidator) *server {
|
||||
if !config.LogEnabled {
|
||||
logger = zap.NewNop()
|
||||
}
|
||||
|
||||
return &server{
|
||||
config: config,
|
||||
logger: logger.Named("websocket"),
|
||||
sessions: make(map[uint64]map[uint64]io.Writer),
|
||||
tokenValidator: tv,
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *server) Open(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if _, ok := err.(websocket.HandshakeError); ok {
|
||||
errors.ProperlyServeHTTP(w, r, errors.Internal("need a websocket handshake"), false)
|
||||
return
|
||||
} else if err != nil {
|
||||
errors.ProperlyServeHTTP(w, r, errors.Internal("failed to upgrade connection").Wrap(err), false)
|
||||
return
|
||||
}
|
||||
|
||||
// init new session
|
||||
//
|
||||
// session will add itself back to server's session map when
|
||||
// ready (if user authenticates itself)
|
||||
ses := Session(ctx, ws, conn)
|
||||
|
||||
if err = ses.Handle(); err != nil {
|
||||
ws.logger.Warn("websocket session handler error", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// Send delivers payload to one, more or all users
|
||||
//
|
||||
// Omit userIDs to deliver to ALL users
|
||||
func (ws *server) Send(t string, payload interface{}, userIDs ...uint64) error {
|
||||
pb, err := MarshalPayload(t, payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var (
|
||||
sendToAll = len(userIDs) == 0
|
||||
uMap = slice.ToUint64BoolMap(userIDs)
|
||||
)
|
||||
|
||||
ws.l.RLock()
|
||||
defer ws.l.RUnlock()
|
||||
|
||||
for uid := range ws.sessions {
|
||||
if sendToAll || (!sendToAll && uMap[uid]) {
|
||||
for _, s := range ws.sessions[uid] {
|
||||
_, err = s.Write(pb)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ws *server) StoreSession(s *session) {
|
||||
ws.l.Lock()
|
||||
defer ws.l.Unlock()
|
||||
if i := s.Identity(); i != nil {
|
||||
ws.storeSession(s, i.Identity(), s.id)
|
||||
}
|
||||
}
|
||||
|
||||
func (ws *server) storeSession(w io.Writer, uid, sid uint64) {
|
||||
if ws.sessions[uid] == nil {
|
||||
ws.sessions[uid] = make(map[uint64]io.Writer)
|
||||
|
||||
}
|
||||
|
||||
ws.sessions[uid][sid] = w
|
||||
}
|
||||
|
||||
func (ws *server) RemoveSession(s *session) {
|
||||
ws.l.Lock()
|
||||
defer ws.l.Unlock()
|
||||
if i := s.Identity(); i != nil {
|
||||
uid := i.Identity()
|
||||
delete(ws.sessions[uid], s.id)
|
||||
|
||||
if len(ws.sessions[uid]) == 0 {
|
||||
delete(ws.sessions, uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user