feat: add http server with a page serving service informations
This commit is contained in:
1
http/assets/bulma-0.9.4.min.css
vendored
Normal file
1
http/assets/bulma-0.9.4.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
29
http/options.go
Normal file
29
http/options.go
Normal file
@ -0,0 +1,29 @@
|
||||
package http
|
||||
|
||||
import "log"
|
||||
|
||||
type Options struct {
|
||||
Logger func(message string, args ...any)
|
||||
CustomDir string `env:"CUSTOM_DIR"`
|
||||
}
|
||||
|
||||
type OptionFunc func(*Options)
|
||||
|
||||
func DefaultOptions() *Options {
|
||||
return &Options{
|
||||
Logger: log.Printf,
|
||||
CustomDir: "",
|
||||
}
|
||||
}
|
||||
|
||||
func WithLogger(logger func(message string, args ...any)) func(*Options) {
|
||||
return func(opts *Options) {
|
||||
opts.Logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func WithCustomDir(customDir string) func(*Options) {
|
||||
return func(opts *Options) {
|
||||
opts.CustomDir = customDir
|
||||
}
|
||||
}
|
130
http/server.go
Normal file
130
http/server.go
Normal file
@ -0,0 +1,130 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/dschmidt/go-layerfs"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//go:embed templates
|
||||
var embeddedTemplates embed.FS
|
||||
|
||||
//go:embed assets
|
||||
var embeddedAssets embed.FS
|
||||
|
||||
type Server struct {
|
||||
http *http.Server
|
||||
opts *Options
|
||||
templates template.Template
|
||||
}
|
||||
|
||||
func (s *Server) serveHomepage(w http.ResponseWriter, r *http.Request) {
|
||||
data := struct {
|
||||
Title string
|
||||
}{
|
||||
Title: "Rebound",
|
||||
}
|
||||
|
||||
s.renderTemplate(w, "index", data)
|
||||
}
|
||||
|
||||
func (s *Server) Serve(l net.Listener) error {
|
||||
templatesFilesystem, err := s.getCustomizedFilesystem(embeddedTemplates)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
if err := s.parseTemplates(templatesFilesystem); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
assetsFilesystem, err := s.getCustomizedFilesystem(embeddedAssets)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/assets/", http.FileServer(http.FS(assetsFilesystem)))
|
||||
mux.HandleFunc("/", s.serveHomepage)
|
||||
|
||||
httpServer := &http.Server{
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
s.http = httpServer
|
||||
|
||||
if err := s.http.Serve(l); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) parseTemplates(fs fs.FS) error {
|
||||
templates, err := template.ParseFS(fs, "templates/*.html")
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
s.templates = *templates
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) renderTemplate(w http.ResponseWriter, name string, data any) {
|
||||
var buff bytes.Buffer
|
||||
|
||||
if err := s.templates.ExecuteTemplate(&buff, name, data); err != nil {
|
||||
s.log("[ERROR] %+s", errors.WithStack(err))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := io.Copy(w, &buff); err != nil {
|
||||
s.log("[ERROR] %+s", errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) log(message string, args ...any) {
|
||||
s.opts.Logger(message, args...)
|
||||
}
|
||||
|
||||
func (s *Server) getCustomizedFilesystem(base fs.FS) (fs.FS, error) {
|
||||
filesystems := []fs.FS{}
|
||||
|
||||
if s.opts.CustomDir != "" {
|
||||
absPath, err := filepath.Abs(s.opts.CustomDir)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
filesystems = append(filesystems, os.DirFS(absPath))
|
||||
}
|
||||
|
||||
filesystems = append(filesystems, base)
|
||||
|
||||
return layerfs.New(filesystems...), nil
|
||||
}
|
||||
|
||||
func NewServer(funcs ...OptionFunc) *Server {
|
||||
opts := DefaultOptions()
|
||||
for _, fn := range funcs {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
return &Server{
|
||||
opts: opts,
|
||||
}
|
||||
}
|
1
http/templates/advertising.html
Normal file
1
http/templates/advertising.html
Normal file
@ -0,0 +1 @@
|
||||
{{ define "advertising" }}{{ end }}
|
9
http/templates/footer.html
Normal file
9
http/templates/footer.html
Normal file
@ -0,0 +1,9 @@
|
||||
{{ define "footer" }}
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<div class="content has-text-centered">
|
||||
Ce service est propulsé par Rebound, un logiciel libre diffusé sous licence <a href="#">AGPL-3.0</a>.
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
{{ end }}
|
6
http/templates/head.html
Normal file
6
http/templates/head.html
Normal file
@ -0,0 +1,6 @@
|
||||
{{ define "head" }}
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ .Title }}</title>
|
||||
<link rel="stylesheet" href="assets/bulma-0.9.4.min.css">
|
||||
{{ end }}
|
31
http/templates/index.html
Normal file
31
http/templates/index.html
Normal file
@ -0,0 +1,31 @@
|
||||
{{ define "index" }}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
{{ template "head" }}
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title is-size-1">
|
||||
Besoin de vous échapper ?
|
||||
</h1>
|
||||
<p class="subtitle is-size-3">
|
||||
Bienvenue sur <strong>Rebound</strong>!
|
||||
</p>
|
||||
<div class="content">
|
||||
<p>Rebound est un serveur SSH permettant de créer des tunnels TCP/IP éphémères et privés entre 2 machines positionnées
|
||||
derrière un <abbr title="Network Address Traversal">NAT</abbr>.</p>
|
||||
<p>Pour l'utiliser <strong>un simple client SSH suffit !</strong></p>
|
||||
<pre class="has-background-dark has-text-white-ter is-family-monospace">ssh -R 0:127.0.0.1:<span class="has-text-info"><port></span> rebound@rebound.cadol.es</pre>
|
||||
<p class="is-italic">Où <span class="has-text-info"><port></span> est à remplacer par le port du service
|
||||
s'exécutant sur votre machine en local.</span>
|
||||
<p>Une fois connecté, suivez les instructions. 😉</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{ template "advertising" . }}
|
||||
{{ template "footer" . }}
|
||||
</body>
|
||||
</html>
|
||||
{{ end }}
|
Reference in New Issue
Block a user