GithubHelp home page GithubHelp logo

reactivex / rxgo Goto Github PK

View Code? Open in Web Editor NEW
4.9K 4.9K 333.0 1.61 MB

Reactive Extensions for the Go language.

License: MIT License

Go 99.95% Makefile 0.05%
async asynchronous concurrency go golang hacktoberfest observable reactivex streaming

rxgo's People

Contributors

0x5010 avatar aaronyaosmith avatar arekczarnik avatar ashwineaso avatar avelino avatar captjt avatar crgimenes avatar darrensapalo avatar dependabot[bot] avatar dparrish avatar driusan avatar geneticgrabbag avatar gitter-badger avatar groszewn avatar jochasinga avatar llleon avatar maguro avatar mareklabuz avatar mimol91 avatar orsenkucher avatar pashaosipyants avatar pocket7878 avatar povilasv avatar roarc0 avatar schmich avatar singyiu avatar teivah avatar v-zubko avatar venth avatar vpashkov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rxgo's Issues

Panic handling

Hi,
first of all, great initiative. Rx is something that should definitely be implemented in Go.
There should be maybe some kind of panic error handling in handlers. For example, basic implementation would be something like:

// OnNext applies Observer's NextHandler to an Item
func (ob Observer) OnNext(item interface{}) {
	defer func() {
		if (recover() != nil) {
			ob.OnError(errors.New(7, "Panicked!"))
		}
	}()
	switch item := item.(type) {
	case error:
		return
	default:
		if ob.NextHandler != nil {
			ob.NextHandler(item)
		}
	}
}

A better approach would be an optional panic handler, as the deffer is not very performant.

Data race detected in tests

When running the tests with the -race flag, there is a warning about a data race:

$ go test -race ./...
?       github.com/reactivex/rxgo       [no test files]
ok      github.com/reactivex/rxgo/connectable   (cached)
ok      github.com/reactivex/rxgo/errors        (cached)
?       github.com/reactivex/rxgo/examples/reactive_sum [no test files]
?       github.com/reactivex/rxgo/examples/scroll       [no test files]
?       github.com/reactivex/rxgo/fx    [no test files]
ok      github.com/reactivex/rxgo/handlers      (cached)
ok      github.com/reactivex/rxgo/iterable      (cached)
ok      github.com/reactivex/rxgo/observable    (cached)
ok      github.com/reactivex/rxgo/observer      (cached)
==================
WARNING: DATA RACE
Read at 0x00c0000a4500 by goroutine 7:
  github.com/reactivex/rxgo/subscription.TestSubscription()
      /Users/tobi/go/src/github.com/ReactiveX/RxGo/subscription/subscription_test.go:30 +0x369
  testing.tRunner()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0x162

Previous write at 0x00c0000a4500 by goroutine 8:
  github.com/reactivex/rxgo/subscription.TestSubscription.func1()
      /Users/tobi/go/src/github.com/ReactiveX/RxGo/subscription/subscription_test.go:22 +0x67

Goroutine 7 (running) created at:
  testing.(*T).Run()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:878 +0x650
  testing.runTests.func1()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1119 +0xa8
  testing.tRunner()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0x162
  testing.runTests()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1117 +0x4ee
  testing.(*M).Run()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1034 +0x2ee
  main.main()
      _testmain.go:44 +0x221

Goroutine 8 (finished) created at:
  github.com/reactivex/rxgo/subscription.TestSubscription()
      /Users/tobi/go/src/github.com/ReactiveX/RxGo/subscription/subscription_test.go:21 +0xb1
  testing.tRunner()
      /usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0x162
==================
--- FAIL: TestSubscription (0.01s)
    testing.go:771: race detected during execution of test
FAIL
FAIL    github.com/reactivex/rxgo/subscription  0.031s

Race test

We should add in the tests performed by Travis the -race option.

Support for Scheduler in Repeat Operator

Have any intresst on scheduler implementation in Repeat Operator ?
One usefull usescase can be to call every 5 minute a rest api.
I would try to implement it.

