1
0
Fork 0

Compare commits

...

30 Commits

Author SHA1 Message Date
Alexander Andreev df3ea75ca9
Added a benchmark for ScanDirectory(). 2023-09-20 04:56:08 +04:00
Alexander Andreev cbe0292e4c
Before allocation of these three vars try to read a dir first. 2023-09-20 04:55:38 +04:00
Alexander Andreev d6463e81e8
A struct DirStats was renamed to DirStat. 2023-09-20 04:07:24 +04:00
Alexander Andreev 99e39fc6c1
Added FLAGS, reorganised targets ${TARGET} and web/*.jade.go. Removed all target. Added clean .PHONY target, removed ${TARGET} from .PHONY. In web/*.jade.go added check for jade executable existence. 2023-09-20 04:06:54 +04:00
Alexander Andreev 5cc9b12030
Updated httpr to v0.3.2. 2023-09-20 04:04:09 +04:00
Alexander Andreev 8b39e60a01
Reorganised CSS. Set min-height for body to 100vh. 2023-08-23 04:49:30 +04:00
Alexander Andreev c06eaecbfc
Removed unused ids. 2023-08-23 04:40:39 +04:00
Alexander Andreev f23e4d713b
Moved error styling to main.css. 2023-08-23 04:40:23 +04:00
Alexander Andreev 1a5d32f1b9
Put my full name in a footer. 2023-08-23 04:33:45 +04:00
Alexander Andreev 775eef657e
Removed id and classes from a logo. 2023-08-23 04:31:57 +04:00
Alexander Andreev 06961fc7c4
Return an error text message if file handling is turned off. 2023-08-23 04:23:51 +04:00
Alexander Andreev 391f589a90
Version set to 23.32.0. 2023-08-13 04:06:34 +04:00
Alexander Andreev 404f88c099
Fix for double slashes. 2023-08-13 03:18:17 +04:00
Alexander Andreev 54bc8d744d
Updated HttpServer to the latest implementation. 2023-08-13 02:25:04 +04:00
Alexander Andreev 6cf74599cc
A separate base.jade template was made. An index.jade rewritten to use it. 2023-08-13 02:24:36 +04:00
Alexander Andreev 4657319d52
Added an error page. 2023-08-13 02:23:47 +04:00
Alexander Andreev c5ffe37c52
Updated httpr to 0.3.1. 2023-08-13 01:58:06 +04:00
Alexander Andreev 0e54693b4a
Added v to archive's name. 2023-06-13 00:15:23 +04:00
Alexander Andreev cc8634fdb5
Oh, remove this test code. 2023-06-13 00:08:12 +04:00
Alexander Andreev 8038a0d551
In a Copyright a year was changed to 2023. 2023-06-13 00:07:34 +04:00
Alexander Andreev aa64903161
Remove jade.go from a repo. 2023-06-13 00:05:05 +04:00
Alexander Andreev 15af164462
Moved to my httpr router. 2023-06-13 00:02:41 +04:00
Alexander Andreev ed62b37dbc
Version was set to 23.24.0. And Makefile and PKGBUILD structure was updated to a recently used one across my other services. 2023-06-12 23:32:54 +04:00
Alexander Andreev 80647144b5
Removed -stdlib that prevented jade.go file's creation. 2023-06-12 23:32:09 +04:00
Alexander Andreev 7d1da65f38
Set Go version to 1.16 as a minimal. 2023-06-12 23:31:34 +04:00
Alexander Andreev eaa49744af
Ignore jade.go and *.jade.go files. 2023-06-12 23:31:06 +04:00
Alexander Andreev 24e46c79e7
In footer 2022 was replaced by 2023. 2023-06-12 23:16:46 +04:00
Alexander Andreev 56399e85bb
Removed Privacy statements section and added a link to it on a main site in a footer. 2023-06-12 23:13:41 +04:00
Alexander Andreev def915607b
ssl is excessive here in nginx.conf. 2023-06-12 23:13:14 +04:00
Alexander Andreev 85e5095120
Do not keep bin directory. 2023-05-14 02:18:15 +04:00
18 changed files with 284 additions and 373 deletions

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
bin/*
!bin/.keep
.vscode
.vscode
web/*.jade.go
web/jade.go

View File

@ -2,29 +2,39 @@ TARGET=dwelling-files
SYSDDIR_=${shell pkg-config systemd --variable=systemdsystemunitdir}
SYSDDIR=${SYSDDIR_:/%=%}
DESTDIR=/
LDFLAGS=-ldflags "-s -w -X main.version=23.8.0" -tags osusergo,netgo
DESTDIR:=
PREFIX:=/usr/local
all: ${TARGET}
VERSION=23.32.0
.PHONY: ${TARGET}
FLAGS=-buildmode=pie -modcacherw -mod=readonly -trimpath
LDFLAGS=-ldflags "-s -w -X main.version=${VERSION}" -tags osusergo,netgo
${TARGET}:
.PHONY: run install uninstall clean
${TARGET}: web/*.jade.go
go build -o bin/$@ ${LDFLAGS} ${FLAGS} cmd/$@/main.go
web/*.jade.go: web/templates/*.jade
ifeq (,$(wildcard $(shell go env GOPATH)/bin/jade))
go install github.com/Joker/jade/cmd/jade@latest
endif
go generate web/web.go
go build -o bin/$@ ${LDFLAGS} cmd/$@/main.go
run:
bin/${TARGET} -file-handling -path /mnt/data -listen 127.0.0.1:19135
install:
install -Dm 0755 bin/${TARGET} ${DESTDIR}usr/bin/${TARGET}
install -Dm 0644 LICENSE ${DESTDIR}usr/share/licenses/${TARGET}/LICENSE
install -Dm 0755 bin/${TARGET} ${DESTDIR}${PREFIX}/bin/${TARGET}
install -Dm 0644 init/systemd/${TARGET}.service ${DESTDIR}${SYSDDIR}/${TARGET}.service
install -Dm 0644 init/systemd/${TARGET}.service ${DESTDIR}/${SYSDDIR}/${TARGET}.service
uninstall:
rm ${DESTDIR}usr/bin/${TARGET}
rm ${DESTDIR}usr/share/licenses/${TARGET}/LICENSE
rm ${DESTDIR}${PREFIX}/bin/${TARGET}
rm ${DESTDIR}${SYSDDIR}/${TARGET}.service
rm ${DESTDIR}/${SYSDDIR}/${TARGET}.service
clean:
rm -f web/*.jade.go
go clean

View File

View File

@ -1,30 +1,24 @@
# Maintainer: Alexander "Arav" Andreev <me@arav.su>
pkgname=dwelling-files
pkgver=23.8.0
pkgver=23.32.0
pkgrel=1
pkgdesc="Arav's dwelling / Files"
arch=('i686' 'x86_64' 'arm' 'armv6h' 'armv7h' 'aarch64')
url="https://git.arav.su/Arav/dwelling-files"
license=('MIT')
groups=()
depends=()
makedepends=('go')
makedepends=('go>=1.16')
provides=('dwelling-files')
conflicts=('dwelling-files')
replaces=()
backup=()
options=()
install=
source=('https://git.arav.su/Arav/dwelling-files/archive/23.8.0.tar.gz')
noextract=()
source=("${pkgver}.tar.gz::https://git.arav.su/Arav/dwelling-files/archive/v${pkgver}.tar.gz")
md5sums=('SKIP')
build() {
cd "$srcdir/$pkgname"
make DESTDIR="$pkgdir/"
export GOPATH="$srcdir"/gopath
make VERSION=$pkgver DESTDIR="$pkgdir" PREFIX="/usr"
}
package() {
cd "$srcdir/$pkgname"
make DESTDIR="$pkgdir/" install
make DESTDIR="$pkgdir" PREFIX="/usr" install
}

View File

@ -1,16 +1,17 @@
package main
import (
"dwelling-files/internal/http"
dwhttp "dwelling-files/internal/http"
"dwelling-files/web"
"flag"
"fmt"
"log"
"net/netip"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"git.arav.su/Arav/httpr"
)
var version string
@ -25,33 +26,20 @@ func main() {
log.SetFlags(0)
if *showVersion {
fmt.Println("dwelling-files ver.", version, "\nCopyright (c) 2022 Alexander \"Arav\" Andreev <me@arav.su>")
fmt.Println("dwelling-files ver.", version, "\nCopyright (c) 2023 Alexander \"Arav\" Andreev <me@arav.su>")
return
}
var network string
if !strings.ContainsRune(*listenAddress, ':') {
network = "unix"
defer os.Remove(*listenAddress)
} else {
ap, err := netip.ParseAddrPort(*listenAddress)
if err != nil {
log.Fatalln(err)
}
hand := dwhttp.New(directoryPath, !*enableFileHandler)
r := httpr.New()
if ap.Addr().Is4() {
network = "tcp4"
} else if ap.Addr().Is6() {
network = "tcp6"
}
}
r.ServeStatic("/assets/*filepath", web.Assets())
r.Handler(http.MethodGet, "/file/*filepath", hand.File)
r.Handler(http.MethodGet, "/*filepath", hand.Index)
r.Handler(http.MethodGet, "/", hand.Index)
hand := http.New(directoryPath, web.Assets(), !*enableFileHandler)
srv := http.NewHttpServer()
srv.GET("/*filepath", hand.Index)
if err := srv.Start(network, *listenAddress); err != nil {
srv := dwhttp.NewHttpServer(r)
if err := srv.Start(*listenAddress); err != nil {
log.Fatalln(err)
}

View File

@ -1,5 +1,5 @@
server {
listen 443 ssl http2;
listen 443 http2;
listen 127.0.0.1:8112; # I2P
listen [300:a98d:d6d0:8a08::d]:80; # Yggdrasil

4
go.mod
View File

@ -1,5 +1,5 @@
module dwelling-files
go 1.19
go 1.16
require github.com/julienschmidt/httprouter v1.3.0
require git.arav.su/Arav/httpr v0.3.2

4
go.sum
View File

@ -1,2 +1,2 @@
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
git.arav.su/Arav/httpr v0.3.2 h1:a+ifu+9+FnQe6p/Kd4kgTDKAFN6zBOJjBTMjbAuHxVk=
git.arav.su/Arav/httpr v0.3.2/go.mod h1:z0SVYwe5dBReeVuFU9QH2PmBxICJwchxqY5OfZbeVzU=

View File

@ -8,17 +8,16 @@ import (
"net/http"
"strings"
"github.com/julienschmidt/httprouter"
"git.arav.su/Arav/httpr"
)
type FilesHandlers struct {
directoryPath string
assetsServer http.Handler
fileServer http.Handler
noFileHandling bool
}
func New(directoryPath *string, assetsFS http.FileSystem, noFileHandling bool) *FilesHandlers {
func New(directoryPath *string, noFileHandling bool) *FilesHandlers {
var fSrv http.Handler
if noFileHandling {
fSrv = nil
@ -27,37 +26,14 @@ func New(directoryPath *string, assetsFS http.FileSystem, noFileHandling bool) *
}
return &FilesHandlers{
directoryPath: *directoryPath,
assetsServer: http.FileServer(assetsFS),
fileServer: fSrv,
noFileHandling: noFileHandling}
}
func (FilesHandlers) AssetsFS() http.FileSystem {
return web.Assets()
}
func (h *FilesHandlers) Index(w http.ResponseWriter, r *http.Request) {
path := httprouter.CleanPath(GetURLParam(r, "filepath"))
if strings.HasPrefix(path, "/assets") {
h.assetsServer.ServeHTTP(w, r)
return
}
if strings.HasPrefix(path, "/robots.txt") {
fc, _ := web.AssetsGetFile("robots.txt")
w.Write(fc)
return
}
if strings.HasPrefix(path, "/file") {
if h.noFileHandling {
w.WriteHeader(http.StatusServiceUnavailable)
return
}
r.URL.Path = path[5:]
h.fileServer.ServeHTTP(w, r)
return
path := "/" + httpr.Param(r, "filepath")
if !strings.HasSuffix(path, "/") {
path += "/"
}
currentPath := files.CurrentPath(path)
@ -65,8 +41,28 @@ func (h *FilesHandlers) Index(w http.ResponseWriter, r *http.Request) {
entries, stats, err := files.ScanDirectory(h.directoryPath+path, path)
if err != nil {
log.Println(err)
Error(w, http.StatusNotFound, "", "", r.Referer())
return
}
web.Index(utils.MainSite(r.Host), currentPath, &stats, &entries, r, w)
web.Index("Files", utils.MainSite(r.Host), currentPath, &stats, &entries, r, w)
}
func (h *FilesHandlers) File(w http.ResponseWriter, r *http.Request) {
if h.noFileHandling {
Error(w, http.StatusServiceUnavailable, "File handling is turned off.", "", r.Referer())
return
}
r.URL.Path = httpr.Param(r, "filepath")
h.fileServer.ServeHTTP(w, r)
}
func RobotsTxt(w http.ResponseWriter, r *http.Request) {
fc, _ := web.AssetsGetFile("robots.txt")
w.Write(fc)
}
func Error(w http.ResponseWriter, code int, reason, message, referer string) {
w.WriteHeader(code)
web.ErrorXXX("/ "+http.StatusText(code), reason, message, referer, code, w)
}

View File

@ -5,39 +5,41 @@ import (
"log"
"net"
"net/http"
"net/netip"
"os"
"strings"
"time"
"github.com/julienschmidt/httprouter"
)
type HttpServer struct {
server *http.Server
router *httprouter.Router
s http.Server
addr net.Addr
}
func NewHttpServer() *HttpServer {
r := httprouter.New()
return &HttpServer{
server: &http.Server{
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
Handler: r,
},
router: r,
func NewHttpServer(r http.Handler) *HttpServer {
return &HttpServer{s: http.Server{
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
Handler: r}}
}
func (s *HttpServer) Start(address string) error {
var network string
if !strings.ContainsRune(address, ':') {
network = "unix"
} else {
ap, err := netip.ParseAddrPort(address)
if err != nil {
return err
}
if ap.Addr().Is4() {
network = "tcp4"
} else if ap.Addr().Is6() {
network = "tcp6"
}
}
}
func (s *HttpServer) GET(path string, handler http.HandlerFunc) {
s.router.Handler(http.MethodGet, path, handler)
}
// GetURLParam wrapper around underlying router for getting URL parameters.
func GetURLParam(r *http.Request, param string) string {
return httprouter.ParamsFromContext(r.Context()).ByName(param)
}
func (s *HttpServer) Start(network, address string) error {
listener, err := net.Listen(network, address)
if err != nil {
return err
@ -47,8 +49,10 @@ func (s *HttpServer) Start(network, address string) error {
os.Chmod(address, 0777)
}
s.addr = listener.Addr()
go func() {
if err = s.server.Serve(listener); err != nil && err != http.ErrServerClosed {
if err = s.s.Serve(listener); err != nil && err != http.ErrServerClosed {
log.Fatalln(err)
}
}()
@ -60,7 +64,11 @@ func (s *HttpServer) Stop() error {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := s.server.Shutdown(ctx); err != nil {
if s.addr.Network() == "unix" {
defer os.Remove(s.addr.String())
}
if err := s.s.Shutdown(ctx); err != nil {
return err
}

View File

@ -9,7 +9,7 @@ import (
const FileDateFormat = "2006-01-02 15:04:05 MST"
type DirStats struct {
type DirStat struct {
Files int64
FilesSize string
Directories int64
@ -22,16 +22,16 @@ type DirEntry struct {
Size string
}
func ScanDirectory(path, urlBase string) (entries []DirEntry, stats DirStats, err error) {
var dirEntries []DirEntry = make([]DirEntry, 0)
var fileEntries []DirEntry = make([]DirEntry, 0)
var totalFilesSize int64 = 0
func ScanDirectory(path, urlBase string) (entries []DirEntry, stats DirStat, err error) {
dir, err := os.ReadDir(path)
if err != nil {
return
}
var dirEntries []DirEntry = make([]DirEntry, 0)
var fileEntries []DirEntry = make([]DirEntry, 0)
var totalFilesSize int64 = 0
for _, ent := range dir {
entry, _ := ent.Info()

13
pkg/files/files_test.go Normal file
View File

@ -0,0 +1,13 @@
package files
import "testing"
const path = "/mnt/data/music/Various"
const urlBase = "/srv/ftp/"
func BenchmarkScanDirectory(b *testing.B) {
for i := 0; i < b.N; i++ {
/*e, _, _ :=*/ ScanDirectory(path, urlBase)
// b.Log(e[len(e)-1], len(e))
}
}

