package routing import ( "context" "errors" "sync" "time" "gitlab.michelsen.id/phillmichelsen/tessera/pkg/data" ) type InprocRouter struct { mu sync.RWMutex streams map[data.StreamID]*inprocStream } func NewInprocRouter() *InprocRouter { return &InprocRouter{ streams: make(map[data.StreamID]*inprocStream), } } func (r *InprocRouter) OpenStream(id data.StreamID) (data.Stream, error) { r.mu.Lock() defer r.mu.Unlock() s := r.streams[id] if s != nil { return s, nil } s = newInprocStream(id) r.streams[id] = s return s, nil } type inprocStream struct { id data.StreamID seq uint64 latest data.Envelope streamClosed bool mu sync.RWMutex } func newInprocStream(id data.StreamID) *inprocStream { return &inprocStream{ id: id, } } func (s *inprocStream) ID() data.StreamID { return s.id } func (s *inprocStream) Sender() data.Sender { return &inprocSender{stream: s} } func (s *inprocStream) Receiver() data.Receiver { s.mu.RLock() cur := s.seq s.mu.RUnlock() return &inprocReceiver{ stream: s, lastSeenSeq: cur, } } type inprocSender struct { stream *inprocStream } func (tx *inprocSender) Send(ctx context.Context, env data.Envelope) error { if err := ctx.Err(); err != nil { return err } s := tx.stream s.mu.Lock() defer s.mu.Unlock() if s.streamClosed { return errors.New("stream closed") } env.SendTime = time.Now().UTC() s.seq++ s.latest = env return nil } func (tx *inprocSender) SendBatch(ctx context.Context, envs []data.Envelope) error { panic("unimplemented") } type inprocReceiver struct { stream *inprocStream lastSeenSeq uint64 } func (rx *inprocReceiver) TryReceive() (data.Envelope, bool, error) { s := rx.stream s.mu.RLock() defer s.mu.RUnlock() if s.streamClosed { return data.Envelope{}, false, errors.New("stream closed") } if s.seq == 0 || s.seq == rx.lastSeenSeq { return data.Envelope{}, false, nil } rx.lastSeenSeq = s.seq return s.latest, true, nil } func (rx *inprocReceiver) ReceiveNext(ctx context.Context) (data.Envelope, error) { panic("unimplemented") } func (rx *inprocReceiver) Seq() uint64 { return rx.lastSeenSeq }