Compare commits

..

2 commits

Author SHA1 Message Date
02ed6be314
feat: add openapi design doc 2022-06-28 10:12:35 +02:00
bffe41a012
feat: add openapi design doc 2022-06-28 10:11:35 +02:00
8 changed files with 212 additions and 19 deletions

15
Caddyfile Normal file
View file

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

View file

@ -1,4 +1,4 @@
FROM golang:1.17.11-alpine3.16 FROM golang:1.18.3-alpine3.16
ENV APP_ROOT /opt/sfu ENV APP_ROOT /opt/sfu
@ -7,7 +7,8 @@ WORKDIR "$APP_ROOT"
COPY go.mod . COPY go.mod .
COPY main.go . COPY main.go .
COPY logger.go .
RUN go build \ RUN go build \
&& rm -r go.mod main.go && rm -r go.mod *.go
ENTRYPOINT [ "/bin/sh", "-c", "$APP_ROOT/main"] ENTRYPOINT [ "/bin/sh", "-c", "$APP_ROOT/main"]

17
design/index.html Normal file
View file

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Scullion REST API</title>
<script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@stoplight/elements/styles.min.css">
</head>
<body>
<elements-api
apiDescriptionUrl="http://localhost:8080/docs/openapi.yml"
router="hash"
layout="sidebar"
/>
</body>
</html>

144
design/openapi.yml Normal file
View file

@ -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"

View file

@ -4,7 +4,15 @@ services:
app: app:
build: build:
context: . context: .
ports: volumes:
- "8080:80" - "${PWD}/files:${SFU_FILES_DIR},z"
env_file: env_file:
- .env - .env
proxy:
image: caddy
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./design:/usr/share/caddy/www/design
ports:
- '8080:80'

2
go.mod
View file

@ -1,3 +1,3 @@
module main module main
go 1.17 go 1.18

11
logger.go Normal file
View file

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

23
main.go
View file

@ -4,15 +4,12 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"os" "os"
) )
var Info = log.New(os.Stdout, "\u001b[34mINFO: \u001B[0m", log.LstdFlags|log.Lshortfile) var SFU_FILES_DIR string = get_envvar_or_fatal("SFU_FILES_DIR")
var Warning = log.New(os.Stdout, "\u001b[33mWARNING: \u001B[0m", log.LstdFlags|log.Lshortfile) var SFU_PORT string = get_envvar_or_fatal("SFU_PORT")
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)
func upload_file(w http.ResponseWriter, req *http.Request) { func upload_file(w http.ResponseWriter, req *http.Request) {
file, fileHeader, err := req.FormFile("file") file, fileHeader, err := req.FormFile("file")
@ -21,19 +18,19 @@ func upload_file(w http.ResponseWriter, req *http.Request) {
} }
defer file.Close() 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() defer f.Close()
io.Copy(f, file) io.Copy(f, file)
w.WriteHeader(http.StatusCreated)
} }
func list_uploaded_files(w http.ResponseWriter, req *http.Request) { 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", SFU_FILES_DIR))
Info.Println(fmt.Sprintf("server: will list uploaded files on %v", files_dir)) files, err := ioutil.ReadDir(SFU_FILES_DIR)
files, err := ioutil.ReadDir(files_dir)
if err != nil { if err != nil {
Warning.Println(fmt.Sprintf("%v does not exist", files_dir)) Warning.Println(fmt.Sprintf("%v does not exist", SFU_FILES_DIR))
Info.Println(fmt.Sprintf("will create %v", files_dir)) Info.Println(fmt.Sprintf("will create %v", SFU_FILES_DIR))
_ = os.Mkdir(files_dir, os.ModePerm) _ = os.Mkdir(SFU_FILES_DIR, os.ModePerm)
} }
for _, f := range files { for _, f := range files {
fmt.Fprintf(w, "%v\n", f.Name()) fmt.Fprintf(w, "%v\n", f.Name())
@ -71,7 +68,7 @@ func main() {
Error.Println(fmt.Sprintf("will return %v", http.StatusMethodNotAllowed)) 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)) Info.Println(fmt.Sprintf("running SFU on port %v", port))
err := http.ListenAndServe(port, nil) err := http.ListenAndServe(port, nil)
if err != nil { if err != nil {