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…
Reference in New Issue
Block a user