package proxy import ( "log" "time" ) type Producer interface { IsAlive() bool Produce(MacVerifier) (Packet, error) } type Consumer interface { IsAlive() bool Consume(Packet, MacGenerator) error } type Reconnectable interface { Reconnect() error } type Source interface { Source() (Packet, error) } type Sink interface { Sink(packet Packet) error } type Proxy struct { Source Source Sink Sink Generator MacGenerator proxyChan chan Packet sinkChan chan Packet } func NewProxy(bufferSize int) *Proxy { return &Proxy{ proxyChan: make(chan Packet, bufferSize), sinkChan: make(chan Packet, bufferSize), } } func (p Proxy) Start() { go func() { for { if packet, err := p.Source.Source(); err != nil { panic(err) return } else { p.proxyChan <- packet } } }() go func() { for { packet := <-p.sinkChan if err := p.Sink.Sink(packet); err != nil { panic(err) return } } }() } func (p Proxy) AddConsumer(c Consumer) { go func() { _, reconnectable := c.(Reconnectable) for once := true; reconnectable || once; once = false { if reconnectable { var err error for once := true; err != nil || once; once = false { log.Printf("attempting to connect consumer `%v`\n", c) err = c.(Reconnectable).Reconnect() if !once { time.Sleep(time.Second) } } log.Printf("connected consumer `%v`\n", c) } for c.IsAlive() { if err := c.Consume(<-p.proxyChan, p.Generator); err != nil { log.Println(err) break } } } log.Printf("closed consumer `%v`\n", c) }() } func (p Proxy) AddProducer(pr Producer, v MacVerifier) { go func() { _, reconnectable := pr.(Reconnectable) for once := true; reconnectable || once; once = false { if reconnectable { var err error for once := true; err != nil || once; once = false { log.Printf("attempting to connect producer `%v`\n", pr) err = pr.(Reconnectable).Reconnect() if !once { time.Sleep(time.Second) } } log.Printf("connected producer `%v`\n", pr) } for pr.IsAlive() { if packet, err := pr.Produce(v); err != nil { log.Println(err) break } else { p.sinkChan <- packet } } } log.Printf("closed producer `%v`\n", pr) }() }