View File

@ -30,6 +30,8 @@
::placeholder { color: var(--primary-color); }
.hidden { display: none; }
a {
color: var(--primary-color);
text-decoration: none; }
@ -58,8 +60,6 @@ h2 {
font-size: 1.4rem;
margin: 1rem 0; }
.hidden { display: none; }
html { margin-left: calc(100vw - 100%); }
body {
@ -69,6 +69,7 @@ body {
font-size: 1.1rem;
margin: 0 auto;
max-width: 960px;
min-height: 100vh;
width: 98%; }
header {
@ -76,24 +77,22 @@ header {
flex-wrap: wrap;
justify-content: space-between; }
#logo {
display: block;
width: 360px; }
header svg { width: 360px; }
#logo text { fill: var(--text-color); }
header svg text { fill: var(--text-color); }
#logo .logo {
header svg text:first-child {
font-size: 2rem;
font-variant-caps: small-caps;
font-weight: bold; }
header svg text:last-child { font-size: .88rem; }
@media screen and (-webkit-min-device-pixel-ratio:0) {
#logo .logo { font-size: 2.082rem; } }
header svg text:first-child { font-size: 2.082rem; } }
@-moz-document url-prefix() {
#logo .logo { font-size: 2rem; } }
#logo .under { font-size: .88rem; }
header svg text:first-child { font-size: 2rem; } }
nav { margin-top: .5rem; }
@ -105,6 +104,60 @@ nav h1 {
section { margin-top: 1rem; }
input[name="filter"] {
background-color: var(--background-color);
border: none;
border-bottom: 1px solid var(--primary-color);
color: var(--text-color);
font: inherit;
width: 100%; }
table {
overflow-y: scroll;
width: 100%; }
tr { vertical-align: top; }
tr:hover,
tr:focus-within {
background-color: var(--primary-color);
color: white; }
tr:hover a,
tr:focus-within a { color: white; }
th { text-align: left; }
th:nth-child(2),
th:last-child {
width: 1%;
white-space: nowrap; }
th,
td { line-break: strict; }
th:nth-child(2),
td:nth-child(2) { padding: 0 1rem; }
td a {
display: block;
width: 100%; }
td a:hover { transition: none; }
td:nth-child(2),
td:last-child { white-space: nowrap; }
thead tr th.clickable { cursor: pointer; }
thead tr th.clickable:hover { color: var(--secondary-color); }
thead tr th.clickable:not(.sort-up):not(.sort-down)::after { content: '⇅'; }
thead tr th.clickable.sort-up::after { content: '↑'; }
thead tr th.clickable.sort-down::after { content: '↓'; }
#overlay {
align-items: center;
background-color: var(--overlay-background-color);
@ -152,51 +205,13 @@ section { margin-top: 1rem; }
background-color: var(--background-color);
color: var(--primary-color); }
input[name="filter"] {
background-color: var(--background-color);
border: none;
border-bottom: 1px solid var(--primary-color);
color: var(--text-color);
font: inherit;
width: 100%; }
#error {
font-size: 3.5rem;
line-height: 5rem;
text-align: center;
margin: 6rem 0; }
table { overflow-y: scroll; width: 100%; }
tr { vertical-align: top; }
tr:hover,
tr:focus-within { background-color: var(--primary-color); color: white; }
tr:hover a,
tr:focus-within a { color: white; }
th { text-align: left; }
th:nth-child(2),
th:last-child { width: 1%; white-space: nowrap; }
th,
td { line-break: strict; }
th:nth-child(2),
td:nth-child(2) { padding: 0 1rem; }
td a { display: block; width: 100%; }
td a:hover { transition: none; }
td:nth-child(2),
td:last-child { white-space: nowrap; }
thead tr th.clickable { cursor: pointer; }
thead tr th.clickable:hover { color: var(--secondary-color); }
thead tr th.clickable:not(.sort-up):not(.sort-down)::after { content: '⇅'; }
thead tr th.clickable.sort-up::after { content: '↑'; }
thead tr th.clickable.sort-down::after { content: '↓'; }
#error h1 { font-size: 8rem; }
footer {
font-size: .8rem;
@ -206,7 +221,7 @@ footer {
@media screen and (max-width: 640px) {
header { display: block; }
#logo {
header svg {
margin: 0 auto;
width: 100%; }

View File

@ -1,141 +0,0 @@
// Code generated by "jade.go"; DO NOT EDIT.
package web
import (
"bytes"
"io"
"strconv"
)
var (
escaped = []byte{'<', '>', '"', '\'', '&'}
replacing = []string{"&lt;", "&gt;", "&#34;", "&#39;", "&amp;"}
)
func WriteEscString(st string, buffer *WriterAsBuffer) {
for i := 0; i < len(st); i++ {
if n := bytes.IndexByte(escaped, st[i]); n >= 0 {
buffer.WriteString(replacing[n])
} else {
buffer.WriteByte(st[i])
}
}
}
type WriterAsBuffer struct {
io.Writer
}
func (w *WriterAsBuffer) WriteString(s string) (n int, err error) {
n, err = w.Write([]byte(s))
return
}
func (w *WriterAsBuffer) WriteByte(b byte) (err error) {
_, err = w.Write([]byte{b})
return
}
type stringer interface {
String() string
}
func WriteAll(a interface{}, escape bool, buffer *WriterAsBuffer) {
switch v := a.(type) {
case string:
if escape {
WriteEscString(v, buffer)
} else {
buffer.WriteString(v)
}
case int:
WriteInt(int64(v), buffer)
case int8:
WriteInt(int64(v), buffer)
case int16:
WriteInt(int64(v), buffer)
case int32:
WriteInt(int64(v), buffer)
case int64:
WriteInt(v, buffer)
case uint:
WriteUint(uint64(v), buffer)
case uint8:
WriteUint(uint64(v), buffer)
case uint16:
WriteUint(uint64(v), buffer)
case uint32:
WriteUint(uint64(v), buffer)
case uint64:
WriteUint(v, buffer)
case float32:
buffer.WriteString(strconv.FormatFloat(float64(v), 'f', -1, 64))
case float64:
buffer.WriteString(strconv.FormatFloat(v, 'f', -1, 64))
case bool:
WriteBool(v, buffer)
case stringer:
if escape {
WriteEscString(v.String(), buffer)
} else {
buffer.WriteString(v.String())
}
default:
buffer.WriteString("\n<<< unprinted type, fmt.Stringer implementation needed >>>\n")
}
}
func ternary(condition bool, iftrue, iffalse interface{}) interface{} {
if condition {
return iftrue
} else {
return iffalse
}
}
// Used part of go source:
// https://github.com/golang/go/blob/master/src/strconv/itoa.go
func WriteUint(u uint64, buffer *WriterAsBuffer) {
var a [64 + 1]byte
i := len(a)
if ^uintptr(0)>>32 == 0 {
for u > uint64(^uintptr(0)) {
q := u / 1e9
us := uintptr(u - q*1e9)
for j := 9; j > 0; j-- {
i--
qs := us / 10
a[i] = byte(us - qs*10 + '0')
us = qs
}
u = q
}
}
us := uintptr(u)
for us >= 10 {
i--
q := us / 10
a[i] = byte(us - q*10 + '0')
us = q
}
i--
a[i] = byte(us + '0')
buffer.Write(a[i:])
}
func WriteInt(i int64, buffer *WriterAsBuffer) {
if i < 0 {
buffer.WriteByte('-')
i = -i
}
WriteUint(uint64(i), buffer)
}
func WriteBool(b bool, buffer *WriterAsBuffer) {
if b {
buffer.WriteString("true")
return
}
buffer.WriteString("false")
}

23
web/templates/base.jade Normal file
View File

@ -0,0 +1,23 @@
doctype html
html(lang='en')
head
block head
title Arav's dwelling / #{title}
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible' content='IE=edge')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
meta(name='theme-color' content='#cd2682')
meta(name='description' content='My file share.')
link(rel='icon' type='image/svg+xml' href='/assets/img/favicon.svg' sizes='any')
link(href='/assets/css/main.css' rel='stylesheet')
script(src='/assets/js/main.js' defer='')
body
header
svg(viewBox='0 -25 216 40')
text Arav's dwelling
text(y='11') Welcome to my sacred place, wanderer
nav
block nav
block content
footer
| 2017&mdash;2023 Alexander &quot;Arav&quot; Andreev &lt;#[a(href='mailto:me@arav.su') me@arav.su]&gt; #[a(href='/privacy') Privacy statements]

View File

@ -0,0 +1,21 @@
extends base.jade
block meta_description
meta(name='description' content=http.StatusText(code))
block nav
a(href='/') Back to index page
h1 #{http.StatusText(code)}
block content
:go:func ErrorXXX(title, reason, message, referer string, code int)
section#error
h1 #{code}
| #{http.StatusText(code)}
if reason != ""
p #{reason}
if message != ""
p #{message}
if referer != ""
section
h2 #[a(href=referer) Go back]

View File

@ -1,60 +1,39 @@
:go:func Index(mainSite, currentPath string, stats *files.DirStats, items *[]files.DirEntry, r *http.Request)
extends base.jade
:go:import "dwelling-files/pkg/files"
:go:import "dwelling-files/pkg/utils"
block nav
a(href=mainSite) Back to main website
h1 Files
doctype html
html(lang='en')
head
title Arav's dwelling / Files
meta(charset='utf-8')
meta(http-equiv='X-UA-Compatible' content='IE=edge')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
meta(name='theme-color' content='#cd2682')
meta(name='description' content='My file share.')
link(rel='icon' type='image/svg+xml' href='/assets/img/favicon.svg' sizes='any')
link(href='/assets/css/main.css' rel='stylesheet')
script(src='/assets/js/main.js' defer='')
body
header
svg#logo(viewBox='0 -25 216 40')
text.logo Arav's dwelling
text.under(y='11') Welcome to my sacred place, wanderer
nav
a(href=mainSite) Back to main website
h1 Files
section#files
span!= currentPath
p Files: #{stats.Files} (#{stats.FilesSize}); Directories: #{stats.Directories}.
input.hidden(type="text", name="filter" placeholder="Type in to filter this directory (case insensitive)")
table
thead
tr
th Name
th Date
th Size
tr(tabindex=0)
td #[a(href="../") ../]
tbody
each item, i in *items
tr(tabindex=i+1)
td #[a(href=item.Link) #{item.Name}]
td!= utils.ToClientTimezone(item.Datetime, r).Format(files.FileDateFormat)
td= item.Size
section
span!= currentPath
section#usage
p On a page use up and down arrow keys to navigate through list. Use home and end keys to go to the start and end of a list. Use Ctrl+Backspace to return to a parent directory.
p In an overlay use a mouse wheel to change a scale of a video or a picture. Use left and right arrow keys to go through media. Use space key to toggle pause. Use escape key to close an overlay, or click outside a media. An audio volume is being kept across site using LocalStorage API.
section#privacy
h2 Privacy statements
p I collect access logs that include access date and time, IP-address, User-Agent, referer URL that tells me where have you came from, request that you sent to me. In addition there are GeoIP information added based on your IP-address that includes country, region, and city for my convenience.
p This site makes use of JavaScript purely for convenient functionality, like being able to watch video, listen to music, and look images in an overlay without the need to open a file in a new tab or return back.
footer
| 2017&mdash;2022 Arav &lt;#[a(href='mailto:me@arav.su') me@arav.su]&gt;
div#overlay
button(name='prev') &#10096;
block content
:go:func Index(title, mainSite, currentPath string, stats *files.DirStat, items *[]files.DirEntry, r *http.Request)
:go:import "dwelling-files/pkg/files"
:go:import "dwelling-files/pkg/utils"
section
span!= currentPath
p Files: #{stats.Files} (#{stats.FilesSize}); Directories: #{stats.Directories}.
input.hidden(type="text", name="filter" placeholder="Type in to filter this directory (case insensitive)")
table
thead
tr
th Name
th Date
th Size
tr(tabindex=0)
td #[a(href="../") ../]
tbody
each item, i in *items
tr(tabindex=i+1)
td #[a(href=item.Link) #{item.Name}]
td!= utils.ToClientTimezone(item.Datetime, r).Format(files.FileDateFormat)
td= item.Size
section
span!= currentPath
section
p On a page use up and down arrow keys to navigate through list. Use home and end keys to go to the start and end of a list. Use Ctrl+Backspace to return to a parent directory.
p In an overlay use a mouse wheel to change a scale of a video or a picture. Use left and right arrow keys to go through media. Use space key to toggle pause. Use escape key to close an overlay, or click outside a media. An audio volume is being kept across site using LocalStorage API.
div#overlay
button(name='prev') &#10096;
div
div
div
span
button(name='next') &#10097;
span
button(name='next') &#10097;

View File

@ -2,16 +2,19 @@ package web
import (
"embed"
"io/fs"
"net/http"
)
//go:generate $GOPATH/bin/jade -pkg=web -stdlib -stdbuf -writer templates/index.jade
//go:generate $GOPATH/bin/jade -pkg=web -stdbuf -writer templates/index.jade
//go:generate $GOPATH/bin/jade -pkg=web -stdbuf -writer templates/errorXXX.jade
//go:embed assets
var assetsDir embed.FS
func Assets() http.FileSystem {
return http.FS(assetsDir)
f, _ := fs.Sub(assetsDir, "assets")
return http.FS(f)
}
func AssetsGetFile(path string) ([]byte, error) {