code proposal (observable.go):

func Repeat(item interface{},cronspec string) Observable

useage (pseudocode)

schedulerstream := Repeat("http://www.example.com", "@every 5m") 
reponsestream := schedulerstream.Map('...make httpcall...')

and

schedulerstream := Repeat("http://www.example.com", "*/5 * * * *")
reponsestream := schedulerstream.Map('...make httpcall...')

New observable types

Hey,

I would like to implement the All operator. According to RxJava: this operator determines whether all items emitted by an Observable meet some criteria.

My question is what would be returned by the All method? Different options:

  • Reuse an Observable to return a single bool.
  • Create a new type SingleBool <-chan bool
  • Create a new type Single <-chan interface{}
  • Something else

I feel like it's important to share a common understanding between the project maintainers and committers. This would really help to boost the project :)

How to use Observables for emitting events?

Hello,

I have a question about the usage of rxgo.

When using rxjs I usually use Subjects and .asObservable to get a simple event pattern. However in rxgo there is no Subject (yet?) and from the tutorials I could not find any way to pass data at runtime.
In the tutorials all observers are generated from existing arrays or functions which provide data, however Usually I would do something like this:

type MyStruct struct {
    s subject.Subject
}

func NewMyStruct() MyStruct {
    m := MyStruct{}
    m.s = subject.New()
    return s
}

func (m *MyStruct) doSomeActionWithNewValue(value interface{}) {
    m.s.Next(value)
}

func(m *MyStruct) getObservable() observable.Observable {
    return m.s.AsObservable()
}

