Skip to content

Commit a550d37

Browse files
authored
Merge pull request #6847 from The-K-R-O-K/illia-malachyn/6845-unify-subscription-and-message-id
[Access] Unify subscription id with client message id
2 parents fedc48a + fe70a58 commit a550d37

33 files changed

+362
-238
lines changed

engine/access/rest/websockets/controller.go

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,12 @@ import (
7777
"encoding/json"
7878
"errors"
7979
"fmt"
80+
"net/http"
8081
"sync"
8182
"time"
8283

8384
"golang.org/x/time/rate"
8485

85-
"github.com/google/uuid"
8686
"github.com/gorilla/websocket"
8787
"github.com/rs/zerolog"
8888
"golang.org/x/sync/errgroup"
@@ -129,7 +129,7 @@ type Controller struct {
129129
// issues such as sending on a closed channel while maintaining proper cleanup.
130130
multiplexedStream chan interface{}
131131

132-
dataProviders *concurrentmap.Map[uuid.UUID, dp.DataProvider]
132+
dataProviders *concurrentmap.Map[SubscriptionID, dp.DataProvider]
133133
dataProviderFactory dp.DataProviderFactory
134134
dataProvidersGroup *sync.WaitGroup
135135
limiter *rate.Limiter
@@ -146,7 +146,7 @@ func NewWebSocketController(
146146
config: config,
147147
conn: conn,
148148
multiplexedStream: make(chan interface{}),
149-
dataProviders: concurrentmap.New[uuid.UUID, dp.DataProvider](),
149+
dataProviders: concurrentmap.New[SubscriptionID, dp.DataProvider](),
150150
dataProviderFactory: dataProviderFactory,
151151
dataProvidersGroup: &sync.WaitGroup{},
152152
limiter: rate.NewLimiter(rate.Limit(config.MaxResponsesPerSecond), 1),
@@ -246,7 +246,7 @@ func (c *Controller) keepalive(ctx context.Context) error {
246246
// If no messages are sent within InactivityTimeout and no active data providers exist,
247247
// the connection will be closed.
248248
func (c *Controller) writeMessages(ctx context.Context) error {
249-
inactivityTicker := time.NewTicker(c.config.InactivityTimeout / 10)
249+
inactivityTicker := time.NewTicker(c.inactivityTickerPeriod())
250250
defer inactivityTicker.Stop()
251251

252252
lastMessageSentAt := time.Now()
@@ -301,6 +301,10 @@ func (c *Controller) writeMessages(ctx context.Context) error {
301301
}
302302
}
303303

304+
func (c *Controller) inactivityTickerPeriod() time.Duration {
305+
return c.config.InactivityTimeout / 10
306+
}
307+
304308
// readMessages continuously reads messages from a client WebSocket connection,
305309
// validates each message, and processes it based on the message type.
306310
func (c *Controller) readMessages(ctx context.Context) error {
@@ -314,7 +318,8 @@ func (c *Controller) readMessages(ctx context.Context) error {
314318
c.writeErrorResponse(
315319
ctx,
316320
err,
317-
wrapErrorMessage(InvalidMessage, "error reading message", "", "", ""))
321+
wrapErrorMessage(http.StatusBadRequest, "error reading message", "", ""),
322+
)
318323
continue
319324
}
320325

@@ -323,7 +328,8 @@ func (c *Controller) readMessages(ctx context.Context) error {
323328
c.writeErrorResponse(
324329
ctx,
325330
err,
326-
wrapErrorMessage(InvalidMessage, "error parsing message", "", "", ""))
331+
wrapErrorMessage(http.StatusBadRequest, "error parsing message", "", ""),
332+
)
327333
continue
328334
}
329335
}
@@ -366,24 +372,34 @@ func (c *Controller) handleMessage(ctx context.Context, message json.RawMessage)
366372
}
367373

368374
func (c *Controller) handleSubscribe(ctx context.Context, msg models.SubscribeMessageRequest) {
375+
subscriptionID, err := c.parseOrCreateSubscriptionID(msg.SubscriptionID)
376+
if err != nil {
377+
c.writeErrorResponse(
378+
ctx,
379+
err,
380+
wrapErrorMessage(http.StatusBadRequest, "error parsing subscription id",
381+
models.SubscribeAction, msg.SubscriptionID),
382+
)
383+
return
384+
}
385+
369386
// register new provider
370-
provider, err := c.dataProviderFactory.NewDataProvider(ctx, msg.Topic, msg.Arguments, c.multiplexedStream)
387+
provider, err := c.dataProviderFactory.NewDataProvider(ctx, subscriptionID.String(), msg.Topic, msg.Arguments, c.multiplexedStream)
371388
if err != nil {
372389
c.writeErrorResponse(
373390
ctx,
374391
err,
375-
wrapErrorMessage(InvalidArgument, "error creating data provider", msg.ClientMessageID, models.SubscribeAction, ""),
392+
wrapErrorMessage(http.StatusBadRequest, "error creating data provider",
393+
models.SubscribeAction, subscriptionID.String()),
376394
)
377395
return
378396
}
379-
c.dataProviders.Add(provider.ID(), provider)
397+
c.dataProviders.Add(subscriptionID, provider)
380398

381399
// write OK response to client
382400
responseOk := models.SubscribeMessageResponse{
383401
BaseMessageResponse: models.BaseMessageResponse{
384-
ClientMessageID: msg.ClientMessageID,
385-
Success: true,
386-
SubscriptionID: provider.ID().String(),
402+
SubscriptionID: subscriptionID.String(),
387403
},
388404
}
389405
c.writeResponse(ctx, responseOk)
@@ -396,72 +412,63 @@ func (c *Controller) handleSubscribe(ctx context.Context, msg models.SubscribeMe
396412
c.writeErrorResponse(
397413
ctx,
398414
err,
399-
wrapErrorMessage(SubscriptionError, "subscription finished with error", "", "", ""),
415+
wrapErrorMessage(http.StatusInternalServerError, "internal error",
416+
models.SubscribeAction, subscriptionID.String()),
400417
)
401418
}
402419

403420
c.dataProvidersGroup.Done()
404-
c.dataProviders.Remove(provider.ID())
421+
c.dataProviders.Remove(subscriptionID)
405422
}()
406423
}
407424

