| 
									
										
										
										
											2017-04-14 10:29:00 +02:00
										 |  |  | // Copyright 2016 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2016-07-19 01:39:12 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package event_test | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This example demonstrates how SubscriptionScope can be used to control the lifetime of | 
					
						
							|  |  |  | // subscriptions. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Our example program consists of two servers, each of which performs a calculation when | 
					
						
							|  |  |  | // requested. The servers also allow subscribing to results of all computations. | 
					
						
							|  |  |  | type divServer struct{ results event.Feed } | 
					
						
							|  |  |  | type mulServer struct{ results event.Feed } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *divServer) do(a, b int) int { | 
					
						
							|  |  |  | 	r := a / b | 
					
						
							|  |  |  | 	s.results.Send(r) | 
					
						
							|  |  |  | 	return r | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *mulServer) do(a, b int) int { | 
					
						
							|  |  |  | 	r := a * b | 
					
						
							|  |  |  | 	s.results.Send(r) | 
					
						
							|  |  |  | 	return r | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The servers are contained in an App. The app controls the servers and exposes them | 
					
						
							|  |  |  | // through its API. | 
					
						
							|  |  |  | type App struct { | 
					
						
							|  |  |  | 	divServer | 
					
						
							|  |  |  | 	mulServer | 
					
						
							|  |  |  | 	scope event.SubscriptionScope | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (s *App) Calc(op byte, a, b int) int { | 
					
						
							|  |  |  | 	switch op { | 
					
						
							|  |  |  | 	case '/': | 
					
						
							|  |  |  | 		return s.divServer.do(a, b) | 
					
						
							|  |  |  | 	case '*': | 
					
						
							|  |  |  | 		return s.mulServer.do(a, b) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		panic("invalid op") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // The app's SubscribeResults method starts sending calculation results to the given | 
					
						
							|  |  |  | // channel. Subscriptions created through this method are tied to the lifetime of the App | 
					
						
							|  |  |  | // because they are registered in the scope. | 
					
						
							|  |  |  | func (s *App) SubscribeResults(op byte, ch chan<- int) event.Subscription { | 
					
						
							|  |  |  | 	switch op { | 
					
						
							|  |  |  | 	case '/': | 
					
						
							|  |  |  | 		return s.scope.Track(s.divServer.results.Subscribe(ch)) | 
					
						
							|  |  |  | 	case '*': | 
					
						
							|  |  |  | 		return s.scope.Track(s.mulServer.results.Subscribe(ch)) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		panic("invalid op") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Stop stops the App, closing all subscriptions created through SubscribeResults. | 
					
						
							|  |  |  | func (s *App) Stop() { | 
					
						
							|  |  |  | 	s.scope.Close() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func ExampleSubscriptionScope() { | 
					
						
							|  |  |  | 	// Create the app. | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		app  App | 
					
						
							|  |  |  | 		wg   sync.WaitGroup | 
					
						
							|  |  |  | 		divs = make(chan int) | 
					
						
							|  |  |  | 		muls = make(chan int) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Run a subscriber in the background. | 
					
						
							|  |  |  | 	divsub := app.SubscribeResults('/', divs) | 
					
						
							|  |  |  | 	mulsub := app.SubscribeResults('*', muls) | 
					
						
							|  |  |  | 	wg.Add(1) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							|  |  |  | 		defer wg.Done() | 
					
						
							|  |  |  | 		defer fmt.Println("subscriber exited") | 
					
						
							|  |  |  | 		defer divsub.Unsubscribe() | 
					
						
							|  |  |  | 		defer mulsub.Unsubscribe() | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case result := <-divs: | 
					
						
							|  |  |  | 				fmt.Println("division happened:", result) | 
					
						
							|  |  |  | 			case result := <-muls: | 
					
						
							|  |  |  | 				fmt.Println("multiplication happened:", result) | 
					
						
							|  |  |  | 			case <-divsub.Err(): | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			case <-mulsub.Err(): | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Interact with the app. | 
					
						
							|  |  |  | 	app.Calc('/', 22, 11) | 
					
						
							|  |  |  | 	app.Calc('*', 3, 4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Stop the app. This shuts down the subscriptions, causing the subscriber to exit. | 
					
						
							|  |  |  | 	app.Stop() | 
					
						
							|  |  |  | 	wg.Wait() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Output: | 
					
						
							|  |  |  | 	// division happened: 2 | 
					
						
							|  |  |  | 	// multiplication happened: 12 | 
					
						
							|  |  |  | 	// subscriber exited | 
					
						
							|  |  |  | } |