feat(module,share): cross-app resource sharing module
All checks were successful
arcad/edge/pipeline/head This commit looks good
All checks were successful
arcad/edge/pipeline/head This commit looks good
This commit is contained in:
@ -26,8 +26,10 @@ import (
|
||||
"forge.cadoles.com/arcad/edge/pkg/module/cast"
|
||||
"forge.cadoles.com/arcad/edge/pkg/module/fetch"
|
||||
netModule "forge.cadoles.com/arcad/edge/pkg/module/net"
|
||||
shareModule "forge.cadoles.com/arcad/edge/pkg/module/share"
|
||||
shareSqlite "forge.cadoles.com/arcad/edge/pkg/module/share/sqlite"
|
||||
"forge.cadoles.com/arcad/edge/pkg/storage"
|
||||
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
|
||||
storageSqlite "forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
|
||||
"forge.cadoles.com/arcad/edge/pkg/bundle"
|
||||
@ -76,6 +78,11 @@ func RunCommand() *cli.Command {
|
||||
Usage: "use `FILE` for SQLite storage database",
|
||||
Value: ".edge/%APPID%/data.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "shared-resources-file",
|
||||
Usage: "use `FILE` for SQLite shared resources database",
|
||||
Value: ".edge/shared-resources.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "accounts-file",
|
||||
Usage: "use `FILE` as local accounts",
|
||||
@ -90,6 +97,7 @@ func RunCommand() *cli.Command {
|
||||
logLevel := ctx.Int("log-level")
|
||||
storageFile := ctx.String("storage-file")
|
||||
accountsFile := ctx.String("accounts-file")
|
||||
sharedResourcesFile := ctx.String("shared-resources-file")
|
||||
|
||||
logger.SetFormat(logger.Format(logFormat))
|
||||
logger.SetLevel(logger.Level(logLevel))
|
||||
@ -135,7 +143,7 @@ func RunCommand() *cli.Command {
|
||||
|
||||
appCtx := logger.With(cmdCtx, logger.F("address", address))
|
||||
|
||||
if err := runApp(appCtx, path, address, storageFile, accountsFile, appsRepository); err != nil {
|
||||
if err := runApp(appCtx, path, address, storageFile, accountsFile, appsRepository, sharedResourcesFile); err != nil {
|
||||
logger.Error(appCtx, "could not run app", logger.E(errors.WithStack(err)))
|
||||
}
|
||||
}(p, port, idx)
|
||||
@ -148,7 +156,7 @@ func RunCommand() *cli.Command {
|
||||
}
|
||||
}
|
||||
|
||||
func runApp(ctx context.Context, path string, address string, storageFile string, accountsFile string, appRepository appModule.Repository) error {
|
||||
func runApp(ctx context.Context, path string, address string, storageFile string, accountsFile string, appRepository appModule.Repository, sharedResourcesFile string) error {
|
||||
absPath, err := filepath.Abs(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not resolve path '%s'", path)
|
||||
@ -172,44 +180,37 @@ func runApp(ctx context.Context, path string, address string, storageFile string
|
||||
|
||||
ctx = logger.With(ctx, logger.F("appID", manifest.ID))
|
||||
|
||||
storageFile = injectAppID(storageFile, manifest.ID)
|
||||
|
||||
if err := ensureDir(storageFile); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
db, err := sqlite.Open(storageFile)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
accountsFile = injectAppID(accountsFile, manifest.ID)
|
||||
|
||||
accounts, err := loadLocalAccounts(accountsFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not load local accounts")
|
||||
}
|
||||
|
||||
// Add auth handler
|
||||
key, err := dummyKey()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
ds := sqlite.NewDocumentStoreWithDB(db)
|
||||
bs := sqlite.NewBlobStoreWithDB(db)
|
||||
bus := memory.NewBus()
|
||||
deps := &moduleDeps{}
|
||||
funcs := []ModuleDepFunc{
|
||||
initMemoryBus,
|
||||
initDatastores(storageFile, manifest.ID),
|
||||
initAccounts(accountsFile, manifest.ID),
|
||||
initShareRepository(sharedResourcesFile),
|
||||
initAppRepository(appRepository),
|
||||
}
|
||||
|
||||
for _, fn := range funcs {
|
||||
if err := fn(deps); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
handler := appHTTP.NewHandler(
|
||||
appHTTP.WithBus(bus),
|
||||
appHTTP.WithServerModules(getServerModules(bus, ds, bs, appRepository)...),
|
||||
appHTTP.WithBus(deps.Bus),
|
||||
appHTTP.WithServerModules(getServerModules(deps)...),
|
||||
appHTTP.WithHTTPMounts(
|
||||
appModule.Mount(appRepository),
|
||||
authModule.Mount(
|
||||
authHTTP.NewLocalHandler(
|
||||
jwa.HS256, key,
|
||||
authHTTP.WithRoutePrefix("/auth"),
|
||||
authHTTP.WithAccounts(accounts...),
|
||||
authHTTP.WithAccounts(deps.Accounts...),
|
||||
),
|
||||
authModule.WithJWT(dummyKeySet),
|
||||
),
|
||||
@ -235,21 +236,34 @@ func runApp(ctx context.Context, path string, address string, storageFile string
|
||||
return nil
|
||||
}
|
||||
|
||||
func getServerModules(bus bus.Bus, ds storage.DocumentStore, bs storage.BlobStore, appRepository appModule.Repository) []app.ServerModuleFactory {
|
||||
type moduleDeps struct {
|
||||
AppID app.ID
|
||||
Bus bus.Bus
|
||||
DocumentStore storage.DocumentStore
|
||||
BlobStore storage.BlobStore
|
||||
AppRepository appModule.Repository
|
||||
ShareRepository shareModule.Repository
|
||||
Accounts []authHTTP.LocalAccount
|
||||
}
|
||||
|
||||
type ModuleDepFunc func(*moduleDeps) error
|
||||
|
||||
func getServerModules(deps *moduleDeps) []app.ServerModuleFactory {
|
||||
return []app.ServerModuleFactory{
|
||||
module.ContextModuleFactory(),
|
||||
module.ConsoleModuleFactory(),
|
||||
cast.CastModuleFactory(),
|
||||
module.LifecycleModuleFactory(),
|
||||
netModule.ModuleFactory(bus),
|
||||
module.RPCModuleFactory(bus),
|
||||
module.StoreModuleFactory(ds),
|
||||
blob.ModuleFactory(bus, bs),
|
||||
netModule.ModuleFactory(deps.Bus),
|
||||
module.RPCModuleFactory(deps.Bus),
|
||||
module.StoreModuleFactory(deps.DocumentStore),
|
||||
blob.ModuleFactory(deps.Bus, deps.BlobStore),
|
||||
authModule.ModuleFactory(
|
||||
authModule.WithJWT(dummyKeySet),
|
||||
),
|
||||
appModule.ModuleFactory(appRepository),
|
||||
fetch.ModuleFactory(bus),
|
||||
appModule.ModuleFactory(deps.AppRepository),
|
||||
fetch.ModuleFactory(deps.Bus),
|
||||
shareModule.ModuleFactory(deps.AppID, deps.ShareRepository),
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,3 +417,65 @@ func newAppRepository(host string, basePort uint64, manifests ...*app.Manifest)
|
||||
manifests...,
|
||||
)
|
||||
}
|
||||
|
||||
func initAppRepository(repo appModule.Repository) ModuleDepFunc {
|
||||
return func(deps *moduleDeps) error {
|
||||
deps.AppRepository = repo
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func initMemoryBus(deps *moduleDeps) error {
|
||||
deps.Bus = memory.NewBus()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initDatastores(storageFile string, appID app.ID) ModuleDepFunc {
|
||||
return func(deps *moduleDeps) error {
|
||||
storageFile = injectAppID(storageFile, appID)
|
||||
|
||||
if err := ensureDir(storageFile); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
db, err := storageSqlite.Open(storageFile)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
deps.DocumentStore = storageSqlite.NewDocumentStoreWithDB(db)
|
||||
deps.BlobStore = storageSqlite.NewBlobStoreWithDB(db)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func initAccounts(accountsFile string, appID app.ID) ModuleDepFunc {
|
||||
return func(deps *moduleDeps) error {
|
||||
accountsFile = injectAppID(accountsFile, appID)
|
||||
|
||||
accounts, err := loadLocalAccounts(accountsFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not load local accounts")
|
||||
}
|
||||
|
||||
deps.Accounts = accounts
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func initShareRepository(shareRepositoryFile string) ModuleDepFunc {
|
||||
return func(deps *moduleDeps) error {
|
||||
if err := ensureDir(shareRepositoryFile); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
repo := shareSqlite.NewRepository(shareRepositoryFile)
|
||||
|
||||
deps.ShareRepository = repo
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user