chore: initial commit of foundryvtt-admin
Spun out of the hbm-books working folder into its own repo. A small backend+frontend+COBOL admin tool for managing Foundry VTT worlds (socket inspection, join/shutdown debugging).
This commit is contained in:
+190
@@ -0,0 +1,190 @@
|
||||
# COBOL Admin Panel Bridge Integration
|
||||
|
||||
Welcome to your COBOL learning project! This container is equipped with **GnuCOBOL** (cobc) and mounts the shared folder at /app/shared.
|
||||
|
||||
## How the Sync Interface Works
|
||||
The Node.js proxy server generates /app/shared/ACTORS.DAT containing actor records.
|
||||
Each record is exactly **80 bytes** (including a trailing newline \n), with the following fixed-width layout:
|
||||
|
||||
| Field | Size (PIC) | Type | Offset | Description |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **ID** | PIC X(a6) | Alphanumeric | 0 - 15 | Foundry Actor Unique ID |
|
||||
| **NAME** | PIC X(20) | Alphanumeric | 16 - 35 | Character Name |
|
||||
| **TYPE** | PIC X(10) | Alphanumeric | 36 - 45 | "character" or "npc" |
|
||||
| **HP-CUR** | PIC 9(3) | Numeric | 46 - 48 | Current HP (zero-padded, e.g. 045) |
|
||||
| **HP-MAX** | PIC 9(3) | Numeric | 49 - 51 | Max HP (zero-padded, e.g. 100) |
|
||||
| **LEVEL** | PIC 9(2) | Numeric | 52 - 53 | Character Level (zero-padded, e.g. 05) |
|
||||
| **PADDING** | PIC X(25) | Alphanumeric | 54 - 78 | Empty padding spaces |
|
||||
| **NEWLINK** | PIC X | Alphanumeric | 79 | Carriage return / line feed \n
|
||||
|
||||
### To Submit Updates
|
||||
When your COBOL program wants to edit a sheet, it writes the updated 80-byte record into /app/shared/UPDATES.DAT.
|
||||
The Node.js/Bun proxy detects writes to this file, parses the record, pushes the edit to Foundry VTT via WebSocket, and then clears UPDATES.DAT.
|
||||
|
||||
---
|
||||
|
||||
## COBOL Snippets for your Project
|
||||
|
||||
### 1. Declaring the Files in your Program
|
||||
````cobol
|
||||
ENVIRONMENT DIVISION.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
* The source database generated by Node.js
|
||||
SELECT ACTORS-FILE ASSIGN TO "/app/shared/ACTORS.DAT"
|
||||
ORGANIZATION IS LINE SEQUENTIAL.
|
||||
|
||||
* The transaction file you write to send updates to Foundry
|
||||
SELECT UPDATES-FILE ASSIGN TO "/app/shared/UPDATES.DAT"
|
||||
ORGANIZATION IS LINE SEQUENTIAL.
|
||||
```
|
||||
|
||||
### 2. Declaring the Data Record Structure
|
||||
````cobol
|
||||
DATA DIVISION.
|
||||
FILE SECTION.
|
||||
FD ACTORS-FILE.
|
||||
01 ACTOR-RECORD.
|
||||
05 ACTOR-ID PIC X(16).
|
||||
05 ACTOR-NAME PIC X(20).
|
||||
05 ACTOR-TYPE PIC X(10).
|
||||
05 ACTOR-HP-CUR PIC 9(3).
|
||||
05 ACTOR-HP-MAX PIC 9(3).
|
||||
05 ACTOR-LEVEL PIC 9(2).
|
||||
05 FILLER PIC X(25). *> Filler for padding
|
||||
```
|
||||
|
||||
### 3. Reading the File Loop
|
||||
````cobol
|
||||
WORKING-STORAGE SECTION.
|
||||
01 WS-EOF-FLAG PIC X VALUE 'N'.
|
||||
88 EOF-REACHED VALUE 'Y'.
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
READ-DATABASE.
|
||||
OPEN INPUT ACTORS-FILE.
|
||||
PERFORM UNTIL EOF-REACHED
|
||||
READ ACTORS-FILE
|
||||
AT END
|
||||
SET EOF-REACHED TO TRUE
|
||||
NOT AT END
|
||||
DISPLAY "Found: " ACTOR-NAME " (HP: " ACTOR-HP-CUR ")"
|
||||
END-READ
|
||||
END-PERFORM.
|
||||
CLOSE ACTORS-FILE.
|
||||
```
|
||||
|
||||
### 4. Writing an Update (Transaction)
|
||||
````cobol
|
||||
PROCEDURE DIVISION.
|
||||
SEND-UPDATE.
|
||||
OPEN OUTPUT UPDATES-FILE.
|
||||
* Fill the record fields (ensure numeric values are zero-padded)
|
||||
MOVE "abc123xyz789" TO ACTOR-ID.
|
||||
MOVE "Gimli" TO ACTOR-NAME.
|
||||
MOVE "character" TO ACTOR-TYPE.
|
||||
MOVE 45 TO ACTOR-HP-CUR.
|
||||
MOVE 100 TO ACTOR-HP-MAX.
|
||||
MOVE 5 TO ACTOR-LEVEL.
|
||||
|
||||
WRITE ACTOR-RECORD.
|
||||
CLOSE UPDATES-FILE.
|
||||
```
|
||||
|
||||
### 5. Alternative: Calling curl Directly from COBOL (REST API Access)
|
||||
If your want to bypass files and hit the Node.js REST API directly from your COBOL program, GnuCOBOL provides the SYSTEM command:
|
||||
```cobol
|
||||
WORKING-STORAGE SECTION.
|
||||
01 API-COMMAND PIC X(200).
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
TRIGGER-API.
|
||||
* Using curl inside the Docker network to fetch the JSON list
|
||||
STRING "curl -s http://backend:3000/api/actors > /app/shared/actors.json"
|
||||
DELIMITED BY SIZE INTO API-COMMAND.
|
||||
|
||||
CALL "SYSTEM" USING API-COMMAND.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Compiling & Running Inside Docker
|
||||
Attach to the running COBOL container shell:
|
||||
```bash
|
||||
docker compose exec -it cobol sh
|
||||
```
|
||||
|
||||
Create your file hbm-admin.cob, then compile it:
|
||||
```bash
|
||||
cobc -x -o hbm-admin hbm-admin.cob
|
||||
```
|
||||
Run the compiled executable:
|
||||
```bash
|
||||
./hbm-admin
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. Native C Bindings (Interfacing with libcurl)
|
||||
Since GnuCOBOL translates COBOL code to C, you can interface with C libraries directly using the `CALL` statement. This allows you to perform real HTTP requests natively without spawning an external shell process.
|
||||
|
||||
1. **Write a C Helper (`http_client.c`)**:
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
int send_actor_update(const char* url, const char* json_data) {
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
int success = 1;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
struct curl_slist *headers = NULL;
|
||||
headers = curl_slist_append(headers, "Content-Type: application/json");
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if(res != CURLE_OK) {
|
||||
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
|
||||
success = 0;
|
||||
}
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
```
|
||||
|
||||
2. **Call it from COBOL (`hbm-admin.cob`)**:
|
||||
```cobol
|
||||
WORKING-STORAGE SECTION.
|
||||
01 URL-STRING PIC X(100) VALUE "http://backend:3000/api/actors/update".
|
||||
01 JSON-PAYLOAD PIC X(500).
|
||||
01 RESULT-CODE PIC S9(9) BINARY.
|
||||
|
||||
PROCEDURE DIVISION.
|
||||
MOVE "{\"id\":\"abc\",\"updates\":{\"system\":{\"attributes\":{\"hp\":{\"value\":45}}}}}"
|
||||
TO JSON-PAYLOAD.
|
||||
|
||||
CALL "send_actor_update" USING BY REFERENCE URL-STRING
|
||||
BY REFERENCE JSON-PAYLOAD
|
||||
RETURNING RESULT-CODE.
|
||||
|
||||
IF RESULT-CODE = 1
|
||||
DISPLAY "Update successful!"
|
||||
ELSE
|
||||
DISPLAY "Update failed."
|
||||
END-IF.
|
||||
```
|
||||
|
||||
3. **Compile and link together**:
|
||||
```bash
|
||||
gcc -c http_client.c -o http_client.o
|
||||
cobc -x -o hbm-admin hbm-admin.cob http_client.o -lcurl
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user