summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile20
-rw-r--r--go.mod8
-rw-r--r--go.sum4
-rw-r--r--main.go98
-rw-r--r--storage/index.html13
-rw-r--r--upload.go46
6 files changed, 189 insertions, 0 deletions
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..1035e2b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,20 @@
+# syntax=docker/dockerfile:1
+FROM gitrepo.ru/base/go:latest AS go
+
+COPY go.mod go.sum ./
+
+RUN go mod download
+
+COPY . .
+
+RUN go generate && CGO_ENABLED=0 GOOS=linux go build -o nixshare
+
+FROM scratch
+
+WORKDIR /app
+
+COPY --from=go /app/nixshare ./nixshare
+
+EXPOSE 8000
+
+CMD ["./nixshare"] \ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..ad3e9c2
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,8 @@
+module gitrepo.ru/neonxp/nixshare
+
+go 1.23.0
+
+require (
+ github.com/google/uuid v1.6.0
+ golang.org/x/sync v0.8.0
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..b1eeaf3
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,4 @@
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..b9154b8
--- /dev/null
+++ b/main.go
@@ -0,0 +1,98 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "io/fs"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "path/filepath"
+ "time"
+
+ "golang.org/x/sync/errgroup"
+)
+
+var (
+ host string
+ listen string
+ path string
+ ttl time.Duration
+)
+
+func init() {
+ flag.StringVar(&host, "host", "https://nixshare.ru/", "host of nixshare")
+ flag.StringVar(&listen, "listen", ":8000", "port to listen")
+ flag.StringVar(&path, "path", "./storage", "storage directory")
+ flag.DurationVar(&ttl, "ttl", 24*time.Hour, "time to delete uploaded file")
+}
+
+func main() {
+ ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
+ defer cancel()
+
+ flag.Parse()
+
+ r := http.NewServeMux()
+
+ r.Handle("POST /upload", http.HandlerFunc(uploadHandler))
+ r.Handle("/", http.FileServer(http.Dir(path)))
+
+ srv := http.Server{
+ Addr: listen,
+ Handler: r,
+ }
+
+ eg, egCtx := errgroup.WithContext(ctx)
+
+ eg.Go(func() error {
+ <-egCtx.Done()
+ srv.Close()
+
+ return nil
+ })
+
+ eg.Go(func() error {
+ if err := srv.ListenAndServe(); err != http.ErrServerClosed {
+ return err
+ }
+
+ return nil
+ })
+
+ eg.Go(func() error {
+ timer := time.NewTimer(1 * time.Minute)
+ defer timer.Stop()
+ for {
+ select {
+ case <-timer.C:
+ now := time.Now()
+ err := filepath.Walk(path, func(p string, info fs.FileInfo, err error) error {
+ if info == nil {
+ return nil
+ }
+ if info.IsDir() {
+ return nil
+ }
+ if now.Sub(info.ModTime()).Seconds() > ttl.Seconds() {
+ log.Println("delete old file:", p)
+ if err := os.Remove(p); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ log.Println(err)
+ }
+ case <-egCtx.Done():
+ return nil
+ }
+ }
+ })
+
+ if err := eg.Wait(); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/storage/index.html b/storage/index.html
new file mode 100644
index 0000000..a83c858
--- /dev/null
+++ b/storage/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>NixShare</title>
+</head>
+<body>
+ <pre>
+ curl -d @FILENAME https://nixshare.ru/upload
+ </pre>
+</body>
+</html> \ No newline at end of file
diff --git a/upload.go b/upload.go
new file mode 100644
index 0000000..719e519
--- /dev/null
+++ b/upload.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+
+ "github.com/google/uuid"
+)
+
+func uploadHandler(w http.ResponseWriter, r *http.Request) {
+ uid := uuid.New().String()
+ section := string(uid[len(uid)-1])
+ if err := os.MkdirAll(filepath.Join(path, section), 0777); err != nil {
+ log.Println(err)
+ http.Error(w, "can't create storage dir", http.StatusInternalServerError)
+ return
+ }
+ fp, err := os.Create(filepath.Join(path, section, uid))
+ if err != nil {
+ log.Println(err)
+ http.Error(w, "can't create storage file", http.StatusInternalServerError)
+ return
+ }
+ defer fp.Close()
+ if _, err := io.Copy(fp, r.Body); err != nil {
+ log.Println(err)
+ http.Error(w, "can't upload storage file", http.StatusInternalServerError)
+ return
+ }
+ h := w.Header()
+ h.Set("Content-Type", "text/plain; charset=utf-8")
+ h.Set("X-Content-Type-Options", "nosniff")
+ w.WriteHeader(http.StatusCreated)
+ u, err := url.JoinPath(host, section, uid)
+ if err != nil {
+ log.Println(err)
+ http.Error(w, "can't get file url", http.StatusInternalServerError)
+ return
+ }
+ fmt.Fprintln(w, u)
+}