Wrote embassy
This commit is contained in:
+186
-9
@@ -2,7 +2,9 @@ package prism
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.wisehodl.dev/jay/go-honeybee"
|
||||
"git.wisehodl.dev/jay/go-mana-component"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -39,6 +41,7 @@ type PoolEventKind = int
|
||||
const (
|
||||
EventConnected PoolEventKind = iota
|
||||
EventDisconnected
|
||||
EventAdded
|
||||
EventRemoved
|
||||
)
|
||||
|
||||
@@ -48,6 +51,15 @@ type PoolEvent struct {
|
||||
At time.Time
|
||||
}
|
||||
|
||||
func NewPoolEvent(id string, kind PoolEventKind, at time.Time) PoolEvent {
|
||||
return PoolEvent{ID: id, Kind: kind, At: at}
|
||||
}
|
||||
|
||||
var convertPoolEvent = map[honeybee.OutboundPoolEventKind]PoolEventKind{
|
||||
honeybee.OutboundEventConnected: EventConnected,
|
||||
honeybee.OutboundEventDisconnected: EventDisconnected,
|
||||
}
|
||||
|
||||
// Adapter
|
||||
|
||||
type Adapter interface {
|
||||
@@ -92,40 +104,205 @@ type Hotel struct {
|
||||
// Embassy (Outbound Adapter)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
func NewEmbassy() *Embassy {
|
||||
return nil
|
||||
func NewEmbassy(
|
||||
ctx context.Context,
|
||||
pool EmbassyPlugin,
|
||||
jc *JournalCollector,
|
||||
handler slog.Handler,
|
||||
) *Embassy {
|
||||
ctx, cancel := context.WithCancel(
|
||||
component.MustNew(ctx, "prism", "embassy"))
|
||||
|
||||
e := &Embassy{
|
||||
pool: pool,
|
||||
peers: make(map[string]bool),
|
||||
eventSubs: make([]chan PoolEvent, 0),
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
if jc != nil {
|
||||
e.journals = make(chan JournalEntry, 16)
|
||||
jc.Enroll(e.journals)
|
||||
}
|
||||
|
||||
if handler != nil {
|
||||
c, ok := component.Get(ctx)
|
||||
if ok {
|
||||
e.logger = slog.New(handler).With(slog.Any("component", c))
|
||||
}
|
||||
}
|
||||
|
||||
e.wg.Add(1)
|
||||
go e.runEventRouter()
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Embassy) Dispatch(url string) error {
|
||||
url, err := honeybee.NormalizeURL(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid url: %s", url)
|
||||
}
|
||||
|
||||
if err := e.pool.Connect(url); err != nil {
|
||||
return fmt.Errorf("dispatch: %w", err)
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
e.peers[url] = false
|
||||
subs := e.eventSubs
|
||||
e.mu.Unlock()
|
||||
|
||||
for _, ch := range subs {
|
||||
select {
|
||||
case <-e.ctx.Done():
|
||||
return fmt.Errorf("closing")
|
||||
case ch <- NewPoolEvent(url, EventAdded, time.Now()):
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Embassy) Dismiss(url string) error {
|
||||
url, err := honeybee.NormalizeURL(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid url: %s", url)
|
||||
}
|
||||
|
||||
if err := e.pool.Remove(url); err != nil {
|
||||
return fmt.Errorf("dismiss: %w", err)
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
delete(e.peers, url)
|
||||
subs := e.eventSubs
|
||||
e.mu.Unlock()
|
||||
|
||||
for _, ch := range subs {
|
||||
select {
|
||||
case <-e.ctx.Done():
|
||||
return fmt.Errorf("closing")
|
||||
case ch <- NewPoolEvent(url, EventRemoved, time.Now()):
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Embassy) Close() {}
|
||||
func (e *Embassy) Close() {
|
||||
e.mu.Lock()
|
||||
peers := e.peers
|
||||
e.peers = make(map[string]bool)
|
||||
e.mu.Unlock()
|
||||
|
||||
// dismiss peers
|
||||
for peer, _ := range peers {
|
||||
e.Dismiss(peer)
|
||||
}
|
||||
|
||||
e.cancel()
|
||||
e.wg.Wait()
|
||||
|
||||
e.mu.Lock()
|
||||
subs := e.eventSubs
|
||||
e.eventSubs = make([]chan PoolEvent, 0)
|
||||
e.mu.Unlock()
|
||||
|
||||
// close subs
|
||||
for _, sub := range subs {
|
||||
close(sub)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Embassy) Peers() []string {
|
||||
return nil
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
|
||||
peers := make([]string, 0, len(e.peers))
|
||||
for p, _ := range e.peers {
|
||||
peers = append(peers, p)
|
||||
}
|
||||
return peers
|
||||
}
|
||||
|
||||
func (e *Embassy) HasPeer(id string) bool {
|
||||
return false
|
||||
func (e *Embassy) HasPeer(url string) bool {
|
||||
url, err := honeybee.NormalizeURL(url)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
|
||||
_, ok := e.peers[url]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (e *Embassy) IsConnected(id string) bool {
|
||||
return false
|
||||
func (e *Embassy) IsConnected(url string) bool {
|
||||
url, err := honeybee.NormalizeURL(url)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
|
||||
connected, _ := e.peers[url]
|
||||
return connected
|
||||
}
|
||||
|
||||
func (e *Embassy) Subscribe() <-chan PoolEvent {
|
||||
return nil
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
ch := make(chan PoolEvent, 16)
|
||||
e.eventSubs = append(e.eventSubs, ch)
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
func (e *Embassy) Send(id string, data Envelope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Internal
|
||||
|
||||
func (e *Embassy) runEventRouter() {
|
||||
defer e.wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-e.ctx.Done():
|
||||
return
|
||||
case ev, ok := <-e.pool.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
kind := convertPoolEvent[ev.Kind]
|
||||
|
||||
e.mu.Lock()
|
||||
switch kind {
|
||||
case EventConnected:
|
||||
e.peers[ev.ID] = true
|
||||
case EventDisconnected:
|
||||
e.peers[ev.ID] = false
|
||||
}
|
||||
subs := e.eventSubs
|
||||
e.mu.Unlock()
|
||||
|
||||
for _, ch := range subs {
|
||||
select {
|
||||
case <-e.ctx.Done():
|
||||
case ch <- NewPoolEvent(ev.ID, kind, ev.At):
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Hotel (Inbound Adapter)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user