91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
// 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)
|
|
}
|
|
}
|
|
}
|