{"id":20668913,"url":"https://github.com/jetspiking/renderonline","last_synced_at":"2025-12-13T13:36:14.831Z","repository":{"id":253407250,"uuid":"843393546","full_name":"jetspiking/RenderOnline","owner":"jetspiking","description":"Dynamic Solution for Managing and Executing Rendering Tasks on HPC Infrastructure","archived":false,"fork":false,"pushed_at":"2025-12-10T19:26:26.000Z","size":850,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-11T06:37:34.265Z","etag":null,"topics":["cli","cloud-computing","computerarchitecture","gpu-acceleration","persistent","pipeline"],"latest_commit_sha":null,"homepage":"https://renderonline.nl","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jetspiking.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-08-16T12:19:23.000Z","updated_at":"2025-12-10T19:38:09.000Z","dependencies_parsed_at":"2025-12-10T23:17:47.703Z","dependency_job_id":null,"html_url":"https://github.com/jetspiking/RenderOnline","commit_stats":null,"previous_names":["jetspiking/renderonline"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jetspiking/RenderOnline","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetspiking%2FRenderOnline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetspiking%2FRenderOnline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetspiking%2FRenderOnline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetspiking%2FRenderOnline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jetspiking","download_url":"https://codeload.github.com/jetspiking/RenderOnline/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jetspiking%2FRenderOnline/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27706411,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-13T02:00:09.769Z","response_time":147,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cloud-computing","computerarchitecture","gpu-acceleration","persistent","pipeline"],"created_at":"2024-11-16T20:12:10.215Z","updated_at":"2025-12-13T13:36:14.822Z","avatar_url":"https://github.com/jetspiking.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003cimg src=\"Readme/favicon_client.png\" width=\"64\" height=\"64\"\u003e RenderOnline\n\nDistributed rendering stack built with .NET, MySQL, Avalonia, and simple HTTP APIs.  \nConsists of:\n\n- **HPCServer** – lightweight render worker that runs render engines.\n- **RenderAPI** – central queue, orchestration, and REST API.\n- **RNOClient** – cross‑platform UI client.\n- **Database** – MySQL schema for users, tasks, engines, and queueing.\n\n---\n\n## Showcase\n\n\u003cimg src=\"Readme/Client.png\" width=\"900\"\u003e\n\n---\n\n## Description\n\nRenderOnline is a small, self‑hosted render farm:\n\n- **Render nodes** run `HPCServer`, which exposes a minimal `/hpc/*` API and wraps CLI render engines (e.g., Blender).\n- A central **`RenderAPI`** service authenticates users, manages the queue, assigns tasks to machines, and tracks status in MySQL.\n- The **`RNOClient`** GUI (Avalonia, desktop and browser targets) lets users enqueue scenes, monitor progress, download results, and manage tasks.\n\n---\n\n## Highlights\n\n- Multi‑machine render farm (MySQL‑driven scheduler).\n- Simple HTTP control plane:\n  - `/renderapi/v1/*` for client access.\n  - `/hpc/*` for render node control.\n- Auth via `email` and `token` headers.\n- Subscription‑based queue limits per user.\n- Pluggable render engines:\n  - Engines defined in DB (`engines` table) and per‑node config (`HPCServer.json`).\n  - Arguments templated with `$RENDERONLINE:\u003cargtype\u003e` placeholders.\n- Safe argument validation using `argtypes` table and regex/type rules.\n- Robust file handling:\n  - Upload project file via multipart/form‑data.\n  - Engine‑specific working directories per task.\n  - On‑demand ZIP packaging of result directories for download.\n- Cross‑platform components:\n  - HPCServer and RenderAPI run on .NET.\n  - RNOClient runs on Windows/Linux/macOS (desktop) and browser (WebAssembly target).\n\n---\n\n## Repository Layout\n\n- `HPCServer/` – render node HTTP server.\n- `RenderAPI/` – central API and scheduler.\n- `RNOClient/` – Avalonia client:\n  - `RNOClient.Desktop/` – desktop entry point.\n  - `RNOClient/` – shared app and views (+ browser entry).\n- `Database/` – MySQL schema scripts (`renderonline_*.sql`).\n- `Readme/` – favicons and screenshots:\n  - `favicon_client.png`, `favicon_server.png`, `favicon_api.png`\n  - `Client.png`, `Database.png`\n\n---\n\n## Quick Start\n\n### Requirements\n\n- **.NET SDK** 8 (or later).\n- **MySQL Server** 8.x.\n- OS:\n  - HPCServer \u0026 RenderAPI: Windows or Linux.\n  - RNOClient: Windows/Linux/macOS for desktop; any modern browser for WebAssembly target.\n- A CLI render engine installed on each render node (e.g., `blender`, custom renderer, etc.).\n\n---\n\n### 1. Set up the Database\n\n1. Create the `renderonline` database if it does not exist:\n\n   ```sql\n   CREATE DATABASE IF NOT EXISTS renderonline;\n   ```\n\n2. Import all SQL scripts from `Database/` into `renderonline`:\n\n   ```bash\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_users.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_subscriptions.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_engines.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_argtypes.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_machines.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_renders.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_tasks.sql\n   mysql -u \u003cuser\u003e -p renderonline \u003c Database/renderonline_queue.sql\n   ```\n\n3. Seed minimal data (adapt values to your environment):\n\n   ```sql\n   INSERT INTO subscriptions (subscription_id, name, queue_limit)\n   VALUES (1, 'Default', 3);\n\n   INSERT INTO users (first_name, last_name, email, subscription_id, is_active, token)\n   VALUES ('Test', 'User', 'user@example.com', 1, 1, 'my-secret-token');\n\n   INSERT INTO engines (engine_id, name, extension, download_path, render_argument)\n   VALUES (\n     1,\n     'blender',\n     '.blend',\n     '/srv/renderonline/downloads',\n     'blender -b $RENDERONLINE:@uploaded_file -s $RENDERONLINE:start_frame -e $RENDERONLINE:end_frame -a'\n   );\n\n   INSERT INTO argtypes (argtype_id, type, regex)\n   VALUES\n     ('start_frame', 'natural', NULL),\n     ('end_frame', 'natural', NULL),\n     ('output_format', 'extension', NULL);\n\n   INSERT INTO machines (machine_id, ip_address, port)\n   VALUES (1, '192.168.1.10', 5001);\n   ```\n\nNotes:\n\n- `engines.name` must match `HPCEngine.EngineId` in each `HPCServer.json`.\n- `download_path` must be writable by RenderAPI and appropriate for your OS.\n- `machines.ip_address` and `port` must point to running HPCServer instances.\n- `users.token` is the raw token the client sends in the `token` header.\n\n---\n\n### 2. Configure and Run HPCServer (render node)\n\nCreate `HPCServer.json` next to the `HPCServer` executable:\n\n```json\n{\n  \"Port\": \"5001\",\n  \"RenderingEngines\": [\n    {\n      \"EngineId\": \"blender\",\n      \"ExecutablePath\": \"/usr/bin/blender\"\n    }\n  ]\n}\n```\n\nKey points:\n\n- `Port` must match the `machines.port` entry for this node.\n- `RenderingEngines[n].EngineId` must exactly match `engines.name` in the DB.\n- `ExecutablePath` points to the renderer binary on that machine.\n\nBuild and run:\n\n```bash\ncd HPCServer\ndotnet build\ndotnet run\n```\n\nThe server will listen on `http://0.0.0.0:\u003cPort\u003e` and expose `/hpc/*` endpoints.\n\n---\n\n### 3. Configure and Run RenderAPI (central API)\n\nCreate `RenderAPI.json` next to the `RenderAPI` executable.\n\nFor HTTP:\n\n```json\n{\n  \"ConnectionString\": \"Server=localhost;Database=renderonline;User Id=renderonline;Password=yourpassword;\",\n  \"Port\": \"5000\",\n  \"Certificate\": null\n}\n```\n\nFor HTTPS with PEM certificate files:\n\n```json\n{\n  \"ConnectionString\": \"Server=localhost;Database=renderonline;User Id=renderonline;Password=yourpassword;\",\n  \"Port\": \"5001\",\n  \"Certificate\": {\n    \"FullchainPemPath\": \"/etc/ssl/renderonline/fullchain.pem\",\n    \"PrivPemPath\": \"/etc/ssl/renderonline/privkey.pem\"\n  }\n}\n```\n\nBuild and run:\n\n```bash\ncd RenderAPI\ndotnet build\ndotnet run\n```\n\nRenderAPI will:\n\n- Validate DB connectivity on startup.\n- Listen on the configured port (HTTP or HTTPS).\n- Start the polling service that assigns queued tasks to machines and monitors completion.\n\n---\n\n### 4. Run the RNOClient\n\n#### Desktop\n\n```bash\ncd RNOClient.Desktop\ndotnet build\ndotnet run\n```\n\nBy default, `MainView` uses:\n\n- `_ipAddress = \"127.0.0.1\"`\n- `_port = null` → HTTPS to `https://127.0.0.1`\n\nAdjust `_ipAddress` and `_port` in `RNOClient/Views/MainView.axaml.cs` to point to your RenderAPI instance. If you are running RenderAPI over HTTP on port 5000, for example:\n\n- Set `_ipAddress` to your API host.\n- Set `_port` to `\"5000\"` (client then uses `http://\u003cip\u003e:\u003cport\u003e`).\n\n#### Browser (WebAssembly)\n\n```bash\ncd RNOClient\ndotnet build\ndotnet run\n```\n\nThis starts the browser‑targeted app (`StartBrowserAppAsync(\"out\")`).  \nRefer to Avalonia Browser documentation for static hosting if you want to deploy it.\n\n#### Logging in and Using the Client\n\n1. Enter the email and token you seeded in the `users` table.\n2. Click **Validate**:\n   - The client calls `GET /renderapi/v1/info`.\n   - On success, tasks and user info are loaded and shown.\n3. Use **Upload** to enqueue a render:\n   - Pick a project file (must match the extension in `engines.extension`, e.g. `.blend`).\n   - Set `start_frame` and `end_frame`.\n   - Pick an output format (mapped to `output_format` argtype).\n4. Monitor tasks:\n   - Green check: finished successfully (download available).\n   - Busy icon: queued or running.\n   - Red error icon: failed.\n5. Use the trash icon to delete a task and its data.\n6. Use the download icon to save a ZIP archive of the render result.\n\n---\n\n## \u003cimg src=\"Readme/favicon_server.png\" width=\"32\" height=\"32\"\u003e HPCServer\n\n### Role\n\nHPCServer runs on each render node and is responsible for:\n\n- Managing at most one render process at a time.\n- Starting CLI render engines with provided arguments.\n- Tracking process lifetime, status, and exit code.\n- Exposing a simple HTTP API for RenderAPI to start/stop tasks and query status.\n\n### Configuration\n\n`HPCServer.json` (see Quick Start) defines:\n\n- `Port`: Kestrel listen port (HTTP only).\n- `RenderingEngines`: array of `HPCEngine`:\n  - `EngineId`: identifier used by RenderAPI; must match `engines.name` in DB.\n  - `ExecutablePath`: full path to renderer binary (e.g., `/usr/bin/blender`).\n\n### HTTP API\n\nBase URL: `http://\u003cip\u003e:\u003cport\u003e`\n\n#### GET `/hpc/status`\n\nReturns machine status and current task information.\n\nExample response:\n\n```json\n{\n  \"EngineIds\": [\"blender\"],\n  \"Task\": {\n    \"TaskId\": 123,\n    \"IsSuccess\": false,\n    \"IsRunning\": true,\n    \"TotalSeconds\": 42\n  }\n}\n```\n\n- `EngineIds`: the configured engine identifiers from `HPCServer.json`.\n- `Task`: null if no task has been started since server start.\n- `IsRunning`: true while the process is active.\n- `IsSuccess`: last exit code equals 0.\n\n#### POST `/hpc/start`\n\nStarts a new render process if none is currently running.\n\nRequest body (`HPCStartArgs`):\n\n```json\n{\n  \"EngineId\": \"blender\",\n  \"TaskId\": 123,\n  \"Arguments\": \"blender -b /path/to/file.blend -s 1 -e 100 -a\"\n}\n```\n\nResponse (`HPCRenderRequestResponse`):\n\n```json\n{\n  \"IsSuccess\": true,\n  \"Message\": \"Rendering using engine with identifier: blender\"\n}\n```\n\nError conditions (HTTP 400):\n\n- A render is already in progress.\n- Engine ID not configured.\n- Invalid arguments.\n\n#### POST `/hpc/stop`\n\nStops the currently running render process (if it matches the task ID).\n\nRequest body (`HPCStopArgs`):\n\n```json\n{\n  \"TaskId\": 123\n}\n```\n\nResponse:\n\n```json\n{\n  \"IsSuccess\": true,\n  \"Message\": \"Active render terminated!\"\n}\n```\n\nIf no active render is running, it still returns HTTP 200 with a message indicating there was no active render.\n\nHPCServer uses `Process.WaitForExitAsync` to determine completion and treats exit code `0` as success.\n\n---\n\n## \u003cimg src=\"Readme/favicon_api.png\" width=\"32\" height=\"32\"\u003e RenderAPI\n\n### Role\n\nRenderAPI is the central orchestration service that:\n\n- Authenticates users via headers.\n- Exposes all public HTTP endpoints (`/renderapi/v1/*`).\n- Manages the render queue and machine inventory in MySQL.\n- Assigns tasks to idle HPCServer nodes.\n- Polls and updates task states based on HPCServer status.\n\n### Authentication\n\nEach HTTP request from RNOClient (or other clients) must include:\n\n- `email` header: matches `users.email`.\n- `token` header: matches `users.token` and `is_active = 1`.\n\nIf missing or invalid, endpoints generally return HTTP 401 or a JSON error response.\n\n---\n\n### Public Endpoints\n\nBase URL: e.g. `https://\u003chost\u003e:\u003cport\u003e` (depending on your `RenderAPI.json`).\n\n#### GET `/renderapi/v1/info`\n\nReturns user info and last tasks for the authenticated user.\n\n- Headers: `email`, `token`\n- Response (`ApiInfoResponse`):\n\n  ```json\n  {\n    \"User\": {\n      \"UserId\": 1,\n      \"FirstName\": \"Test\",\n      \"LastName\": \"User\",\n      \"Email\": \"user@example.com\",\n      \"SubscriptionId\": 1,\n      \"IsActive\": true\n    },\n    \"Tasks\": [\n      {\n        \"Task\": {\n          \"TaskId\": 123,\n          \"UserId\": 1,\n          \"QueueTime\": \"2024-08-27T20:00:00\",\n          \"StartTime\": \"2024-08-27T20:01:00\",\n          \"EndTime\": \"2024-08-27T20:05:00\",\n          \"IsRunning\": false,\n          \"IsSuccess\": true,\n          \"RenderId\": 5,\n          \"MachineId\": 1\n        },\n        \"Render\": {\n          \"RenderId\": 5,\n          \"FileName\": \"scene.blend\",\n          \"FilePath\": \"\",\n          \"FileSize\": 12345678,\n          \"Arguments\": \"blender -b ...\",\n          \"EngineId\": 1\n        },\n        \"Engine\": {\n          \"EngineId\": 1,\n          \"Name\": \"blender\",\n          \"Extension\": \".blend\",\n          \"DownloadPath\": \"/srv/renderonline/downloads\",\n          \"RenderArgument\": \"blender -b ...\"\n        }\n      }\n    ]\n  }\n  ```\n\nOnly the last 15 tasks per user are returned, ordered by `task_id` descending.\n\n---\n\n#### POST `/renderapi/v1/enqueue`\n\nEnqueues a new render task.\n\n- Headers: `email`, `token`\n- Content type: `multipart/form-data`\n- Parts:\n  - **`request`** – JSON `ApiEnqueueRequest`:\n    ```json\n    {\n      \"EngineId\": \"1\",\n      \"Arguments\": [\n        { \"ArgTypeId\": \"start_frame\", \"Value\": \"1\" },\n        { \"ArgTypeId\": \"end_frame\", \"Value\": \"100\" },\n        { \"ArgTypeId\": \"output_format\", \"Value\": \".png\" }\n      ]\n    }\n    ```\n  - **File** – a single project file (e.g., `.blend`).\n\nValidation performed:\n\n- User’s `subscription.queue_limit` vs current queued tasks for that user.\n- Engine existence and `extension` matching the file extension.\n- Each argument’s `ArgTypeId` must exist in `argtypes`.\n- Value checked either with:\n  - Built‑in regex for `argtypes.type` (`file`, `path`, `extension`, `word`, `sentence`, `natural`, `integer`, `real`), **or**\n  - Custom `argtypes.regex` if provided.\n\nArgument expansion:\n\n- Starts from `engines.render_argument`.\n- Replaces `$RENDERONLINE:\u003cArgTypeId\u003e` with provided values.\n- Replaces `$RENDERONLINE:@uploaded_file` with the saved file path.\n\nPersistence:\n\n- Saves uploaded file under `engines.download_path/\u003cuser_id\u003e/\u003cqueue_time_ticks\u003e/`.\n- Inserts row in `renders`.\n- Inserts row in `tasks` with `queue_time`, `is_running = 0`, `is_success = 0`.\n- Inserts row in `queue` with `task_id`.\n\nResponse (`ApiEnqueueResponse`):\n\n```json\n{\n  \"IsAdded\": true,\n  \"ErrorMessage\": \"Task successfully enqueued.\"\n}\n```\n\nOn validation errors, returns appropriate HTTP 4xx and `IsAdded = false` with details.\n\n---\n\n#### POST `/renderapi/v1/dequeue`\n\nRemoves a queued task from the queue (and optionally stops it on the machine).\n\n- Headers: `email`, `token`\n- Content type: `application/json`\n- Body (`ApiDequeueRequest`):\n\n  ```json\n  {\n    \"TaskId\": 123\n  }\n  ```\n\nFlow:\n\n1. Validate task ownership (`tasks.user_id == current user`).\n2. Confirm the task is present in `queue`.\n3. Delete the row from `queue`.\n4. Load the full task (joins `tasks`, `renders`, `engines`).\n5. If `tasks.machine_id` is not null:\n   - Lookup machine IP and port in `machines`.\n   - Call `POST /hpc/stop` on that machine with matching `TaskId`.\n\nResponse (`ApiDequeueResponse`):\n\n```json\n{\n  \"IsRemoved\": true,\n  \"ErrorMessage\": \"Task successfully dequeued.\"\n}\n```\n\n---\n\n#### POST `/renderapi/v1/download`\n\nDownloads a ZIP archive of the render output directory.\n\n- Headers: `email`, `token`\n- Content type: `application/json`\n- Body (`ApiDownloadRequest`):\n\n  ```json\n  {\n    \"TaskId\": 123\n  }\n  ```\n\nFlow:\n\n1. Validate task ownership.\n2. Retrieve `renders.file_path` for that task.\n3. Compute parent directory of `file_path`.\n4. Create a temporary ZIP using `ZipFile.CreateFromDirectory`.\n5. Stream the ZIP with headers:\n   - `Content-Type: application/zip`\n   - `Content-Disposition: attachment; filename=\u003cguid\u003e.zip`\n6. Attempt to delete the temporary ZIP after sending.\n\nOn success, binary ZIP is returned. On failure, JSON `ApiDownloadResponse` is returned with `DownloadProvided = false`.\n\n---\n\n#### POST `/renderapi/v1/delete`\n\nFully deletes a task and its associated render.\n\n- Headers: `email`, `token`\n- Content type: `application/json`\n- Body (`ApiDeleteRequest`):\n\n  ```json\n  {\n    \"TaskId\": 123\n  }\n  ```\n\nFlow:\n\n1. Validate task belongs to current user.\n2. Resolve `render_id` and `file_path` via join on `tasks` and `renders`.\n3. Remove from `queue` (if present).\n4. Delete the directory that contains `file_path` (with retries).\n5. Delete the row from `tasks`.\n6. Delete the row from `renders`.\n\nResponse (`ApiDeleteResponse`):\n\n```json\n{\n  \"IsDeleted\": true,\n  \"ErrorMessage\": \"Task and associated render successfully deleted.\"\n}\n```\n\n---\n\n### Scheduler / Polling Loop\n\n`StartPollingService()` runs an infinite background loop:\n\n- Every 15 seconds:\n\n  1. Query all tasks that:\n     - Are in `queue` (via join).\n     - Have `is_success = 0`.\n  2. For each `ApiTaskInfo`:\n\n     - If `task.MachineId == null` and `task.IsRunning == false`:\n       - Call `AssignTaskToMachine(task)`:\n         - Enumerates machines from `machines`.\n         - For each, calls `GET http://\u003cip\u003e:\u003cport\u003e/hpc/status`.\n         - If machine idle (no running task), calls `POST /hpc/start` with:\n           - `EngineId` = `engine.Name` (matches HPCServer engine ID).\n           - `Arguments` = `render.Arguments`.\n         - On success, calls `UpdateTaskStartDetails(taskId, machineId)` (sets `start_time`, `is_running`, `machine_id`).\n     - Else:\n       - Call `CheckTaskStatusOnMachine(task.Task)`:\n         - Finds machine by `task.MachineId`.\n         - Calls `/hpc/status`.\n         - If `status.Task` present:\n           - If not running and success: `CompleteTask(taskId)`:\n             - Sets `end_time`, `is_running = 0`, `is_success = 1`, removes from `queue`.\n           - If not running and failure: `HandleTaskFailure(taskId, machineId)`:\n             - Sets `start_time/end_time` to now, `is_running = 0`, `is_success = 0`, removes from `queue`.\n\nThis design keeps HPCServer mostly stateless, with RenderAPI and the database being the source of truth.\n\n---\n\n## \u003cimg src=\"Readme/favicon_client.png\" width=\"32\" height=\"32\"\u003e RNOClient\n\n### Role\n\nRNOClient is a thin UI client for RenderAPI:\n\n- Shows authenticated user info and last tasks.\n- Visualizes states: queued, running, success, failure.\n- Provides an upload dialog for enqueueing tasks.\n- Wraps delete and download flows with confirmation and OS file pickers.\n\n### Key Components\n\n- `MainView.axaml.cs`\n  - Handles:\n    - Login (email/token headers).\n    - `GET /renderapi/v1/info`.\n    - Delete, download, and enqueue triggers.\n- `UploadView.axaml.cs`\n  - Provides file picker and argument fields (`start_frame`, `end_frame`, `output_format`).\n- `TaskView.axaml.cs`\n  - Visual representation of each `ApiTaskInfo` with icons and action buttons.\n- `ITaskListener` / `IUIInfluencer`\n  - Interfaces for wiring views to actions and navigation.\n\n### Typical Flow\n\n1. User enters email and token, presses **Validate**.\n2. `RenderAPIInfoRequest` loads tasks and shows them in `TasksPanel`.\n3. Clicking **Upload** shows `UploadView`:\n   - `Browse` selects project file.\n   - User sets frame range and format.\n   - Enqueue sends `ApiEnqueueRequest` + file via multipart/form‑data.\n4. After enqueue or delete, `RenderAPIInfoRequest` refreshes the task list.\n5. Download uses `SaveFileUsingStorageProvider` to store ZIP from `RenderAPI`.\n\n---\n\n## Database\n\n\u003cimg src=\"Readme/Database.png\" width=\"900\"\u003e\n\nThe database scripts in `Database/` (`renderonline_*.sql`) create the following schema:\n\n- **`users`**\n  - `user_id`, `first_name`, `last_name`, `email`\n  - `subscription_id` (FK conceptually to `subscriptions`)\n  - `is_active`\n  - `token` (used verbatim as API token)\n- **`subscriptions`**\n  - `subscription_id`, `name`, `queue_limit`\n  - Controls maximum number of queued tasks per user.\n- **`engines`**\n  - `engine_id`, `name`, `extension`, `download_path`, `render_argument`\n  - `name` is referenced by HPCServer (`EngineId`).\n  - `extension` is used to validate upload file type.\n  - `download_path` is the root directory for per‑task folders.\n  - `render_argument` is a template string with `$RENDERONLINE:...` placeholders.\n- **`argtypes`**\n  - `argtype_id`, `type`, `regex`\n  - Defines allowed argument types for templating:\n    - Supported `type` values: `file`, `path`, `extension`, `word`, `sentence`, `natural`, `integer`, `real`.\n    - If `regex` is null, RenderAPI uses built‑in regex for the given `type`.\n- **`machines`**\n  - `machine_id`, `ip_address`, `port`\n  - Describes available HPCServer nodes; `ip_address` and `port` must match node configuration.\n- **`renders`**\n  - `render_id`, `file_name`, `file_path`, `file_size`, `arguments`, `engine_id`\n  - Stores uploaded file metadata and fully expanded render arguments.\n- **`tasks`**\n  - `task_id`, `user_id`, `queue_time`, `start_time`, `end_time`\n  - `is_running`, `is_success`\n  - `render_id`, `machine_id`\n  - Represents individual render jobs.\n- **`queue`**\n  - `queue_id`, `task_id`\n  - Presence in this table means the task is queued; scheduler logic removes entries on completion, failure, or dequeue.\n\nThe SQL scripts do not declare foreign keys but the logical relationships are as described above.\n\n---\n\n## Development Notes\n\n- Projects are plain .NET applications:\n  - HPCServer and RenderAPI use ASP.NET Core minimal hosting with manual route mapping (`MapGet`, `MapPost`).\n  - RNOClient uses Avalonia for the cross‑platform UI.\n- Logging is currently console‑based.\n- JSON serialization uses Newtonsoft.Json (`JsonConvert`).\n- Render execution is delegated to external processes via `System.Diagnostics.Process`.\n\nTo build all components:\n\n```bash\ndotnet build HPCServer\ndotnet build RenderAPI\ndotnet build RNOClient.Desktop\ndotnet build RNOClient\n```\n\n---\n\n## Roadmap (Ideas)\n\n- More advanced scheduling:\n  - Priorities, retries, backoff, and machine load awareness.\n- Multi‑engine and multi‑output support per task.\n- Per‑task logs and stdout/stderr streaming.\n- Web (HTML) client alternative to the Avalonia application.\n- Stronger authentication and user/role management APIs.\n- Optional metrics and monitoring endpoints.\n\n---\n\n## Contributing\n\nContributions are welcome.\n\n- Open issues for bugs or feature requests.\n- Submit PRs focused on a single area (HPCServer, RenderAPI, RNOClient, or Database).\n- Please keep code style consistent with the existing C#.\n\n---\n\n## License\n\nSee `LICENSE`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetspiking%2Frenderonline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjetspiking%2Frenderonline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjetspiking%2Frenderonline/lists"}