diff --git a/README.md b/README.md index c1216e9..f9af1ca 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # Gymboard Leaderboards for your local community gym. + +## Development +Gymboard is comprised of a variety of components, each in its own directory, and with its own project format. Follow the instructions in the README of the respective project to set that one up. + +A `docker-compose.yml` file is defined in this directory, and it defines a set of services that may be used by one or more services. Install docker on your system if you haven't already, and run `docker-compose up -d` to start the services. diff --git a/docker-compose.yml b/docker-compose.yml index 9cb3126..ffe7fe9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,16 @@ services: environment: POSTGRES_USER: gymboard-api-dev POSTGRES_PASSWORD: testpass + + # Database for the gymboard-cdn. + cdn-db: + image: postgres + restart: always + ports: + - "5433:5432" + environment: + POSTGRES_USER: gymboard-cdn-dev + POSTGRES_PASSWORD: testpass mailhog: image: mailhog/mailhog diff --git a/gymboard-cdn/README.md b/gymboard-cdn/README.md new file mode 100644 index 0000000..51c7fb9 --- /dev/null +++ b/gymboard-cdn/README.md @@ -0,0 +1,9 @@ +# Gymboard-CDN + +To avoid having to do expensive and complex computations in the main Gymboard API to handle user video uploads, that functionality is provided by this _Gymboard-CDN_ project. + +This CDN offers basic, unauthenticated upload and download capabilities, as well as asynchronous processing of video files to reduce disk usage. + +It offers the following endpoints: +- `POST /uploads` - Upload files here. +- `GET /uploads/{id}` - Fetch uploaded files. diff --git a/gymboard-cdn/dub.json b/gymboard-cdn/dub.json index 0baf7d5..d7b47fb 100644 --- a/gymboard-cdn/dub.json +++ b/gymboard-cdn/dub.json @@ -4,7 +4,8 @@ ], "copyright": "Copyright © 2023, Andrew Lalis", "dependencies": { - "handy-httpd": "~>4.0.2" + "dpq2": "~>1.1.3", + "handy-httpd": "~>5.0.0" }, "description": "Content delivery network for Gymboard.", "license": "proprietary", diff --git a/gymboard-cdn/dub.selections.json b/gymboard-cdn/dub.selections.json new file mode 100644 index 0000000..1d63656 --- /dev/null +++ b/gymboard-cdn/dub.selections.json @@ -0,0 +1,14 @@ +{ + "fileVersion": 1, + "versions": { + "derelict-pq": "4.0.0", + "derelict-util": "3.0.0-beta.2", + "dpq2": "1.1.3", + "handy-httpd": "5.0.0", + "httparsed": "1.2.1", + "money": "3.0.2", + "stdx-allocator": "2.77.5", + "unit-threaded": "2.1.2", + "vibe-d": "0.9.5" + } +} diff --git a/gymboard-cdn/source/app.d b/gymboard-cdn/source/app.d index c3eec7f..57a6cbb 100644 --- a/gymboard-cdn/source/app.d +++ b/gymboard-cdn/source/app.d @@ -1,6 +1,47 @@ +import handy_httpd; +import handy_httpd.handlers.path_delegating_handler; +import dpq2; import std.stdio; -void main() -{ - writeln("Edit source/app.d to start your project."); +const DB_URL = "host=127.0.0.1 port=5433 dbname=gymboard-cdn-dev user=gymboard-cdn-dev password=testpass"; + +void main() { + ServerConfig config = ServerConfig.defaultValues(); + config.port = 8082; + config.reuseAddress = true; + config.workerPoolSize = 10; + PathDelegatingHandler handler = new PathDelegatingHandler(); + handler.addMapping("GET", "/uploads/{uploadId}", new VideoFetcher()); + handler.addMapping("POST", "/uploads", new VideoUploader()); + HttpServer server = new HttpServer(handler, config); + server.start(); +} + +Connection connectToDb() { + return new Connection(DB_URL); +} + +/** + * Handler that fetches a video by its id (if it exists). + */ +class VideoFetcher : HttpRequestHandler { + void handle(ref HttpRequestContext ctx) { + long uploadId = ctx.request.getPathParamAs!ulong("uploadId", 0); + writeln(uploadId); + auto conn = connectToDb(); + QueryParams p; + p.sqlCommand = "SELECT 'hello world';"; + auto answer = conn.execParams(p); + scope(exit) destroy(answer); + writeln(answer[0][0].as!PGtext); + } +} + +/** + * Handler that processes a video upload. + */ +class VideoUploader : HttpRequestHandler { + void handle(ref HttpRequestContext ctx) { + + } }