基于ebitengine/purego的easytier-ffi golang 包

以前简单基于cgo 处理过easytier-ffi 的集成,以下是通过ebitengine/purego 实现一个基于purego 的集成

方法定义

实际核心是通过ebitengine/purego 进行方法注册,代码上就是标准的purego玩法

package easytier

import (
	"os"
	"os/exec"

	"github.com/ebitengine/purego"
)

type KeyValuePair struct {
	Key   *byte
	Value *byte
}

var (
	GetErrorMsg           func(*byte)
	FreeString            func(*byte)
	ParseConfig           func(*byte) int32
	RunNetworkInstance    func(*byte) int32
	RetainNetworkInstance func(*byte, uintptr) int32
	CollectNetworkInfos   func(*KeyValuePair, uintptr) int32
)

func findLibrary() string {
	// Env var
	if envPath := os.Getenv("EASYTIER_FFI_LIB_PATH"); envPath != "" {
		return envPath
	}

	// ldconfig with Linux
	if path, err := exec.LookPath("libeasytier_ffi.so"); err == nil {
		return path
	}

	// default path
	commonPaths := []string{
		"/usr/local/lib/libeasytier_ffi.so",
		"./lib/libeasytier_ffi.dylib",
		"./lib/libeasytier_ffi.so",
		"./lib/libeasytier_ffi.dll",
		"/usr/lib/libeasytier_ffi.so",
		"/opt/homebrew/lib/libeasytier_ffi.dylib",
	}

	for _, p := range commonPaths {
		if _, err := os.Stat(p); err == nil {
			return p
		}
	}

	return "libeasytier_ffi.so"
}
func init() {
	path := findLibrary()
	libeasytier, err := purego.Dlopen(path, purego.RTLD_NOW|purego.RTLD_GLOBAL)
	if err != nil {
		panic(err)
	}
	purego.RegisterLibFunc(&GetErrorMsg, libeasytier, "get_error_msg")
	purego.RegisterLibFunc(&FreeString, libeasytier, "free_string")
	purego.RegisterLibFunc(&ParseConfig, libeasytier, "parse_config")
	purego.RegisterLibFunc(&RunNetworkInstance, libeasytier, "run_network_instance")
	purego.RegisterLibFunc(&RetainNetworkInstance, libeasytier, "retain_network_instance")
	purego.RegisterLibFunc(&CollectNetworkInfos, libeasytier, "collect_network_infos")
}

应用使用

为了方便基于配置,然后调用ffi 的方法

  • main.go
package main

import (
	"fmt"
	"os"
	"time"

	easytierffigo "github.com/rongfengliang/easytier-ffi-go/easytier"
)

func main() {
	data, err := os.ReadFile("app.yaml")
	if err != nil {
		panic(err)
	}
	content := string(data)
        // 使用工具类,讲string 转为*byte
	_, cstr := easytierffigo.CString(content)
	result := easytierffigo.ParseConfig(cstr)
	fmt.Println("ParseConfig result", result)
	if result != 0 {
		fmt.Println("Error parsing config:")
	}
	result = easytierffigo.RunNetworkInstance(cstr)
	if result != 0 {
		fmt.Println("Error running network instance")
	} else {
		fmt.Println("Network instance started successfully")
	}
	for {
		fmt.Println("looping...")
		time.Sleep(1 * time.Second)
	}
}

说明

基于ebitengine/purego的好处是我们的代码是纯go的,跨平台会好一些,但是实际问题也是有的,比如性能可能不如cgo 好,但是对于easytier 来时没啥影响,相关代码我已经push github 了,可以直接使用

参考资料

https://github.com/rongfengliang/easytier-ffi-go

https://github.com/chdb-io/chdb-go

https://github.com/ebitengine/purego

https://github.com/rongfengliang/easytier-ffi-cgo

https://pkg.go.dev/cmd/cgo

https://go.dev/blog/cgo

https://github.com/ebitengine/purego

https://easytier.cn/web/index.html#/config_generator

https://github.com/EasyTier/EasyTier/tree/main/easytier-contrib/easytier-ffi

posted on 2025-08-12 08:34  荣锋亮  阅读(28)  评论(0)    收藏  举报

导航