131 lines
2.1 KiB
Go
131 lines
2.1 KiB
Go
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
|
|
}
|