diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..644627c --- /dev/null +++ b/Caddyfile @@ -0,0 +1,15 @@ +http://localhost + +route /api/v1/* { + uri strip_prefix /api/v1 + reverse_proxy app +} + +route /docs/* { + uri strip_prefix /docs + file_server { + root /usr/share/caddy/www/design + index index.html + browse true + } +} diff --git a/Dockerfile b/Dockerfile index 0da2d38..5b8fe3e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.17.11-alpine3.16 +FROM golang:1.18.3-alpine3.16 ENV APP_ROOT /opt/sfu @@ -7,7 +7,8 @@ WORKDIR "$APP_ROOT" COPY go.mod . COPY main.go . +COPY logger.go . RUN go build \ - && rm -r go.mod main.go + && rm -r go.mod *.go ENTRYPOINT [ "/bin/sh", "-c", "$APP_ROOT/main"] \ No newline at end of file diff --git a/design/index.html b/design/index.html new file mode 100644 index 0000000..c055fa0 --- /dev/null +++ b/design/index.html @@ -0,0 +1,17 @@ + + + + + + Scullion REST API + + + + + + + diff --git a/design/openapi.yml b/design/openapi.yml new file mode 100644 index 0000000..9538001 --- /dev/null +++ b/design/openapi.yml @@ -0,0 +1,144 @@ +openapi: "3.0.3" +info: + title: sfu + version: 0.1.0 + description: file upload server +servers: + - url: http://localhost:8080/api/v1/ + description: local server +paths: + /: + get: + summary: "list all uploaded files" + description: "list all uploaded files" + operationId: "list_files" + responses: + 200: + description: "file list successful" + content: + text/plain: + schema: + type: array + items: + type: string + format: uri + + 500: + description: "internal server error" + content: + text/plain: + schema: + type: string + default: "internal server error" + post: + summary: "upload file" + description: "uploaded a file" + operationId: "upload_file" + requestBody: + content: + multipart/form-data: + schema: + type: object + properties: + file: + type: string + format: binary + description: "file to upload" + parameters: + - name: force + in: query + description: "force upload file which may overwrite an existing file with the same name" + required: false + schema: + type: boolean + default: false + responses: + 201: + description: "file upload successful" + content: + text/plain: + schema: + type: array + items: + type: string + 409: + description: "file already exists" + content: + text/plain: + schema: + type: string + default: "file already exists" + 500: + description: "internal server error" + content: + text/plain: + schema: + type: string + default: "internal server error" + /{file_name}: + get: + summary: "get file" + description: "get file" + operationId: "get_file" + parameters: + - name: file_name + in: path + description: "file name" + required: true + schema: + type: string + responses: + 200: + description: "file download successful" + content: + text/plain: + schema: + type: string + format: binary + 404: + description: "file not found" + content: + text/plain: + schema: + type: string + default: "file not found" + 500: + description: "internal server error" + content: + text/plain: + schema: + type: string + default: "internal server error" + delete: + summary: "delete file" + description: "delete file" + operationId: "delete_file" + parameters: + - name: file_name + in: path + description: "file name" + required: true + schema: + type: string + responses: + 200: + description: "file delete successful" + content: + text/plain: + schema: + type: string + default: "file delete successful" + 404: + description: "file not found" + content: + text/plain: + schema: + type: string + default: "file not found" + 500: + description: "internal server error" + content: + text/plain: + schema: + type: string + default: "internal server error" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 456d0b5..c6b60e7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,15 @@ services: app: build: context: . - ports: - - "8080:80" + volumes: + - "${PWD}/files:${SFU_FILES_DIR},z" env_file: - - .env \ No newline at end of file + - .env + + proxy: + image: caddy + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - ./design:/usr/share/caddy/www/design + ports: + - '8080:80' diff --git a/go.mod b/go.mod index c0ecf8b..6967dfd 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module main -go 1.17 +go 1.18 diff --git a/logger.go b/logger.go new file mode 100644 index 0000000..a150e41 --- /dev/null +++ b/logger.go @@ -0,0 +1,11 @@ +package main + +import ( + "log" + "os" +) + +var Info = log.New(os.Stdout, "\u001b[34mINFO: \u001B[0m", log.LstdFlags|log.Lshortfile) +var Warning = log.New(os.Stdout, "\u001b[33mWARNING: \u001B[0m", log.LstdFlags|log.Lshortfile) +var Error = log.New(os.Stdout, "\u001b[31mERROR: \u001b[0m", log.LstdFlags|log.Lshortfile) +var Debug = log.New(os.Stdout, "\u001b[36mDEBUG: \u001B[0m", log.LstdFlags|log.Lshortfile) diff --git a/main.go b/main.go index 8b11de7..e408be7 100644 --- a/main.go +++ b/main.go @@ -4,15 +4,12 @@ import ( "fmt" "io" "io/ioutil" - "log" "net/http" "os" ) -var Info = log.New(os.Stdout, "\u001b[34mINFO: \u001B[0m", log.LstdFlags|log.Lshortfile) -var Warning = log.New(os.Stdout, "\u001b[33mWARNING: \u001B[0m", log.LstdFlags|log.Lshortfile) -var Error = log.New(os.Stdout, "\u001b[31mERROR: \u001b[0m", log.LstdFlags|log.Lshortfile) -var Debug = log.New(os.Stdout, "\u001b[36mDEBUG: \u001B[0m", log.LstdFlags|log.Lshortfile) +var SFU_FILES_DIR string = get_envvar_or_fatal("SFU_FILES_DIR") +var SFU_PORT string = get_envvar_or_fatal("SFU_PORT") func upload_file(w http.ResponseWriter, req *http.Request) { file, fileHeader, err := req.FormFile("file") @@ -21,19 +18,19 @@ func upload_file(w http.ResponseWriter, req *http.Request) { } defer file.Close() - f, err := os.OpenFile(fmt.Sprintf("%v/%v", get_envvar_or_fatal("SFU_FILES_DIR"), fileHeader.Filename), os.O_WRONLY|os.O_CREATE, 0666) + f, err := os.OpenFile(fmt.Sprintf("%v/%v", SFU_FILES_DIR, fileHeader.Filename), os.O_WRONLY|os.O_CREATE, 0666) defer f.Close() io.Copy(f, file) + w.WriteHeader(http.StatusCreated) } func list_uploaded_files(w http.ResponseWriter, req *http.Request) { - files_dir := get_envvar_or_fatal("SFU_FILES_DIR") - Info.Println(fmt.Sprintf("server: will list uploaded files on %v", files_dir)) - files, err := ioutil.ReadDir(files_dir) + 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", files_dir)) - Info.Println(fmt.Sprintf("will create %v", files_dir)) - _ = os.Mkdir(files_dir, os.ModePerm) + 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) } for _, f := range files { fmt.Fprintf(w, "%v\n", f.Name()) @@ -71,7 +68,7 @@ func main() { Error.Println(fmt.Sprintf("will return %v", http.StatusMethodNotAllowed)) } }) - port := fmt.Sprintf(":%v", get_envvar_or_fatal("SFU_PORT")) + port := fmt.Sprintf(":%v", SFU_PORT) Info.Println(fmt.Sprintf("running SFU on port %v", port)) err := http.ListenAndServe(port, nil) if err != nil {