// 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("(i) [http-server] 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, "inventory") fmt.Fprintf(res, "") for item, count := range this.database.Inventory() { fmt.Fprintf(res, "", item, count) } fmt.Fprintf(res, "
ItemCount
%s%d
") fmt.Fprintf(res, "") } // 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) } } }