summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarin Ivanov <[email protected]>2025-06-12 22:29:56 +0300
committerMarin Ivanov <[email protected]>2025-06-12 22:29:56 +0300
commit2a18ce1b0d8a5c1edb1927171482d3c5cf696691 (patch)
treee22b1d836bd069b637809aef90089b671bc57de4
parent109c9f0e7644acf26b3c08ac7ddbfd236f62ba6b (diff)
add metadata and ansihtml
-rw-r--r--main.go102
1 files changed, 89 insertions, 13 deletions
diff --git a/main.go b/main.go
index a542ddb..315f0d2 100644
--- a/main.go
+++ b/main.go
@@ -3,34 +3,67 @@ package main
import (
"crypto/rand"
"encoding/base64"
+ "encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"path/filepath"
+ "strings"
"github.com/robert-nix/ansihtml"
flag "github.com/spf13/pflag"
)
-type server struct {
+const (
+ MetadataExt = ".metadata"
+)
+
+type Server struct {
data string
}
-func (s *server) Post(w http.ResponseWriter, r *http.Request) {
+type Metadata struct {
+ ContentType string `json:"contentType"`
+}
+
+func writeMetadata(filename string, m *Metadata) error {
+ f, err := os.OpenFile(filename, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
+ if err != nil {
+ return err
+ }
+ j := json.NewEncoder(f)
+ return j.Encode(m)
+}
+
+func readMetadata(filename string) (*Metadata, error) {
+ f, err := os.Open(filename)
+ if err != nil {
+ return nil, err
+ }
+ var m Metadata
+ j := json.NewDecoder(f)
+ if err := j.Decode(&m); err != nil {
+ return nil, err
+ }
+ return &m, nil
+}
+
+func (s *Server) Post(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
return
}
var random [16]byte
_, err := io.ReadFull(rand.Reader, random[:])
if err != nil {
+ log.Print("io.ReadFull(rand.Reader): ", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
- filename := base64.RawURLEncoding.EncodeToString(random[:])
- path := filepath.Join(s.data, filename)
- f, err := os.OpenFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
+ name := base64.RawURLEncoding.EncodeToString(random[:])
+ filename := filepath.Join(s.data, name)
+ f, err := os.OpenFile(filename, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
if err != nil {
log.Print("OpenFile(): ", err)
w.WriteHeader(http.StatusInternalServerError)
@@ -38,20 +71,67 @@ func (s *server) Post(w http.ResponseWriter, r *http.Request) {
}
defer f.Close()
if _, err = io.Copy(f, r.Body); err != nil {
+ log.Print("io.Copy(): ", err)
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ m := Metadata{
+ ContentType: r.Header.Get("content-type"),
+ }
+ if err = writeMetadata(filename+MetadataExt, &m); err != nil {
+ log.Print("writeMetadata(): ", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
- fmt.Fprintf(w, "/%s", filename)
+ fmt.Fprintf(w, "/%s\n", name)
}
-func (s *server) Get(w http.ResponseWriter, r *http.Request) {
+func serveAnsiHtml(w http.ResponseWriter, filename string) {
+ f, err := os.Open(filename)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ w.Header().Add("content-type", "text/html")
+ data, err := io.ReadAll(f)
+ if err != nil {
+ w.WriteHeader(http.StatusInternalServerError)
+ return
+ }
+ data = ansihtml.ConvertToHTML(data)
+ data = []byte(fmt.Sprintf("<pre>%s</pre>", strings.ReplaceAll(string(data), "\n", "<br>")))
+ w.Write(data)
+}
+
+func (s *Server) Get(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
+ if path == "/" {
+ w.Header().Add("content-type", "text/plain; charset=UTF-8")
+ w.Write([]byte("Bin-ки и глогинки"))
+ return
+ }
filename := filepath.Join(s.data, path)
+ m, err := readMetadata(filename + MetadataExt)
+ if err != nil {
+ log.Print("readMetadata(): ", err)
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ h := w.Header()
+ switch m.ContentType {
+ case "text/x-ansi":
+ serveAnsiHtml(w, filename)
+ return
+ case "":
+ m.ContentType = "application/octet-stream"
+ default:
+ }
+ h.Add("content-type", m.ContentType)
http.ServeFile(w, r, filename)
}
-func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "POST":
s.Post(w, r)
@@ -69,15 +149,11 @@ func main() {
flag.StringVarP(&data, "data-path", "d", "./data", "The path to the data")
flag.Parse()
- html := ansihtml.ConvertToHTML([]byte("\x1b[33mThis text is yellow.\x1b[m"))
- // html: `<span style="color:olive;">This text is yellow.</span>`
- println(string(html))
-
datadir, err := filepath.Abs(data)
if err != nil {
log.Fatal(err)
}
- s := &server{
+ s := &Server{
data: datadir,
}
log.Printf("Listening at '%s'...", addr)