internal/dis/componeont/control: Move paths
This commit is contained in:
parent
52559e4d68
commit
e5ddede0c7
43 changed files with 8 additions and 8 deletions
291
internal/dis/component/control/info/html/index.html
Normal file
291
internal/dis/component/control/info/html/index.html
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Distillery Control Page</title>
|
||||
{{ CSS }}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1 id="top">Distillery Control Page</h1>
|
||||
<small>Generated at <code class="date">{{ .Time.Format "2006-01-02T15:04:05Z07:00" }}</code></small>
|
||||
<p>
|
||||
<a class="pure-button pure-button-primary" href="/dis/index">Control</a>
|
||||
</p>
|
||||
</header>
|
||||
<main>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="overview">Distillery Configuration</h2>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-1-3">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Domains
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Primary
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.DefaultDomain}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Extra
|
||||
</td>
|
||||
<td>
|
||||
{{ range .Config.SelfExtraDomains }}
|
||||
<code>{{.}}</code><br />
|
||||
{{ end }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Email <small>(HTTPS)</small>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.CertbotEmail}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-1-3">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Database Settings
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
MySQL User Prefix
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.MysqlUserPrefix}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
MySQL Database Prefix
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.MysqlDatabasePrefix}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
GraphDB User Prefix
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.GraphDBUserPrefix}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
GraphDB Database Prefix
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.GraphDBRepoPrefix}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Bookkeeping Database
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.DistilleryDatabase}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-1-3">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Directory Settings
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>root</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.DeployRoot}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>config</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.ConfigPath}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>authorized_keys</code>
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.GlobalAuthorizedKeysFile}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Misc Settings
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Homepage
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{.Config.SelfRedirect}}" target="_blank" rel="noopener noreferrer">{{.Config.SelfRedirect}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Docker Network Name
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.DockerNetworkName}}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Backup Age
|
||||
</td>
|
||||
<td>
|
||||
<code>{{.Config.MaxBackupAge}}</code> Day(s)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="backups">Backups</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<table class="pure-table pure-table-bordered padding">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Path</th>
|
||||
<th>Created</th>
|
||||
<th>Packed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Backups }}
|
||||
<tr>
|
||||
<td>
|
||||
<code class="path">{{ .Path }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .Created.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
<td>
|
||||
{{ .Packed }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<h2 id="instances">Instances</h2>
|
||||
|
||||
<table class="pure-table pure-table-bordered padding">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Total</th>
|
||||
<th>Running</th>
|
||||
<th>Stopped</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
{{ .TotalCount }}
|
||||
</td>
|
||||
<td>
|
||||
{{ .RunningCount }}
|
||||
</td>
|
||||
<td>
|
||||
{{ .StoppedCount }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<span class="hspace"></span>
|
||||
</div>
|
||||
|
||||
{{range .Instances}}
|
||||
<div class="pure-u-1 pure-u-xl-1-3">
|
||||
<div class="wisski {{ if .Running }}running{{ else }}stopped{{ end }}">
|
||||
<h3>
|
||||
{{.Slug}}
|
||||
{{ if not .Running }} <small>not running</small>{{ end }}
|
||||
</h3>
|
||||
<p>
|
||||
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.URL}}</a><br>
|
||||
|
||||
<a class="pure-button" href="/dis/instance/{{.Slug}}">Details</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
Generated at <code>{{ .Time }}</code>
|
||||
</footer>
|
||||
|
||||
{{ JS }}
|
||||
</body>
|
||||
312
internal/dis/component/control/info/html/instance.html
Normal file
312
internal/dis/component/control/info/html/instance.html
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Distillery Control Page - {{ .Info.Slug }}</title>
|
||||
{{ CSS }}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1 id="top">Distillery Control Page - {{ .Info.Slug }}</h1>
|
||||
<small>Generated at <code class="date">{{ .Time.Format "2006-01-02T15:04:05Z07:00" }}</code></small>
|
||||
<p>
|
||||
<a class="pure-button" href="/dis/index">Control</a> >
|
||||
<a class="pure-button pure-button-primary" href="/dis/instance/{{ .Info.Slug }}">Instance</a>
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="overview">Info & Status</h2>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Overview
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Slug
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Info.Slug }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
URL
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ .Info.URL }}" target="_blank" rel="noopener noreferrer">{{ .Info.URL }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Running
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Info.Running }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Locked
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Info.Locked }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Component Settings
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Directory
|
||||
</td>
|
||||
<td>
|
||||
<code style="overflow: auto;">{{ .Instance.FilesystemBase }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
SQL DB
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Instance.SqlDatabase }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
SQL User
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Instance.SqlUsername }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TS Repo
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Instance.GraphDBRepository }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
TS User
|
||||
</td>
|
||||
<td>
|
||||
<code>{{ .Instance.GraphDBUsername }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Build Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
Created
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .Instance.Created.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Last Rebuild <br>
|
||||
<button class="remote-action pure-button pure-button-action" data-action="rebuild" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Rebuild</button>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .Info.LastRebuild.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Last Cron<br>
|
||||
<button class="remote-action pure-button pure-button-action" data-action="cron" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Cron</button>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .Info.LastRebuild.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Last Update <br>
|
||||
<button class="remote-action pure-button pure-button-action" data-action="update" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Update</button>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .Info.LastUpdate.Format "2006-01-02T15:04:05Z07:00" }}</code><br>
|
||||
(Automatic: <code>{{ .Instance.AutoBlindUpdateEnabled }}</code>)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-2-5">
|
||||
<!--
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Composer Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
???
|
||||
</td>
|
||||
<td>
|
||||
???
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="wisski">WissKI Data</h2>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">
|
||||
Pathbuilders
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{{ range $name, $xml := .Info.Pathbuilders }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $name }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="pathbuilder" data-name="{{ $name }}">{{ $xml }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-xl-1-2">
|
||||
<div class="padding">
|
||||
<div class="overflow">
|
||||
<table class="pure-table pure-table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
URI Prefixes
|
||||
|
||||
{{ if .Info.NoPrefixes }}
|
||||
(excluded from resolver)
|
||||
{{ end }}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range $index, $prefix := .Info.Prefixes }}
|
||||
<tr>
|
||||
<td>
|
||||
<code>{{ $prefix }}</code>
|
||||
</td>
|
||||
</tr>
|
||||
{{ end }}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1-1">
|
||||
<h2 id="snapshots">Snapshots</h2>
|
||||
<p>
|
||||
<button class="remote-action pure-button pure-button-action" data-action="snapshot" data-param="{{ .Instance.Slug }}" data-buffer="1000" data-force-reload="true">Take a snapshot</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<table class="pure-table pure-table-bordered padding">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Path</th>
|
||||
<th>Created</th>
|
||||
<th>Packed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Info.Snapshots }}
|
||||
<tr>
|
||||
<td>
|
||||
<code class="path">{{ .Path }}</code>
|
||||
</td>
|
||||
<td>
|
||||
<code class="date">{{ .Created.Format "2006-01-02T15:04:05Z07:00" }}</code>
|
||||
</td>
|
||||
<td>
|
||||
{{ .Packed }}
|
||||
</td>
|
||||
</tr>
|
||||
{{ end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{ JS }}
|
||||
</body>
|
||||
85
internal/dis/component/control/info/index.go
Normal file
85
internal/dis/component/control/info/index.go
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/config"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/info"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
//go:embed "html/index.html"
|
||||
var indexTemplateStr string
|
||||
var indexTemplate = static.AssetsControlIndex.MustParse(indexTemplateStr)
|
||||
|
||||
type indexPageContext struct {
|
||||
Time time.Time
|
||||
|
||||
Config *config.Config
|
||||
|
||||
Instances []info.WissKIInfo
|
||||
|
||||
TotalCount int
|
||||
RunningCount int
|
||||
StoppedCount int
|
||||
|
||||
Backups []models.Export
|
||||
}
|
||||
|
||||
func (nfo *Info) indexPageAPI(r *http.Request) (idx indexPageContext, err error) {
|
||||
var group errgroup.Group
|
||||
|
||||
group.Go(func() error {
|
||||
// list all the instances
|
||||
all, err := nfo.Instances.All()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get all of their info!
|
||||
idx.Instances = make([]info.WissKIInfo, len(all))
|
||||
for i, instance := range all {
|
||||
{
|
||||
i := i
|
||||
instance := instance
|
||||
|
||||
// store the info for this group!
|
||||
group.Go(func() (err error) {
|
||||
idx.Instances[i], err = instance.Info().Information(true)
|
||||
return err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// get the log entries
|
||||
group.Go(func() (err error) {
|
||||
idx.Backups, err = nfo.SnapshotsLog.For("")
|
||||
return
|
||||
})
|
||||
|
||||
// get the static properties
|
||||
idx.Config = nfo.Config
|
||||
idx.Time = time.Now().UTC()
|
||||
|
||||
group.Wait()
|
||||
|
||||
// count how many are running and how many are stopped
|
||||
for _, i := range idx.Instances {
|
||||
if i.Running {
|
||||
idx.RunningCount++
|
||||
} else {
|
||||
idx.StoppedCount++
|
||||
}
|
||||
}
|
||||
idx.TotalCount = len(idx.Instances)
|
||||
|
||||
return
|
||||
}
|
||||
60
internal/dis/component/control/info/info.go
Normal file
60
internal/dis/component/control/info/info.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"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/exporter/logger"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
type Info struct {
|
||||
component.Base
|
||||
|
||||
Exporter *exporter.Exporter
|
||||
Instances *instances.Instances
|
||||
SnapshotsLog *logger.Logger
|
||||
}
|
||||
|
||||
func (*Info) Routes() []string { return []string{"/dis/"} }
|
||||
|
||||
func (info *Info) Handler(route string, context context.Context, io stream.IOStream) (http.Handler, error) {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// handle everything
|
||||
mux.HandleFunc(route, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == route {
|
||||
http.Redirect(w, r, route+"/index", http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
})
|
||||
|
||||
// add a handler for the index page
|
||||
mux.Handle(route+"index", httpx.HTMLHandler[indexPageContext]{
|
||||
Handler: info.indexPageAPI,
|
||||
Template: indexTemplate,
|
||||
})
|
||||
|
||||
// add a handler for the instance page
|
||||
mux.Handle(route+"instance/", httpx.HTMLHandler[instancePageContext]{
|
||||
Handler: info.instancePageAPI,
|
||||
Template: instanceTemplate,
|
||||
})
|
||||
|
||||
handler := &httpx.WebSocket{
|
||||
Context: context,
|
||||
Fallback: mux,
|
||||
Handler: info.serveSocket,
|
||||
}
|
||||
|
||||
// ensure that everyone is logged in!
|
||||
return httpx.BasicAuth(handler, "WissKI Distillery Admin", func(user, pass string) bool {
|
||||
return user == info.Config.DisAdminUser && pass == info.Config.DisAdminPassword
|
||||
}), nil
|
||||
}
|
||||
52
internal/dis/component/control/info/instance.go
Normal file
52
internal/dis/component/control/info/instance.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/models"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski/ingredient/info"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/httpx"
|
||||
)
|
||||
|
||||
//go:embed "html/instance.html"
|
||||
var instanceTemplateString string
|
||||
var instanceTemplate = static.AssetsControlInstance.MustParse(instanceTemplateString)
|
||||
|
||||
type instancePageContext struct {
|
||||
Time time.Time
|
||||
|
||||
Instance models.Instance
|
||||
Info info.WissKIInfo
|
||||
}
|
||||
|
||||
func (info *Info) instancePageAPI(r *http.Request) (is instancePageContext, err error) {
|
||||
// find the slug as the last component of path!
|
||||
slug := strings.TrimSuffix(r.URL.Path, "/")
|
||||
slug = slug[strings.LastIndex(slug, "/")+1:]
|
||||
|
||||
// find the instance itself!
|
||||
instance, err := info.Instances.WissKI(slug)
|
||||
if err == instances.ErrWissKINotFound {
|
||||
return is, httpx.ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return is, err
|
||||
}
|
||||
is.Instance = instance.Instance
|
||||
|
||||
// get some more info about the wisski
|
||||
is.Info, err = instance.Info().Information(false)
|
||||
if err != nil {
|
||||
return is, err
|
||||
}
|
||||
|
||||
// current time
|
||||
is.Time = time.Now().UTC()
|
||||
|
||||
return
|
||||
}
|
||||
86
internal/dis/component/control/info/socket.go
Normal file
86
internal/dis/component/control/info/socket.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package info
|
||||
|
||||
import (
|
||||
"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"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
type instanceActionFunc = func(info *Info, instance *wisski.WissKI, str stream.IOStream) error
|
||||
|
||||
var socketInstanceActions = map[string]instanceActionFunc{
|
||||
"snapshot": func(info *Info, instance *wisski.WissKI, str stream.IOStream) error {
|
||||
return info.Exporter.MakeExport(
|
||||
str,
|
||||
exporter.ExportTask{
|
||||
Dest: "",
|
||||
Instance: instance,
|
||||
|
||||
StagingOnly: false,
|
||||
},
|
||||
)
|
||||
},
|
||||
"rebuild": func(_ *Info, instance *wisski.WissKI, str stream.IOStream) error {
|
||||
return instance.Barrel().Build(str, true)
|
||||
},
|
||||
"update": func(_ *Info, instance *wisski.WissKI, str stream.IOStream) error {
|
||||
return instance.Drush().Update(str)
|
||||
},
|
||||
"cron": func(_ *Info, instance *wisski.WissKI, str stream.IOStream) error {
|
||||
return instance.Drush().Cron(str)
|
||||
},
|
||||
}
|
||||
|
||||
func (info *Info) serveSocket(conn httpx.WebSocketConnection) {
|
||||
// read the next message to act on
|
||||
message, ok := <-conn.Read()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// perform an action if it exists!
|
||||
if action, ok := socketInstanceActions[string(message.Bytes)]; ok {
|
||||
info.handleInstanceAction(conn, action)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action instanceActionFunc) {
|
||||
|
||||
// read the slug
|
||||
slug, ok := <-conn.Read()
|
||||
if !ok {
|
||||
conn.WriteText("Error reading slug")
|
||||
return
|
||||
}
|
||||
|
||||
// resolve the instance
|
||||
instance, err := info.Instances.WissKI(string(slug.Bytes))
|
||||
if err != nil {
|
||||
conn.WriteText("Instance not found")
|
||||
return
|
||||
}
|
||||
|
||||
// build a stream
|
||||
writer := &status.LineBuffer{
|
||||
Line: func(line string) {
|
||||
<-conn.WriteText(line)
|
||||
},
|
||||
FlushLineOnClose: true,
|
||||
}
|
||||
defer writer.Close()
|
||||
|
||||
str := stream.NewIOStream(writer, writer, nil, 0)
|
||||
|
||||
// and perform the action
|
||||
{
|
||||
err := action(info, instance, str)
|
||||
if err != nil {
|
||||
str.EPrintln(err)
|
||||
return
|
||||
}
|
||||
str.Println("done")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue