From c8841833fad2510400400fe030a2c95d6dc220ab Mon Sep 17 00:00:00 2001 From: Heron Date: Mon, 18 Nov 2024 16:13:48 +0800 Subject: [PATCH] Add CGO MakeFile --- .gitignore | 1 + Makefile | 41 +++++++++ lib/libnkntunnel.go | 196 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 lib/libnkntunnel.go diff --git a/.gitignore b/.gitignore index ee900e7..6762c69 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ main Tunnel.framework tunnel.aar tunnel-sources.jar +*.tar.gz \ No newline at end of file diff --git a/Makefile b/Makefile index 9d8a23f..b65d811 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,10 @@ BUILD=go build -ldflags "-s -w -X main.Version=$(VERSION)" BUILD_DIR=build BIN_NAME=nkn-tunnel MAIN=bin/main.go +LIB_NAME:=libnkntunnel +LIB_SRC_FILE:=lib/libnkntunnel.go +LIB_BUILD_DIR:=$(BUILD_DIR)/lib + ifdef GOARM BIN_DIR=$(GOOS)-$(GOARCH)v$(GOARM) else @@ -65,3 +69,40 @@ android: gomobile bind -target=android -ldflags "-s -w" github.com/nknorg/nkn-tunnel github.com/nknorg/nkn-tuna-session github.com/nknorg/ncp-go github.com/nknorg/tuna github.com/nknorg/nkn-sdk-go github.com/nknorg/nkngomobile mv tunnel.aar tunnel-sources.jar $(BUILD_DIR)/android/ ${MAKE} zip BIN_DIR=android + +.PHONY: lib +lib: + rm -rf $(BUILD_DIR)/lib + mkdir -p $(BUILD_DIR)/lib + + for target in \ + "darwin arm64 darwin-arm64 .dylib clang" \ + "windows amd64 win-amd64 .dll x86_64-w64-mingw32-gcc " \ + "linux amd64 linux-amd64 .so x86_64-linux-musl-gcc"; \ + do \ + set -- $$target; \ + GOOS=$$1 GOARCH=$$2 PLATFORM=$$3 EXT=$$4 CC=$$5; \ + echo "Building for $$GOOS/$$GOARCH..."; \ + BUILD_OUTPUT=$(LIB_BUILD_DIR)/$$GOOS_$$PLATFORM/$(LIB_NAME)$$EXT; \ + mkdir -p $(dir $$BUILD_OUTPUT); \ + CGO_ENABLED=1 GOOS=$$GOOS GOARCH=$$GOARCH CC=$$CC go build -buildmode=c-shared \ + -ldflags "-s -w -X main.Version=$(VERSION)" \ + -o $$BUILD_OUTPUT $(LIB_SRC_FILE); \ + if [ $$? -ne 0 ]; then \ + echo "Failed to build $$GOOS/$$GOARCH"; \ + exit 1; \ + fi; \ + echo "Successfully built $$GOOS/$$GOARCH"; \ + done + + CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 CC=clang go build -buildmode=c-archive -ldflags "-s -w -X main.Version=$(VERSION)" -o $(LIB_BUILD_DIR)/ios-arm64/$(LIB_NAME).a $(LIB_SRC_FILE) + CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 CC=clang go build -buildmode=c-archive -ldflags "-s -w -X main.Version=$(VERSION)" -o $(LIB_BUILD_DIR)/ios-amd64/$(LIB_NAME).a $(LIB_SRC_FILE) + mkdir -p $(LIB_BUILD_DIR)/ios + lipo -create -output $(LIB_BUILD_DIR)/ios/libnkntunnel.a $(LIB_BUILD_DIR)/ios-amd64/libnkntunnel.a $(LIB_BUILD_DIR)/ios-arm64/libnkntunnel.a + cp $(LIB_BUILD_DIR)/ios-arm64/$(LIB_NAME).h $(LIB_BUILD_DIR)/ios/$(LIB_NAME).h + @echo "All platforms built successfully. Output in $(LIB_BUILD_DIR)/" + +.PHONY: package_lib +package_lib: lib + cd $(BUILD_DIR) && rm -f lib.tar.gz && tar -czf lib.tar.gz lib + @echo "Library package created: $(BUILD_DIR)/lib.tar.gz" diff --git a/lib/libnkntunnel.go b/lib/libnkntunnel.go new file mode 100644 index 0000000..c3596ea --- /dev/null +++ b/lib/libnkntunnel.go @@ -0,0 +1,196 @@ +package main + +/* +#include +*/ +import "C" +import ( + "encoding/hex" + "github.com/nknorg/ncp-go" + "github.com/nknorg/nkn-sdk-go" + ts "github.com/nknorg/nkn-tuna-session" + tunnel "github.com/nknorg/nkn-tunnel" + "github.com/nknorg/nkngomobile" + "log" + "os" + "strings" + "sync" +) + +var ( + instanceTunnel *tunnel.Tunnel + tunnelMutex sync.Mutex + logMutex sync.Mutex + + logFilePath string + logFile *os.File + logToFile bool + + DefaultTunaMaxPrice = "0.01" + DefaultTunaMinFee = "0.00001" + DefaultTunaFeeRatio = 0.1 +) + +func initLogger() error { + if logFilePath == "" { + logToFile = false + log.SetOutput(os.Stdout) + return nil + } + + var err error + logFile, err = os.OpenFile(logFilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + logToFile = false + log.SetOutput(os.Stdout) + log.Println("Failed to open log file, defaulting to stdout:", err) + return err + } + + log.SetOutput(logFile) + logToFile = true + log.Println("Log initialized, writing to file:", logFilePath) + return nil +} + +func closeLogger() { + logMutex.Lock() + defer logMutex.Unlock() + + if logFile != nil { + log.Println("Closing log file") + logFile.Close() + logFile = nil + logToFile = false + } +} + +//export SetLogFilePath +func SetLogFilePath(path *C.char) { + logMutex.Lock() + defer logMutex.Unlock() + + logFilePath = C.GoString(path) + initLogger() +} + +//export StartNknTunnel +func StartNknTunnel(numClients C.int, seedRpcServers *C.char, seedHex *C.char, identifier *C.char, from *C.char, to *C.char, udp C.int, useTuna C.int, tunaMaxPrice *C.char, tunaMinFee *C.char, tunaFeeRatio C.float, verbose C.int) C.int { + tunnelMutex.Lock() + defer tunnelMutex.Unlock() + + if instanceTunnel != nil { + log.Println("Closing existing tunnel before starting a new one...") + instanceTunnel.Close() + instanceTunnel = nil + } + + numClientsGo := int(numClients) + seedRpcServersGo := C.GoString(seedRpcServers) + seedHexGo := C.GoString(seedHex) + identifierGo := C.GoString(identifier) + fromGo := C.GoString(from) + toGo := C.GoString(to) + udpGo := udp != 0 + useTunaGo := useTuna != 0 + tunaMaxPriceGo := C.GoString(tunaMaxPrice) + tunaMinFeeGo := C.GoString(tunaMinFee) + tunaFeeRatioGo := float64(tunaFeeRatio) + verboseGo := verbose != 0 + + if seedHexGo == "" { + log.Println("Seed hex cannot be empty") + return 1 + } + + if tunaMaxPriceGo == "" { + tunaMaxPriceGo = DefaultTunaMaxPrice + } + if tunaMinFeeGo == "" { + tunaMinFeeGo = DefaultTunaMinFee + } + if tunaFeeRatioGo == 0 { + tunaFeeRatioGo = DefaultTunaFeeRatio + } + + seedRpcServerList := strings.Split(seedRpcServersGo, ",") + seedRpcServerAddr := nkngomobile.NewStringArray(seedRpcServerList...) + + var seed []byte + var err error + + seed, err = hex.DecodeString(seedHexGo) + if err != nil { + log.Println("Invalid seed hex: ", err) + return 2 + } + account, err := nkn.NewAccount(seed) + if err != nil { + log.Println("Failed to create account:", err) + return 3 + } + clientConfig := &nkn.ClientConfig{ + SeedRPCServerAddr: seedRpcServerAddr, + } + walletConfig := &nkn.WalletConfig{ + SeedRPCServerAddr: seedRpcServerAddr, + } + sessionConfig := &ncp.Config{ + MTU: int32(0), + } + + var tsConfig *ts.Config + if useTunaGo { + tsConfig = &ts.Config{ + NumTunaListeners: numClientsGo, + SessionConfig: sessionConfig, + TunaMaxPrice: tunaMaxPriceGo, + TunaMinNanoPayFee: tunaMinFeeGo, + TunaNanoPayFeeRatio: tunaFeeRatioGo, + } + } + + config := &tunnel.Config{ + NumSubClients: numClientsGo, + ClientConfig: clientConfig, + WalletConfig: walletConfig, + TunaSessionConfig: tsConfig, + UDP: udpGo, + Verbose: verboseGo, + } + t, err := tunnel.NewTunnel(account, identifierGo, fromGo, toGo, useTunaGo, config, nil) + if err != nil { + log.Println("Failed to create tunnel:", err) + return 4 + } + + instanceTunnel = t + + go func() { + if err := t.Start(); err != nil { + log.Println("Tunnel failed to start:", err) + } + }() + log.Println("Tunnel started successfully") + return 0 +} + +//export CloseNknTunnel +func CloseNknTunnel() C.int { + tunnelMutex.Lock() + defer tunnelMutex.Unlock() + + if instanceTunnel == nil { + log.Println("No tunnel to close") + return -1 + } + + instanceTunnel.Close() + instanceTunnel = nil + log.Println("Tunnel closed successfully") + return 0 +} + +func main() { + defer closeLogger() +}