408425
func (c *Controller) handleUnsubscribe(ctx context.Context, msg models.UnsubscribeMessageRequest) {
409-
id, err := uuid.Parse(msg.SubscriptionID)
426+
subscriptionID, err := ParseClientSubscriptionID(msg.SubscriptionID)
410427
if err != nil {
411428
c.writeErrorResponse(
412429
ctx,
413430
err,
414-
wrapErrorMessage(InvalidArgument, "error parsing subscription ID", msg.ClientMessageID, models.UnsubscribeAction, msg.SubscriptionID),
431+
wrapErrorMessage(http.StatusBadRequest, "error parsing subscription id",
432+
models.UnsubscribeAction, msg.SubscriptionID),
415433
)
416434
return
417435
}
418436

419-
provider, ok := c.dataProviders.Get(id)
437+
provider, ok := c.dataProviders.Get(subscriptionID)
420438
if !ok {
421439
c.writeErrorResponse(
422440
ctx,
423441
err,
424-
wrapErrorMessage(NotFound, "subscription not found", msg.ClientMessageID, models.UnsubscribeAction, msg.SubscriptionID),
442+
wrapErrorMessage(http.StatusNotFound, "subscription not found",
443+
models.UnsubscribeAction, subscriptionID.String()),
425444
)
426445
return
427446
}
428447

429448
provider.Close()
430-
c.dataProviders.Remove(id)
449+
c.dataProviders.Remove(subscriptionID)
431450

432451
responseOk := models.UnsubscribeMessageResponse{
433452
BaseMessageResponse: models.BaseMessageResponse{
434-
ClientMessageID: msg.ClientMessageID,
435-
Success: true,
436-
SubscriptionID: msg.SubscriptionID,
453+
SubscriptionID: subscriptionID.String(),
437454
},
438455
}
439456
c.writeResponse(ctx, responseOk)
440457
}
441458

442-
func (c *Controller) handleListSubscriptions(ctx context.Context, msg models.ListSubscriptionsMessageRequest) {
459+
func (c *Controller) handleListSubscriptions(ctx context.Context, _ models.ListSubscriptionsMessageRequest) {
443460
var subs []*models.SubscriptionEntry
444-
err := c.dataProviders.ForEach(func(id uuid.UUID, provider dp.DataProvider) error {
461+
_ = c.dataProviders.ForEach(func(id SubscriptionID, provider dp.DataProvider) error {
445462
subs = append(subs, &models.SubscriptionEntry{
446-
ID: id.String(),
447-
Topic: provider.Topic(),
463+
SubscriptionID: id.String(),
464+
Topic: provider.Topic(),
448465
})
449466
return nil
450467
})
451468

452-
if err != nil {
453-
c.writeErrorResponse(
454-
ctx,
455-
err,
456-
wrapErrorMessage(NotFound, "error listing subscriptions", msg.ClientMessageID, models.ListSubscriptionsAction, ""),
457-
)
458-
return
459-
}
460-
461469
responseOk := models.ListSubscriptionsMessageResponse{
462-
Success: true,
463-
ClientMessageID: msg.ClientMessageID,
464-
Subscriptions: subs,
470+
Subscriptions: subs,
471+
Action: models.ListSubscriptionsAction,
465472
}
466473
c.writeResponse(ctx, responseOk)
467474
}
@@ -472,13 +479,10 @@ func (c *Controller) shutdownConnection() {
472479
c.logger.Debug().Err(err).Msg("error closing connection")
473480
}
474481

475-
err = c.dataProviders.ForEach(func(_ uuid.UUID, provider dp.DataProvider) error {
482+
_ = c.dataProviders.ForEach(func(_ SubscriptionID, provider dp.DataProvider) error {
476483
provider.Close()
477484
return nil
478485
})
479-
if err != nil {
480-
c.logger.Debug().Err(err).Msg("error closing data provider")
481-
}
482486

483487
c.dataProviders.Clear()
484488
c.dataProvidersGroup.Wait()
@@ -498,15 +502,26 @@ func (c *Controller) writeResponse(ctx context.Context, response interface{}) {
498502
}
499503
}
500504

501-
func wrapErrorMessage(code Code, message string, msgId string, action string, subscriptionID string) models.BaseMessageResponse {
505+
func wrapErrorMessage(code int, message string, action string, subscriptionID string) models.BaseMessageResponse {
502506
return models.BaseMessageResponse{
503-
ClientMessageID: msgId,
504-
Success: false,
505-
SubscriptionID: subscriptionID,
507+
SubscriptionID: subscriptionID,
506508
Error: models.ErrorMessage{
507-
Code: int(code),
509+
Code: code,
508510
Message: message,
509-
Action: action,
510511
},
512+
Action: action,
511513
}
512514
}
515+
516+
func (c *Controller) parseOrCreateSubscriptionID(id string) (SubscriptionID, error) {
517+
newId, err := NewSubscriptionID(id)
518+
if err != nil {
519+
return SubscriptionID{}, err
520+
}
521+
522+
if c.dataProviders.Has(newId) {
523+
return SubscriptionID{}, fmt.Errorf("subscription ID is already in use: %s", newId)
524+
}
525+
526+
return newId, nil
527+
}

0 commit comments

Comments
 (0)