libeasytier-ffi ctypes 集成
主要是为了方便python 使用,基于ctypes包装一个,相比基于cffi 的安装比较方便,以下是简单说明
代码结构
代码基于flit 进行包管理
- 结构
├── app.py
├── app.yaml
├── ctypes_easytier_ffi
│ ├── __init__.py
│ └── lib
│ ├── libeasytier_ffi.dylib
│ └── libeasytier_ffi.so
├── LICENSE
├── pyproject.toml
└── README.md
- ctypes_easytier_ffi 代码
比较简单,就是类型以及方法定义,同时为了方便直接讲库放到包中了
import ctypes
from ctypes import c_char_p, c_int32, POINTER, Structure, c_size_t
# 定义结构体 KeyValuePair
class KeyValuePair(Structure):
_fields_ = [
('key', c_char_p),
('value', c_char_p),
]
def find_library():
import os
import sys
lib_dir = os.path.join(os.path.dirname(__file__), 'lib')
if sys.platform == 'win32':
lib_path = os.path.join(lib_dir, 'easytier_ffi.dll')
elif sys.platform == 'darwin':
lib_path = os.path.join(lib_dir, 'libeasytier_ffi.dylib')
else:
lib_path = os.path.join(lib_dir, 'libeasytier_ffi.so')
if not os.path.exists(lib_path):
raise FileNotFoundError(f"Library not found.")
return lib_path
lib = ctypes.CDLL(find_library())
# void get_error_msg(const char **out);
lib.get_error_msg.argtypes = [POINTER(c_char_p)]
lib.get_error_msg.restype = None
# void free_string(char* s);
lib.free_string.argtypes = [c_char_p]
lib.free_string.restype = None
# int32_t parse_config(const char* cfg_str);
lib.parse_config.argtypes = [c_char_p]
lib.parse_config.restype = c_int32
# int32_t run_network_instance(const char* cfg_str);
lib.run_network_instance.argtypes = [c_char_p]
lib.run_network_instance.restype = c_int32
# int32_t retain_network_instance(const char** inst_names, uintptr_t length);
lib.retain_network_instance.argtypes = [POINTER(c_char_p), c_size_t]
lib.retain_network_instance.restype = c_int32
# int32_t collect_network_infos(KeyValuePair* infos, uintptr_t max_length);
lib.collect_network_infos.argtypes = [POINTER(KeyValuePair), c_size_t]
lib.collect_network_infos.restype = c_int32
__version__ = "0.1.0"
__doc__ = """
ctypes_easytier_ffi - A Python FFI for EasyTier
"""
使用
基于配置方便测试
- 测试代码
app.yaml 方便测试配置
instance_name = "xxxx"
instance_id = "xxxxxx"
dhcp = true
listeners = [
"tcp://0.0.0.0:11010",
"udp://0.0.0.0:11010",
"wg://0.0.0.0:11011",
]
rpc_portal = "0.0.0.0:0"
[network_identity]
network_name = "xxxxx"
network_secret = "xxxxx"
[[peer]]
uri = "tcp://xxxxx:11010"
[flags]
app.py
import time
from ctypes_easytier_ffi import lib, KeyValuePair
config = ""
with open("app.yaml","r") as f:
config = f.read()
result = lib.run_network_instance(config.encode())
if result == 0:
print("Network instance started successfully.")
while True:
try:
print("Collecting network infos...")
time.sleep(3)
MAX_LEN = 10
infos = (KeyValuePair * MAX_LEN)()
result = lib.collect_network_infos(infos, MAX_LEN)
for i in range(result):
print(f"{infos[i].key.decode()} => {infos[i].value.decode()}")
except Exception as e:
print(f"An error occurred: {e}")
break
说明
基于ctypes 的特定就是比较方便,没有cffi 那些复杂的依赖,直接使用就可以了,代码我已经push github了
参考资料
https://github.com/rongfengliang/easytier-ffii-ctypes
https://github.com/rongfengliang/easytier-ffi-python
https://github.com/EasyTier/EasyTier/tree/main/easytier-contrib/easytier-ffi