internal/component => internal/dis/component
This commit is contained in:
parent
9443217441
commit
b5b1ce2340
123 changed files with 76 additions and 76 deletions
70
internal/dis/component/home/home.go
Normal file
70
internal/dis/component/home/home.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package home
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/lazy"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
type Home struct {
|
||||
component.Base
|
||||
|
||||
Instances *instances.Instances
|
||||
|
||||
RefreshInterval time.Duration
|
||||
|
||||
redirect lazy.Lazy[*Redirect]
|
||||
instanceNames lazy.Lazy[map[string]struct{}]
|
||||
homeBytes lazy.Lazy[[]byte]
|
||||
}
|
||||
|
||||
func (*Home) Routes() []string { return []string{"/"} }
|
||||
|
||||
func (home *Home) Handler(route string, context context.Context, io stream.IOStream) (http.Handler, error) {
|
||||
home.updateRedirect(context, io)
|
||||
home.updateInstances(context, io)
|
||||
home.updateRender(context, io)
|
||||
return home, nil
|
||||
}
|
||||
|
||||
func (home *Home) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
slug, ok := home.Config.SlugFromHost(r.Host)
|
||||
switch {
|
||||
case !ok:
|
||||
http.NotFound(w, r)
|
||||
case slug != "":
|
||||
home.serveWissKI(w, slug, r)
|
||||
default:
|
||||
home.serveRoot(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (home *Home) serveRoot(w http.ResponseWriter, r *http.Request) {
|
||||
// not the root url => server the fallback
|
||||
if !(r.URL.Path == "" || r.URL.Path == "/") {
|
||||
home.redirect.Get(nil).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
w.Write(home.homeBytes.Get(nil))
|
||||
}
|
||||
|
||||
func (home *Home) serveWissKI(w http.ResponseWriter, slug string, r *http.Request) {
|
||||
if _, ok := home.instanceNames.Get(nil)[slug]; !ok {
|
||||
// Get(nil) guaranteed to work by precondition
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
fmt.Fprintf(w, "WissKI %q not found\n", slug)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusBadGateway)
|
||||
fmt.Fprintf(w, "WissKI %q is currently offline\n", slug)
|
||||
}
|
||||
40
internal/dis/component/home/home.html
Normal file
40
internal/dis/component/home/home.html
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>WissKI Distillery</title>
|
||||
{{ CSS }}
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>WissKI Distillery</h1>
|
||||
</header>
|
||||
<main>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1">
|
||||
<p>
|
||||
For more information, see <a href="{{ .SelfRedirect }}">{{ .SelfRedirect }}</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="pure-u-1">
|
||||
<h2>WissKIs on this Distillery</h2>
|
||||
</div>
|
||||
|
||||
{{range .Instances}}
|
||||
{{ if .Running }}
|
||||
<div class="pure-u-1-3">
|
||||
<h3>{{.Slug}}</h3>
|
||||
<p>
|
||||
<a href="{{.URL}}" target="_blank" rel="noopener noreferrer">{{.URL}}</a><br>
|
||||
</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
Generated at <code>{{ .Time }}</code>
|
||||
</footer>
|
||||
|
||||
{{ JS }}
|
||||
</body>
|
||||
94
internal/dis/component/home/public.go
Normal file
94
internal/dis/component/home/public.go
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package home
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"time"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/static"
|
||||
"github.com/FAU-CDI/wisski-distillery/internal/wisski"
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/timex"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
func (home *Home) updateInstances(ctx context.Context, io stream.IOStream) {
|
||||
go func() {
|
||||
for t := range timex.TickContext(ctx, home.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading instance list\n", t.Format(time.Stamp))
|
||||
|
||||
names, _ := home.instanceMap()
|
||||
home.instanceNames.Set(names)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (home *Home) instanceMap() (map[string]struct{}, error) {
|
||||
wissKIs, err := home.Instances.All()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
names := make(map[string]struct{}, len(wissKIs))
|
||||
for _, w := range wissKIs {
|
||||
names[w.Slug] = struct{}{}
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
|
||||
func (home *Home) updateRender(ctx context.Context, io stream.IOStream) {
|
||||
go func() {
|
||||
for t := range timex.TickContext(ctx, home.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading home render\n", t.Format(time.Stamp))
|
||||
|
||||
bytes, _ := home.homeRender()
|
||||
home.homeBytes.Set(bytes)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
//go:embed "home.html"
|
||||
var homeHTMLStr string
|
||||
var homeTemplate = static.AssetsHomeHome.MustParse(homeHTMLStr)
|
||||
|
||||
func (home *Home) homeRender() ([]byte, error) {
|
||||
var context HomeContext
|
||||
|
||||
// setup a couple of static things
|
||||
context.Time = time.Now().UTC()
|
||||
context.SelfRedirect = home.Config.SelfRedirect.String()
|
||||
|
||||
// find all the WissKIs
|
||||
wissKIs, err := home.Instances.All()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
context.Instances = make([]wisski.WissKIInfo, len(wissKIs))
|
||||
|
||||
// determine their infos
|
||||
var eg errgroup.Group
|
||||
for i, instance := range wissKIs {
|
||||
i := i
|
||||
wissKI := instance
|
||||
eg.Go(func() (err error) {
|
||||
context.Instances[i], err = wissKI.Info(true)
|
||||
return
|
||||
})
|
||||
}
|
||||
eg.Wait()
|
||||
|
||||
// render the template
|
||||
var buffer bytes.Buffer
|
||||
homeTemplate.Execute(&buffer, context)
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
type HomeContext struct {
|
||||
Instances []wisski.WissKIInfo
|
||||
|
||||
Time time.Time
|
||||
|
||||
SelfRedirect string
|
||||
}
|
||||
117
internal/dis/component/home/redirect.go
Normal file
117
internal/dis/component/home/redirect.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package home
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/FAU-CDI/wisski-distillery/pkg/timex"
|
||||
"github.com/tkw1536/goprogram/stream"
|
||||
)
|
||||
|
||||
func (home *Home) updateRedirect(ctx context.Context, io stream.IOStream) {
|
||||
go func() {
|
||||
for t := range timex.TickContext(ctx, home.RefreshInterval) {
|
||||
io.Printf("[%s]: reloading overrides\n", t.Format(time.Stamp))
|
||||
|
||||
redirect, _ := home.loadRedirect()
|
||||
home.redirect.Set(&redirect)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (home *Home) loadRedirect() (redirect Redirect, err error) {
|
||||
if redirect.Overrides == nil {
|
||||
redirect.Overrides = make(map[string]string)
|
||||
}
|
||||
redirect.Overrides[""] = home.Config.SelfRedirect.String()
|
||||
|
||||
redirect.Absolute = false
|
||||
redirect.Permanent = false
|
||||
|
||||
// load the overrides file
|
||||
overrides, err := home.Environment.Open(home.Config.SelfOverridesFile)
|
||||
if err != nil {
|
||||
return redirect, err
|
||||
}
|
||||
defer overrides.Close()
|
||||
|
||||
// decode the overrides file
|
||||
if err := json.NewDecoder(overrides).Decode(&redirect.Overrides); err != nil {
|
||||
return redirect, err
|
||||
}
|
||||
|
||||
// and return!
|
||||
return redirect, nil
|
||||
}
|
||||
|
||||
// Redirect implements a redirect server that redirects all requests.
|
||||
// It implements http.Handler.
|
||||
type Redirect struct {
|
||||
// Target is the target URL to redirect to.
|
||||
Target string
|
||||
|
||||
// Fallback is used when target is the empty string.
|
||||
Fallback http.Handler
|
||||
|
||||
// Absolute determines if the request path should be appended to the target URL when redirecting.
|
||||
// By default this path is always appended, set Absolute to true to prevent this.
|
||||
Absolute bool
|
||||
|
||||
// Overrides is a map from paths to URLs that should override the default target.
|
||||
Overrides map[string]string
|
||||
|
||||
// Permanent determines if the redirect responses issued should return
|
||||
// Permanent Redirect (Status Code 308) or Temporary Redirect (Status Code 307).
|
||||
Permanent bool
|
||||
}
|
||||
|
||||
// Redirect determines the redirect URL for a specific incoming request
|
||||
// If it returns the empty string, the fallback is used.
|
||||
func (redirect Redirect) Redirect(r *http.Request) string {
|
||||
// if we have an override for this URL, use it immediatly
|
||||
url := strings.TrimSuffix(r.URL.Path, "/")
|
||||
if override, ok := redirect.Overrides[url]; ok {
|
||||
return override
|
||||
}
|
||||
|
||||
if redirect.Target == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// if we are in absolute redirect mode, always return the absolute URL
|
||||
if redirect.Absolute {
|
||||
return redirect.Target
|
||||
}
|
||||
|
||||
// return the target + the redirected URL
|
||||
dest := strings.TrimSuffix(redirect.Target, "/") + r.URL.Path
|
||||
if len(r.URL.RawQuery) > 0 {
|
||||
dest += "?" + r.URL.RawQuery
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
// ServeHTTP implements the http.Handler interface and redirects a single request to redirect.Target.
|
||||
func (redirect Redirect) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
dest := redirect.Redirect(r)
|
||||
if dest == "" {
|
||||
if redirect.Fallback == nil {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
redirect.Fallback.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// determine if we are temporary or permanent redirect
|
||||
status := http.StatusTemporaryRedirect
|
||||
if redirect.Permanent {
|
||||
status = http.StatusPermanentRedirect
|
||||
}
|
||||
|
||||
// and do the redirect
|
||||
http.Redirect(w, r, dest, status)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue