Add veilid_features API and logging

This commit is contained in:
Brandon Vandegrift 2025-05-02 19:20:02 -04:00
parent ec887d3bec
commit 81b265e4bf
21 changed files with 140 additions and 8 deletions

View file

@ -15,6 +15,8 @@
- Direct bootstrap now filters out Relayed nodes correctly - Direct bootstrap now filters out Relayed nodes correctly
- Closed issue #400: https://gitlab.com/veilid/veilid/-/issues/400 - Closed issue #400: https://gitlab.com/veilid/veilid/-/issues/400
- Closed issue #377: https://gitlab.com/veilid/veilid/-/issues/377 - Closed issue #377: https://gitlab.com/veilid/veilid/-/issues/377
- Add the `veilid_features()` API, which lists the compile-time features that were enabled when `veilid-core` was built (available in language bindings as well). ([!401](https://gitlab.com/veilid/veilid/-/issues/400))
- When `veilid-core` starts up, log the version number, and the compile-time features that were enabled when it was built. ([!401](https://gitlab.com/veilid/veilid/-/issues/400))
- veilid-flutter: - veilid-flutter:
- Bindings updated for API changes - Bindings updated for API changes

10
Cargo.lock generated
View file

@ -834,6 +834,15 @@ dependencies = [
"cmake", "cmake",
] ]
[[package]]
name = "bosion"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "858150532ced83f59a49236ccade71f0ec46362dbd1632affdf79a5c299462cd"
dependencies = [
"time",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.17.0" version = "3.17.0"
@ -6455,6 +6464,7 @@ dependencies = [
"async_executors", "async_executors",
"backtrace", "backtrace",
"blake3", "blake3",
"bosion",
"capnp", "capnp",
"capnpc", "capnpc",
"cfg-if 1.0.0", "cfg-if 1.0.0",

View file

@ -283,6 +283,8 @@ filetime = "0.2.25"
sha2 = "0.10.8" sha2 = "0.10.8"
hex = "0.4.3" hex = "0.4.3"
reqwest = { version = "0.11", features = ["blocking"], optional = true } reqwest = { version = "0.11", features = ["blocking"], optional = true }
bosion = { version = "1.1.2", default-features = false }
[package.metadata.wasm-pack.profile.release] [package.metadata.wasm-pack.profile.release]
wasm-opt = ["-O", "--enable-mutable-globals"] wasm-opt = ["-O", "--enable-mutable-globals"]

View file

@ -242,6 +242,9 @@ fn main() {
return; return;
} }
// Gather build-time information, such as the features that were enabled when veilid-core was built.
bosion::gather();
if is_input_file_outdated("./proto/veilid.capnp", "./proto/veilid_capnp.rs").unwrap() { if is_input_file_outdated("./proto/veilid.capnp", "./proto/veilid_capnp.rs").unwrap() {
println!("cargo:warning=rebuilding proto/veilid_capnp.rs because it has changed from the last generation of proto/veilid.capnp"); println!("cargo:warning=rebuilding proto/veilid_capnp.rs because it has changed from the last generation of proto/veilid.capnp");
do_capnp_build(); do_capnp_build();

View file

@ -71,6 +71,8 @@ impl VeilidCoreContext {
let registry = VeilidComponentRegistry::new(config); let registry = VeilidComponentRegistry::new(config);
veilid_log!(registry info "Veilid API starting up"); veilid_log!(registry info "Veilid API starting up");
veilid_log!(registry info "Version: {}", veilid_version_string());
veilid_log!(registry info "Features: {:?}", veilid_features());
// Register all components // Register all components
registry.register(ProtectedStore::new); registry.register(ProtectedStore::new);

View file

@ -105,6 +105,15 @@ pub fn veilid_version() -> (u32, u32, u32) {
) )
} }
include!(env!("BOSION_PATH"));
/// Return the features that were enabled when veilid-core was built.
#[must_use]
pub fn veilid_features() -> Vec<String> {
let features = Bosion::CRATE_FEATURES.to_vec();
features.into_iter().map(String::from).collect()
}
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
pub use intf::android::veilid_core_setup_android; pub use intf::android::veilid_core_setup_android;

View file

@ -66,11 +66,12 @@ impl RoutingTable {
let mut out = String::new(); let mut out = String::new();
let inner = self.inner.read(); let inner = self.inner.read();
out += &format!("Node Ids: {}\n", self.node_ids()); out += &format!("Node Ids: {}\n", self.node_ids());
out += &format!("Version: {}\n", veilid_version_string());
out += &format!("Features: {:?}\n", veilid_features());
out += &format!( out += &format!(
"Self Transfer Stats:\n{}", "Self Transfer Stats:\n{}",
indent_all_string(&inner.self_transfer_stats) indent_all_string(&inner.self_transfer_stats)
); );
out += &format!("Version: {}", veilid_version_string());
out out
} }

View file

@ -121,6 +121,7 @@ pub enum RequestOp {
}, },
VeilidVersionString, VeilidVersionString,
VeilidVersion, VeilidVersion,
VeilidFeatures,
DefaultVeilidConfig, DefaultVeilidConfig,
} }
@ -238,6 +239,9 @@ pub enum ResponseOp {
DefaultVeilidConfig { DefaultVeilidConfig {
value: String, value: String,
}, },
VeilidFeatures {
value: Vec<String>,
},
} }
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]

