func (dispatcher *dispatcher) Dispatch(in stream.Readable, writables ...stream.Writable) stream.Readable { notDispatchedReadable, notDispatchedWritable := stream.New(in.Capacity()) dispatchedCount := 0 done := make(chan bool, len(writables)) closeWritables := func() { defer func() { for _, writable := range writables { close(writable) } }() expectedDoneMessages := dispatchedCount * len(writables) for i := 0; i < expectedDoneMessages; i++ { select { case <-dispatcher.context.Failure(): return case <-time.After(dispatcher.context.Deadline()): panic(stream.Timeout) case <-done: continue } } } go func() { defer dispatcher.context.Recover() defer close(notDispatchedWritable) defer closeWritables() for data := range in { select { case <-dispatcher.context.Failure(): return case <-time.After(dispatcher.context.Deadline()): panic(stream.Timeout) default: if dispatcher.fn(data) { dispatchedCount++ for _, writable := range writables { // dispatch data asynchronously so that // slow receivers don't block the dispatch // process go func(w stream.Writable, d stream.T) { w <- d done <- true }(writable, data) } } else { notDispatchedWritable <- data } } } }() return notDispatchedReadable }
func (observer *Observer) Transform(in stream.Readable) stream.Readable { readable, writable := stream.New(in.Capacity()) emitter := stream.NewEmitter(observer.context, writable) go func() { defer observer.context.Recover() defer close(writable) for { select { case <-observer.context.Failure(): return case <-observer.context.Done(): return case <-time.After(observer.context.Deadline()): panic(stream.Timeout) default: data, more := <-in if !more { if observer.OnCompleted != nil { observer.OnCompleted(emitter) } return } if observer.OnNext == nil { continue } if err := observer.OnNext(data, emitter); err != nil { if err == stream.Done { // Tell producer to shutdown without errors observer.context.Close(nil) return } panic(err) } } } }() return readable }