A bunch of updatesss
This commit is contained in:
zervo 2025-07-31 05:19:15 +02:00
parent 56ddd764ee
commit cbc66c5651
14 changed files with 227 additions and 13 deletions

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"log" "log"
@ -9,7 +10,19 @@ import (
) )
func main() { func main() {
cfg, err := config.LoadConfig("config.yaml") var cfgFlag = flag.String("c", "config.yaml", "Configuration file to load")
var genFlag = flag.String("g", "", "Generate an example configuration to the given file")
flag.Parse()
if *genFlag != "" {
if err := config.WriteExampleConfig(*genFlag); err != nil {
log.Fatalf("Failed to create example config: %v", err)
}
log.Printf("Generated example configuration at: %s\n", *genFlag)
return
}
cfg, err := config.LoadConfig(*cfgFlag)
if err != nil { if err != nil {
log.Fatalf("Failed to load config: %v", err) log.Fatalf("Failed to load config: %v", err)
} }

View file

@ -4,3 +4,6 @@ import "embed"
//go:embed templates/* //go:embed templates/*
var TemplateFS embed.FS var TemplateFS embed.FS
//go:embed static/*
var StaticFS embed.FS

View file

@ -6,12 +6,34 @@ import (
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
type Config struct { var defaultCfg = Config{
ServeDirectory string `yaml:"serveDirectory"` ServerName: "My Fileserver",
Port int `int:"port"` Port: 8080,
Directories: []Directory{
{
Id: "example",
DisplayName: "Example Directory",
Path: "/path/to/directory",
},
},
} }
// LoadConfig loads a Config from the given path. // Directory represents a configuration for a directory to be served.
type Directory struct {
Id string `yaml:"id"`
DisplayName string `yaml:"display_name"`
Description string `yaml:"description"`
Path string `yaml:"path"`
}
// Config represents a configuration for the fileserver.
type Config struct {
ServerName string `yaml:"server_name"`
Port int `yaml:"port"`
Directories []Directory `yaml:"directories"`
}
// LoadConfig loads configuration from a YAML file.
func LoadConfig(path string) (*Config, error) { func LoadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
@ -25,3 +47,13 @@ func LoadConfig(path string) (*Config, error) {
return &cfg, nil return &cfg, nil
} }
// WriteExampleConfig writes an example configuration to a YAML file.
func WriteExampleConfig(filepath string) error {
data, err := yaml.Marshal(&defaultCfg)
if err != nil {
return err
}
return os.WriteFile(filepath, data, 0644)
}

View file

@ -0,0 +1,16 @@
package controllers
import (
"git.zervo.org/zervo/fileserver/internal/config"
"git.zervo.org/zervo/fileserver/internal/server/views"
"github.com/kataras/iris/v12"
)
// DirectoriesRoute registers all routes under /directories
func DirectoriesRoute(app *iris.Application, cfg *config.Config) {
party := app.Party("/directories")
party.Get("/", func(ctx iris.Context) {
views.DirectoriesView(ctx, cfg)
})
}

View file

@ -1,6 +1,7 @@
package server package server
import ( import (
"errors"
"fmt" "fmt"
"io/fs" "io/fs"
"net/http" "net/http"
@ -9,6 +10,7 @@ import (
"git.zervo.org/zervo/fileserver" "git.zervo.org/zervo/fileserver"
"git.zervo.org/zervo/fileserver/internal/config" "git.zervo.org/zervo/fileserver/internal/config"
"git.zervo.org/zervo/fileserver/internal/server/controllers"
"github.com/kataras/iris/v12" "github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/view" "github.com/kataras/iris/v12/view"
) )
@ -17,16 +19,23 @@ import (
func Start(cfg *config.Config) error { func Start(cfg *config.Config) error {
app := iris.New() app := iris.New()
subFs, err := fs.Sub(fileserver.TemplateFS, "templates") templates, err := fs.Sub(fileserver.TemplateFS, "templates")
if err != nil { if err != nil {
return fmt.Errorf("Failed to sub fs") return errors.New("fs.Sub operation on TemplateFS")
} }
tmpl := view.HTML(subFs, ".html") templater := view.HTML(templates, ".html").Layout("layouts/main.html")
app.RegisterView(tmpl) app.RegisterView(templater)
app.Get("/", func(ctx iris.Context) { // Register core routes
files, err := os.ReadDir(cfg.ServeDirectory) app.Get("/", index)
app.Get("/favicon.ico", favicon)
// Register controller routes
controllers.DirectoriesRoute(app, cfg)
app.Get("/aaa", func(ctx iris.Context) {
files, err := os.ReadDir("test")
if err != nil { if err != nil {
ctx.StatusCode(http.StatusInternalServerError) ctx.StatusCode(http.StatusInternalServerError)
ctx.WriteString("Could not read directory") ctx.WriteString("Could not read directory")
@ -48,9 +57,25 @@ func Start(cfg *config.Config) error {
app.Get("/download/{filename:string}", func(ctx iris.Context) { app.Get("/download/{filename:string}", func(ctx iris.Context) {
filename := ctx.Params().Get("filename") filename := ctx.Params().Get("filename")
filePath := filepath.Join(cfg.ServeDirectory, filename) filePath := filepath.Join("test", filename)
ctx.SendFile(filePath, filename) ctx.SendFile(filePath, filename)
}) })
return app.Listen(":" + fmt.Sprint(cfg.Port)) return app.Listen(":" + fmt.Sprint(cfg.Port))
} }
// index redirects request from '/' to '/directories'.
func index(ctx iris.Context) {
ctx.Redirect("/directories")
}
// favicon returns favicon data upon request.
func favicon(ctx iris.Context) {
data, err := fileserver.StaticFS.ReadFile("static/favicon.ico")
if err != nil {
ctx.StatusCode(http.StatusNotFound)
return
}
ctx.ContentType("image/x-icon")
ctx.Write(data)
}

View file

@ -0,0 +1,29 @@
package views
import (
"fmt"
"git.zervo.org/zervo/fileserver/internal/config"
"git.zervo.org/zervo/fileserver/internal/util/data"
"github.com/kataras/iris/v12"
)
type directorypage struct {
Directories []config.Directory
}
// DirectoriesView renders the view for '/directories'.
func DirectoriesView(ctx iris.Context, cfg *config.Config) {
ctx.CompressWriter(true)
ctx.ViewData("", data.LayoutData{
ServerName: cfg.ServerName,
ServerVersion: "0.0.1",
Page: directorypage{
Directories: cfg.Directories,
},
})
if err := ctx.View("directories.html"); err != nil {
errorView(ctx, fmt.Errorf("Failed to render DirectoriesView: %v", err))
return
}
}

View file

@ -0,0 +1,8 @@
package views
import "github.com/kataras/iris/v12"
// errorView renders a view for unexpected errors.
func errorView(ctx iris.Context, err error) {
ctx.HTML(`<h2>Unexpected Error</h2><br><p style="color:red;">%s</p>`, err.Error())
}

View file

@ -0,0 +1,13 @@
package data
// LayoutData holds templating data for a layout.
type LayoutData struct {
// ServerName is the custom name of the server instance.
ServerName string
// ServerVersion is a string representing the server version.
ServerVersion string
// Page contains page/view-specific data.
Page any
}

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<body class="ma-6">
<h4 class="mt-4 mb-3">Welcome To</h4>
{{ render "partials/badge.html" . }}
<h3 class="p-3 mb-3">Select Directory</h3>
<div class="d-flex flex-column align-items-center gap-4 mb-3">
{{range .Page.Directories}}
<div class="card shadow w-100 text-start bg-dark-subtle" style="max-width: 500px;">
<div class="card-body">
<h5 class="card-title text-primary"><i class="bi bi-folder2-open me-2"></i>{{.DisplayName}}</h5>
<p class="card-text">{{.Description}}</p>
<a href="/b/{{.Id}}" class="btn btn-primary"><i class="bi bi-arrow-up-right-square-fill me-1"></i>Open</a>
</div>
</div>
{{else}}
<h5 class="text-warning-emphasis">
No directories found.<br>If you are the administrator of this server,<br>you can add directories in the server configuration.
</h5>
{{end}}
</div>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css " rel="stylesheet">
<title>{{.ServerName}}</title>
<style>
html, body {
height: 100%;
}
</style>
</head>
<body class="d-flex flex-column min-vh-100">
<main class="flex-grow-1 d-flex justify-content-center">
<div class="container text-center">
{{ yield . }}
</div>
</main>
{{ render "partials/footer.html" . }}
</footer>
</body>
</html>

View file

@ -2,7 +2,6 @@
<html> <html>
<head> <head>
<title>Go FileServer</title> <title>Go FileServer</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.7/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-LN+7fdVzj6u52u30Kp6M/trliBMCMKTyK833zpbD+pXdCLuTusPj697FH4R/5mcr" crossorigin="anonymous">
</head> </head>
<body class="container mt-5"> <body class="container mt-5">
<h1 class="mb-4">File Server</h1> <h1 class="mb-4">File Server</h1>

View file

@ -0,0 +1,3 @@
<div class="d-inline-block shadow p-2 px-3 mb-5 border rounded bg-dark-subtle">
<h1><i class="bi bi-file-zip me-2"></i>{{if .ServerName}}{{.ServerName}}{{else}}My Fileserver{{end}}</h1>
</div>

View file

@ -0,0 +1,23 @@
<footer class="bg-secondary-subtle text-secondary-emphasis py-1 mt-auto w-100">
<div class="container">
<div class="d-flex flex-row justify-content-between text-center">
<div class="mt-2">
<h5>Fileserver</h5>
</div>
<div class="mt-2">
<a href="http://git.zervo.org/zervo/Fileserver" class="text-secondary-emphasis text-decoration-none mx-2">
<i class="bi bi-git me-1"></i>Source
</a>
<a href="/directories" class="text-secondary-emphasis text-decoration-none mx-2">
<i class="bi bi-folder-fill me-1"></i>Directories
</a>
<a href="#" class="text-secondary-emphasis text-decoration-none mx-2">
<i class="bi bi-info-circle-fill me-1"></i>Information
</a>
</div>
<div class="mt-2">
<h5>v{{.ServerVersion}}</h5>
</div>
</div>
</div>
</footer>