From a3ffecb1db3867cf8a5036e903b13031aa315c76 Mon Sep 17 00:00:00 2001 From: yggverse Date: Mon, 22 Apr 2024 10:51:20 +0300 Subject: [PATCH] initial commit --- LICENSE | 22 +++++++++ Makefile | 2 + README.md | 19 ++++++++ nexd.go | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 186 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 nexd.go diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9600bd2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 m15o + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4866c26 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +build: + GOARCH=amd64 go build -o nexd nexd.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a7aebe --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# nexd - Server for Nex Protocol written in Go + +Unofficial GIT build of [nexd](https://hg.sr.ht/~m15o/nexd) Mercurial repository. + +Includes [nex-pfm](https://hg.sr.ht/~m15o/nex-pfm) + modified for Linux / amd64 makefile version. + +## Install + +* `git clone https://github.com/YGGverse/nexd.git` +* `cd nexd` +* `make` + +## Launch + +``` +nexd path/to/destination/folder +``` + +* server open `index` file by default, directory listing instead \ No newline at end of file diff --git a/nexd.go b/nexd.go new file mode 100644 index 0000000..8dc9ac2 --- /dev/null +++ b/nexd.go @@ -0,0 +1,143 @@ +package main + +import ( + "bufio" + "io" + "io/fs" + "log" + "net" + "os" + "path" + "sort" + "strings" +) + +func write(w io.Writer, s string) (int, error) { + return w.Write([]byte(s + "\n")) +} + +type Handler struct { + FS fs.FS +} + +func (h *Handler) handleDir(p string, w io.Writer) error { + if header, err := fs.ReadFile(h.FS, path.Join(p, ".header")); err == nil { + write(w, string(header)) + } + modified := true + if _, err := fs.Stat(h.FS, path.Join(p, ".modified")); err != nil { + modified = false + } + asc := false + if _, err := fs.Stat(h.FS, path.Join(p, ".desc")); err != nil { + asc = true + } + dirents, err := fs.ReadDir(h.FS, p) + if err != nil { + return err + } + sort.Slice(dirents, func(i, j int) bool { + if modified { + st1, err := dirents[i].Info() + if err != nil { + return false + } + st2, err := dirents[j].Info() + if err != nil { + return false + } + return st1.ModTime().After(st2.ModTime()) + } else if asc { + return dirents[i].Name() < dirents[j].Name() + } else { + return dirents[i].Name() > dirents[j].Name() + } + }) + for _, entry := range dirents { + name := entry.Name() + if strings.HasPrefix(name, ".") { + continue + } + i, err := entry.Info() + if err != nil { + continue + } + if i.Mode()&(1<<2) == 0 { + continue + } + if entry.IsDir() { + name += "/" + } + if _, err := write(w, "=> "+name); err != nil { + return err + } + } + return nil +} + +func (h *Handler) Handle(p string, w io.Writer) error { + if p == "/" || p == "" { + p = "." + } else { + p = strings.Trim(p, "/") + } + + f, err := h.FS.Open(p) + if err != nil { + return err + } + defer f.Close() + + stat, err := f.Stat() + if err != nil { + return err + } + + if stat.IsDir() { + index, err := h.FS.Open(path.Join(p, "index")) + if err != nil { + return h.handleDir(p, w) + } + defer index.Close() + f = index + } + + _, err = io.Copy(w, f) + return err +} + +func serve(h *Handler, rw io.ReadWriteCloser) { + defer rw.Close() + scanner := bufio.NewScanner(rw) + scanner.Scan() + sel := scanner.Text() + if err := h.Handle(sel, rw); err != nil { + rw.Write([]byte("document not found")) + log.Println(err) + } +} + +func listenAndServe(h *Handler) error { + l, err := net.Listen("tcp", ":1900") + if err != nil { + return err + } + defer l.Close() + + for { + rw, err := l.Accept() + if err != nil { + return err + } + go serve(h, rw) + } +} + +func main() { + if len(os.Args) < 2 { + log.Fatal("usage: nexd path") + } + + h := Handler{FS: os.DirFS(os.Args[1])} + log.Fatal(listenAndServe(&h)) +} \ No newline at end of file