diff --git a/.gitignore b/.gitignore index e6b17a7..402782d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ .env .vscode/ -.ash_history/ files/ -.cache/ main \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index cda8681..5b8fe3e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,14 @@ -FROM golang:1.18.3-alpine3.16 AS base +FROM golang:1.18.3-alpine3.16 ENV APP_ROOT /opt/sfu -ARG gid=1000 -ARG uid=1000 -RUN mkdir -p "$APP_ROOT" \ - && addgroup --system sfu -g $gid \ - && adduser -h "$APP_ROOT" --disabled-password --system -u $uid --ingroup sfu sfu \ - && apk add curl~=7 -WORKDIR "$APP_ROOT" -USER sfu:sfu -FROM base AS build +RUN mkdir -p "$APP_ROOT" +WORKDIR "$APP_ROOT" + COPY go.mod . -COPY *.go ./ +COPY main.go . +COPY logger.go . + RUN go build \ && rm -r go.mod *.go - -FROM build AS run_prod -ENTRYPOINT [ "/bin/sh", "-c", "$APP_ROOT/main"] - -FROM base AS run_dev -ENTRYPOINT [ "/usr/local/go/bin/go", "run", "." ] +ENTRYPOINT [ "/bin/sh", "-c", "$APP_ROOT/main"] \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index c2a337c..0000000 --- a/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# sfu - -simple requirementsless, authenticationless file upload server - -## prod version - -WIP - -## dev version - -### using docker - -1. take a look at [docker-compose](docker-compose.yml) and modify the envvars accordingly. the default values **should work** as long as you're ok with a `files/` folder being created and **your user UID and GID are 1000**. if for some reason you need other ids, please add them like this: - -```docker-compose -... - -app: - build: - context: . - target: run_dev - environment: - - SFU_PORT=80 - - SFU_FILES_DIR=./files - - gid=1234 - - uid=1234 -... -``` - -### dockerless - -1. sfu needs two envvars to be set -- `SFU_PORT`: the port to listen on -- `SFU_FILES_DIR`: the directory to store files in -2. run the server -```shell -go build -SFU_PORT=80 SFU_FILES_DIR=./files ./main -``` \ No newline at end of file diff --git a/design/openapi.yml b/design/openapi.yml index 099b95a..9538001 100644 --- a/design/openapi.yml +++ b/design/openapi.yml @@ -7,7 +7,7 @@ servers: - url: http://localhost:8080/api/v1/ description: local server paths: - /files: + /: get: summary: "list all uploaded files" description: "list all uploaded files" @@ -18,9 +18,11 @@ paths: content: text/plain: schema: - type: string - format: html - + type: array + items: + type: string + format: uri + 500: description: "internal server error" content: @@ -72,9 +74,8 @@ paths: text/plain: schema: type: string - default: "internal server error" - /files/{file_name}: + /{file_name}: get: summary: "get file" description: "get file" @@ -134,26 +135,6 @@ paths: schema: type: string default: "file not found" - 500: - description: "internal server error" - content: - text/plain: - schema: - type: string - default: "internal server error" - /health: - get: - summary: "health check" - description: "health check" - operationId: "health_check" - responses: - 200: - description: "health check successful" - content: - text/plain: - schema: - type: string - default: "health check successful" 500: description: "internal server error" content: diff --git a/docker-compose.yml b/docker-compose.yml index a9346a4..c6b60e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,24 +4,11 @@ services: app: build: context: . - target: run_dev - environment: - - SFU_PORT=80 - - SFU_FILES_DIR=./files volumes: - - ./:/opt/sfu - healthcheck: - test: "curl http://localhost:$SFU_PORT/health" - interval: 1s - timeout: 1s - retries: 3 - start_period: 1s - deploy: - resources: - limits: - cpus: "0.5" - memory: "200M" - restart: always + - "${PWD}/files:${SFU_FILES_DIR},z" + env_file: + - .env + proxy: image: caddy volumes: @@ -29,6 +16,3 @@ services: - ./design:/usr/share/caddy/www/design ports: - '8080:80' - depends_on: - app: - condition: service_healthy diff --git a/handlers.go b/handlers.go deleted file mode 100644 index 348a913..0000000 --- a/handlers.go +++ /dev/null @@ -1,103 +0,0 @@ -package main - -import ( - "fmt" - "io" - "io/ioutil" - "net/http" - "os" - "time" -) - -func downloadFile(w http.ResponseWriter, req *http.Request, fileName string) { - Info.Println(fmt.Sprintf("server: will download %v", fileName)) - file, err := os.Open(fmt.Sprintf("%v/%v", SFU_FILES_DIR, fileName)) - if err != nil { - Error.Println(err) - http.Error(w, "File not found", http.StatusNotFound) - return - } - defer file.Close() - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%v", fileName)) - http.ServeContent(w, req, fileName, time.Now(), file) -} - -func fileExists(fileName string) bool { - _, err := os.Stat(fmt.Sprintf("%v/%v", SFU_FILES_DIR, fileName)) - if err == nil { - return true - } - if os.IsNotExist(err) { - return false - } - return false -} - -func deleteFile(w http.ResponseWriter, req *http.Request, fileName string) { - Info.Println(fmt.Sprintf("server: will delete %v", fileName)) - if !fileExists(fileName) { - Error.Println(fmt.Sprintf("%v does not exist", fileName)) - http.Error(w, "File not found", http.StatusNotFound) - return - } - err := os.Remove(fmt.Sprintf("%v/%v", SFU_FILES_DIR, fileName)) - if err != nil { - Error.Println(err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusOK) - w.Write([]byte("file deleted")) -} - -func uploadFile(w http.ResponseWriter, req *http.Request) { - file, fileHeader, err := req.FormFile("file") - if err != nil { - Error.Println(err) - } - defer file.Close() - fileExists := fileExists(fileHeader.Filename) - forceOverwrite := req.FormValue("force") - if fileExists && forceOverwrite != "true" { - Error.Println(fmt.Sprintf("file %v already exists", fileHeader.Filename)) - http.Error(w, "File already exists", http.StatusConflict) - return - } - if !fileExists || (forceOverwrite == "true" && fileExists) { - Info.Println(fmt.Sprintf("server: will upload %v", fileHeader.Filename)) - out, err := os.Create(fmt.Sprintf("%v/%v", SFU_FILES_DIR, fileHeader.Filename)) - if err != nil { - Error.Println(err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - defer out.Close() - _, err = io.Copy(out, file) - if err != nil { - Error.Println(err) - http.Error(w, "Internal Server Error", http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusCreated) - w.Write([]byte("file uploaded")) - return - } - http.Error(w, "internal server error", http.StatusInternalServerError) - return -} - -func listFiles(w http.ResponseWriter, req *http.Request) { - Info.Println(fmt.Sprintf("server: will list uploaded files on %v", SFU_FILES_DIR)) - files, err := ioutil.ReadDir(SFU_FILES_DIR) - if err != nil { - Warning.Println(fmt.Sprintf("%v does not exist", SFU_FILES_DIR)) - Info.Println(fmt.Sprintf("will create %v", SFU_FILES_DIR)) - _ = os.Mkdir(SFU_FILES_DIR, os.ModePerm) - } - fmt.Fprint(w, "