feat(napi P1): Go-implemented libfivenode (c-shared) for the N-API bridge

Faithful port of the C++ fivenode topology — node hosts the existing N-API
addon, which now links a libfivenode implemented in Go (CGO c-shared)
instead of the Harbour-C core. cmd/libfivenode exports the C ABI the addon
expects (hb_bridge_init/shutdown/handle_request/last_error/set_auth/
clear_auth/free, tfn_register_callbacks). Build:
  go build -buildmode=c-shared \
    -ldflags="-extldflags=-Wl,-install_name,@rpath/libfivenode.dylib" \
    -o native/output/darwin/libfivenode.dylib ./cmd/libfivenode

P1 proven: node → addon → Go hb_bridge_handle_request round-trips a
response in-process (no Harbour-C, no subprocess). P2 wires the real PRG
dispatcher; P3 the npm callbacks (tfn_register_callbacks → Require); P4
the node main-thread marshaling. (goja probe removed — pure-JS only,
insufficient for full npm.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
CharlesKWON
2026-06-15 22:25:46 +09:00
parent 76853d4beb
commit f2eada1a33
4 changed files with 74 additions and 2 deletions

1
.gitignore vendored
View File

@@ -10,3 +10,4 @@
*.frb
*.pgo
*.log
/native/output/

62
cmd/libfivenode/main.go Normal file
View File

@@ -0,0 +1,62 @@
// cmd/libfivenode — Go c-shared 구현의 libfivenode (P1 스켈레톤).
//
// 기존 C++ fivenode N-API 애드온(fivenode.node)이 기대하는 C ABI 를 Go 가
// CGO //export 로 제공한다. Harbour-C 코어를 Go 런타임으로 교체하는 첫 단계.
//
// go build -buildmode=c-shared -o ../../native/output/darwin/libfivenode.dylib ./cmd/libfivenode
//
// P1 목표: 심볼 export + 애드온 로드·왕복(canned 응답). 실제 PRG 디스패치/
// npm 콜백은 P2~P4 에서.
package main
/*
#include <stdlib.h>
*/
import "C"
import "unsafe"
//export hb_bridge_init
func hb_bridge_init() C.int {
return 1
}
//export hb_bridge_shutdown
func hb_bridge_shutdown() {}
//export hb_bridge_handle_request
func hb_bridge_handle_request(reqJSON *C.char) *C.char {
// P1: 고정 응답으로 node↔Go 왕복만 증명.
_ = C.GoString(reqJSON)
resp := `{"status":200,"headers":{"Content-Type":"text/plain; charset=utf-8"},"body":"hello from Go-implemented libfivenode (N-API P1)"}`
return C.CString(resp)
}
//export hb_bridge_last_error
func hb_bridge_last_error() *C.char {
return C.CString("")
}
//export hb_bridge_set_auth
func hb_bridge_set_auth(authJSON *C.char) {}
//export hb_bridge_clear_auth
func hb_bridge_clear_auth() {}
//export hb_bridge_free
func hb_bridge_free(ptr *C.char) {
if ptr != nil {
C.free(unsafe.Pointer(ptr))
}
}
// tfn_register_callbacks — 애드온이 npm 콜백 묶음을 등록(P3 에서 저장·사용).
// P1 에선 void* 로 받아 보관만(구조체 레이아웃은 P3 에서 정의).
//
//export tfn_register_callbacks
func tfn_register_callbacks(cb unsafe.Pointer) {
npmCallbacks = cb
}
var npmCallbacks unsafe.Pointer
func main() {}

6
go.mod
View File

@@ -2,12 +2,14 @@ module fivenode_go
go 1.25.0
require five v0.0.0
require (
five v0.0.0
github.com/jackc/pgx/v5 v5.9.2
)
require (
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.9.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/text v0.29.0 // indirect

7
go.sum
View File

@@ -1,4 +1,6 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
@@ -7,13 +9,18 @@ github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=