func main() {
    myStruct := NewMyStruct()
    myStruct.getObservable().Subscribe(func(value interface{}) {
        // do work here
    }
    myStruct.doSomeActionWithNewValue("hello world")
}

Is it just because subjects are not yet implemented or is it intended to do something like this in a totally different way in go?

I already tried using a channel as base for the observable and using closures to provide a provider function for the observable, but both resulted in go telling me, that my application deadlocked, when waiting for the subscriptions.

Operators Zip

The Zip method returns an Observable that applies a function of your choosing to the combination of items emitted, in sequence, by two (or more) other Observables, with the results of this function becoming the items emitted by the returned Observable. It applies this function in strict sequence, so the first item emitted by the new Observable will be the result of the function applied to the first item emitted by Observable #1 and the first item emitted by Observable #2; the second item emitted by the new zip-Observable will be the result of the function applied to the second item emitted by Observable #1 and the second item emitted by Observable #2; and so forth. It will only emit as many items as the number of items emitted by the source Observable that emits the fewest items.

reference http://reactivex.io/documentation/operators/zip.html

How to dispose a subscription?

As the example code:
subscription := observable.Subscribe(observer)
The Subscribe function will return a disposable in other Rx implementations such as RxSwift, RxJS etc.
But in RxGo, I think that shouldn't return a subscription when call Subscribe.

In sources, I found that an observable is a chan. I think that it's an error prototype. Thinking that we want to implement the operators "Materialize/Dematerialize" or "Combine/Merge/Concat" or "Catch". The observable should process error event, next event and completed event.

code proposal:
dispose := observable.Create(func(o observer.Observer) disposable.Disposable{ // create a network request // ............. return disposable.Disposable(func(){ // cancel network request. }) })

Sorry for my poor english.

fx types are coupled to a given operator

fx types are coupled to a given operator. For example, a function taking two interfaces as an argument and returning an interface is defined this way:

// ScannableFunc defines a function that acts as a predicate to the Scan operator.
ScannableFunc func(interface{}, interface{}) interface{}

My opinion is that those types should be as generic as possible. For example, if we need to implement a zip operator, we can't reuse the same type as it's tied to the scan operator. So we'll have to duplicate the code and create a ZipableFunc func(interface{}, interface{}) interface{}. I don't really like this approach.

If we take a look at RxJava for instace, there is an interface called BiFunction. What about reusing these conventions rather?

ref: http://reactivex.io/documentation/operators/zip.html

Retry operators

As per contribution guidelines, I'm opening an issue for discussion regarding the implementation of Retry.

Per Documentation:

The Retry operator responds to an onError notification from the source Observable by not passing that call through to its observers, but instead by resubscribing to the source Observable and giving it another opportunity to complete its sequence without error. Retry always passes onNext notifications through to its observers, even from sequences that terminate with an error, so this can cause duplicate emissions (as shown in the diagram above)

I have an implementation of Retry on my for, as linked below

reference: http://reactivex.io/documentation/operators/retry.html

`observer.OnCompleted` should be optional

Right now it will panic

panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference

Whenever an OnCompleted handler isn't defined in an Observer. (Try to comment this out to see what I mean).

Strange behaviour with two and more pipes

Hi,
I was doing some testing and found package behaves strange with more than one observers connected to source.

A simple app is listening for Stdin and sends all the values into channel which is in turn connected with observers via iterable source. With this scenario app requires me to put values twice to have it processed. Am i doing something wrong?

func main() {

	lines := make(chan interface{})
	go func() {
		defer close(lines)
		scanner := bufio.NewScanner(os.Stdin)
		for scanner.Scan() {
			lines <- scanner.Text()
		}
	}()

	process := observer.Observer{

		// Register a handler function for every next available item.
		NextHandler: func(item interface{}) {
			fmt.Printf("Processing: %v\n", item)			
		},

		// Register a handler for any emitted error.
		ErrHandler: func(err error) {
			fmt.Printf("Encountered error: %v\n", err)
		},

		// Register a handler when a stream is completed.
		DoneHandler: func() {
			fmt.Println("Done!")
		},
	}

	isOne := func(str interface{}) bool {
		return str == "one"
	}

	isTwo := func(str interface{}) bool {
		return str == "two"
	}

	mapOne := func(str interface{}) interface{} {
		return str
	}

	mapTwo := func(str interface{}) interface{} {
		return str
	}

	it, err := iterable.New(lines)
	if err != nil {
		fmt.Printf(err.Error())
	}

	src := observable.From(it)
	pipe1 := src.Filter(isOne).Map(mapOne).Subscribe(process)
	pipe2 := src.Filter(isTwo).Map(mapTwo).Subscribe(process)

	select {
	case <-pipe1:
	case <-pipe2:
	}
}

A question about signal processing in the Connectable.Connect method.

Hello there!

When I read the source code, I am confused about the way the signal is handled:

go func(ob observer.Observer) {
			<-fin
			if sub.Error == nil {
				ob.OnDone()
				sub.Unsubscribe()
			}

			go func() {
				temp <- sub // Because no one reads sub, so it will be blocked here
				fmt.Println("test") // The code can not be executed here.
				done <- temp // So temp will not be sent to done, it is impossible for others to read the temp from done.
			}()
			wg.Done()
		}(ob)

But when I run the test program, it passes the test.

func TestDoOperator(t *testing.T) {
	co := Just(1, 2, 3)
	num := 0

	nextf := func(item interface{}) {
		num += item.(int)
	}

	co = co.Do(nextf)
	sub := co.Connect()
	v := <-sub
	fmt.Println("v --->", v)

	assert.Equal(t, 6, num)
}

It prints out the result is:

v ---> <nil>

Do not know if I have a clear expression, why is this handled? Hope to get help, thank you for your answer.

Add Observable variant `Single`

RxJava and other have implemented the variant called Single:
http://reactivex.io/documentation/single.html

I believe since golang is heavily used in developing Restful APIs the Single pattern will be really effective in developing microservices where to satisfy a single Rest call the server has to actual coordinate with multiple backends. In this scenario the Single patter will allow for asynchronous handling of Rest requests, making the code a lot more declarative.

Add Buffer Operator

A propose to add the buffer operator. See: http://reactivex.io/documentation/operators/buffer.html

An signature to match the syntax of the other languages could look like this:

func (o Observable) Buffer(boundary Observable) Observable {}

// skip should be optional
func (o Observable) BufferWithCount(count int, skip ...int) Observable {}

// timeshift should be optional
func (o Observable) BufferWithTime(timespan time.Duration, timeshift ...time.Duration) Observable {}

func (o Observable) BufferWithTimeOrCount(timespan time.Duration, count int) Observable {}

For the moment, I omitted the case for opening and closing observables since it's more difficult to implement.

If there are no concerns about this, I can send a PR.

impact of interface{}?

I have limited experience with it, but I've often read that there is a cost associated with the use of the empty interface in the boxing and unboxing. If you use reactivex in the data access layer and basically all your data is filtered by it, or at least the filtered/indexed fields, is there a noticeable impact to be observed by it's use? I usually just use the explicit data types, but I recognize where interface{} is useful. I used it to generate json in my JsonBuilder package as it would have been basically impossible otherwise.

Feature request: Flatmap

As per contribution guidelines, I'm opening an issue for discussion regarding the implementation of Flatmap.

Per Documentation:

The FlatMap operator transforms an Observable by applying a function that you specify to each item emitted by the source Observable, where that function returns an Observable that itself emits items. FlatMap then merges the emissions of these resulting Observables, emitting these merged results as its own sequence.

A naive implementation could look like

func (o Observable) FlatMap(apply fx.FlatMappableFunc) Observable {
	out := make(chan interface{})
	go func() {
		for item := range o {
                        go func(sub Observable) {
                                handler := observer.Observer{
                                        NextHandler: func(i interface{}) {
                                                out <- i
                                        },
                                        ErrHandler: func(err error) {
                                                out <- err
                                        },
                                }
                                s := sub.Subscribe(handler)
                                <-s
                        }(apply(item))
		}           
		close(out)
	}()
	return Observable(out)
}

I see that the dev branch has a Merge function, however I'm not sure how to exploit the underlying reflect.SelecCase with a dynamic number of Observables. Creating a subscriber (and a go routine) for each element seems sub-optimal, but out of the top of my head I'm not aware of a different solution.

I'd be happy to submit a PR once agreement of the implementation is reached.

Support for Repeat (Creating Operator)

Have any one interest of Repeat Creating Operator? I would try to implement it.


http://reactivex.io/documentation/operators/repeat.html

Repeat
create an Observable that emits a particular item multiple times.
Image of repeat
The Repeat operator emits an item repeatedly. Some implementations of this operator allow you to repeat a sequence of items, and some permit you to limit the number of repetitions.

code proposal (observable.go):

func Repeat() Observable
func Repeat(ntimes int) Observable

Proposal - change Observer to interface

Hi,

I've tried to create TestObserver to simplify testing process.
type TestObserver{ observer.Observer }
Unfortunately there was no way to subscribe custom observer (TestObserver in my case). Working code looked like that:
sequence.subscribe(testObserver.Observer)
I scrutinized source code and saw that Observer is a struct. If observer would be interface then there will be no issue. I made a try of Observer interface introduction.

I replaced Observer with wrappingObserver (private to keep one entry point - New function in observer package). Then introduced Observer interface. There was no need to keep rx.EventHandler - handlers conversion in kept in handlers package.

If you consider the proposal is valid, please take a look at: https://github.com/venth/RxGo/tree/introduction-of-observer-interface

I stored there afore mentioned changes.

RxGo v2

This issue is a placeholder to discuss the future v2 release.

I know for example migrating Observable, Observer etc. should be part of the v1 according to this card: https://github.com/ReactiveX/RxGo/projects/1#card-6433015

Yet, if we do that it will not be backward compatible anymore with the existing API. For example, an user cannot wait anymore on the end of an Observable by doing a:

<-myObservable

Regarding the v2, I've started to implement few stuf which are part of this PR: #95. In a nutshell, it contains a migration of the main types into interfaces, a creation of new types (Optional, Single etc.) and new operators. Is this PR going in the right direction for the v2?

What else should we include?

Furthermore, what are the plans for the v2 in terms of scheduling? Shall we release something before or after Go 2?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.