View file

@ -859,6 +859,9 @@ impl JsonRequestProcessor {
patch, patch,
} }
} }
RequestOp::VeilidFeatures => ResponseOp::VeilidFeatures {
value: veilid_features(),
},
RequestOp::DefaultVeilidConfig => ResponseOp::DefaultVeilidConfig { RequestOp::DefaultVeilidConfig => ResponseOp::DefaultVeilidConfig {
value: default_veilid_config(), value: default_veilid_config(),
}, },

View file

@ -190,4 +190,7 @@ abstract class Veilid {
VeilidVersion veilidVersion(); VeilidVersion veilidVersion();
String defaultVeilidConfig(); String defaultVeilidConfig();
Future<String> debug(String command); Future<String> debug(String command);
/// Return the features that were enabled when veilid-core was built.
List<String> veilidFeatures();
} }

View file

@ -250,6 +250,9 @@ typedef _VeilidVersionDart = VeilidVersionFFI Function();
// fn default_veilid_config() -> *mut c_char // fn default_veilid_config() -> *mut c_char
typedef _DefaultVeilidConfigDart = Pointer<Utf8> Function(); typedef _DefaultVeilidConfigDart = Pointer<Utf8> Function();
// fn veilid_features() -> *mut c_char
typedef _VeilidFeaturesDart = Pointer<Utf8> Function();
// Async message types // Async message types
const int messageOk = 0; const int messageOk = 0;
const int messageErr = 1; const int messageErr = 1;
@ -1257,8 +1260,9 @@ class VeilidFFI extends Veilid {
_startupVeilidCore = dylib.lookupFunction< _startupVeilidCore = dylib.lookupFunction<
Void Function(Int64, Int64, Pointer<Utf8>), Void Function(Int64, Int64, Pointer<Utf8>),
_StartupVeilidCoreDart>('startup_veilid_core'), _StartupVeilidCoreDart>('startup_veilid_core'),
_isShutdown = dylib.lookupFunction<Void Function(Int64), _IsShutdownDart>( _isShutdown =
'is_shutdown'), dylib.lookupFunction<Void Function(Int64), _IsShutdownDart>(
'is_shutdown'),
_getVeilidState = _getVeilidState =
dylib.lookupFunction<Void Function(Int64), _GetVeilidStateDart>( dylib.lookupFunction<Void Function(Int64), _GetVeilidStateDart>(
'get_veilid_state'), 'get_veilid_state'),
@ -1476,7 +1480,10 @@ class VeilidFFI extends Veilid {
_veilidVersion = dylib.lookupFunction<VeilidVersionFFI Function(), _veilidVersion = dylib.lookupFunction<VeilidVersionFFI Function(),
_VeilidVersionDart>('veilid_version'), _VeilidVersionDart>('veilid_version'),
_defaultVeilidConfig = dylib.lookupFunction<Pointer<Utf8> Function(), _defaultVeilidConfig = dylib.lookupFunction<Pointer<Utf8> Function(),
_DefaultVeilidConfigDart>('default_veilid_config') { _DefaultVeilidConfigDart>('default_veilid_config'),
_veilidFeatures =
dylib.lookupFunction<Pointer<Utf8> Function(), _VeilidFeaturesDart>(
'veilid_features') {
// Get veilid_flutter initializer // Get veilid_flutter initializer
final initializeVeilidFlutter = _dylib.lookupFunction< final initializeVeilidFlutter = _dylib.lookupFunction<
Void Function(Pointer<_DartPostCObject>, Pointer<Utf8>), Void Function(Pointer<_DartPostCObject>, Pointer<Utf8>),
@ -1579,6 +1586,7 @@ class VeilidFFI extends Veilid {
final _VeilidVersionStringDart _veilidVersionString; final _VeilidVersionStringDart _veilidVersionString;
final _VeilidVersionDart _veilidVersion; final _VeilidVersionDart _veilidVersion;
final _DefaultVeilidConfigDart _defaultVeilidConfig; final _DefaultVeilidConfigDart _defaultVeilidConfig;
final _VeilidFeaturesDart _veilidFeatures;
@override @override
void initializeVeilidCore(Map<String, dynamic> platformConfigJson) { void initializeVeilidCore(Map<String, dynamic> platformConfigJson) {
@ -1834,9 +1842,18 @@ class VeilidFFI extends Veilid {
@override @override
String defaultVeilidConfig() { String defaultVeilidConfig() {
final defaultVeilidConfig = _defaultVeilidConfig(); final ptr = _defaultVeilidConfig();
final ret = defaultVeilidConfig.toDartString(); final out = ptr.toDartString();
_freeString(defaultVeilidConfig); _freeString(ptr);
return ret; return out;
}
@override
List<String> veilidFeatures() {
final ptr = _veilidFeatures();
final str = ptr.toDartString();
_freeString(ptr);
final features = jsonDecode(str) as List<dynamic>;
return features.map((e) => e as String).toList();
} }
} }

View file

@ -757,6 +757,12 @@ class VeilidJS extends Veilid {
jsonVersion['minor'] as int, jsonVersion['patch'] as int); jsonVersion['minor'] as int, jsonVersion['patch'] as int);
} }
@override
List<String> veilidFeatures() {
final features = js_util.callMethod(wasm, 'veilid_features', []);
return (features as js_interop.JSArray).dartify()! as List<String>;
}
@override @override
String defaultVeilidConfig() => String defaultVeilidConfig() =>
js_util.callMethod(wasm, 'default_veilid_config', []); js_util.callMethod(wasm, 'default_veilid_config', []);

View file

@ -2049,3 +2049,11 @@ pub extern "C" fn veilid_version() -> VeilidVersion {
pub extern "C" fn default_veilid_config() -> *mut c_char { pub extern "C" fn default_veilid_config() -> *mut c_char {
veilid_core::default_veilid_config().into_ffi_value() veilid_core::default_veilid_config().into_ffi_value()
} }
#[no_mangle]
#[instrument(level = "trace", target = "ffi", skip_all)]
pub extern "C" fn veilid_features() -> *mut c_char {
serde_json::to_string(&veilid_core::veilid_features())
.expect("Failed to serialize features")
.into_ffi_value()
}

View file

@ -44,6 +44,13 @@ async def test_version(api_connection: veilid.VeilidAPI):
print(f"veilid_version_string: {vstr}") print(f"veilid_version_string: {vstr}")
@pytest.mark.asyncio
async def test_features(api_connection: veilid.VeilidAPI):
features = await api_connection.veilid_features()
print(f"veilid_features: {features}")
assert isinstance(features, list)
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_config(api_connection: veilid.VeilidAPI): async def test_config(api_connection: veilid.VeilidAPI):
cfgstr = await api_connection.default_veilid_config() cfgstr = await api_connection.default_veilid_config()

View file

@ -462,6 +462,10 @@ class VeilidAPI(ABC):
async def veilid_version_string(self) -> str: async def veilid_version_string(self) -> str:
pass pass
@abstractmethod
async def veilid_features(self) -> list[str]:
pass
@abstractmethod @abstractmethod
async def veilid_version(self) -> types.VeilidVersion: async def veilid_version(self) -> types.VeilidVersion:
pass pass

View file

@ -490,6 +490,9 @@ class _JsonVeilidAPI(VeilidAPI):
v = await self.send_ndjson_request(Operation.VEILID_VERSION) v = await self.send_ndjson_request(Operation.VEILID_VERSION)
return VeilidVersion(v["major"], v["minor"], v["patch"]) return VeilidVersion(v["major"], v["minor"], v["patch"])
async def veilid_features(self) -> list[str]:
return raise_api_result(await self.send_ndjson_request(Operation.VEILID_FEATURES))
async def default_veilid_config(self) -> str: async def default_veilid_config(self) -> str:
return raise_api_result(await self.send_ndjson_request(Operation.DEFAULT_VEILID_CONFIG)) return raise_api_result(await self.send_ndjson_request(Operation.DEFAULT_VEILID_CONFIG))

View file

@ -29,6 +29,7 @@ class Operation(StrEnum):
DEBUG = "Debug" DEBUG = "Debug"
VEILID_VERSION_STRING = "VeilidVersionString" VEILID_VERSION_STRING = "VeilidVersionString"
VEILID_VERSION = "VeilidVersion" VEILID_VERSION = "VeilidVersion"
VEILID_FEATURES = "VeilidFeatures"
DEFAULT_VEILID_CONFIG = "DefaultVeilidConfig" DEFAULT_VEILID_CONFIG = "DefaultVeilidConfig"

View file

@ -2479,6 +2479,27 @@
"type": "string" "type": "string"
} }
} }
},
{
"type": "object",
"required": [
"op",
"value"
],
"properties": {
"op": {
"type": "string",
"enum": [
"VeilidFeatures"
]
},
"value": {
"type": "array",
"items": {
"type": "string"
}
}
}
} }
], ],
"required": [ "required": [

View file

@ -1617,6 +1617,20 @@
} }
} }
}, },
{
"type": "object",
"required": [
"op"
],
"properties": {
"op": {
"type": "string",
"enum": [
"VeilidFeatures"
]
}
}
},
{ {
"type": "object", "type": "object",
"required": [ "required": [

View file

@ -207,6 +207,12 @@ impl VeilidClient {
} }
} }
/// Return the features that were enabled when veilid-core was built.
#[must_use]
pub fn features() -> Vec<String> {
veilid_core::veilid_features()
}
/// Return the cargo package version of veilid-core, in string format. /// Return the cargo package version of veilid-core, in string format.
#[must_use] #[must_use]
pub fn versionString() -> String { pub fn versionString() -> String {

View file

@ -29,6 +29,12 @@ describe('veilidClient', function () {
expect(version.length).toBeGreaterThan(0); expect(version.length).toBeGreaterThan(0);
}); });
it('should print features', async function () {
const features = veilidClient.features();
expect(Array.isArray(features)).toBe(true);
expect(features.length).toBeGreaterThan(0);
});
it('should get config string', async function () { it('should get config string', async function () {
const defaultConfig = veilidClient.defaultConfig(); const defaultConfig = veilidClient.defaultConfig();
expect(typeof defaultConfig).toBe('string'); expect(typeof defaultConfig).toBe('string');