edge/cmd/cli/command/app/run.go

124 lines
3.1 KiB
Go

package app
import (
"database/sql"
"net/http"
"path/filepath"
"forge.cadoles.com/arcad/edge/pkg/bus/memory"
appHTTP "forge.cadoles.com/arcad/edge/pkg/http"
"forge.cadoles.com/arcad/edge/pkg/module"
"forge.cadoles.com/arcad/edge/pkg/module/cast"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
_ "modernc.org/sqlite"
)
func RunCommand() *cli.Command {
return &cli.Command{
Name: "run",
Usage: "Run the specified app bundle",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "path",
Usage: "use `PATH` as app bundle (zipped bundle or directory)",
Aliases: []string{"p"},
Value: ".",
},
&cli.StringFlag{
Name: "address",
Usage: "use `ADDRESS` as http server listening address",
Aliases: []string{"a"},
Value: ":8080",
},
&cli.StringFlag{
Name: "log-format",
Usage: "use `LOG-FORMAT` ('json' or 'human')",
Value: "human",
},
&cli.IntFlag{
Name: "log-level",
Usage: "use `LOG-LEVEL` (0: debug -> 5: fatal)",
Value: 0,
},
&cli.StringFlag{
Name: "storage-file",
Usage: "use `FILE` for SQLite storage database",
Value: "data.sqlite",
},
},
Action: func(ctx *cli.Context) error {
address := ctx.String("address")
path := ctx.String("path")
logFormat := ctx.String("log-format")
logLevel := ctx.Int("log-level")
storageFile := ctx.String("storage-file")
logger.SetFormat(logger.Format(logFormat))
logger.SetLevel(logger.Level(logLevel))
cmdCtx := ctx.Context
absPath, err := filepath.Abs(path)
if err != nil {
return errors.Wrapf(err, "could not resolve path '%s'", path)
}
logger.Info(cmdCtx, "opening app bundle", logger.F("path", absPath))
bundle, err := bundle.FromPath(path)
if err != nil {
return errors.Wrapf(err, "could not open path '%s' as an app bundle", path)
}
mux := chi.NewMux()
mux.Use(middleware.Logger)
bus := memory.NewBus()
db, err := sql.Open("sqlite", storageFile)
if err != nil {
return errors.Wrapf(err, "could not open database with path '%s'", storageFile)
}
documentStore := sqlite.NewDocumentStoreWithDB(db)
blobStore := sqlite.NewBlobStoreWithDB(db)
handler := appHTTP.NewHandler(
appHTTP.WithBus(bus),
appHTTP.WithServerModules(
module.ContextModuleFactory(),
module.ConsoleModuleFactory(),
cast.CastModuleFactory(),
module.LifecycleModuleFactory(bus),
module.NetModuleFactory(bus),
module.RPCModuleFactory(bus),
module.StoreModuleFactory(documentStore),
module.BlobModuleFactory(bus, blobStore),
),
)
if err := handler.Load(bundle); err != nil {
return errors.Wrap(err, "could not load app bundle")
}
mux.Handle("/*", handler)
logger.Info(cmdCtx, "listening", logger.F("address", address))
if err := http.ListenAndServe(address, mux); err != nil {
return errors.WithStack(err)
}
return nil
},
}
}