forked from security/hakurei
cmd/pkgserver: basic web ui
This commit is contained in:
55
cmd/pkgserver/main.go
Normal file
55
cmd/pkgserver/main.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate sh -c "sass ui/static/dark.scss ui/static/dark.css && sass ui/static/light.scss ui/static/light.css && tsc ui/static/index.ts"
|
||||||
|
//go:embed ui/*
|
||||||
|
var content embed.FS
|
||||||
|
|
||||||
|
func serveWebUI(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Printf("serveWebUI: %s\n", r.URL.Path)
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
w.Header().Set("Expires", "0")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("X-XSS-Protection", "1")
|
||||||
|
w.Header().Set("X-Frame-Options", "DENY")
|
||||||
|
|
||||||
|
http.ServeFileFS(w, r, content, "ui/index.html")
|
||||||
|
}
|
||||||
|
func serveStaticContent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Printf("serveStaticContent: %s\n", r.URL.Path)
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/static/style.css":
|
||||||
|
darkTheme := r.CookiesNamed("dark_theme")
|
||||||
|
if len(darkTheme) > 0 && darkTheme[0].Value == "true" {
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/dark.css")
|
||||||
|
} else {
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/light.css")
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "/favicon.ico":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/favicon.ico")
|
||||||
|
break
|
||||||
|
case "/static/index.js":
|
||||||
|
http.ServeFileFS(w, r, content, "ui/static/index.js")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func serveAPI(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
http.HandleFunc("GET /{$}", serveWebUI)
|
||||||
|
http.HandleFunc("GET /favicon.ico", serveStaticContent)
|
||||||
|
http.HandleFunc("GET /static/", serveStaticContent)
|
||||||
|
http.HandleFunc("GET /api/", serveAPI)
|
||||||
|
http.ListenAndServe(":8067", nil)
|
||||||
|
}
|
||||||
23
cmd/pkgserver/ui/index.html
Normal file
23
cmd/pkgserver/ui/index.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="stylesheet" href="static/style.css">
|
||||||
|
<title>Hakurei PkgServer</title>
|
||||||
|
<script src="static/index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Hakurei PkgServer</h1>
|
||||||
|
<span><label for="count">Entries per page:</label><select name="count" id="count">
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="25">25</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
</select></span>
|
||||||
|
<table id="pkg-list">
|
||||||
|
<tr><th>Status</th><th>Name</th><th>Version</th></tr>
|
||||||
|
</table>
|
||||||
|
<p>Showing entries <span id="entry-counter"></span>.</p>
|
||||||
|
<span class="bottom-nav"><a href="javascript:prevPage()">« Previous</a><span id="page-number"></span><a href="javascript:nextPage">Next »</a></span>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
0
cmd/pkgserver/ui/static/_common.scss
Normal file
0
cmd/pkgserver/ui/static/_common.scss
Normal file
6
cmd/pkgserver/ui/static/dark.css
Normal file
6
cmd/pkgserver/ui/static/dark.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
html {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
color: ghostwhite; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=dark.css.map */
|
||||||
7
cmd/pkgserver/ui/static/dark.css.map
Normal file
7
cmd/pkgserver/ui/static/dark.css.map
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAAA,aAAa;AAEb,IAAK;EACH,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,UAAU",
|
||||||
|
"sources": ["dark.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "dark.css"
|
||||||
|
}
|
||||||
6
cmd/pkgserver/ui/static/dark.scss
Normal file
6
cmd/pkgserver/ui/static/dark.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
|
||||||
|
html {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
color: ghostwhite;
|
||||||
|
}
|
||||||
BIN
cmd/pkgserver/ui/static/favicon.ico
Normal file
BIN
cmd/pkgserver/ui/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
4
cmd/pkgserver/ui/static/index.js
Normal file
4
cmd/pkgserver/ui/static/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function prevPage() {
|
||||||
|
}
|
||||||
|
function nextPage() {
|
||||||
|
}
|
||||||
6
cmd/pkgserver/ui/static/index.ts
Normal file
6
cmd/pkgserver/ui/static/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
function prevPage() {
|
||||||
|
|
||||||
|
}
|
||||||
|
function nextPage() {
|
||||||
|
|
||||||
|
}
|
||||||
6
cmd/pkgserver/ui/static/light.css
Normal file
6
cmd/pkgserver/ui/static/light.css
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
html {
|
||||||
|
background-color: #d3d3d3;
|
||||||
|
color: black; }
|
||||||
|
|
||||||
|
/*# sourceMappingURL=light.css.map */
|
||||||
7
cmd/pkgserver/ui/static/light.css.map
Normal file
7
cmd/pkgserver/ui/static/light.css.map
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"mappings": "AAAA,aAAa;AAEb,IAAK;EACH,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,KAAK",
|
||||||
|
"sources": ["light.scss"],
|
||||||
|
"names": [],
|
||||||
|
"file": "light.css"
|
||||||
|
}
|
||||||
6
cmd/pkgserver/ui/static/light.scss
Normal file
6
cmd/pkgserver/ui/static/light.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
@use 'common';
|
||||||
|
|
||||||
|
html {
|
||||||
|
background-color: #d3d3d3;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
0
internal/azalea/azalea.bnf
Normal file
0
internal/azalea/azalea.bnf
Normal file
69
internal/azalea/azalea.go
Normal file
69
internal/azalea/azalea.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
//go:generate gocc -a azalea.bnf
|
||||||
|
package azalea
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"hakurei.app/container/check"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
Generator
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParser(gen Generator) *Parser {
|
||||||
|
return &Parser{
|
||||||
|
Generator: gen,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (p Parser) Initialise() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Parser) Consume(ns string, file io.Reader) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeDir walks a directory and consumes all Azalea source files within it and all its subdirectories, as long as they end with the .az extension.
|
||||||
|
func (p Parser) ConsumeDir(dir *check.Absolute) error {
|
||||||
|
ds := dir.String()
|
||||||
|
return filepath.WalkDir(ds, func(path string, d fs.DirEntry, err error) (e error) {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.IsDir() || !strings.HasSuffix(d.Name(), ".az") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rel, e := filepath.Rel(ds, path)
|
||||||
|
ns := strings.TrimSuffix(rel, ".az")
|
||||||
|
f, e := os.Open(path)
|
||||||
|
return p.Consume(ns, f)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeAll consumes all provided readers as Azalea source code, each given the namespace `r%d` where `%d` is the index of the reader in the provided arguments.
|
||||||
|
func (p Parser) ConsumeAll(in ...io.Reader) error {
|
||||||
|
for i, r := range in {
|
||||||
|
err := p.Consume("r"+strconv.FormatInt(int64(i), 10), r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeStrings consumes all provided strings as Azalea source code, each given the namespace `s%d` where `%d` is the index of the string in the provided arugments.
|
||||||
|
func (p Parser) ConsumeStrings(in ...string) error {
|
||||||
|
for i, s := range in {
|
||||||
|
err := p.Consume("s"+strconv.FormatInt(int64(i), 10), strings.NewReader(s))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
36
internal/azalea/generator.go
Normal file
36
internal/azalea/generator.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package azalea
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Generator interface {
|
||||||
|
Finalise() (error, io.Writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
type JsonGenerator struct {
|
||||||
|
t any
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewJsonGenerator[T any]() JsonGenerator {
|
||||||
|
t := new(T)
|
||||||
|
|
||||||
|
return JsonGenerator{
|
||||||
|
t,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (j *JsonGenerator) Finalise() (error, io.Writer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type PkgIRGenerator struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPkgIRGenerator() PkgIRGenerator {
|
||||||
|
return PkgIRGenerator{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PkgIRGenerator) Finalise() (error, io.Writer) {
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user