More Advanced file handling

added /files support
This commit is contained in:
Caleb Gardner
2023-04-24 06:32:45 -05:00
parent ec5a5fbb78
commit a0f63aaee8
3 changed files with 116 additions and 69 deletions
+95
View File
@@ -0,0 +1,95 @@
package darkstormtech
import (
"context"
"io/fs"
"log"
"net/http"
"os"
"strings"
"time"
"github.com/CalebQ42/stupid-backend"
"github.com/CalebQ42/stupid-backend/pkg/defaultapp"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type DarkstormTech struct {
*defaultapp.App
filesFolder string
}
func NewDarkstormTech(c *mongo.Client, filesFolder string) *DarkstormTech {
return &DarkstormTech{
App: defaultapp.NewDefaultApp(c.Database("darkstormtech")),
filesFolder: filesFolder,
}
}
func (d *DarkstormTech) Extension(req *stupid.Request) bool {
if req.Path[0] != "page" {
return false
}
if len(req.Path) == 1 {
req.Resp.WriteHeader(http.StatusBadRequest)
return true
}
if req.Path[1] == "files" {
return d.handleFiles(req)
}
res := d.DB.Collection("pages").FindOne(context.TODO(), bson.M{"_id": strings.Join(req.Path[1:], "/")}, options.FindOne().SetProjection(bson.M{"_id": 0, "content": 1}))
if res.Err() == mongo.ErrNoDocuments {
req.Resp.WriteHeader(http.StatusNotFound) //TODO: Give some sort of default page.
return true
} else if res.Err() != nil {
log.Println("Error while getting page:", res.Err())
req.Resp.WriteHeader(http.StatusInternalServerError)
return true
}
pag := struct { //TODO: Add favicon and title support.
Content string
}{}
err := res.Decode(&pag)
if err != nil {
log.Println("Error while decoding page:", err)
req.Resp.WriteHeader(http.StatusInternalServerError)
return true
}
_, err = req.Resp.Write([]byte(pag.Content))
if err != nil {
log.Println("Error while writing response:", err)
req.Resp.WriteHeader(http.StatusInternalServerError)
}
return true
}
func (d *DarkstormTech) handleFiles(req *stupid.Request) bool {
fils, err := os.ReadDir(d.filesFolder)
if err != nil {
log.Println("Error while getting files:", err)
req.Resp.WriteHeader(http.StatusInternalServerError)
return true
}
out := ""
var inf fs.FileInfo
for _, f := range fils {
if f.IsDir() {
continue
}
inf, err = f.Info()
if err != nil {
log.Println("Error while getting FileInfo for", f.Name(), err)
req.Resp.WriteHeader(http.StatusInternalServerError)
return true
}
out += "<p><a href='https://darkstorm.tech/files/" + f.Name() + "'>" + f.Name() + "</a> " + inf.ModTime().Round(time.Minute).String() + "</p>\n"
}
_, err = req.Resp.Write([]byte(out))
if err != nil {
log.Println("Error while writing output:", err)
req.Resp.WriteHeader(http.StatusInternalServerError)
}
return true
}
+5 -2
View File
@@ -2,11 +2,14 @@ package main
import ( import (
"context" "context"
"flag"
"io" "io"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath"
"github.com/CalebQ42/darkstorm-server/internal/darkstormtech"
"github.com/CalebQ42/stupid-backend" "github.com/CalebQ42/stupid-backend"
"github.com/CalebQ42/stupid-backend/pkg/db" "github.com/CalebQ42/stupid-backend/pkg/db"
"github.com/CalebQ42/stupid-backend/pkg/defaultapp" "github.com/CalebQ42/stupid-backend/pkg/defaultapp"
@@ -28,7 +31,7 @@ func setupStupid(keyPath, mongoStr string) error {
stupid := stupid.NewStupidBackend(db.NewMongoTable(client.Database("stupid").Collection("keys")), map[string]stupid.App{ stupid := stupid.NewStupidBackend(db.NewMongoTable(client.Database("stupid").Collection("keys")), map[string]stupid.App{
"swassistant": defaultapp.NewDefaultApp(client.Database("swassistant")), "swassistant": defaultapp.NewDefaultApp(client.Database("swassistant")),
"cdr": defaultapp.NewDefaultApp(client.Database("cdr")), "cdr": defaultapp.NewDefaultApp(client.Database("cdr")),
"darkstormtech": defaultapp.NewUnauthorizedDataApp(client.Database("darkstormtech")), "darkstormtech": darkstormtech.NewDarkstormTech(client, filepath.Join(flag.Arg(0), "files")),
}) })
users := true users := true
var pub, priv []byte var pub, priv []byte
@@ -57,7 +60,7 @@ func setupStupid(keyPath, mongoStr string) error {
if users { if users {
stupid.EnableUserAuth(db.NewMongoTable(client.Database("stupid").Collection("keys")), pub, priv) stupid.EnableUserAuth(db.NewMongoTable(client.Database("stupid").Collection("keys")), pub, priv)
} }
stupid.SetHeaderValues(map[string]string{"Access-Control-Allow-Origin": "https://darkstorm.tech"}) stupid.SetHeaderValues(map[string]string{"Access-Control-Allow-Origin": "*"})
http.Handle("api.darkstorm.tech/", stupid) http.Handle("api.darkstorm.tech/", stupid)
return nil return nil
} }
+16 -67
View File
@@ -3,7 +3,6 @@ package main
import ( import (
"crypto/tls" "crypto/tls"
"flag" "flag"
"fmt"
"log" "log"
"net/http" "net/http"
"net/http/httputil" "net/http/httputil"
@@ -62,75 +61,25 @@ type fileOrIndexHandler struct {
appFolders []string appFolders []string
} }
func (f *fileOrIndexHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) { func (f *fileOrIndexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
reqPath := strings.Split(strings.TrimPrefix(path.Clean(req.URL.Path), "/"), "/") reqPath := strings.TrimPrefix(path.Clean(r.URL.Path), "/")
if len(reqPath) == 0 { if reqPath == "" || reqPath == "index.html" {
reqPath = []string{"index.html"} http.ServeFile(w, r, path.Join(f.baseFolder, "index.html"))
}
fils, err := os.ReadDir(f.baseFolder)
if err != nil {
if os.IsNotExist(err) {
writer.WriteHeader(http.StatusNotFound)
} else {
log.Println("Error while ReadDir:", err)
writer.WriteHeader(http.StatusInternalServerError)
}
return return
} }
filename := path.Clean(f.baseFolder) reqPath = path.Join(f.baseFolder, reqPath)
var found bool if fil, err := os.Open(reqPath); err == nil {
outer: inf, _ := fil.Stat()
for pathI := 0; pathI < len(reqPath); pathI++ { if !inf.IsDir() {
found = false http.ServeFile(w, r, reqPath)
for filI := range fils {
if strings.EqualFold(strings.ToLower(fils[filI].Name()), reqPath[pathI]) {
found = true
filename = path.Join(filename, fils[filI].Name())
if pathI == len(reqPath)-1 {
if fils[filI].IsDir() {
reqPath = append(reqPath, "index.html")
}
break
} else if !fils[filI].IsDir() {
break outer
} else {
fils, err = os.ReadDir(filename)
if err != nil {
log.Println("Error while ReadDir:", err)
writer.WriteHeader(http.StatusInternalServerError)
return
}
}
break
}
}
if !found {
break
}
}
if !found {
for _, a := range f.appFolders {
if strings.EqualFold(reqPath[0], a) {
http.ServeFile(writer, req, path.Join(f.baseFolder, a, "index.html"))
return
}
}
}
fil, err := os.Open(filename)
if err != nil {
writer.WriteHeader(http.StatusInternalServerError)
return
}
st, _ := fil.Stat()
if st.IsDir() {
var subFil *os.File
subFil, err = os.Open(path.Join(filename, "index.html"))
if os.IsNotExist(err) {
fmt.Println("file server for", filename)
http.FileServer(http.Dir(filename)).ServeHTTP(writer, req)
return return
} }
fil = subFil
} }
http.ServeFile(writer, req, fil.Name()) for _, a := range f.appFolders {
if strings.HasPrefix(reqPath, path.Join(f.baseFolder, a)) {
http.ServeFile(w, r, path.Join(f.baseFolder, a, "index.html"))
return
}
}
http.ServeFile(w, r, path.Join(f.baseFolder, "index.html"))
} }