SubscribeAuthorized subscribes an already-authorized chat to merged stream updates. The passed chat row proves authorization, but SubscribeAuthorized still reloads the chat after the stream subscriptions are armed so the initial status and relay setup use fresh state.
( ctx context.Context, chat database.Chat, requestHeader http.Header, afterMessageID int64, )
| 4957 | // still reloads the chat after the stream subscriptions are armed so the |
| 4958 | // initial status and relay setup use fresh state. |
| 4959 | func (p *Server) SubscribeAuthorized( |
| 4960 | ctx context.Context, |
| 4961 | chat database.Chat, |
| 4962 | requestHeader http.Header, |
| 4963 | afterMessageID int64, |
| 4964 | ) ( |
| 4965 | []codersdk.ChatStreamEvent, |
| 4966 | <-chan codersdk.ChatStreamEvent, |
| 4967 | func(), |
| 4968 | bool, |
| 4969 | ) { |
| 4970 | if p == nil { |
| 4971 | return nil, nil, nil, false |
| 4972 | } |
| 4973 | chatID := chat.ID |
| 4974 | |
| 4975 | // Subscribe to the local stream for message_parts and same-replica |
| 4976 | // persisted messages. Capture the current retry phase under the same |
| 4977 | // lock so the transient snapshot and subscriber registration reflect |
| 4978 | // a single moment in time. |
| 4979 | localSnapshot, localRetry, localParts, localCancel := p.subscribeToStream(chatID) |
| 4980 | |
| 4981 | // Merge all event sources. |
| 4982 | mergedCtx, mergedCancel := context.WithCancel(ctx) |
| 4983 | mergedEvents := make(chan codersdk.ChatStreamEvent, 128) |
| 4984 | |
| 4985 | var allCancels []func() |
| 4986 | allCancels = append(allCancels, localCancel) |
| 4987 | |
| 4988 | // Subscribe to pubsub for durable and structured control |
| 4989 | // events (status, messages, queue updates, retry, errors). |
| 4990 | // When pubsub is nil (e.g. in-memory |
| 4991 | // single-instance) we skip this and deliver all local events. |
| 4992 | // |
| 4993 | // This MUST happen before the DB queries below so that any |
| 4994 | // notification published between the query and the subscription |
| 4995 | // is not lost (subscribe-first-then-query pattern). |
| 4996 | var notifications <-chan coderdpubsub.ChatStreamNotifyMessage |
| 4997 | var errCh <-chan error |
| 4998 | if p.pubsub != nil { |
| 4999 | notifyCh := make(chan coderdpubsub.ChatStreamNotifyMessage, 10) |
| 5000 | errNotifyCh := make(chan error, 1) |
| 5001 | notifications = notifyCh |
| 5002 | errCh = errNotifyCh |
| 5003 | |
| 5004 | listener := func(_ context.Context, message []byte, listenErr error) { |
| 5005 | if listenErr != nil { |
| 5006 | select { |
| 5007 | case <-mergedCtx.Done(): |
| 5008 | case errNotifyCh <- listenErr: |
| 5009 | } |
| 5010 | return |
| 5011 | } |
| 5012 | var notify coderdpubsub.ChatStreamNotifyMessage |
| 5013 | if unmarshalErr := json.Unmarshal(message, ¬ify); unmarshalErr != nil { |
| 5014 | select { |
| 5015 | case <-mergedCtx.Done(): |
| 5016 | case errNotifyCh <- xerrors.Errorf("unmarshal chat stream notify: %w", unmarshalErr): |