2019-07-25 16:02:47 +02:00
|
|
|
package v2
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
# Message passing between components
|
|
|
|
* output of one routine becomes input for all other routines
|
|
|
|
* avoid loops somehow
|
|
|
|
* Message priority
|
|
|
|
|
|
|
|
# Components have isolated lifecycle management
|
|
|
|
* Lifecycle management
|
|
|
|
* Setup
|
|
|
|
* Teardown
|
|
|
|
# Individual
|
|
|
|
* message passing should be non blocking
|
|
|
|
* backpressure between components
|
|
|
|
* Lifecycle management of components
|
|
|
|
* Observable behavior:
|
|
|
|
* progress
|
|
|
|
* blocking components
|
|
|
|
What would look a test look like?
|
|
|
|
Lifecycle management
|
|
|
|
Start/Stop
|
|
|
|
|
|
|
|
How to make this non blocking?
|
|
|
|
|
|
|
|
How to avoid Thread saturation
|
|
|
|
How to handle concurrency
|
|
|
|
*/
|
|
|
|
|
|
|
|
type testEvent struct {
|
|
|
|
msg string
|
|
|
|
time time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
type testEventTwo struct {
|
|
|
|
msg string
|
|
|
|
}
|
|
|
|
|
|
|
|
type stopEvent struct{}
|
2019-07-27 00:25:32 +02:00
|
|
|
type timeCheck struct {
|
|
|
|
time time.Time
|
|
|
|
}
|
2019-07-25 16:02:47 +02:00
|
|
|
|
2019-07-27 10:58:58 +02:00
|
|
|
// scheduler
|
|
|
|
|
|
|
|
type scheduler struct {
|
2019-07-27 00:25:32 +02:00
|
|
|
input chan Event
|
|
|
|
output chan Event
|
2019-07-25 16:02:47 +02:00
|
|
|
}
|
|
|
|
|
2019-07-27 10:58:58 +02:00
|
|
|
func newScheduler(output chan Event) *scheduler {
|
|
|
|
input := make(chan Event, 1)
|
|
|
|
return &scheduler{
|
|
|
|
input: input,
|
|
|
|
output: output,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hd *scheduler) run() {
|
|
|
|
fmt.Println("scheduler run")
|
2019-07-25 16:02:47 +02:00
|
|
|
for {
|
2019-07-27 00:25:32 +02:00
|
|
|
iEvent := <-hd.input
|
2019-07-27 10:58:58 +02:00
|
|
|
_, ok := iEvent.(stopEvent)
|
2019-07-27 00:25:32 +02:00
|
|
|
if ok {
|
2019-07-27 10:58:58 +02:00
|
|
|
fmt.Println("stopping scheduler")
|
2019-07-25 16:02:47 +02:00
|
|
|
break
|
|
|
|
}
|
2019-07-27 00:25:32 +02:00
|
|
|
oEvents := hd.handle(iEvent)
|
|
|
|
for _, event := range oEvents {
|
|
|
|
hd.output <- event
|
|
|
|
}
|
2019-07-25 16:02:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-27 10:58:58 +02:00
|
|
|
func (fs *scheduler) send(event Event) bool {
|
|
|
|
fmt.Println("scheduler send")
|
2019-07-27 00:25:32 +02:00
|
|
|
select {
|
|
|
|
case fs.input <- event:
|
|
|
|
return true
|
|
|
|
default:
|
2019-07-27 10:58:58 +02:00
|
|
|
fmt.Println("scheduler channel was full")
|
2019-07-27 00:25:32 +02:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (sc *scheduler) handle(event Event) Events {
|
2019-07-27 10:58:58 +02:00
|
|
|
switch event.(type) {
|
2019-07-27 00:25:32 +02:00
|
|
|
case timeCheck:
|
|
|
|
fmt.Println("scheduler handle timeCheck")
|
|
|
|
case testEvent:
|
|
|
|
fmt.Println("scheduler handle testEvent")
|
|
|
|
}
|
|
|
|
return Events{}
|
|
|
|
}
|
|
|
|
|
2019-07-27 10:58:58 +02:00
|
|
|
func (hd *scheduler) stop() {
|
|
|
|
fmt.Println("scheduler stop")
|
|
|
|
hd.input <- stopEvent{}
|
|
|
|
}
|
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
// processor
|
|
|
|
type processor struct {
|
2019-07-27 10:58:58 +02:00
|
|
|
input chan Event
|
|
|
|
output chan Event
|
2019-07-27 00:25:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func newProcessor(output chan Event) *processor {
|
2019-07-27 10:58:58 +02:00
|
|
|
input := make(chan Event, 1)
|
2019-07-27 00:25:32 +02:00
|
|
|
return &processor{
|
2019-07-27 10:58:58 +02:00
|
|
|
input: input,
|
|
|
|
output: output,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hd *processor) run() {
|
|
|
|
fmt.Println("processor run")
|
|
|
|
for {
|
|
|
|
iEvent := <-hd.input
|
|
|
|
_, ok := iEvent.(stopEvent)
|
|
|
|
if ok {
|
|
|
|
fmt.Println("stopping processor")
|
|
|
|
break
|
|
|
|
}
|
|
|
|
oEvents := hd.handle(iEvent)
|
|
|
|
for _, event := range oEvents {
|
|
|
|
hd.output <- event
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (fs *processor) send(event Event) bool {
|
|
|
|
fmt.Println("processor send")
|
|
|
|
select {
|
|
|
|
case fs.input <- event:
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
fmt.Println("processor channel was full")
|
|
|
|
return false
|
2019-07-25 16:02:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
func (sc *processor) handle(event Event) Events {
|
2019-07-27 10:58:58 +02:00
|
|
|
switch event.(type) {
|
2019-07-27 00:25:32 +02:00
|
|
|
case timeCheck:
|
2019-07-27 10:58:58 +02:00
|
|
|
fmt.Println("processor handle timeCheck")
|
2019-07-27 00:25:32 +02:00
|
|
|
case testEvent:
|
|
|
|
fmt.Println("processor handle testEvent")
|
|
|
|
}
|
|
|
|
return Events{}
|
|
|
|
}
|
|
|
|
|
2019-07-27 10:58:58 +02:00
|
|
|
func (hd *processor) stop() {
|
|
|
|
fmt.Println("processor stop")
|
|
|
|
hd.input <- stopEvent{}
|
|
|
|
}
|
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
// demuxer
|
|
|
|
type demuxer struct {
|
2019-07-27 10:58:58 +02:00
|
|
|
input chan Event
|
|
|
|
output chan Event
|
2019-07-27 00:25:32 +02:00
|
|
|
scheduler *scheduler
|
|
|
|
processor *processor
|
|
|
|
}
|
|
|
|
|
|
|
|
func newDemuxer(output chan Event, scheduler *scheduler, processor *processor) *demuxer {
|
2019-07-27 10:58:58 +02:00
|
|
|
input := make(chan Event, 1)
|
2019-07-27 00:25:32 +02:00
|
|
|
return &demuxer{
|
2019-07-27 10:58:58 +02:00
|
|
|
input: input,
|
|
|
|
output: output,
|
2019-07-27 00:25:32 +02:00
|
|
|
scheduler: scheduler,
|
|
|
|
processor: processor,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (dm *demuxer) run() {
|
2019-07-27 10:58:58 +02:00
|
|
|
fmt.Println("Running demuxer")
|
2019-07-25 16:02:47 +02:00
|
|
|
for {
|
2019-07-27 10:58:58 +02:00
|
|
|
event := <-dm.input
|
|
|
|
// event.time = time.Now()
|
|
|
|
received := dm.scheduler.send(event)
|
|
|
|
if !received {
|
|
|
|
panic("couldn't send to scheduler")
|
|
|
|
}
|
|
|
|
|
|
|
|
received = dm.processor.send(event)
|
|
|
|
if !received {
|
|
|
|
panic("couldn't send to the processor")
|
|
|
|
}
|
|
|
|
|
|
|
|
_, ok := event.(stopEvent)
|
|
|
|
if ok {
|
|
|
|
fmt.Println("demuxer stopping")
|
|
|
|
break
|
2019-07-25 16:02:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-27 10:58:58 +02:00
|
|
|
func (fs *demuxer) send(event Event) bool {
|
|
|
|
fmt.Println("demuxer send")
|
|
|
|
select {
|
|
|
|
case fs.input <- event:
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
fmt.Println("demuxer channel was full")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (hd *demuxer) stop() {
|
|
|
|
fmt.Println("demuxer stop")
|
|
|
|
hd.input <- stopEvent{}
|
|
|
|
}
|
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
// reactor
|
|
|
|
|
2019-07-25 16:02:47 +02:00
|
|
|
type DummyReactor struct {
|
2019-07-27 00:25:32 +02:00
|
|
|
events chan Event
|
|
|
|
demuxer *demuxer
|
2019-07-27 10:58:58 +02:00
|
|
|
ticker *time.Ticker
|
2019-07-25 16:02:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (dr *DummyReactor) Start() {
|
2019-07-27 00:25:32 +02:00
|
|
|
bufferSize := 10
|
|
|
|
events := make(chan Event, bufferSize)
|
|
|
|
|
|
|
|
scheduler := newScheduler(events)
|
|
|
|
processor := newProcessor(events)
|
|
|
|
dr.demuxer = newDemuxer(events, scheduler, processor)
|
2019-07-27 10:58:58 +02:00
|
|
|
dr.ticker = time.NewTicker(1 * time.Second)
|
2019-07-27 00:25:32 +02:00
|
|
|
|
|
|
|
go scheduler.run()
|
|
|
|
go processor.run()
|
|
|
|
go dr.demuxer.run()
|
2019-07-27 10:58:58 +02:00
|
|
|
go func() {
|
|
|
|
for t := range dr.ticker.C {
|
|
|
|
dr.demuxer.send(timeCheck{t})
|
|
|
|
}
|
|
|
|
}()
|
2019-07-25 16:02:47 +02:00
|
|
|
}
|
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
func (dr *DummyReactor) Stop() {
|
2019-07-27 10:58:58 +02:00
|
|
|
// this should be synchronous
|
|
|
|
dr.ticker.Stop()
|
|
|
|
dr.demuxer.stop()
|
2019-07-27 00:25:32 +02:00
|
|
|
}
|
2019-07-25 16:02:47 +02:00
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
func (dr *DummyReactor) Receive(event Event) {
|
2019-07-27 10:58:58 +02:00
|
|
|
fmt.Println("receive event")
|
2019-07-27 00:25:32 +02:00
|
|
|
sent := dr.demuxer.send(event)
|
|
|
|
if !sent {
|
|
|
|
panic("demuxer is full")
|
|
|
|
}
|
|
|
|
}
|
2019-07-25 16:02:47 +02:00
|
|
|
|
2019-07-27 00:25:32 +02:00
|
|
|
func (dr *DummyReactor) AddPeer() {
|
|
|
|
// TODO: add peer event and send to demuxer
|
|
|
|
}
|