# 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 #include 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 ```