Server for Nex Protocol written in Go
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

143 lines
2.4 KiB

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))
}