MCPcopy Index your code
hub / github.com/coder/coder / OneWayWebSocketEventSender

Function OneWayWebSocketEventSender

coderd/httpapi/httpapi.go:422–511  ·  view source on GitHub ↗

OneWayWebSocketEventSender establishes a new WebSocket connection that enforces one-way communication from the server to the client. The function returned allows you to send a single message to the client, while the channel lets you listen for when the connection closes. We must use an approach li

(log slog.Logger)

Source from the content-addressed store, hash-verified

420// WebSockets have no such limitation, no matter what HTTP protocol was used to
421// establish the connection.
422func OneWayWebSocketEventSender(log slog.Logger) func(rw http.ResponseWriter, r *http.Request) (
423 func(event codersdk.ServerSentEvent) error,
424 <-chan struct{},
425 error,
426) {
427 return func(rw http.ResponseWriter, r *http.Request) (
428 func(event codersdk.ServerSentEvent) error,
429 <-chan struct{},
430 error,
431 ) {
432 ctx, cancel := context.WithCancel(r.Context())
433 r = r.WithContext(ctx)
434 socket, err := websocket.Accept(rw, r, nil)
435 if err != nil {
436 cancel()
437 return nil, nil, xerrors.Errorf("cannot establish connection: %w", err)
438 }
439 go HeartbeatClose(ctx, log, cancel, socket)
440
441 eventC := make(chan codersdk.ServerSentEvent, 64)
442 socketErrC := make(chan websocket.CloseError, 1)
443 closed := make(chan struct{})
444 go func() {
445 defer cancel()
446 defer close(closed)
447
448 for {
449 select {
450 case event := <-eventC:
451 writeCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
452 err := wsjson.Write(writeCtx, socket, event)
453 cancel()
454 if err == nil {
455 continue
456 }
457 _ = socket.Close(websocket.StatusInternalError, "Unable to send newest message")
458 case err := <-socketErrC:
459 _ = socket.Close(err.Code, err.Reason)
460 case <-ctx.Done():
461 _ = socket.Close(websocket.StatusNormalClosure, "Connection closed")
462 }
463 return
464 }
465 }()
466
467 // We have some tools in the UI code to help enforce one-way WebSocket
468 // connections, but there's still the possibility that the client could send
469 // a message when it's not supposed to. If that happens, the client likely
470 // forgot to use those tools, and communication probably can't be trusted.
471 // Better to just close the socket and force the UI to fix its mess
472 go func() {
473 _, _, err := socket.Read(ctx)
474 if errors.Is(err, context.Canceled) {
475 return
476 }
477 if err != nil {
478 socketErrC <- websocket.CloseError{
479 Code: websocket.StatusInternalError,

Callers 3

watchWorkspaceWSMethod · 0.92

Calls 11

HeartbeatCloseFunction · 0.85
WithContextMethod · 0.80
ErrMethod · 0.80
ContextMethod · 0.65
WriteMethod · 0.65
CloseMethod · 0.65
ReadMethod · 0.65
AcceptMethod · 0.45
ErrorfMethod · 0.45
DoneMethod · 0.45
IsMethod · 0.45

Tested by 1