diff --git a/internal/dis/component/server/admin/admin.go b/internal/dis/component/server/admin/admin.go
index e85091b..e9a2023 100644
--- a/internal/dis/component/server/admin/admin.go
+++ b/internal/dis/component/server/admin/admin.go
@@ -7,9 +7,7 @@ import (
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth/policy"
- "github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter"
- "github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter/logger"
- "github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances/purger"
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/templating"
"github.com/julienschmidt/httprouter"
"github.com/rs/zerolog"
@@ -24,9 +22,7 @@ type Admin struct {
Dependencies struct {
Fetchers []component.DistilleryFetcher
- Exporter *exporter.Exporter
- Instances *instances.Instances
- SnapshotsLog *logger.Logger
+ Instances *instances.Instances
Auth *auth.Auth
@@ -34,7 +30,7 @@ type Admin struct {
Templating *templating.Templating
- Purger *purger.Purger
+ Sockets *socket.Sockets
}
Analytics *lazy.PoolAnalytics
@@ -75,7 +71,7 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
handler = &httpx.WebSocket{
Context: ctx,
Fallback: router,
- Handler: admin.serveSocket,
+ Handler: admin.Dependencies.Sockets.Serve,
}
}
diff --git a/internal/dis/component/server/admin/html/index.html b/internal/dis/component/server/admin/html/index.html
index 458e02f..2fe2a0b 100644
--- a/internal/dis/component/server/admin/html/index.html
+++ b/internal/dis/component/server/admin/html/index.html
@@ -180,6 +180,9 @@
Backups
+
+
+
diff --git a/internal/dis/component/server/admin/socket.go b/internal/dis/component/server/admin/socket.go
deleted file mode 100644
index fb41a06..0000000
--- a/internal/dis/component/server/admin/socket.go
+++ /dev/null
@@ -1,158 +0,0 @@
-package admin
-
-import (
- "context"
- "fmt"
- "io"
- "time"
-
- "github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter"
- "github.com/FAU-CDI/wisski-distillery/internal/wisski"
- "github.com/FAU-CDI/wisski-distillery/pkg/httpx"
- "github.com/tkw1536/goprogram/status"
-)
-
-type InstanceAction struct {
- NumParams int
-
- HandleInteractive func(ctx context.Context, info *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error
-}
-
-func (ia *InstanceAction) AsGenericAction() GenericAction {
- return GenericAction{
- NumParams: ia.NumParams + 1,
- HandleInteractive: func(ctx context.Context, info *Admin, out io.Writer, params ...string) error {
- instance, err := info.Dependencies.Instances.WissKI(ctx, params[0])
- if err != nil {
- return err
- }
-
- return ia.HandleInteractive(ctx, info, instance, out, params[1:]...)
- },
- }
-}
-
-type GenericAction struct {
- NumParams int
-
- HandleInteractive func(ctx context.Context, info *Admin, out io.Writer, params ...string) error
-}
-
-// non-instance specific actions
-var genericActions = map[string]GenericAction{}
-
-// socket specific actions
-var socketInstanceActions = map[string]InstanceAction{
- "snapshot": {
- HandleInteractive: func(ctx context.Context, admin *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error {
- return admin.Dependencies.Exporter.MakeExport(
- ctx,
- out,
- exporter.ExportTask{
- Dest: "",
- Instance: instance,
-
- StagingOnly: false,
- },
- )
- },
- },
- "rebuild": {
- HandleInteractive: func(ctx context.Context, _ *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error {
- return instance.Barrel().Build(ctx, out, true)
- },
- },
- "update": {
- HandleInteractive: func(ctx context.Context, _ *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error {
- return instance.Drush().Update(ctx, out)
- },
- },
- "cron": {
- HandleInteractive: func(ctx context.Context, _ *Admin, instance *wisski.WissKI, str io.Writer, params ...string) error {
- return instance.Drush().Cron(ctx, str)
- },
- },
- "start": {
- HandleInteractive: func(ctx context.Context, _ *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error {
- return instance.Barrel().Stack().Up(ctx, out)
- },
- },
- "stop": {
- HandleInteractive: func(ctx context.Context, _ *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error {
- return instance.Barrel().Stack().Down(ctx, out)
- },
- },
- "purge": {
- HandleInteractive: func(ctx context.Context, admin *Admin, instance *wisski.WissKI, out io.Writer, params ...string) error {
- return admin.Dependencies.Purger.Purge(ctx, out, instance.Slug)
- },
- },
-}
-
-var socketGenericActions = func() map[string]GenericAction {
- generics := make(map[string]GenericAction, len(socketInstanceActions))
- for n, a := range socketInstanceActions {
- generics[n] = a.AsGenericAction()
- }
- return generics
-}()
-
-func (admin *Admin) serveSocket(conn httpx.WebSocketConnection) {
- // read the next message to act on
- message, ok := <-conn.Read()
- if !ok {
- return
- }
-
- name := string(message.Bytes)
-
- // perform a generic action first
- if action, ok := genericActions[name]; ok {
- admin.handleGenericAction(conn, action)
- return
- }
-
- // then do the socket actions
- if action, ok := socketGenericActions[name]; ok {
- admin.handleGenericAction(conn, action)
- }
-}
-
-var instanceParamsTimeout = time.Second
-
-func (admin *Admin) handleGenericAction(conn httpx.WebSocketConnection, action GenericAction) {
- // read the parameters
- params := make([]string, action.NumParams)
- for i := range params {
- select {
- case message, ok := <-conn.Read():
- if !ok {
- <-conn.WriteText("Insufficient parameters")
- return
- }
- params[i] = string(message.Bytes)
- case <-time.After(instanceParamsTimeout):
- <-conn.WriteText("Timed out reading parameters")
- return
- }
- }
-
- // build a stream
- writer := &status.LineBuffer{
- Line: func(line string) {
- <-conn.WriteText(line)
- },
- FlushLineOnClose: true,
- }
- defer writer.Close()
-
- // handle the interactive action
- if action.HandleInteractive != nil {
- err := action.HandleInteractive(conn.Context(), admin, writer, params...)
- if err != nil {
- fmt.Fprintln(writer, err)
- return
- }
- fmt.Fprintln(writer, "done")
- }
-}
diff --git a/internal/dis/component/server/admin/socket/actions.go b/internal/dis/component/server/admin/socket/actions.go
new file mode 100644
index 0000000..40dc86d
--- /dev/null
+++ b/internal/dis/component/server/admin/socket/actions.go
@@ -0,0 +1,83 @@
+package socket
+
+import (
+ "context"
+ "io"
+
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter"
+ "github.com/FAU-CDI/wisski-distillery/internal/wisski"
+)
+
+// non-instance specific actions
+var actions = map[string]SocketAction{
+ "backup": {
+ HandleInteractive: func(ctx context.Context, socket *Sockets, out io.Writer, params ...string) error {
+ return socket.Dependencies.Exporter.MakeExport(
+ ctx,
+ out,
+ exporter.ExportTask{
+ Dest: "",
+ Instance: nil,
+
+ StagingOnly: false,
+ },
+ )
+ },
+ },
+}
+
+// socket specific actions
+var iActions = map[string]IAction{
+ "snapshot": {
+ HandleInteractive: func(ctx context.Context, socket *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error {
+ return socket.Dependencies.Exporter.MakeExport(
+ ctx,
+ out,
+ exporter.ExportTask{
+ Dest: "",
+ Instance: instance,
+
+ StagingOnly: false,
+ },
+ )
+ },
+ },
+ "rebuild": {
+ HandleInteractive: func(ctx context.Context, _ *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error {
+ return instance.Barrel().Build(ctx, out, true)
+ },
+ },
+ "update": {
+ HandleInteractive: func(ctx context.Context, _ *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error {
+ return instance.Drush().Update(ctx, out)
+ },
+ },
+ "cron": {
+ HandleInteractive: func(ctx context.Context, _ *Sockets, instance *wisski.WissKI, str io.Writer, params ...string) error {
+ return instance.Drush().Cron(ctx, str)
+ },
+ },
+ "start": {
+ HandleInteractive: func(ctx context.Context, _ *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error {
+ return instance.Barrel().Stack().Up(ctx, out)
+ },
+ },
+ "stop": {
+ HandleInteractive: func(ctx context.Context, _ *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error {
+ return instance.Barrel().Stack().Down(ctx, out)
+ },
+ },
+ "purge": {
+ HandleInteractive: func(ctx context.Context, sockets *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error {
+ return sockets.Dependencies.Purger.Purge(ctx, out, instance.Slug)
+ },
+ },
+}
+
+var igActions = func() map[string]SocketAction {
+ generics := make(map[string]SocketAction, len(iActions))
+ for n, a := range iActions {
+ generics[n] = a.AsGenericAction()
+ }
+ return generics
+}()
diff --git a/internal/dis/component/server/admin/socket/socket.go b/internal/dis/component/server/admin/socket/socket.go
new file mode 100644
index 0000000..4ef0fb2
--- /dev/null
+++ b/internal/dis/component/server/admin/socket/socket.go
@@ -0,0 +1,116 @@
+package socket
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "time"
+
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component"
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component/exporter"
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances/purger"
+ "github.com/FAU-CDI/wisski-distillery/internal/wisski"
+ "github.com/FAU-CDI/wisski-distillery/pkg/httpx"
+ "github.com/tkw1536/goprogram/status"
+)
+
+type Sockets struct {
+ component.Base
+
+ Dependencies struct {
+ Instances *instances.Instances
+ Exporter *exporter.Exporter
+ Purger *purger.Purger
+ }
+}
+
+// Serve handles a connection to the websocket api
+func (socket *Sockets) Serve(conn httpx.WebSocketConnection) {
+ // read the next message to act on
+ message, ok := <-conn.Read()
+ if !ok {
+ return
+ }
+
+ name := string(message.Bytes)
+
+ // perform a generic action first
+ if action, ok := actions[name]; ok {
+ socket.Handle(conn, action)
+ return
+ }
+
+ // then do the socket actions
+ if action, ok := igActions[name]; ok {
+ socket.Handle(conn, action)
+ }
+}
+
+var instanceParamsTimeout = time.Second
+
+func (socket *Sockets) Handle(conn httpx.WebSocketConnection, action SocketAction) {
+ // read the parameters
+ params := make([]string, action.NumParams)
+ for i := range params {
+ select {
+ case message, ok := <-conn.Read():
+ if !ok {
+ <-conn.WriteText("Insufficient parameters")
+ return
+ }
+ params[i] = string(message.Bytes)
+ case <-time.After(instanceParamsTimeout):
+ <-conn.WriteText("Timed out reading parameters")
+ return
+ }
+ }
+
+ // build a stream
+ writer := &status.LineBuffer{
+ Line: func(line string) {
+ <-conn.WriteText(line)
+ },
+ FlushLineOnClose: true,
+ }
+ defer writer.Close()
+
+ // handle the interactive action
+ if action.HandleInteractive != nil {
+ err := action.HandleInteractive(conn.Context(), socket, writer, params...)
+ if err != nil {
+ fmt.Fprintln(writer, err)
+ return
+ }
+ fmt.Fprintln(writer, "done")
+ }
+}
+
+// IAction is like SocketAction, but takes the slug of an instance (runnning or not) as the first parameter
+type IAction struct {
+ NumParams int
+
+ HandleInteractive func(ctx context.Context, sockets *Sockets, instance *wisski.WissKI, out io.Writer, params ...string) error
+}
+
+// AsGenericAction turns this InstanceAction into a generic action
+func (ia IAction) AsGenericAction() SocketAction {
+ return SocketAction{
+ NumParams: ia.NumParams + 1,
+ HandleInteractive: func(ctx context.Context, sockets *Sockets, out io.Writer, params ...string) error {
+ instance, err := sockets.Dependencies.Instances.WissKI(ctx, params[0])
+ if err != nil {
+ return err
+ }
+
+ return ia.HandleInteractive(ctx, sockets, instance, out, params[1:]...)
+ },
+ }
+}
+
+// SocketAction represents an action handled via socket
+type SocketAction struct {
+ NumParams int
+
+ HandleInteractive func(ctx context.Context, sockets *Sockets, out io.Writer, params ...string) error
+}
diff --git a/internal/dis/distillery.go b/internal/dis/distillery.go
index 39797a4..dc0a942 100644
--- a/internal/dis/distillery.go
+++ b/internal/dis/distillery.go
@@ -20,6 +20,7 @@ import (
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/resolver"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin"
+ "github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/admin/socket"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/assets"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/cron"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/server/home"
@@ -186,6 +187,7 @@ func (dis *Distillery) allComponents() []initFunc {
manual(func(admin *admin.Admin) {
admin.Analytics = &dis.pool.Analytics
}),
+ auto[*socket.Sockets],
auto[*legal.Legal],
auto[*news.News],