Pulls bridge_context.prg, bridge_request.prg, bridge_session.prg, and
bridge_cookie.prg from upstream fivenode into app/bridge/ so the
mod_harbour AP_* surface (AP_METHOD, AP_BODY, AP_ARGS, AP_USERIP,
AP_RPUTS, AP_JSONRESPONSE, AP_SETCONTENTTYPE, ctx_get, ctx_set, ...)
runs unchanged on top of fivenode_go's Go RTL.
bridge_main.prg deliberately omitted — its REQUEST sweep pulls in
TDrMySQL / hbct / hbcurl symbols fivenode_go neither has nor needs.
fivenode_go runs ahead-of-time with the Five compiler, so the
REQUEST trick that keeps fnb-runtime symbols alive isn't required.
One upstream patch was unavoidable: AP_RPUTS / AP_ECHO were variadic
(`( ... )`) and used PValue() to walk caller args. Five's PValue
returns the caller's LOCAL slot (not the actual variadic args, which
aren't copied into locals when declared params is 0), so the body
came back as "1" instead of the JSON payload. Collapsed both to a
single-argument form; every call site in fivenode_go already passes
exactly one value. Patched-out spots are marked with a TODO so we
can revert once Five gains real variadic PValue support.
app/bridge_server.prg ties it all together: starts httpserver on
:8090 with BRIDGEDISPATCH as the handler, hand-translates the Go
request hash into the ctx fields the AP_* layer reads, dispatches by
URL path (hard-coded /api/hello and /api/echo for now — file-name
dispatch lands in 1a.4), and assembles the response from the buffered
AP_* output + ctx_get("status") + ctx_get("headers_out").
Verified end-to-end:
GET /api/hello -> 200 JSON, method/ip echoed
POST /api/echo?lang=ko (16-byte body) -> 200 JSON, body_parsed,
query, user-agent
GET /api/nope -> 404 JSON
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
79 lines
1.4 KiB
Plaintext
79 lines
1.4 KiB
Plaintext
/*
|
|
* bridge_context.prg - FiveNode Request Context (Harbour side)
|
|
* JSON-based context access, output buffer wrappers
|
|
*
|
|
* Copyright (c) 2026 Charles KWON ( Charles KWON Ohjun, charleskwonohjun@gmail.com )
|
|
* All rights reserved.
|
|
*/
|
|
|
|
FUNCTION BRIDGE_SETUP_ERRORBLOCK()
|
|
|
|
LOCAL nH := FCreate( hb_DirTemp() + "errblock_proof.txt" )
|
|
|
|
FWrite( nH, "ErrorBlock SET at " + Time() )
|
|
FClose( nH )
|
|
|
|
ErrorBlock( {| e | Break( e ) } )
|
|
|
|
RETURN NIL
|
|
|
|
FUNCTION BRIDGE_PING()
|
|
|
|
hb_MemoWrit( hb_DirTemp() + "ping_proof.txt", "PING_EXECUTED" )
|
|
_BRIDGE_SET_RESULT( "PONG" )
|
|
|
|
RETURN NIL
|
|
|
|
FUNCTION hb_bridge_get_output()
|
|
RETURN _OUT_GET()
|
|
|
|
FUNCTION hb_bridge_clear_output()
|
|
|
|
_OUT_CLEAR()
|
|
|
|
RETURN NIL
|
|
|
|
FUNCTION bridge_output_append( cText )
|
|
|
|
_OUT_APPEND( cText )
|
|
|
|
RETURN NIL
|
|
|
|
// ── Context value accessor (extract from JSON via hb_jsonDecode) ──
|
|
|
|
FUNCTION ctx_get( cKey, xDefault )
|
|
|
|
LOCAL cJson := _CTX_GET_JSON()
|
|
LOCAL hCtx
|
|
|
|
IF Empty( cJson )
|
|
RETURN xDefault
|
|
ENDIF
|
|
|
|
hb_jsonDecode( cJson, @hCtx )
|
|
|
|
IF ValType( hCtx ) == "H" .AND. hb_HHasKey( hCtx, cKey )
|
|
RETURN hCtx[ cKey ]
|
|
ENDIF
|
|
|
|
RETURN xDefault
|
|
|
|
FUNCTION ctx_set( cKey, xValue )
|
|
|
|
LOCAL cJson := _CTX_GET_JSON()
|
|
LOCAL hCtx
|
|
|
|
IF Empty( cJson )
|
|
hCtx := { => }
|
|
ELSE
|
|
hb_jsonDecode( cJson, @hCtx )
|
|
IF ValType( hCtx ) != "H"
|
|
hCtx := { => }
|
|
ENDIF
|
|
ENDIF
|
|
|
|
hCtx[ cKey ] := xValue
|
|
_CTX_SET_JSON( hb_jsonEncode( hCtx ) )
|
|
|
|
RETURN xValue
|