examples/http: Add HTTP example to demonstrate RunShutdownable
This commit is contained in:
		
							parent
							
								
									5e38cec135
								
							
						
					
					
						commit
						772e9ca290
					
				
							
								
								
									
										90
									
								
								examples/http/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								examples/http/main.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | |||||||
|  | // Example http demonstrates the usage of [camfish.RunShutdowner] to run an http | ||||||
|  | // server. | ||||||
|  | package main | ||||||
|  | 
 | ||||||
|  | import "fmt" | ||||||
|  | import "log" | ||||||
|  | import "iter" | ||||||
|  | import "errors" | ||||||
|  | import "context" | ||||||
|  | import "net/http" | ||||||
|  | import "git.tebibyte.media/sashakoshka/camfish" | ||||||
|  | import "git.tebibyte.media/sashakoshka/go-util/sync" | ||||||
|  | 
 | ||||||
|  | func main() { | ||||||
|  | 	camfish.Run("http", | ||||||
|  | 		"Example http demonstrates the usage of " + | ||||||
|  | 		"camfish.RunShutdowner to run an http server", | ||||||
|  | 		new(httpServer), | ||||||
|  | 		new(database)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // httpServer serves data over http. | ||||||
|  | type httpServer struct { | ||||||
|  | 	server *http.Server | ||||||
|  | 	database *database | ||||||
|  | } | ||||||
|  | var _ camfish.RunShutdownable = new(httpServer) | ||||||
|  | var _ camfish.Initializable = new(httpServer) | ||||||
|  | func (this *httpServer) Type() string { return "http-server" } | ||||||
|  | 
 | ||||||
|  | func (this *httpServer) Init(ctx context.Context) error { | ||||||
|  | 	this.server = &http.Server { | ||||||
|  | 		Addr: "localhost:8080", | ||||||
|  | 		Handler: this, | ||||||
|  | 	} | ||||||
|  | 	if actor, ok := camfish.Find("database").(*database); ok { | ||||||
|  | 		this.database = actor | ||||||
|  | 	} else { | ||||||
|  | 		return errors.New("could not locate database") | ||||||
|  | 	} | ||||||
|  | 	return ctx.Err() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (this *httpServer) Run() error { | ||||||
|  | 	log.Printf("[http] listening on %s", this.server.Addr) | ||||||
|  | 	err := this.server.ListenAndServe() | ||||||
|  | 	if errors.Is(err, http.ErrServerClosed) { return nil } | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (this *httpServer) Shutdown(ctx context.Context) error { | ||||||
|  | 	return this.server.Shutdown(ctx) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (this *httpServer) ServeHTTP(res http.ResponseWriter, req *http.Request) { | ||||||
|  | 	fmt.Fprintf(res, "<!DOCTYPE html><html><head><title>inventory</title></head><body>") | ||||||
|  | 	fmt.Fprintf(res, "<table><tr><th>Item</th><th>Count</th></tr>") | ||||||
|  | 	for item, count := range this.database.Inventory() { | ||||||
|  | 		fmt.Fprintf(res, "<tr><td>%s</td><td>%d</td></tr>", item, count) | ||||||
|  | 	} | ||||||
|  | 	fmt.Fprintf(res, "</table>") | ||||||
|  | 	fmt.Fprintf(res, "</body></html>") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // database provides data that can be served. | ||||||
|  | type database struct { | ||||||
|  | 	inventory usync.RWMonitor[map[string] int] | ||||||
|  | } | ||||||
|  | func (this *database) Type() string { return "database" } | ||||||
|  | 
 | ||||||
|  | func (this *database) Init(ctx context.Context) error { | ||||||
|  | 	this.inventory.Set(map[string] int { | ||||||
|  | 		"screws": 34, | ||||||
|  | 		"blood": 90, | ||||||
|  | 		"paperclips": 5230, | ||||||
|  | 		"wood": 3, | ||||||
|  | 		"grains of rice": 238409, | ||||||
|  | 	}) | ||||||
|  | 	return ctx.Err() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (this *database) Inventory() iter.Seq2[string, int] { | ||||||
|  | 	return func(yield func(string, int) bool) { | ||||||
|  | 		inventory, done := this.inventory.RBorrow() | ||||||
|  | 		defer done() | ||||||
|  | 		for item, amount := range inventory { | ||||||
|  | 			yield(item, amount) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user