pool: Reddo component-like fields
This commit is contained in:
parent
99983ee6db
commit
337a5fbeba
48 changed files with 291 additions and 163 deletions
|
|
@ -37,33 +37,32 @@ var errServerListen = exit.Error{
|
||||||
func (s server) Run(context wisski_distillery.Context) error {
|
func (s server) Run(context wisski_distillery.Context) error {
|
||||||
dis := context.Environment
|
dis := context.Environment
|
||||||
|
|
||||||
|
// if the caller requested a trigger, just trigger the cron tasks
|
||||||
if s.Trigger {
|
if s.Trigger {
|
||||||
context.Println("Triggering Cron Tasks")
|
|
||||||
return dis.Control().Trigger(context.Context, context.Environment.Environment)
|
return dis.Control().Trigger(context.Context, context.Environment.Environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// start the cron tasks
|
|
||||||
{
|
{
|
||||||
// create a channel for notifications
|
// create a channel for notifications
|
||||||
notify, cancel := dis.Cron().Listen(context.Context)
|
notify, cancel := dis.Cron().Listen(context.Context)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// start the cron tasks
|
// start the cron tasks
|
||||||
context.Printf("Starting cron tasks %s\n", s.Bind)
|
|
||||||
done := dis.Cron().Start(context.Context, notify)
|
done := dis.Cron().Start(context.Context, notify)
|
||||||
defer func() {
|
defer func() {
|
||||||
<-done
|
<-done
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// and start the server
|
||||||
handler, err := dis.Control().Server(context.Context, context.Stderr)
|
handler, err := dis.Control().Server(context.Context, context.Stderr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
context.Printf("Listening on %s\n", s.Bind)
|
zerolog.Ctx(context.Context).Info().Str("bind", s.Bind).Msg("listening")
|
||||||
|
|
||||||
// make a new listener
|
// create a new listener
|
||||||
listener, err := dis.Still.Environment.Listen("tcp", s.Bind)
|
listener, err := dis.Still.Environment.Listen("tcp", s.Bind)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errServerListen.Wrap(err)
|
return errServerListen.Wrap(err)
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,11 @@ import (
|
||||||
// Control represents the running control server.
|
// Control represents the running control server.
|
||||||
type Control struct {
|
type Control struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Servables []component.Servable
|
Servables []component.Servable
|
||||||
Cronables []component.Cronable
|
Cronables []component.Cronable
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.Installable = (*Control)(nil)
|
_ component.Installable = (*Control)(nil)
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,10 @@ import (
|
||||||
|
|
||||||
type Cron struct {
|
type Cron struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Tasks []component.Cronable
|
Tasks []component.Cronable
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Listen returns a channel that listens for triggers in the current process.
|
// Listen returns a channel that listens for triggers in the current process.
|
||||||
// It is intended to be passed to Start.
|
// It is intended to be passed to Start.
|
||||||
|
|
@ -51,11 +52,11 @@ func (control *Cron) Listen(ctx context.Context) (<-chan struct{}, func()) {
|
||||||
// Once should not be called concurrently with Cron.
|
// Once should not be called concurrently with Cron.
|
||||||
func (control *Cron) Once(ctx context.Context) {
|
func (control *Cron) Once(ctx context.Context) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(control.Tasks))
|
wg.Add(len(control.Dependencies.Tasks))
|
||||||
|
|
||||||
zerolog.Ctx(ctx).Info().Time("time", time.Now()).Msg("Starting Cron")
|
zerolog.Ctx(ctx).Info().Time("time", time.Now()).Msg("Starting Cron")
|
||||||
|
|
||||||
for _, task := range control.Tasks {
|
for _, task := range control.Dependencies.Tasks {
|
||||||
go func(task component.Cronable) {
|
go func(task component.Cronable) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@ import (
|
||||||
|
|
||||||
type UpdateInstanceList struct {
|
type UpdateInstanceList struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Home *Home
|
Home *Home
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.Cronable = (*UpdateInstanceList)(nil)
|
_ component.Cronable = (*UpdateInstanceList)(nil)
|
||||||
|
|
@ -20,19 +22,21 @@ func (*UpdateInstanceList) TaskName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ul *UpdateInstanceList) Cron(ctx context.Context) error {
|
func (ul *UpdateInstanceList) Cron(ctx context.Context) error {
|
||||||
names, err := ul.Home.instanceMap(ctx)
|
names, err := ul.Dependencies.Home.instanceMap(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.Home.instanceNames.Set(names)
|
ul.Dependencies.Home.instanceNames.Set(names)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateRedirect struct {
|
type UpdateRedirect struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Home *Home
|
Home *Home
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.Cronable = (*UpdateRedirect)(nil)
|
_ component.Cronable = (*UpdateRedirect)(nil)
|
||||||
|
|
@ -43,19 +47,21 @@ func (ur *UpdateRedirect) TaskName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ur *UpdateRedirect) Cron(ctx context.Context) error {
|
func (ur *UpdateRedirect) Cron(ctx context.Context) error {
|
||||||
redirect, err := ur.Home.loadRedirect(ctx)
|
redirect, err := ur.Dependencies.Home.loadRedirect(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ur.Home.redirect.Set(&redirect)
|
ur.Dependencies.Home.redirect.Set(&redirect)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateHome struct {
|
type UpdateHome struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Home *Home
|
Home *Home
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.Cronable = (*UpdateHome)(nil)
|
_ component.Cronable = (*UpdateHome)(nil)
|
||||||
|
|
@ -66,11 +72,11 @@ func (ur *UpdateHome) TaskName() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ur *UpdateHome) Cron(ctx context.Context) error {
|
func (ur *UpdateHome) Cron(ctx context.Context) error {
|
||||||
bytes, err := ur.Home.homeRender(ctx)
|
bytes, err := ur.Dependencies.Home.homeRender(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ur.Home.homeBytes.Set(bytes)
|
ur.Dependencies.Home.homeBytes.Set(bytes)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ import (
|
||||||
|
|
||||||
type Home struct {
|
type Home struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
|
}
|
||||||
|
|
||||||
redirect lazy.Lazy[*Redirect]
|
redirect lazy.Lazy[*Redirect]
|
||||||
instanceNames lazy.Lazy[map[string]struct{}]
|
instanceNames lazy.Lazy[map[string]struct{}]
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (home *Home) instanceMap(ctx context.Context) (map[string]struct{}, error) {
|
func (home *Home) instanceMap(ctx context.Context) (map[string]struct{}, error) {
|
||||||
wissKIs, err := home.Instances.All(ctx)
|
wissKIs, err := home.Dependencies.Instances.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ func (home *Home) homeRender(ctx context.Context) ([]byte, error) {
|
||||||
context.SelfRedirect = home.Config.SelfRedirect.String()
|
context.SelfRedirect = home.Config.SelfRedirect.String()
|
||||||
|
|
||||||
// find all the WissKIs
|
// find all the WissKIs
|
||||||
wissKIs, err := home.Instances.All(ctx)
|
wissKIs, err := home.Dependencies.Instances.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (info *Info) ingredients(r *http.Request) (cp ingredientsContext, err error
|
||||||
cp.Time = time.Now().UTC()
|
cp.Time = time.Now().UTC()
|
||||||
|
|
||||||
// find the instance itself!
|
// find the instance itself!
|
||||||
instance, err := info.Instances.WissKI(r.Context(), mux.Vars(r)["slug"])
|
instance, err := info.Dependencies.Instances.WissKI(r.Context(), mux.Vars(r)["slug"])
|
||||||
if err == instances.ErrWissKINotFound {
|
if err == instances.ErrWissKINotFound {
|
||||||
return cp, httpx.ErrNotFound
|
return cp, httpx.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ func (info *Info) Status(ctx context.Context, QuickInformation bool) (target sta
|
||||||
|
|
||||||
group.Go(func() error {
|
group.Go(func() error {
|
||||||
// list all the instances
|
// list all the instances
|
||||||
all, err := info.Instances.All(ctx)
|
all, err := info.Dependencies.Instances.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ func (info *Info) Status(ctx context.Context, QuickInformation bool) (target sta
|
||||||
flags := component.FetcherFlags{
|
flags := component.FetcherFlags{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
}
|
}
|
||||||
for _, o := range info.Fetchers {
|
for _, o := range info.Dependencies.Fetchers {
|
||||||
o := o
|
o := o
|
||||||
group.Go(func() error {
|
group.Go(func() error {
|
||||||
return o.Fetch(flags, &target)
|
return o.Fetch(flags, &target)
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@ import (
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Analytics *lazy.PoolAnalytics
|
|
||||||
Fetchers []component.DistilleryFetcher
|
Fetchers []component.DistilleryFetcher
|
||||||
|
|
||||||
Exporter *exporter.Exporter
|
Exporter *exporter.Exporter
|
||||||
|
|
@ -25,6 +24,9 @@ type Info struct {
|
||||||
SnapshotsLog *logger.Logger
|
SnapshotsLog *logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Analytics *lazy.PoolAnalytics
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.DistilleryFetcher = (*Info)(nil)
|
_ component.DistilleryFetcher = (*Info)(nil)
|
||||||
_ component.Servable = (*Info)(nil)
|
_ component.Servable = (*Info)(nil)
|
||||||
|
|
@ -33,7 +35,9 @@ var (
|
||||||
func (*Info) Routes() []string { return []string{"/dis/"} }
|
func (*Info) Routes() []string { return []string{"/dis/"} }
|
||||||
|
|
||||||
func (info *Info) Handler(ctx context.Context, route string) (handler http.Handler, err error) {
|
func (info *Info) Handler(ctx context.Context, route string) (handler http.Handler, err error) {
|
||||||
|
|
||||||
router := httprouter.New()
|
router := httprouter.New()
|
||||||
|
|
||||||
{
|
{
|
||||||
socket := &httpx.WebSocket{
|
socket := &httpx.WebSocket{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
|
|
@ -47,41 +51,41 @@ func (info *Info) Handler(ctx context.Context, route string) (handler http.Handl
|
||||||
|
|
||||||
// handle everything
|
// handle everything
|
||||||
router.HandlerFunc(http.MethodGet, route, func(w http.ResponseWriter, r *http.Request) {
|
router.HandlerFunc(http.MethodGet, route, func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "index", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, route+"index", http.StatusTemporaryRedirect)
|
||||||
})
|
})
|
||||||
|
|
||||||
// add a handler for the index page
|
// add a handler for the index page
|
||||||
router.Handler(http.MethodGet, "index", httpx.HTMLHandler[indexContext]{
|
router.Handler(http.MethodGet, route+"index", httpx.HTMLHandler[indexContext]{
|
||||||
Handler: info.index,
|
Handler: info.index,
|
||||||
Template: indexTemplate,
|
Template: indexTemplate,
|
||||||
})
|
})
|
||||||
|
|
||||||
// add a handler for the component page
|
// add a handler for the component page
|
||||||
router.Handler(http.MethodGet, "components", httpx.HTMLHandler[componentContext]{
|
router.Handler(http.MethodGet, route+"components", httpx.HTMLHandler[componentContext]{
|
||||||
Handler: info.components,
|
Handler: info.components,
|
||||||
Template: componentsTemplate,
|
Template: componentsTemplate,
|
||||||
})
|
})
|
||||||
|
|
||||||
// add a handler for the component page
|
// add a handler for the component page
|
||||||
router.Handler(http.MethodGet, "ingredients/{slug}", httpx.HTMLHandler[ingredientsContext]{
|
router.Handler(http.MethodGet, route+"ingredients/:slug", httpx.HTMLHandler[ingredientsContext]{
|
||||||
Handler: info.ingredients,
|
Handler: info.ingredients,
|
||||||
Template: ingredientsTemplate,
|
Template: ingredientsTemplate,
|
||||||
})
|
})
|
||||||
|
|
||||||
// add a handler for the instance page
|
// add a handler for the instance page
|
||||||
router.Handler(http.MethodGet, "instance/{slug}", httpx.HTMLHandler[instanceContext]{
|
router.Handler(http.MethodGet, route+"instance/:slug", httpx.HTMLHandler[instanceContext]{
|
||||||
Handler: info.instance,
|
Handler: info.instance,
|
||||||
Template: instanceTemplate,
|
Template: instanceTemplate,
|
||||||
})
|
})
|
||||||
|
|
||||||
router.Handler(http.MethodPost, "api/login", httpx.RedirectHandler(func(r *http.Request) (string, int, error) {
|
router.Handler(http.MethodPost, route+"api/login", httpx.RedirectHandler(func(r *http.Request) (string, int, error) {
|
||||||
// parse the form
|
// parse the form
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
return "", 0, err
|
return "", 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the instance
|
// get the instance
|
||||||
instance, err := info.Instances.WissKI(r.Context(), r.PostFormValue("slug"))
|
instance, err := info.Dependencies.Instances.WissKI(r.Context(), r.PostFormValue("slug"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 0, httpx.ErrNotFound
|
return "", 0, httpx.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ type instanceContext struct {
|
||||||
|
|
||||||
func (info *Info) instance(r *http.Request) (is instanceContext, err error) {
|
func (info *Info) instance(r *http.Request) (is instanceContext, err error) {
|
||||||
// find the instance itself!
|
// find the instance itself!
|
||||||
instance, err := info.Instances.WissKI(r.Context(), mux.Vars(r)["slug"])
|
instance, err := info.Dependencies.Instances.WissKI(r.Context(), mux.Vars(r)["slug"])
|
||||||
if err == instances.ErrWissKINotFound {
|
if err == instances.ErrWissKINotFound {
|
||||||
return is, httpx.ErrNotFound
|
return is, httpx.ErrNotFound
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ type InstanceAction struct {
|
||||||
var socketInstanceActions = map[string]InstanceAction{
|
var socketInstanceActions = map[string]InstanceAction{
|
||||||
"snapshot": {
|
"snapshot": {
|
||||||
HandleInteractive: func(ctx context.Context, info *Info, instance *wisski.WissKI, out io.Writer, params ...string) error {
|
HandleInteractive: func(ctx context.Context, info *Info, instance *wisski.WissKI, out io.Writer, params ...string) error {
|
||||||
return info.Exporter.MakeExport(
|
return info.Dependencies.Exporter.MakeExport(
|
||||||
ctx,
|
ctx,
|
||||||
out,
|
out,
|
||||||
exporter.ExportTask{
|
exporter.ExportTask{
|
||||||
|
|
@ -78,7 +78,7 @@ func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action In
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve the instance
|
// resolve the instance
|
||||||
instance, err := info.Instances.WissKI(conn.Context(), string(slug.Bytes))
|
instance, err := info.Dependencies.Instances.WissKI(conn.Context(), string(slug.Bytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
<-conn.WriteText("Instance not found")
|
<-conn.WriteText("Instance not found")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func (control *Control) Server(ctx context.Context, progress io.Writer) (*http.S
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
// add all the servable routes!
|
// add all the servable routes!
|
||||||
for _, s := range control.Servables {
|
for _, s := range control.Dependencies.Servables {
|
||||||
for _, route := range s.Routes() {
|
for _, route := range s.Routes() {
|
||||||
zerolog.Ctx(ctx).Info().Str("component", s.Name()).Str("route", route).Msg("mounting route")
|
zerolog.Ctx(ctx).Info().Str("component", s.Name()).Str("route", route).Msg("mounting route")
|
||||||
handler, err := s.Handler(ctx, route)
|
handler, err := s.Handler(ctx, route)
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,17 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ range $name, $comp := .DCFields }}
|
||||||
|
<tr>
|
||||||
|
<td>Component Pointer</td>
|
||||||
|
<td>
|
||||||
|
<code>Dependencies/{{ $name }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code><a href="#{{ $comp }}">{{ $comp }}</a></code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
{{ range $name, $iface := .IFields }}
|
{{ range $name, $iface := .IFields }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Interface Slice</td>
|
<td>Interface Slice</td>
|
||||||
|
|
@ -47,6 +58,17 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ range $name, $iface := .DIFields }}
|
||||||
|
<tr>
|
||||||
|
<td>Interface Slice</td>
|
||||||
|
<td>
|
||||||
|
<code>Dependencies/{{ $name }}</code>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<code><a href="#{{ $iface }}">[]{{ $iface }}</a></code>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{ end }}
|
||||||
{{ range $name, $sig := $comp.Methods }}
|
{{ range $name, $sig := $comp.Methods }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp
|
||||||
defer done()
|
defer done()
|
||||||
|
|
||||||
// create a new status display
|
// create a new status display
|
||||||
backups := exporter.Backupable
|
backups := exporter.Dependencies.Backupable
|
||||||
backup.ComponentErrors = make(map[string]error, len(backups))
|
backup.ComponentErrors = make(map[string]error, len(backups))
|
||||||
|
|
||||||
// Component backup tasks
|
// Component backup tasks
|
||||||
|
|
@ -125,7 +125,7 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp
|
||||||
}
|
}
|
||||||
|
|
||||||
// list all instances
|
// list all instances
|
||||||
wissKIs, err := exporter.Instances.All(ctx)
|
wissKIs, err := exporter.Dependencies.Instances.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
backup.InstanceListErr = err
|
backup.InstanceListErr = err
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import (
|
||||||
// Exporter manages snapshots and backups
|
// Exporter manages snapshots and backups
|
||||||
type Exporter struct {
|
type Exporter struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
SQL *sql.SQL
|
SQL *sql.SQL
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
ExporterLogger *logger.Logger
|
ExporterLogger *logger.Logger
|
||||||
|
|
@ -26,6 +26,7 @@ type Exporter struct {
|
||||||
Snapshotable []component.Snapshotable
|
Snapshotable []component.Snapshotable
|
||||||
Backupable []component.Backupable
|
Backupable []component.Backupable
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Path returns the path that contains all snapshot related data.
|
// Path returns the path that contains all snapshot related data.
|
||||||
func (dis *Exporter) Path() string {
|
func (dis *Exporter) Path() string {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ import (
|
||||||
|
|
||||||
type Pathbuilders struct {
|
type Pathbuilders struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.Snapshotable = (*Pathbuilders)(nil)
|
_ component.Snapshotable = (*Pathbuilders)(nil)
|
||||||
|
|
@ -24,7 +26,7 @@ func (Pathbuilders) SnapshotName() string { return "pathbuilders" }
|
||||||
|
|
||||||
func (pbs *Pathbuilders) Snapshot(wisski models.Instance, scontext component.StagingContext) error {
|
func (pbs *Pathbuilders) Snapshot(wisski models.Instance, scontext component.StagingContext) error {
|
||||||
return scontext.AddDirectory(".", func(ctx context.Context) error {
|
return scontext.AddDirectory(".", func(ctx context.Context) error {
|
||||||
builders, err := pbs.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil)
|
builders, err := pbs.Dependencies.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ func (exporter *Exporter) MakeExport(ctx context.Context, progress io.Writer, ta
|
||||||
// write out the log entry
|
// write out the log entry
|
||||||
entry.Path = stagingDir
|
entry.Path = stagingDir
|
||||||
entry.Packed = false
|
entry.Packed = false
|
||||||
exporter.ExporterLogger.Add(ctx, entry)
|
exporter.Dependencies.ExporterLogger.Add(ctx, entry)
|
||||||
|
|
||||||
logging.ProgressF(progress, ctx, "Wrote %s\n", stagingDir)
|
logging.ProgressF(progress, ctx, "Wrote %s\n", stagingDir)
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -159,7 +159,7 @@ func (exporter *Exporter) MakeExport(ctx context.Context, progress io.Writer, ta
|
||||||
logging.LogMessage(progress, ctx, "Writing Log Entry")
|
logging.LogMessage(progress, ctx, "Writing Log Entry")
|
||||||
entry.Path = archivePath
|
entry.Path = archivePath
|
||||||
entry.Packed = true
|
entry.Packed = true
|
||||||
exporter.ExporterLogger.Add(ctx, entry)
|
exporter.Dependencies.ExporterLogger.Add(ctx, entry)
|
||||||
|
|
||||||
// and we're done!
|
// and we're done!
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,10 @@ import (
|
||||||
// Logger is responsible for logging backups and snapshots
|
// Logger is responsible for logging backups and snapshots
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
SQL *sql.SQL
|
SQL *sql.SQL
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// For retrieves (and prunes) the ExportLog.
|
// For retrieves (and prunes) the ExportLog.
|
||||||
// Slug determines if entries for Backups (empty slug)
|
// Slug determines if entries for Backups (empty slug)
|
||||||
|
|
@ -35,7 +36,7 @@ func (log *Logger) For(ctx context.Context, slug string) (exports []models.Expor
|
||||||
// Log retrieves (and prunes) all entries in the snapshot log.
|
// Log retrieves (and prunes) all entries in the snapshot log.
|
||||||
func (log *Logger) Log(ctx context.Context) ([]models.Export, error) {
|
func (log *Logger) Log(ctx context.Context) ([]models.Export, error) {
|
||||||
// query the table!
|
// query the table!
|
||||||
table, err := log.SQL.QueryTable(ctx, false, models.ExportTable)
|
table, err := log.Dependencies.SQL.QueryTable(ctx, false, models.ExportTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +68,7 @@ func (log *Logger) Log(ctx context.Context) ([]models.Export, error) {
|
||||||
// AddToExportLog adds the provided export to the log.
|
// AddToExportLog adds the provided export to the log.
|
||||||
func (log *Logger) Add(ctx context.Context, export models.Export) error {
|
func (log *Logger) Add(ctx context.Context, export models.Export) error {
|
||||||
// find the table
|
// find the table
|
||||||
table, err := log.SQL.QueryTable(ctx, false, models.ExportTable)
|
table, err := log.Dependencies.SQL.QueryTable(ctx, false, models.ExportTable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,6 @@ func (exporter *Exporter) PruneExports(ctx context.Context, progress io.Writer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prune the snapshot log!
|
// prune the snapshot log!
|
||||||
_, err = exporter.ExporterLogger.Log(ctx)
|
_, err = exporter.Dependencies.ExporterLogger.Log(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ func (snapshot *Snapshot) makeParts(ctx context.Context, progress io.Writer, sna
|
||||||
defer st.Stop()
|
defer st.Stop()
|
||||||
|
|
||||||
// get all the components
|
// get all the components
|
||||||
comps := collection.FilterClone(snapshots.Snapshotable, func(sc component.Snapshotable) bool {
|
comps := collection.FilterClone(snapshots.Dependencies.Snapshotable, func(sc component.Snapshotable) bool {
|
||||||
return sc.SnapshotNeedsRunning() == needsRunning
|
return sc.SnapshotNeedsRunning() == needsRunning
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,11 @@ import (
|
||||||
// Instances manages multiple WissKI Instances.
|
// Instances manages multiple WissKI Instances.
|
||||||
type Instances struct {
|
type Instances struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Malt *malt.Malt
|
Malt *malt.Malt
|
||||||
SQL *sql.SQL
|
SQL *sql.SQL
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (instances *Instances) Path() string {
|
func (instances *Instances) Path() string {
|
||||||
return filepath.Join(instances.Still.Config.DeployRoot, "instances")
|
return filepath.Join(instances.Still.Config.DeployRoot, "instances")
|
||||||
|
|
@ -38,13 +39,13 @@ var errSQL = exit.Error{
|
||||||
|
|
||||||
// use uses the non-nil wisski instance with this instances
|
// use uses the non-nil wisski instance with this instances
|
||||||
func (instances *Instances) use(wisski *wisski.WissKI) {
|
func (instances *Instances) use(wisski *wisski.WissKI) {
|
||||||
wisski.Liquid.Malt = instances.Malt
|
wisski.Liquid.Malt = instances.Dependencies.Malt
|
||||||
}
|
}
|
||||||
|
|
||||||
// WissKI returns the WissKI with the provided slug, if it exists.
|
// WissKI returns the WissKI with the provided slug, if it exists.
|
||||||
// It the WissKI does not exist, returns ErrWissKINotFound.
|
// It the WissKI does not exist, returns ErrWissKINotFound.
|
||||||
func (instances *Instances) WissKI(ctx context.Context, slug string) (wissKI *wisski.WissKI, err error) {
|
func (instances *Instances) WissKI(ctx context.Context, slug string) (wissKI *wisski.WissKI, err error) {
|
||||||
sql := instances.SQL
|
sql := instances.Dependencies.SQL
|
||||||
if err := sql.WaitQueryTable(ctx); err != nil {
|
if err := sql.WaitQueryTable(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -84,7 +85,7 @@ func (instances *Instances) Instance(ctx context.Context, instance models.Instan
|
||||||
// Has checks if a WissKI with the provided slug exists inside the database.
|
// Has checks if a WissKI with the provided slug exists inside the database.
|
||||||
// It does not perform any checks on the WissKI itself.
|
// It does not perform any checks on the WissKI itself.
|
||||||
func (instances *Instances) Has(ctx context.Context, slug string) (ok bool, err error) {
|
func (instances *Instances) Has(ctx context.Context, slug string) (ok bool, err error) {
|
||||||
sql := instances.SQL
|
sql := instances.Dependencies.SQL
|
||||||
if err := sql.WaitQueryTable(ctx); err != nil {
|
if err := sql.WaitQueryTable(ctx); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +129,7 @@ func (instances *Instances) Load(ctx context.Context, slugs ...string) ([]*wissk
|
||||||
|
|
||||||
// find finds instances based on the provided query
|
// find finds instances based on the provided query
|
||||||
func (instances *Instances) find(ctx context.Context, order bool, query func(table *gorm.DB) *gorm.DB) (results []*wisski.WissKI, err error) {
|
func (instances *Instances) find(ctx context.Context, order bool, query func(table *gorm.DB) *gorm.DB) (results []*wisski.WissKI, err error) {
|
||||||
sql := instances.SQL
|
sql := instances.Dependencies.SQL
|
||||||
if err := sql.WaitQueryTable(ctx); err != nil {
|
if err := sql.WaitQueryTable(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ import (
|
||||||
type Malt struct {
|
type Malt struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
|
||||||
TS *triplestore.Triplestore
|
TS *triplestore.Triplestore `auto:"true"`
|
||||||
SQL *sql.SQL
|
SQL *sql.SQL `auto:"true"`
|
||||||
Meta *meta.Meta
|
Meta *meta.Meta `auto:"true"`
|
||||||
ExporterLog *logger.Logger
|
ExporterLog *logger.Logger `auto:"true"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@ import (
|
||||||
// Component meta is responsible for managing metadata per WissKI Instance
|
// Component meta is responsible for managing metadata per WissKI Instance
|
||||||
type Meta struct {
|
type Meta struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
SQL *sql.SQL
|
SQL *sql.SQL
|
||||||
|
}
|
||||||
|
|
||||||
sl sync.Mutex
|
sl sync.Mutex
|
||||||
sc map[string]*Storage
|
sc map[string]*Storage
|
||||||
|
|
@ -40,7 +41,7 @@ func (meta *Meta) Storage(slug string) *Storage {
|
||||||
// create a new storage
|
// create a new storage
|
||||||
meta.sc[slug] = &Storage{
|
meta.sc[slug] = &Storage{
|
||||||
Slug: slug,
|
Slug: slug,
|
||||||
sql: meta.SQL,
|
sql: meta.Dependencies.SQL,
|
||||||
}
|
}
|
||||||
return meta.sc[slug]
|
return meta.sc[slug]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ func (resolver *Resolver) Cron(ctx context.Context) error {
|
||||||
// AllPrefixes returns a list of all prefixes from the server.
|
// AllPrefixes returns a list of all prefixes from the server.
|
||||||
// Prefixes may be cached on the server
|
// Prefixes may be cached on the server
|
||||||
func (resolver *Resolver) AllPrefixes(ctx context.Context) (map[string]string, error) {
|
func (resolver *Resolver) AllPrefixes(ctx context.Context) (map[string]string, error) {
|
||||||
instances, err := resolver.Instances.All(ctx)
|
instances, err := resolver.Dependencies.Instances.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,9 @@ import (
|
||||||
|
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
|
}
|
||||||
|
|
||||||
prefixes lazy.Lazy[map[string]string] // cached prefixes (from the server)
|
prefixes lazy.Lazy[map[string]string] // cached prefixes (from the server)
|
||||||
RefreshInterval time.Duration
|
RefreshInterval time.Duration
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ func (ssh2 *SSH2) handleAuth(ctx ssh.Context, key ssh.PublicKey) bool {
|
||||||
|
|
||||||
// grab permissions for each instance
|
// grab permissions for each instance
|
||||||
{
|
{
|
||||||
instances, err := ssh2.Instances.All(ctx)
|
instances, err := ssh2.Dependencies.Instances.All(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,10 @@ import (
|
||||||
|
|
||||||
type SSH2 struct {
|
type SSH2 struct {
|
||||||
component.Base
|
component.Base
|
||||||
|
Dependencies struct {
|
||||||
Instances *instances.Instances
|
Instances *instances.Instances
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ component.Installable = (*SSH2)(nil)
|
_ component.Installable = (*SSH2)(nil)
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,11 @@ import (
|
||||||
// Barrel provides access to the underlying Barrel
|
// Barrel provides access to the underlying Barrel
|
||||||
type Barrel struct {
|
type Barrel struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Locker *locker.Locker
|
Locker *locker.Locker
|
||||||
MStore *mstore.MStore
|
MStore *mstore.MStore
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (barrel *Barrel) DataPath() string {
|
func (barrel *Barrel) DataPath() string {
|
||||||
return filepath.Join(barrel.FilesystemBase, "data")
|
return filepath.Join(barrel.FilesystemBase, "data")
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ import (
|
||||||
//
|
//
|
||||||
// It also logs the current time into the metadata belonging to this instance.
|
// It also logs the current time into the metadata belonging to this instance.
|
||||||
func (barrel *Barrel) Build(ctx context.Context, progress io.Writer, start bool) error {
|
func (barrel *Barrel) Build(ctx context.Context, progress io.Writer, start bool) error {
|
||||||
if !barrel.Locker.TryLock(ctx) {
|
if !barrel.Dependencies.Locker.TryLock(ctx) {
|
||||||
return locker.Locked
|
return locker.Locked
|
||||||
}
|
}
|
||||||
defer barrel.Locker.Unlock(ctx)
|
defer barrel.Dependencies.Locker.Unlock(ctx)
|
||||||
|
|
||||||
stack := barrel.Stack()
|
stack := barrel.Stack()
|
||||||
|
|
||||||
|
|
@ -48,7 +48,7 @@ func (barrel *Barrel) Build(ctx context.Context, progress io.Writer, start bool)
|
||||||
var lastRebuild = mstore.For[int64]("lastRebuild")
|
var lastRebuild = mstore.For[int64]("lastRebuild")
|
||||||
|
|
||||||
func (barrel Barrel) LastRebuild(ctx context.Context) (t time.Time, err error) {
|
func (barrel Barrel) LastRebuild(ctx context.Context) (t time.Time, err error) {
|
||||||
epoch, err := lastRebuild.Get(ctx, barrel.MStore)
|
epoch, err := lastRebuild.Get(ctx, barrel.Dependencies.MStore)
|
||||||
if err == meta.ErrMetadatumNotSet {
|
if err == meta.ErrMetadatumNotSet {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
@ -61,16 +61,17 @@ func (barrel Barrel) LastRebuild(ctx context.Context) (t time.Time, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (barrel *Barrel) setLastRebuild(ctx context.Context) error {
|
func (barrel *Barrel) setLastRebuild(ctx context.Context) error {
|
||||||
return lastRebuild.Set(ctx, barrel.MStore, time.Now().Unix())
|
return lastRebuild.Set(ctx, barrel.Dependencies.MStore, time.Now().Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
type LastRebuildFetcher struct {
|
type LastRebuildFetcher struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Barrel *Barrel
|
Barrel *Barrel
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (lbr *LastRebuildFetcher) Fetch(ctx context.Context, flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
func (lbr *LastRebuildFetcher) Fetch(ctx context.Context, flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||||
info.LastRebuild, _ = lbr.Barrel.LastRebuild(ctx)
|
info.LastRebuild, _ = lbr.Dependencies.Barrel.LastRebuild(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ var errCronFailed = exit.Error{
|
||||||
}
|
}
|
||||||
|
|
||||||
func (drush *Drush) Cron(ctx context.Context, progress io.Writer) error {
|
func (drush *Drush) Cron(ctx context.Context, progress io.Writer) error {
|
||||||
code := drush.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/cron.sh")()
|
code := drush.Dependencies.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/cron.sh")()
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
// keep going, because we want to run as many crons as possible
|
// keep going, because we want to run as many crons as possible
|
||||||
logging.ProgressF(progress, ctx, "%v", errCronFailed.WithMessageF(drush.Slug, code))
|
logging.ProgressF(progress, ctx, "%v", errCronFailed.WithMessageF(drush.Slug, code))
|
||||||
|
|
@ -31,7 +31,7 @@ func (drush *Drush) Cron(ctx context.Context, progress io.Writer) error {
|
||||||
|
|
||||||
func (drush *Drush) LastCron(ctx context.Context, server *phpx.Server) (t time.Time, err error) {
|
func (drush *Drush) LastCron(ctx context.Context, server *phpx.Server) (t time.Time, err error) {
|
||||||
var timestamp int64
|
var timestamp int64
|
||||||
err = drush.PHP.EvalCode(ctx, server, ×tamp, `$val = \Drupal::state()->get('system.cron_last'); return $val; `)
|
err = drush.Dependencies.PHP.EvalCode(ctx, server, ×tamp, `$val = \Drupal::state()->get('system.cron_last'); return $val; `)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -40,9 +40,10 @@ func (drush *Drush) LastCron(ctx context.Context, server *phpx.Server) (t time.T
|
||||||
|
|
||||||
type LastCronFetcher struct {
|
type LastCronFetcher struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Drush *Drush
|
Drush *Drush
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*LastCronFetcher)(nil)
|
_ ingredient.WissKIFetcher = (*LastCronFetcher)(nil)
|
||||||
|
|
@ -53,6 +54,6 @@ func (lbr *LastCronFetcher) Fetch(flags ingredient.FetcherFlags, info *status.Wi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
info.LastRebuild, _ = lbr.Drush.LastCron(flags.Context, flags.Server)
|
info.LastRebuild, _ = lbr.Dependencies.Drush.LastCron(flags.Context, flags.Server)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,9 @@ import (
|
||||||
// Drush implements commands related to drush
|
// Drush implements commands related to drush
|
||||||
type Drush struct {
|
type Drush struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Barrel *barrel.Barrel
|
Barrel *barrel.Barrel
|
||||||
MStore *mstore.MStore
|
MStore *mstore.MStore
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ var errBlindUpdateFailed = exit.Error{
|
||||||
|
|
||||||
// Update performs a blind drush update
|
// Update performs a blind drush update
|
||||||
func (drush *Drush) Update(ctx context.Context, progress io.Writer) error {
|
func (drush *Drush) Update(ctx context.Context, progress io.Writer) error {
|
||||||
code := drush.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/blind_update.sh")()
|
code := drush.Dependencies.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/blind_update.sh")()
|
||||||
if code != 0 {
|
if code != 0 {
|
||||||
return errBlindUpdateFailed.WithMessageF(drush.Slug, code)
|
return errBlindUpdateFailed.WithMessageF(drush.Slug, code)
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ func (drush *Drush) Update(ctx context.Context, progress io.Writer) error {
|
||||||
const lastUpdate = mstore.For[int64]("lastUpdate")
|
const lastUpdate = mstore.For[int64]("lastUpdate")
|
||||||
|
|
||||||
func (drush *Drush) LastUpdate(ctx context.Context) (t time.Time, err error) {
|
func (drush *Drush) LastUpdate(ctx context.Context) (t time.Time, err error) {
|
||||||
epoch, err := lastUpdate.Get(ctx, drush.MStore)
|
epoch, err := lastUpdate.Get(ctx, drush.Dependencies.MStore)
|
||||||
if err == meta.ErrMetadatumNotSet {
|
if err == meta.ErrMetadatumNotSet {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
@ -44,20 +44,21 @@ func (drush *Drush) LastUpdate(ctx context.Context) (t time.Time, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (drush *Drush) setLastUpdate(ctx context.Context) error {
|
func (drush *Drush) setLastUpdate(ctx context.Context) error {
|
||||||
return lastUpdate.Set(ctx, drush.MStore, time.Now().Unix())
|
return lastUpdate.Set(ctx, drush.Dependencies.MStore, time.Now().Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
type LastUpdateFetcher struct {
|
type LastUpdateFetcher struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Drush *Drush
|
Drush *Drush
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*LastUpdateFetcher)(nil)
|
_ ingredient.WissKIFetcher = (*LastUpdateFetcher)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (lbr *LastUpdateFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
func (lbr *LastUpdateFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||||
info.LastUpdate, err = lbr.Drush.LastUpdate(flags.Context)
|
info.LastUpdate, err = lbr.Dependencies.Drush.LastUpdate(flags.Context)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,16 @@ import (
|
||||||
// Instead, this should code directly defined in go.
|
// Instead, this should code directly defined in go.
|
||||||
type Provisioner struct {
|
type Provisioner struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Barrel *barrel.Barrel
|
Barrel *barrel.Barrel
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Provision provisions an instance, assuming that the required databases already exist.
|
// Provision provisions an instance, assuming that the required databases already exist.
|
||||||
func (provision *Provisioner) Provision(ctx context.Context, progress io.Writer) error {
|
func (provision *Provisioner) Provision(ctx context.Context, progress io.Writer) error {
|
||||||
|
|
||||||
// build the container
|
// build the container
|
||||||
if err := provision.Barrel.Build(ctx, progress, false); err != nil {
|
if err := provision.Dependencies.Barrel.Build(ctx, progress, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +57,7 @@ func (provision *Provisioner) Provision(ctx context.Context, progress io.Writer)
|
||||||
// TODO: Move the provision script into the control plane!
|
// TODO: Move the provision script into the control plane!
|
||||||
provisionScript := "sudo PATH=$PATH -u www-data /bin/bash /provision_container.sh " + strings.Join(provisionParams, " ")
|
provisionScript := "sudo PATH=$PATH -u www-data /bin/bash /provision_container.sh " + strings.Join(provisionParams, " ")
|
||||||
|
|
||||||
code, err := provision.Barrel.Stack().Run(ctx, stream.NonInteractive(progress), true, "barrel", "/bin/bash", "-c", provisionScript)
|
code, err := provision.Dependencies.Barrel.Stack().Run(ctx, stream.NonInteractive(progress), true, "barrel", "/bin/bash", "-c", provisionScript)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,16 @@ func (barrel *Barrel) Running(ctx context.Context, progress io.Writer) (bool, er
|
||||||
|
|
||||||
type RunningFetcher struct {
|
type RunningFetcher struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Barrel *Barrel
|
Barrel *Barrel
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*RunningFetcher)(nil)
|
_ ingredient.WissKIFetcher = (*RunningFetcher)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (rf *RunningFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
func (rf *RunningFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||||
info.Running, err = rf.Barrel.Running(flags.Context, io.Discard)
|
info.Running, err = rf.Dependencies.Barrel.Running(flags.Context, io.Discard)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,17 @@ import (
|
||||||
|
|
||||||
type SSH struct {
|
type SSH struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Barrel *barrel.Barrel
|
Barrel *barrel.Barrel
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*SSH)(nil)
|
_ ingredient.WissKIFetcher = (*SSH)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ssh *SSH) Keys() ([]ssh.PublicKey, error) {
|
func (ssh *SSH) Keys() ([]ssh.PublicKey, error) {
|
||||||
file, err := ssh.Environment.Open(ssh.Barrel.AuthorizedKeysPath())
|
file, err := ssh.Environment.Open(ssh.Dependencies.Barrel.AuthorizedKeysPath())
|
||||||
if environment.IsNotExist(err) {
|
if environment.IsNotExist(err) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@ import (
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
Fetchers []ingredient.WissKIFetcher
|
Fetchers []ingredient.WissKIFetcher
|
||||||
|
}
|
||||||
|
|
||||||
Analytics *lazy.PoolAnalytics
|
Analytics *lazy.PoolAnalytics
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +36,7 @@ func (wisski *Info) Information(ctx context.Context, quick bool) (info status.Wi
|
||||||
|
|
||||||
// potentially setup a new server
|
// potentially setup a new server
|
||||||
if !flags.Quick {
|
if !flags.Quick {
|
||||||
flags.Server = wisski.PHP.NewServer()
|
flags.Server = wisski.Dependencies.PHP.NewServer()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer flags.Server.Close()
|
defer flags.Server.Close()
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +44,7 @@ func (wisski *Info) Information(ctx context.Context, quick bool) (info status.Wi
|
||||||
|
|
||||||
// run all the fetchers!
|
// run all the fetchers!
|
||||||
var group errgroup.Group
|
var group errgroup.Group
|
||||||
for _, fetcher := range wisski.Fetchers {
|
for _, fetcher := range wisski.Dependencies.Fetchers {
|
||||||
fetcher := fetcher
|
fetcher := fetcher
|
||||||
group.Go(func() error {
|
group.Go(func() error {
|
||||||
return fetcher.Fetch(flags, &info)
|
return fetcher.Fetch(flags, &info)
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ import (
|
||||||
|
|
||||||
type SnapshotsFetcher struct {
|
type SnapshotsFetcher struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
|
||||||
Info *Info
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,10 @@ import (
|
||||||
|
|
||||||
type Pathbuilder struct {
|
type Pathbuilder struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*Pathbuilder)(nil)
|
_ ingredient.WissKIFetcher = (*Pathbuilder)(nil)
|
||||||
|
|
@ -28,7 +29,7 @@ var pathbuilderPHP string
|
||||||
//
|
//
|
||||||
// server is the server to fetch the pathbuilders from, any may be nil.
|
// server is the server to fetch the pathbuilders from, any may be nil.
|
||||||
func (pathbuilder *Pathbuilder) All(ctx context.Context, server *phpx.Server) (ids []string, err error) {
|
func (pathbuilder *Pathbuilder) All(ctx context.Context, server *phpx.Server) (ids []string, err error) {
|
||||||
err = pathbuilder.PHP.ExecScript(ctx, server, &ids, pathbuilderPHP, "all_list")
|
err = pathbuilder.Dependencies.PHP.ExecScript(ctx, server, &ids, pathbuilderPHP, "all_list")
|
||||||
slices.Sort(ids)
|
slices.Sort(ids)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +39,7 @@ func (pathbuilder *Pathbuilder) All(ctx context.Context, server *phpx.Server) (i
|
||||||
//
|
//
|
||||||
// server is the server to fetch the pathbuilders from, any may be nil.
|
// server is the server to fetch the pathbuilders from, any may be nil.
|
||||||
func (pathbuilder *Pathbuilder) Get(ctx context.Context, server *phpx.Server, id string) (xml string, err error) {
|
func (pathbuilder *Pathbuilder) Get(ctx context.Context, server *phpx.Server, id string) (xml string, err error) {
|
||||||
err = pathbuilder.PHP.ExecScript(ctx, server, &xml, pathbuilderPHP, "one_xml", id)
|
err = pathbuilder.Dependencies.PHP.ExecScript(ctx, server, &xml, pathbuilderPHP, "one_xml", id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,7 +47,7 @@ func (pathbuilder *Pathbuilder) Get(ctx context.Context, server *phpx.Server, id
|
||||||
//
|
//
|
||||||
// server is the server to fetch the pathbuilders from, any may be nil.
|
// server is the server to fetch the pathbuilders from, any may be nil.
|
||||||
func (pathbuilder *Pathbuilder) GetAll(ctx context.Context, server *phpx.Server) (pathbuilders map[string]string, err error) {
|
func (pathbuilder *Pathbuilder) GetAll(ctx context.Context, server *phpx.Server) (pathbuilders map[string]string, err error) {
|
||||||
err = pathbuilder.PHP.ExecScript(ctx, server, &pathbuilders, pathbuilderPHP, "all_xml")
|
err = pathbuilder.Dependencies.PHP.ExecScript(ctx, server, &pathbuilders, pathbuilderPHP, "all_xml")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,11 @@ import (
|
||||||
// Prefixes implements reading and writing prefix
|
// Prefixes implements reading and writing prefix
|
||||||
type Prefixes struct {
|
type Prefixes struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
MStore *mstore.MStore
|
MStore *mstore.MStore
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*Prefixes)(nil)
|
_ ingredient.WissKIFetcher = (*Prefixes)(nil)
|
||||||
|
|
@ -58,7 +59,7 @@ func (prefixes *Prefixes) All(ctx context.Context, server *phpx.Server) ([]strin
|
||||||
|
|
||||||
func (wisski *Prefixes) database(ctx context.Context, server *phpx.Server) (prefixes []string, err error) {
|
func (wisski *Prefixes) database(ctx context.Context, server *phpx.Server) (prefixes []string, err error) {
|
||||||
// get all the ugly prefixes
|
// get all the ugly prefixes
|
||||||
err = wisski.PHP.ExecScript(ctx, server, &prefixes, listURIPrefixesPHP, "list_prefixes")
|
err = wisski.Dependencies.PHP.ExecScript(ctx, server, &prefixes, listURIPrefixesPHP, "list_prefixes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -149,7 +150,7 @@ var prefix = mstore.For[string]("prefix")
|
||||||
|
|
||||||
// Prefixes returns the cached prefixes from the given instance
|
// Prefixes returns the cached prefixes from the given instance
|
||||||
func (wisski *Prefixes) AllCached(ctx context.Context) (results []string, err error) {
|
func (wisski *Prefixes) AllCached(ctx context.Context) (results []string, err error) {
|
||||||
return prefix.GetAll(ctx, wisski.MStore)
|
return prefix.GetAll(ctx, wisski.Dependencies.MStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the cached prefixes of this instance
|
// Update updates the cached prefixes of this instance
|
||||||
|
|
@ -158,7 +159,7 @@ func (wisski *Prefixes) Update(ctx context.Context) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return prefix.SetAll(ctx, wisski.MStore, prefixes...)
|
return prefix.SetAll(ctx, wisski.Dependencies.MStore, prefixes...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (prefixes *Prefixes) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
func (prefixes *Prefixes) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) {
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,19 @@ import (
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//go:embed settings.php
|
//go:embed settings.php
|
||||||
var settingsPHP string
|
var settingsPHP string
|
||||||
|
|
||||||
func (settings *Settings) Get(ctx context.Context, server *phpx.Server, key string) (value any, err error) {
|
func (settings *Settings) Get(ctx context.Context, server *phpx.Server, key string) (value any, err error) {
|
||||||
err = settings.PHP.ExecScript(ctx, server, &value, settingsPHP, "get_setting", key)
|
err = settings.Dependencies.PHP.ExecScript(ctx, server, &value, settingsPHP, "get_setting", key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (settings *Settings) Set(ctx context.Context, server *phpx.Server, key string, value any) error {
|
func (settings *Settings) Set(ctx context.Context, server *phpx.Server, key string, value any) error {
|
||||||
return settings.PHP.ExecScript(ctx, server, nil, settingsPHP, "set_setting", key, value)
|
return settings.Dependencies.PHP.ExecScript(ctx, server, nil, settingsPHP, "set_setting", key, value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@ import (
|
||||||
|
|
||||||
type Stats struct {
|
type Stats struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*Stats)(nil)
|
_ ingredient.WissKIFetcher = (*Stats)(nil)
|
||||||
|
|
@ -25,7 +26,7 @@ var statsPHP string
|
||||||
|
|
||||||
// Get fetches all statistics from the server
|
// Get fetches all statistics from the server
|
||||||
func (stats *Stats) Get(ctx context.Context, server *phpx.Server) (data status.Statistics, err error) {
|
func (stats *Stats) Get(ctx context.Context, server *phpx.Server) (data status.Statistics, err error) {
|
||||||
err = stats.PHP.ExecScript(ctx, server, &data, statsPHP, "export_statistics")
|
err = stats.Dependencies.PHP.ExecScript(ctx, server, &data, statsPHP, "export_statistics")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ import (
|
||||||
|
|
||||||
type PHP struct {
|
type PHP struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
Barrel *barrel.Barrel
|
Barrel *barrel.Barrel
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ExecScript executes the PHP code as a script on the given server.
|
// ExecScript executes the PHP code as a script on the given server.
|
||||||
// When server is nil, creates a new server and automatically closes it after execution.
|
// When server is nil, creates a new server and automatically closes it after execution.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,6 @@ func (php *PHP) NewServer() *phpx.Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (php *PHP) spawn(ctx context.Context, str stream.IOStream, code string) error {
|
func (php *PHP) spawn(ctx context.Context, str stream.IOStream, code string) error {
|
||||||
php.Barrel.Shell(ctx, str, "-c", shellescape.QuoteCommand([]string{"drush", "php:eval", code}))()
|
php.Dependencies.Barrel.Shell(ctx, str, "-c", shellescape.QuoteCommand([]string{"drush", "php:eval", code}))()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ import (
|
||||||
var errGetValidator = errors.New("GetPasswordValidator: Unknown Error")
|
var errGetValidator = errors.New("GetPasswordValidator: Unknown Error")
|
||||||
|
|
||||||
func (u *Users) GetPasswordValidator(ctx context.Context, username string) (pv PasswordValidator, err error) {
|
func (u *Users) GetPasswordValidator(ctx context.Context, username string) (pv PasswordValidator, err error) {
|
||||||
server := u.PHP.NewServer()
|
server := u.Dependencies.PHP.NewServer()
|
||||||
|
|
||||||
var hash string
|
var hash string
|
||||||
err = u.PHP.ExecScript(ctx, server, &hash, usersPHP, "get_password_hash", username)
|
err = u.Dependencies.PHP.ExecScript(ctx, server, &hash, usersPHP, "get_password_hash", username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.Close()
|
server.Close()
|
||||||
return pv, err
|
return pv, err
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,10 @@ import (
|
||||||
|
|
||||||
type Users struct {
|
type Users struct {
|
||||||
ingredient.Base
|
ingredient.Base
|
||||||
|
Dependencies struct {
|
||||||
PHP *php.PHP
|
PHP *php.PHP
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ ingredient.WissKIFetcher = (*Users)(nil)
|
_ ingredient.WissKIFetcher = (*Users)(nil)
|
||||||
|
|
@ -27,7 +28,7 @@ var usersPHP string
|
||||||
|
|
||||||
// All returns all known usernames
|
// All returns all known usernames
|
||||||
func (u *Users) All(ctx context.Context, server *phpx.Server) (users []status.User, err error) {
|
func (u *Users) All(ctx context.Context, server *phpx.Server) (users []status.User, err error) {
|
||||||
err = u.PHP.ExecScript(ctx, server, &users, usersPHP, "list_users")
|
err = u.Dependencies.PHP.ExecScript(ctx, server, &users, usersPHP, "list_users")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -38,7 +39,7 @@ func (u *Users) Login(ctx context.Context, server *phpx.Server, username string)
|
||||||
|
|
||||||
// generate a (relative) link
|
// generate a (relative) link
|
||||||
var path string
|
var path string
|
||||||
err = u.PHP.ExecScript(ctx, server, &path, usersPHP, "get_login_link", username)
|
err = u.Dependencies.PHP.ExecScript(ctx, server, &path, usersPHP, "get_login_link", username)
|
||||||
|
|
||||||
// if something went wrong, return
|
// if something went wrong, return
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -64,7 +65,7 @@ var errSetPassword = errors.New("SetPassword: Unknown Error")
|
||||||
// SetPassword sets the password for a given user
|
// SetPassword sets the password for a given user
|
||||||
func (u *Users) SetPassword(ctx context.Context, server *phpx.Server, username, password string) error {
|
func (u *Users) SetPassword(ctx context.Context, server *phpx.Server, username, password string) error {
|
||||||
var ok bool
|
var ok bool
|
||||||
err := u.PHP.ExecScript(ctx, server, &ok, usersPHP, "set_user_password", username, password)
|
err := u.Dependencies.PHP.ExecScript(ctx, server, &ok, usersPHP, "set_user_password", username, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,11 @@ func (di *delayedInit[Component]) Run(all []Component) {
|
||||||
// - A pointer to a struct type that implements component
|
// - A pointer to a struct type that implements component
|
||||||
// - A slice type of an interface type that implements component
|
// - A slice type of an interface type that implements component
|
||||||
//
|
//
|
||||||
|
// Such component-like fields are only initialized if one of the following conditions are met:
|
||||||
|
//
|
||||||
|
// - The field has a tag 'auto' with the value `true`
|
||||||
|
// - The field lives inside a struct field named `Dependencies`
|
||||||
|
//
|
||||||
// These fields are initialized in an undefined order during initialization.
|
// These fields are initialized in an undefined order during initialization.
|
||||||
// The init function may not rely on these existing.
|
// The init function may not rely on these existing.
|
||||||
// Furthermore, the init function may not cause other components to be initialized.
|
// Furthermore, the init function may not cause other components to be initialized.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ type PoolAnalyticsComponent struct {
|
||||||
CFields map[string]string // fields with type C for which C implements component
|
CFields map[string]string // fields with type C for which C implements component
|
||||||
IFields map[string]string // fields []I where I is an interface that implements component
|
IFields map[string]string // fields []I where I is an interface that implements component
|
||||||
|
|
||||||
|
DCFields map[string]string // fields of the auto field with type C for which C implements component
|
||||||
|
DIFields map[string]string // fields of the auto field []I where I is an interface that implements component
|
||||||
|
|
||||||
Methods map[string]string // Method signatures of type
|
Methods map[string]string // Method signatures of type
|
||||||
}
|
}
|
||||||
type PoolAnalyticsGroup struct {
|
type PoolAnalyticsGroup struct {
|
||||||
|
|
@ -61,11 +64,18 @@ func (context *PoolContext[Component]) anal(anal *PoolAnalytics, groups []reflec
|
||||||
anal.Components[meta.Name].CFields = collection.MapValues(meta.CFields, func(key string, tp reflect.Type) string {
|
anal.Components[meta.Name].CFields = collection.MapValues(meta.CFields, func(key string, tp reflect.Type) string {
|
||||||
return nameOf(tp.Elem())
|
return nameOf(tp.Elem())
|
||||||
})
|
})
|
||||||
|
anal.Components[meta.Name].DCFields = collection.MapValues(meta.DCFields, func(key string, tp reflect.Type) string {
|
||||||
|
return nameOf(tp.Elem())
|
||||||
|
})
|
||||||
|
|
||||||
anal.Components[meta.Name].IFields = collection.MapValues(meta.IFields, func(key string, iface reflect.Type) string {
|
anal.Components[meta.Name].IFields = collection.MapValues(meta.IFields, func(key string, iface reflect.Type) string {
|
||||||
ifaces = append(ifaces, iface)
|
ifaces = append(ifaces, iface)
|
||||||
return nameOf(iface)
|
return nameOf(iface)
|
||||||
})
|
})
|
||||||
|
anal.Components[meta.Name].DIFields = collection.MapValues(meta.DIFields, func(key string, iface reflect.Type) string {
|
||||||
|
ifaces = append(ifaces, iface)
|
||||||
|
return nameOf(iface)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// and analyze all ifaces
|
// and analyze all ifaces
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,14 @@ type meta[Component any] struct {
|
||||||
|
|
||||||
CFields map[string]reflect.Type // fields with type C for which C implements component
|
CFields map[string]reflect.Type // fields with type C for which C implements component
|
||||||
IFields map[string]reflect.Type // fields []I where I is an interface that implements component
|
IFields map[string]reflect.Type // fields []I where I is an interface that implements component
|
||||||
|
|
||||||
|
DCFields map[string]reflect.Type // fields with type C for which C inside auto field which implement component
|
||||||
|
DIFields map[string]reflect.Type // fields []I where I is an interface inside auto field that implements component
|
||||||
}
|
}
|
||||||
|
|
||||||
// init initializes this meta
|
// init initializes this meta
|
||||||
func (m *meta[Component]) init(tp reflect.Type) {
|
func (m *meta[Component]) init(tp reflect.Type) {
|
||||||
var componentType = reflectx.TypeOf[Component]()
|
var component = reflectx.TypeOf[Component]()
|
||||||
|
|
||||||
if tp.Kind() != reflect.Pointer && tp.Elem().Kind() != reflect.Struct {
|
if tp.Kind() != reflect.Pointer && tp.Elem().Kind() != reflect.Struct {
|
||||||
panic("GetMeta: Type (" + tp.String() + ") must be backed by a pointer to slice")
|
panic("GetMeta: Type (" + tp.String() + ") must be backed by a pointer to slice")
|
||||||
|
|
@ -47,25 +50,59 @@ func (m *meta[Component]) init(tp reflect.Type) {
|
||||||
|
|
||||||
m.CFields = make(map[string]reflect.Type)
|
m.CFields = make(map[string]reflect.Type)
|
||||||
m.IFields = make(map[string]reflect.Type)
|
m.IFields = make(map[string]reflect.Type)
|
||||||
|
scanForFields(component, m.Name, m.Elem, false, m.CFields, m.IFields)
|
||||||
|
|
||||||
// fill the above variables, with a mapping of field name to struct
|
// check if we have a dependencies field of struct type
|
||||||
count := m.Elem.NumField()
|
dependenciesField, ok := m.Elem.FieldByName(dependencies)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dependenciesField.Type.Kind() != reflect.Struct {
|
||||||
|
panic("GetMeta: " + dependencies + " field (" + m.Name + ") is not a struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
// and initialize the type map of the given map
|
||||||
|
m.DCFields = make(map[string]reflect.Type)
|
||||||
|
m.DIFields = make(map[string]reflect.Type)
|
||||||
|
scanForFields(component, m.Name, dependenciesField.Type, true, m.DCFields, m.DIFields)
|
||||||
|
}
|
||||||
|
|
||||||
|
// scanForFields scans the structtype for fields of component-like fields.
|
||||||
|
// they are then writen to the cFields and iFields maps.
|
||||||
|
// inDependenciesStruct indicates if we are inside a dependency struct
|
||||||
|
func scanForFields(component reflect.Type, elem string, structType reflect.Type, inDependenciesStruct bool, cFields map[string]reflect.Type, iFields map[string]reflect.Type) {
|
||||||
|
count := structType.NumField()
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
field := m.Elem.Field(i)
|
field := structType.Field(i)
|
||||||
|
|
||||||
|
if !inDependenciesStruct && field.Tag.Get("auto") != "true" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if inDependenciesStruct && field.Tag != "" {
|
||||||
|
panic("GetMeta: " + dependencies + " field (" + elem + ") contains field (" + field.Name + ") with tag")
|
||||||
|
}
|
||||||
|
|
||||||
name := field.Name
|
|
||||||
tp := field.Type
|
tp := field.Type
|
||||||
|
name := field.Name
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
// field is a pointer to struct that implements a component
|
case implementsComponent(component, tp):
|
||||||
case tp.Implements(componentType) && tp.Kind() == reflect.Pointer && tp.Elem().Kind() == reflect.Struct:
|
cFields[name] = tp
|
||||||
m.CFields[name] = tp
|
case implementsSlice(component, tp):
|
||||||
|
iFields[name] = tp.Elem()
|
||||||
|
case inDependenciesStruct:
|
||||||
|
panic("GetMeta: " + dependencies + " field (" + elem + ") contains non-auto fields")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// field is []I, where I is an interface that implements component
|
func implementsComponent(component reflect.Type, tp reflect.Type) bool {
|
||||||
case tp.Kind() == reflect.Slice && tp.Elem().Kind() == reflect.Interface && tp.Elem().Implements(componentType):
|
return tp.Implements(component) && tp.Kind() == reflect.Pointer && tp.Elem().Kind() == reflect.Struct
|
||||||
m.IFields[name] = tp.Elem()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func implementsSlice(component reflect.Type, tp reflect.Type) bool {
|
||||||
|
return tp.Kind() == reflect.Slice && tp.Elem().Kind() == reflect.Interface && tp.Elem().Implements(component)
|
||||||
}
|
}
|
||||||
|
|
||||||
func nameOf(tp reflect.Type) string {
|
func nameOf(tp reflect.Type) string {
|
||||||
|
|
@ -79,12 +116,16 @@ func (m meta[Component]) New() Component {
|
||||||
|
|
||||||
// NeedsInitComponent
|
// NeedsInitComponent
|
||||||
func (m meta[Component]) NeedsInitComponent() bool {
|
func (m meta[Component]) NeedsInitComponent() bool {
|
||||||
return len(m.CFields) > 0 || len(m.IFields) > 0
|
return len(m.CFields) > 0 || len(m.IFields) > 0 || len(m.DCFields) > 0 || len(m.DIFields) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// name of the dependencies field
|
||||||
|
const dependencies = "Dependencies"
|
||||||
|
|
||||||
// InitComponent sets up the fields of the given instance of a component.
|
// InitComponent sets up the fields of the given instance of a component.
|
||||||
func (m meta[Component]) InitComponent(instance reflect.Value, all []Component) {
|
func (m meta[Component]) InitComponent(instance reflect.Value, all []Component) {
|
||||||
elem := instance.Elem()
|
elem := instance.Elem()
|
||||||
|
dependenciesElem := elem.FieldByName(dependencies)
|
||||||
|
|
||||||
// assign the component fields
|
// assign the component fields
|
||||||
for field, eType := range m.CFields {
|
for field, eType := range m.CFields {
|
||||||
|
|
@ -95,14 +136,28 @@ func (m meta[Component]) InitComponent(instance reflect.Value, all []Component)
|
||||||
field := elem.FieldByName(field)
|
field := elem.FieldByName(field)
|
||||||
field.Set(reflect.ValueOf(c))
|
field.Set(reflect.ValueOf(c))
|
||||||
}
|
}
|
||||||
|
for field, eType := range m.DCFields {
|
||||||
|
c := collection.First(all, func(c Component) bool {
|
||||||
|
return reflect.TypeOf(c).AssignableTo(eType)
|
||||||
|
})
|
||||||
|
|
||||||
// assign the multi subtypes
|
field := dependenciesElem.FieldByName(field)
|
||||||
|
field.Set(reflect.ValueOf(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
// assign the interface subtypes
|
||||||
registryR := reflect.ValueOf(all)
|
registryR := reflect.ValueOf(all)
|
||||||
for field, eType := range m.IFields {
|
for field, eType := range m.IFields {
|
||||||
cs := filterSubtype(registryR, eType)
|
cs := filterSubtype(registryR, eType)
|
||||||
field := elem.FieldByName(field)
|
field := elem.FieldByName(field)
|
||||||
field.Set(cs)
|
field.Set(cs)
|
||||||
}
|
}
|
||||||
|
for field, eType := range m.DIFields {
|
||||||
|
cs := filterSubtype(registryR, eType)
|
||||||
|
field := dependenciesElem.FieldByName(field)
|
||||||
|
field.Set(cs)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterSubtype filters the slice of type []S into a slice of type []iface.
|
// filterSubtype filters the slice of type []S into a slice of type []iface.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue