func MaterializeUnion(name string, field ...string) Reflex { reflex, eye := plumb.NewEye(append(field, name)...) go func() { conj := New() for { dvalve, dvalue := eye.See() if dvalve == name { // conjunction updated y := make(chan struct{}) // block and for _, f_ := range field { // send updated conjunction to all field valves f := f_ go func() { eye.Show(f, dvalue.(Circuit).At(f)) y <- struct{}{} }() } for _ = range field { <-y } } else { // field updated conj.Abandon(dvalve).Grow(dvalve, dvalue) if conj.Len() == len(field) { eye.Show(name, conj) } } } }() return reflex }
func (Ticker) Materialize() be.Reflex { reflex, eye := plumb.NewEye("Tick", "Duration") go func() { for { valve, value := eye.See() switch valve { case "Duration": dur := time.Duration(plumb.AsInt(value)) if dur <= 0 { panic(4) } abr := make(chan struct{}) go func() { start := time.Now() tkr := time.NewTicker(dur) defer tkr.Stop() for { select { case <-abr: return case t := <-tkr.C: eye.Show("Tick", int(t.Sub(start))) } } }() } } }() return reflex }
func MaterializeSubscription(kind string) be.Reflex { reflex, eye := plumb.NewEye("Server", "_") go func() { var server string for { valve, value := eye.See() ?? // use containerlike spawn param with server and name!! if valve != "Server" || server != "" { continue } server = value.(string) go func() { id := ChooseID() anchor := program.Client.Walk( ?? []string{ server, "escher", program.Name, "circuit." + kind, id, }, ) var ss client.Subscription var err error switch kind { case "Joining": ss, err = anchor.MakeOnJoin() case "Leaving": ss, err = anchor.MakeOnLeave() default: panic(2) } if err != nil { panic("plugging") } defer anchor.Scrub() for { v, ok := ss.Consume() if !ok { panic("subscription should not be closing ever") } eye.Show("_", v) } }() } }() return reflex }
// Fix creates a gate that waits until all fix valves are set and // then outputs a singular conjunction of all values. func MaterializeFix(fwd string, fix ...string) be.Reflex { reflex, eye := plumb.NewEye(append(fix, fwd)...) go func() { conj := New() for { dvalve, dvalue := eye.See() if dvalve == fwd { // conjunction updated continue // ignore upstream updates } else { // field updated conj.Abandon(dvalve).Grow(dvalve, dvalue) if conj.Len() == len(fix) { eye.Show(fwd, conj) eye.Drain() // As soon as the conjunction is output, this gate is done. } } } }() return reflex }
func (Delay) Materialize() be.Reflex { reflex, eye := plumb.NewEye("X", "Y", "Duration") go func() { ds := make(chan time.Duration, 2) dur := ds xy, yx := make(chan interface{}, 1), make(chan interface{}, 1) go func() { d := <-dur for { v := <-xy time.Sleep(d) eye.Show("Y", v) } }() go func() { d := <-dur for { v := <-yx time.Sleep(d) eye.Show("X", v) } }() for { valve, value := eye.See() switch valve { case "X": xy <- value case "Y": yx <- value case "Duration": if ds == nil { break } d := time.Duration(value.(int)) ds <- d ds <- d close(ds) ds = nil } } }() return reflex }
// File string // Put {Key []byte, Value []byte} // Query {Name interface{}, Start []byte, Limit []byte} // Result {Name interface{}, Result Image} func (File) Materialize() be.Reflex { reflex, eye := plumb.NewEye("File", "Put", "Query", "Result") go func() { // dispatch var err error var db *leveldb.DB connected, put, query := make(chan struct{}), make(chan Image, 5), make(chan Image, 5) go func() { // Put loop <-connected // wait for db connection for { p := <-put if err := db.Put(p[see.Name("Key")].([]byte), p[see.Name("Value")].([]byte), nil); err != nil { panic(err) } } }() go func() { // Query loop <-connected // wait for db connection for { q := <-query iter := db.NewIterator( &util.Range{ Start: q[see.Name("Start")].([]byte), Limit: q[see.Name("Limit")].([]byte), }, nil, ) slice := Make() if iter.First() { for i := 0; ; i++ { if err := iter.Error(); err != nil { panic(err) } slice.Grow( see.Number(i), Image{ see.Name("Key"): iter.Key(), see.Name("Value"): iter.Value(), }, ) if !iter.Next() { break } } } eye.Show("Result", Make().Grow(see.Name("Name"), q[see.Name("Name")]).Grow(see.Name("Slice"), slice)) } }() for { valve, value := eye.See() switch valve { case "File": if db, err = leveldb.OpenFile(value.(string), nil); err != nil { panic(err) } close(connected) case "Put": put <- value.(Image) case "Query": query <- value.(Image) } } }() return reflex }