diff --git a/.gitignore b/.gitignore index bc8c141..3b11171 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ - +.idea obj bin - +*.user +package/ diff --git a/README.md b/README.md index 031235f..ff17d0c 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,57 @@ ![zenoh banner](./zenoh-dragon.png) -[![NuGet](https://img.shields.io/nuget/v/Zenoh.svg)](https://www.nuget.org/packages/Zenoh) -[![Gitter](https://badges.gitter.im/atolab/zenoh.svg)](https://gitter.im/atolab/zenoh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +[![NuGet](https://img.shields.io/nuget/v/Zenoh-CS?color=blue)](https://www.nuget.org/packages/Zenoh-CS/) [![License](https://img.shields.io/badge/License-EPL%202.0-blue)](https://choosealicense.com/licenses/epl-2.0/) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) -# Eclipse zenoh C# API +# Zenoh C# API -[Eclipse zenoh](http://zenoh.io) is an extremely efficient and fault-tolerant [Named Data Networking](http://named-data.net) (NDN) protocol -that is able to scale down to extremely constrainded devices and networks. +[中文/chinese readme](https://github.com/sanri/zenoh-csharp/blob/master/README.zh.md) + +[Zenoh](http://zenoh.io) is an extremely efficient and fault-tolerant [Named Data Networking](http://named-data.net) (NDN) protocol that is able to scale down to extremely constrainded devices and networks. + +The C# API is for pure clients, in other terms does not support peer-to-peer communication, +can be easily tested against a zenoh router running in a Docker container (see https://zenoh.io/docs/getting-started/quick-test/). -The C# API is for pure clients, in other terms does not support peer-to-peer communication, can be easily tested against a zenoh router running in a Docker container (see https://github.com/eclipse-zenoh/zenoh#how-to-test-it). ------------------------------- ## How to install it Requirements: - - The [zenoh-c](https://github.com/eclipse-zenoh/zenoh-c) library must be installed on your host - -The Eclipse zenoh C# library is available on NuGet: +- The [zenoh-c](https://github.com/eclipse-zenoh/zenoh-c) library must be installed on your host +- The zenoh C# library [Zenoh-CS](https://www.nuget.org/packages/Zenoh-CS/) is available on NuGet(Only x64). ### Supported .NET Standards +- .NET 6.0 +- .NET 7.0 + +### Supported CPU arch +- x64 +- arm64 (untested) -The library is configured to target the **.NET Standard 2.0** at minimum. +### Mapping between Zenoh-CS and Zenoh-C versions +| Zenoh-C | Zenoh-CS | +|:---------:|:--------:| +| v0.7.2-rc | v0.1.* | ------------------------------- ## How to build it -Requirements: +Requirements: * The [zenoh-c](https://github.com/eclipse-zenoh/zenoh-c) library must be installed on your host - * A .NET environment - -Simply run `dotnet build Zenoh/`. + * A .NET environment. .NET6 or .NET7 [SDK](https://dotnet.microsoft.com/zh-cn/download/dotnet) +Build: +Because some of Zenoh-C data structures are not the same length in `x64` and `arm64`, you need to add the option `-p:Platform=x64` or `-p:Platform=ARM64` when building. +```shell +# x64 CPU +dotnet build Zenoh.csproj -c Release -p:Platform=x64 +# arm64 CPU +dotnet build Zenoh.csproj -c Release -p:Platform=ARM64 +``` ------------------------------- ## Running the Examples -The examples are configured to target **net5.0**. - -The simplest way to run some of the examples is to get a Docker image of the **zenoh** network router (see https://github.com/eclipse-zenoh/zenoh#how-to-test-it) and then to run the examples on your machine. - -Then, run the zenoh-csharp examples following the instructions in [examples/Zenoh.Net/README.md](https://github.com/eclipse-zenoh/zenoh-csharp/blob/master/examples/Zenoh.Net/README.md) +Build and run the zenoh-csharp examples following the instructions in [examples/README.md](https://github.com/sanri/zenoh-csharp/blob/master/examples/README.md) diff --git a/README.zh.md b/README.zh.md new file mode 100644 index 0000000..998e29e --- /dev/null +++ b/README.zh.md @@ -0,0 +1,55 @@ +![zenoh banner](./zenoh-dragon.png) + +[![NuGet](https://img.shields.io/nuget/v/Zenoh-CS?color=blue)](https://www.nuget.org/packages/Zenoh-CS/) +[![License](https://img.shields.io/badge/License-EPL%202.0-blue)](https://choosealicense.com/licenses/epl-2.0/) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +# Zenoh C# API + +[Zenoh](http://zenoh.io)是一种非常高效和容错的命名数据网络([NDN](http://named-data.net))协议, 能够在非常受限制的设备和网络中运行. + +C# API是用于纯客户端的, 可以很容易地针对运行在Docker容器中的zenoh路由器进行测试 (参考[快速测试](https://zenoh.io/docs/getting-started/quick-test/)). + +------------------------------- +## 如何安装 + +需求: +- 库 [zenoh-c](https://github.com/eclipse-zenoh/zenoh-c) 必需被安装在你的主机上. +- Zenoh C# 库 [Zenoh-CS](https://www.nuget.org/packages/Zenoh-CS/) 库在NuGet上可用(只支持x64) + +### 支持的 .NET 标准 +- .NET 6.0 +- .NET 7.0 + +### 支持的CPU架构 +- x64 +- arm64 (未测试) + +### Zenoh-CS 版本与 Zenoh-C 版本对应关系 +| Zenoh-C | Zenoh-CS | +|:---------:|:--------:| +| v0.7.2-rc | v0.1.* | + + +------------------------------- +## 如何构建 + +需求: +- 库 [zenoh-c](https://github.com/eclipse-zenoh/zenoh-c) 必需被安装在你的主机上. +- 主机安装有 .NET6 或 .NET7 的 [SDK](https://dotnet.microsoft.com/zh-cn/download/dotnet) + +构建命令: +由于Zenoh-C的部分数据结构在 `x64` 与 `arm64` 下长度不一样, 所以构建时需要增加选项 `-p:Platform=x64` 或 `-p:Platform=ARM64` +```shell +# x64 CPU +dotnet build Zenoh.csproj -c Release -p:Platform=x64 +# arm64 CPU +dotnet build Zenoh.csproj -c Release -p:Platform=ARM64 +``` + + +------------------------------- +## 运行示例 + +构建和运行示程序, 参考 [examples/README.zh.md](https://github.com/sanri/zenoh-csharp/blob/master/examples/README.zh.md) + diff --git a/Zenoh/Config.cs b/Zenoh/Config.cs new file mode 100644 index 0000000..f59488b --- /dev/null +++ b/Zenoh/Config.cs @@ -0,0 +1,166 @@ +#nullable enable + +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Zenoh; + +public class Config : IDisposable +{ + public enum Mode + { + Peer, + Client, + } + + internal unsafe ZOwnedConfig* ownedConfig; + private bool _disposed; + + + public Config() + { + unsafe + { + ZOwnedConfig config = ZenohC.z_config_default(); + nint p = Marshal.AllocHGlobal(Marshal.SizeOf(config)); + Marshal.StructureToPtr(config, p, false); + ownedConfig = (ZOwnedConfig*)p; + } + + _disposed = false; + } + + public static Config? LoadFromFile(string path) + { + unsafe + { + ZOwnedConfig config = ZenohC.zc_config_from_file(path); + int b = ZenohC.z_config_check(&config); + // if (!ZenohC.z_config_check(&config)) + if (b==0) + { + ZenohC.z_config_drop(&config); + return null; + } + + nint p = Marshal.AllocHGlobal(Marshal.SizeOf(config)); + Marshal.StructureToPtr(config, p, false); + return new Config + { + ownedConfig = (ZOwnedConfig*)p, + _disposed = false, + }; + } + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + if (_disposed) return; + + unsafe + { + ZenohC.z_config_drop(ownedConfig); + Marshal.FreeHGlobal((nint)ownedConfig); + } + + _disposed = true; + } + + public string ToStr() + { + if (_disposed) return ""; + + unsafe + { + ZConfig config = ZenohC.z_config_loan(ownedConfig); + ZOwnedStr str = ZenohC.zc_config_to_string(config); + string o = ZenohC.ZOwnedStrToString(&str); + ZenohC.z_str_drop(&str); + return o; + } + } + + + public bool SetMode(Mode mode) + { + if (_disposed) return false; + + string value = ""; + switch (mode) + { + case Mode.Client: + value = "\"client\""; + break; + case Mode.Peer: + value = "\"peer\""; + break; + } + + unsafe + { + ZConfig config = ZenohC.z_config_loan(ownedConfig); + sbyte r = ZenohC.zc_config_insert_json(config, ZenohC.zConfigModeKey, value); + return r == 0; + } + } + + // The v such as "tcp/172.30.1.1:7447" + public bool SetConnect(string[] v) + { + if (_disposed) return false; + + StringBuilder value = new StringBuilder("["); + foreach (var ele in v) + { + value.Append($"\"{ele}\","); + } + + value.Append("]"); + + unsafe + { + ZConfig config = ZenohC.z_config_loan(ownedConfig); + sbyte r = ZenohC.zc_config_insert_json(config, ZenohC.zConfigConnectKey, value.ToString()); + return r == 0; + } + } + + // The v such as "tcp/127.0.0.1:7888" + public bool SetListen(string[] v) + { + if (_disposed) return false; + + StringBuilder value = new StringBuilder("["); + foreach (var ele in v) + { + value.Append($"\"{ele}\","); + } + + value.Append("]"); + + unsafe + { + ZConfig config = ZenohC.z_config_loan(ownedConfig); + sbyte r = ZenohC.zc_config_insert_json(config, ZenohC.zConfigListenKey, value.ToString()); + return r == 0; + } + } + + // Whether data messages should be timestamped + public bool SetTimestamp(bool b) + { + if (_disposed) return false; + + string value = b ? "true" : "false"; + + unsafe + { + ZConfig config = ZenohC.z_config_loan(ownedConfig); + sbyte r = ZenohC.zc_config_insert_json(config, ZenohC.zConfigAddTimestampKey, value); + return r == 0; + } + } +} \ No newline at end of file diff --git a/Zenoh/Id.cs b/Zenoh/Id.cs new file mode 100644 index 0000000..c573637 --- /dev/null +++ b/Zenoh/Id.cs @@ -0,0 +1,82 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Zenoh; + +public struct Id +{ + internal byte[] data; + + internal Id(ZId zid) + { + data = new byte[16]; + for (int i = 0; i < 16; i++) + { + unsafe + { + data[i] = zid.id[i]; + } + } + } + + public string ToStr() + { + StringBuilder sb = new StringBuilder(); + foreach (byte b in data) + { + sb.Append(b.ToString("x")); + } + + return sb.ToString(); + } +} + +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal unsafe struct ZIdBuffer +{ + internal nuint count = 0; + internal fixed byte data[256 * 16]; + + public ZIdBuffer() + { + } + + internal void Add(ZId* zId) + { + if (count >= 256) return; + for (nuint i = 0; i < 16; i++) + { + data[count * 16 + i] = zId->id[i]; + } + + count += 1; + } + + internal Id[] ToIds() + { + Id[] ids = new Id[count]; + for (nuint i = 0; i < count; i++) + { + byte[] o = new byte[16]; + for (nuint j = 0; j < 16; j++) + { + o[j] = data[i * 16 + j]; + } + + Id id = new Id + { + data = o, + }; + ids[i] = id; + } + + return ids; + } + + internal static void z_id_call(ZId* zId, void* context) + { + ZIdBuffer* pIdBuffer = (ZIdBuffer*)context; + pIdBuffer->Add(zId); + } +} \ No newline at end of file diff --git a/Zenoh/Net/Session.cs b/Zenoh/Net/Session.cs deleted file mode 100644 index dc25109..0000000 --- a/Zenoh/Net/Session.cs +++ /dev/null @@ -1,172 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// - -using System; -using System.Runtime.InteropServices; -using System.Collections.Generic; -using System.Text; -using System.Threading; - -namespace Zenoh.Net -{ - - public class Session : IDisposable - { - private IntPtr /*zn_session_t*/ _nativePtr = IntPtr.Zero; - - // keep a reference to the SubscriberCallbackNative delegate to avoid garbage collection - private SubscriberCallbackNative _subscriberCallbackNative; - - // counter for subscriber handles generation - private Int32 _subscriberCounter = Int32.MinValue; - // map of declared subscribers - internal Dictionary Subscribers; - - private Session(IntPtr /*zn_session_t*/ nativeSession) - { - this._nativePtr = nativeSession; - this._subscriberCallbackNative = new SubscriberCallbackNative(SubscriberCallbackNativeImpl); - this.Subscribers = new Dictionary(); - } - - public void Dispose() => Dispose(true); - - protected virtual void Dispose(bool disposing) - { - if (_nativePtr != IntPtr.Zero) - { - // make sure each Subscriber is disposed before closing the Session - foreach (Subscriber s in Subscribers.Values) - { - s.Dispose(); - } - Subscribers.Clear(); - - ZnClose(_nativePtr); - _nativePtr = IntPtr.Zero; - } - } - - public static Session Open(Dictionary config) - { - // It's simpler to encode the config as a single string to pass it to Rust where is will be decoded - string configStr = ""; - foreach (KeyValuePair kvp in config) - { - configStr += kvp.Key + "=" + kvp.Value + ";"; - } - var props = Zenoh.ZnConfigFromStr(configStr); - - var nativeSession = ZnOpen(props); - // TODO: check errors... - return new Session(nativeSession); - } - - public Dictionary Info() - { - var zstr = ZnInfoAsStr(_nativePtr); - return ZTypes.ZStringToProperties(zstr); - } - - public ulong DeclareResource(ResKey reskey) - { - return ZnDeclareResource(_nativePtr, reskey._key); - } - - unsafe public void Write(ResKey reskey, byte[] payload) - { - fixed (byte* p = payload) - { - ZnWrite(_nativePtr, reskey._key, (IntPtr)p, (uint)payload.Length); - } - } - - unsafe public void Write(ResKey reskey, byte[] payload, uint encoding, uint kind, CongestionControl congestionControl) - { - fixed (byte* p = payload) - { - ZnWriteExt(_nativePtr, reskey._key, (IntPtr)p, (uint)payload.Length, encoding, kind, congestionControl); - } - } - - internal void SubscriberCallbackNativeImpl(IntPtr /* *const zn_sample_t */ samplePtr, IntPtr /* *const c_void */ callBackPtr) - { - Sample s = new Sample(samplePtr); - try - { - Int32 subscriberHandle = callBackPtr.ToInt32(); - Subscriber subscriber = Subscribers[subscriberHandle]; - subscriber.UserCallback(s); - } - catch (OverflowException) - { - Console.WriteLine("Internal error: invalid subscriberHandle received in Subscriber callback: {0}", callBackPtr); - } - catch (KeyNotFoundException) - { - // The subscriber has been unregistered - } - } - - public Subscriber DeclareSubscriber(ResKey reskey, SubInfo subInfo, SubscriberCallback callback) - { - Int32 subscriberHandle = Interlocked.Increment(ref _subscriberCounter); - var nativeSubscriber = ZnDeclareSubscriber(_nativePtr, reskey._key, subInfo._subInfo, _subscriberCallbackNative, new IntPtr(subscriberHandle)); - var subscriber = new Subscriber(this, subscriberHandle, nativeSubscriber, callback); - Subscribers[subscriberHandle] = subscriber; - return subscriber; - } - - [DllImport("zenohc", EntryPoint = "zn_open")] - internal static extern IntPtr /*zn_session_t*/ ZnOpen(IntPtr /*zn_properties_t*/ config); - - [DllImport("zenohc", EntryPoint = "zn_info_as_str")] - internal static extern ZString ZnInfoAsStr(IntPtr /*zn_session_t*/ rustSession); - - [DllImport("zenohc", EntryPoint = "zn_close")] - internal static extern void ZnClose(IntPtr /*zn_session_t*/ rustSession); - - [DllImport("zenohc", EntryPoint = "zn_declare_resource")] - internal static extern ulong ZnDeclareResource(IntPtr /*zn_session_t*/ rustSession, ResKey.NativeType zResKey); - - [DllImport("zenohc", EntryPoint = "zn_write")] - internal static extern int ZnWrite( - IntPtr /*zn_session_t*/ rustSession, - ResKey.NativeType zResKey, - IntPtr payload, - uint len); - - [DllImport("zenohc", EntryPoint = "zn_write_ext")] - internal static extern int ZnWriteExt( - IntPtr /*zn_session_t*/ rustSession, - ResKey.NativeType zResKey, - IntPtr payload, - uint len, - uint encoding, - uint kind, - CongestionControl congestion); - - [DllImport("zenohc", EntryPoint = "zn_declare_subscriber")] - internal static extern IntPtr /*zn_subscriber_t*/ ZnDeclareSubscriber( - IntPtr /*zn_session_t*/ rustSession, - ResKey.NativeType zResKey, - SubInfo.NativeType zSubInfo, - SubscriberCallbackNative callback, - IntPtr /*void* */ arg); - - [DllImport("zenohc", EntryPoint = "zn_undeclare_subscriber")] - internal static extern void ZnUndeclareSubscriber(IntPtr /*zn_subscriber_t*/ sub); - - } -} \ No newline at end of file diff --git a/Zenoh/Net/Types.cs b/Zenoh/Net/Types.cs deleted file mode 100644 index d26dd8c..0000000 --- a/Zenoh/Net/Types.cs +++ /dev/null @@ -1,226 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// -using System; -using System.Runtime.InteropServices; - - -namespace Zenoh.Net -{ - public class ResKey - { - [StructLayout(LayoutKind.Sequential)] - internal struct NativeType // zn_reskey_t - { - internal ulong id; // c_ulong - internal IntPtr suffix; // *const c_char - } - - internal NativeType _key; - - public ulong Id - { - get - { - return _key.id; - } - } - - public string Suffix - { - get - { - return Marshal.PtrToStringAnsi(_key.suffix); - } - } - - internal ResKey(NativeType resKey) - { - this._key = resKey; - } - - public static ResKey RId(ulong id) - { - NativeType resKey; - resKey.id = id; - resKey.suffix = IntPtr.Zero; - return new ResKey(resKey); - } - - public static ResKey RName(string suffix) - { - NativeType resKey; - resKey.id = 0; - resKey.suffix = Marshal.StringToHGlobalAnsi(suffix); - return new ResKey(resKey); - } - - public static ResKey RIdWithSuffix(ulong id, string suffix) - { - NativeType resKey; - resKey.id = id; - resKey.suffix = Marshal.StringToHGlobalAnsi(suffix); - return new ResKey(resKey); - } - - public bool IsNumerical() - { - return _key.suffix == IntPtr.Zero; - } - } - - public enum CongestionControl - { - BLOCK, - DROP - } - - public class Sample - { - [StructLayout(LayoutKind.Sequential)] - internal struct NativeType // zn_sample_t - { - internal ZString key; // z_string_t - internal ZBytes value; // z_bytes_t - } - - public string ResName - { get; } - public byte[] Payload - { get; } - - unsafe internal Sample(IntPtr /* *const zn_sample_t */ _sample) - { - // Note: copies are made here. Could we avoid this ? - NativeType* s = (NativeType*)_sample; - ResName = ZTypes.ZStringToString(s->key); - Payload = ZTypes.ZBytesToBytesArray(s->value); - } - - internal Sample(NativeType _sample) - { - // Note: copies are made here. Could we avoid this ? - ResName = ZTypes.ZStringToString(_sample.key); - Payload = ZTypes.ZBytesToBytesArray(_sample.value); - ZnSampleFree(_sample); - } - - [DllImport("zenohc", EntryPoint = "zn_sample_free")] - internal static extern void ZnSampleFree(NativeType sample); - } - - public enum Reliability - { - BEST_EFFORT, - RELIABLE, - } - - public enum SubMode - { - PUSH, - PULL, - } - - [StructLayout(LayoutKind.Sequential)] - public struct Period // zn_period_t - { - public uint origin; // c_uint - public uint period; // c_uint - public uint duration; // c_uint - - public Period(uint origin, uint period, uint duration) - { - this.origin = origin; - this.period = period; - this.duration = duration; - } - - public static Period None() - { - return new Period(0, 0, 0); - } - - public override string ToString() - { - return String.Format("origin={0}, period={1}, duration={2}", origin, period, duration); - } - } - - - public class SubInfo - { - [StructLayout(LayoutKind.Sequential)] - public struct NativeType // zn_subinfo_t - { - public Reliability reliability; // zn_reliability_t - public SubMode mode; // zn_submode_t - public IntPtr period; // *mut zn_period_t - } - - public NativeType _subInfo; - - public SubInfo() - { - this._subInfo = ZnSubInfoDefault(); - } - - public SubInfo(SubMode mode) : this() - { - _subInfo.mode = mode; - } - - // TODO: add period param - public SubInfo(Reliability reliability, SubMode mode) : this() - { - _subInfo.reliability = reliability; - _subInfo.mode = mode; - } - - [DllImport("zenohc", EntryPoint = "zn_subinfo_default")] - internal static extern NativeType ZnSubInfoDefault(); - } - - // SubscriberCallback to be implemented by user. - public delegate void SubscriberCallback(Sample sample); - - // Type of the callback function expected by zenoh-c - internal delegate void SubscriberCallbackNative(IntPtr /* *const zn_sample_t */ samplePtr, IntPtr /* *const c_void */ callBackPtr); - - public class Subscriber - { - private Session _session; - private Int32 _subscriberHandle; - private IntPtr /*zn_subscriber_t*/ _nativePtr = IntPtr.Zero; - internal SubscriberCallback UserCallback; - - internal Subscriber(Session session, Int32 subscriberHandle, IntPtr nativeSubscriber, SubscriberCallback userCallback) - { - this._session = session; - this._subscriberHandle = subscriberHandle; - this._nativePtr = nativeSubscriber; - this.UserCallback = userCallback; - } - - public void Dispose() => Dispose(true); - - protected virtual void Dispose(bool disposing) - { - if (_nativePtr != IntPtr.Zero) - { - Session.ZnUndeclareSubscriber(_nativePtr); - _session.Subscribers.Remove(_subscriberHandle); - _nativePtr = IntPtr.Zero; - } - } - } -} \ No newline at end of file diff --git a/Zenoh/Publisher.cs b/Zenoh/Publisher.cs new file mode 100644 index 0000000..e84afa6 --- /dev/null +++ b/Zenoh/Publisher.cs @@ -0,0 +1,46 @@ +using System; +using System.Runtime.InteropServices; + +namespace Zenoh; + +public struct PublisherHandle +{ + internal int handle; +} + +public class Publisher : IDisposable +{ + internal unsafe ZOwnedPublisher* ownedPublisher; + internal readonly ZPublisherOptions options; + internal readonly string keyexpr; + private bool _disposed; + + public Publisher(string key) : this(key, CongestionControl.Block, Priority.RealTime) + { + } + + public Publisher(string key, CongestionControl control, Priority priority) + { + unsafe + { + keyexpr = key; + _disposed = false; + ownedPublisher = null; + options.congestion_control = control; + options.priority = priority; + } + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + if (_disposed) return; + unsafe + { + Marshal.FreeHGlobal((nint)ownedPublisher); + } + + _disposed = true; + } +} \ No newline at end of file diff --git a/Zenoh/Querier.cs b/Zenoh/Querier.cs new file mode 100644 index 0000000..31678cb --- /dev/null +++ b/Zenoh/Querier.cs @@ -0,0 +1,113 @@ +#pragma warning disable CS8500 + +using System; +using System.Runtime.InteropServices; + +namespace Zenoh; + +public class QueryOptions +{ + internal string keyexpr; + internal QueryTarget target; + internal ConsolidationMode mode; + internal EncodingPrefix encodingPrefix; + internal byte[] payload; + + public QueryOptions(string keyexpr) : + this(keyexpr, QueryTarget.BestMatching, ConsolidationMode.Auto, EncodingPrefix.Empty, Array.Empty()) + { + } + + public QueryOptions(string keyexpr, QueryTarget target, ConsolidationMode mode) : + this(keyexpr, target, mode, EncodingPrefix.Empty, Array.Empty()) + { + } + + public QueryOptions(string keyexpr, EncodingPrefix encodingPrefix, byte[] payload) : + this(keyexpr, QueryTarget.BestMatching, ConsolidationMode.Auto, encodingPrefix, payload) + { + } + + public QueryOptions(string keyexpr, QueryTarget target, ConsolidationMode mode, + EncodingPrefix encodingPrefix, byte[] payload) + { + this.keyexpr = keyexpr; + this.target = target; + this.mode = mode; + this.encodingPrefix = encodingPrefix; + this.payload = payload; + } +} + +public delegate void QuerierCallback(Sample sample); + +public class Querier : IDisposable +{ + internal unsafe ZOwnedReplyChannel* _channel; + internal unsafe ZOwnedReply* _reply; + private bool _disposed; + + internal Querier() + { + unsafe + { + _disposed = false; + + ZOwnedReplyChannel channel = ZenohC.zc_reply_fifo_new(0); + nint pChannel = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(channel, pChannel, false); + _channel = (ZOwnedReplyChannel*)pChannel; + + ZOwnedReply reply = ZenohC.z_reply_null(); + nint pReply = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(reply, pReply, false); + _reply = (ZOwnedReply*)pReply; + } + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + if (_disposed) return; + + unsafe + { + ZenohC.z_reply_drop(_reply); + ZenohC.z_reply_channel_drop(_channel); + + Marshal.FreeHGlobal((nint)_reply); + Marshal.FreeHGlobal((nint)_channel); + } + + _disposed = true; + } + + public bool GetSamples(QuerierCallback callback) + { + if (_disposed) + return false; + + while (true) + { + unsafe + { + sbyte b = ZenohC.z_reply_channel_closure_call(&_channel->recv, _reply); + if (b != 1) + return false; + + b = ZenohC.z_reply_check(_reply); + if (b != 1) + return true; + + b = ZenohC.z_reply_is_ok(_reply); + if (b != 1) + return false; + + ZSample zSample = ZenohC.z_reply_ok(_reply); + Sample sample = new Sample(&zSample); + callback(sample); + } + } + } +} \ No newline at end of file diff --git a/Zenoh/Queryable.cs b/Zenoh/Queryable.cs new file mode 100644 index 0000000..a883524 --- /dev/null +++ b/Zenoh/Queryable.cs @@ -0,0 +1,172 @@ +#pragma warning disable CS8500 + +using System; +using System.Runtime.InteropServices; +using System.Text; + + +namespace Zenoh; + +public struct QueryableHandle +{ + internal int handle; +} + +public delegate void QueryableCallback(Query query); + +public class Queryable : IDisposable +{ + internal string keyexpr; + internal unsafe ZOwnedQueryable* zOwnedQueryable; + internal unsafe ZOwnedClosureQuery* closureQuery; + internal unsafe ZQueryableOptions* options; + private readonly ZOwnedClosureQuery _ownedClosureQuery; + private GCHandle _userCallbackGcHandle; + private bool _disposed; + + public Queryable(string keyexpr, QueryableCallback userCallback, bool complete = false) + { + unsafe + { + this.keyexpr = keyexpr; + _disposed = false; + zOwnedQueryable = null; + _userCallbackGcHandle = GCHandle.Alloc(userCallback); + + _ownedClosureQuery = new ZOwnedClosureQuery + { + context = (void*)GCHandle.ToIntPtr(_userCallbackGcHandle), + call = Call, + drop = null, + }; + nint p = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(_ownedClosureQuery, p, false); + closureQuery = (ZOwnedClosureQuery*)p; + + nint pOptions = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.WriteByte(pOptions, complete ? (byte)1 : (byte)0); + options = (ZQueryableOptions*)pOptions; + } + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + if (_disposed) return; + + unsafe + { + Marshal.FreeHGlobal((nint)closureQuery); + Marshal.FreeHGlobal((nint)options); + Marshal.FreeHGlobal((nint)zOwnedQueryable); + } + + _userCallbackGcHandle.Free(); + _disposed = true; + } + + private static unsafe void Call(ZQuery* zQuery, void* context) + { + var gch = GCHandle.FromIntPtr((nint)context); + var callback = (QueryableCallback?)gch.Target; + var query = new Query(zQuery); + if (callback != null) + { + callback(query); + } + } +} + +public class Query +{ + private unsafe ZQuery* _query; + + internal unsafe Query(ZQuery* query) + { + _query = query; + } + + public string GetKeyexpr() + { + unsafe + { + ZKeyexpr keyexpr = ZenohC.z_query_keyexpr(_query); + string keyStr = ZenohC.ZKeyexprToString(keyexpr); + return keyStr; + } + } + + public Value GetValue() + { + unsafe + { + ZValue zValue = ZenohC.z_query_value(_query); + return new Value(zValue); + } + } + + public bool Reply(string key, byte[] payload, EncodingPrefix encodingPrefix, byte[]? encodingSuffix) + { + unsafe + { + sbyte r; + fixed (byte* pv = payload) + { + nint pKey = Marshal.StringToHGlobalAnsi(key); + ZKeyexpr keyexpr = ZenohC.z_keyexpr((byte*)pKey); + if (encodingSuffix is null) + { + ZQueryReplyOptions options = new ZQueryReplyOptions + { + encoding = ZenohC.z_encoding(encodingPrefix, null), + }; + nuint len = (nuint)payload.Length; + r = ZenohC.z_query_reply(_query, keyexpr, pv, len, &options); + } + else + { + fixed (byte* suffix = encodingSuffix) + { + ZQueryReplyOptions options = new ZQueryReplyOptions + { + encoding = ZenohC.z_encoding(encodingPrefix, suffix), + }; + nuint len = (nuint)payload.Length; + r = ZenohC.z_query_reply(_query, keyexpr, pv, len, &options); + } + } + + Marshal.FreeHGlobal(pKey); + } + + return r == 0; + } + } + + public bool ReplyStr(string key, string value) + { + byte[] payload = Encoding.UTF8.GetBytes(value); + return Reply(key, payload, EncodingPrefix.TextPlain, null); + } + + public bool ReplyJson(string key, string value) + { + byte[] payload = Encoding.UTF8.GetBytes(value); + return Reply(key, payload, EncodingPrefix.AppJson, null); + } + + public bool ReplyInt(string key, long value) + { + string s = value.ToString("G"); + byte[] payload = Encoding.UTF8.GetBytes(s); + return Reply(key, payload, EncodingPrefix.AppInteger, null); + } + + public bool ReplyFloat(string key, double value) + { + string s = value.ToString("G"); + byte[] payload = Encoding.UTF8.GetBytes(s); + return Reply(key, payload, EncodingPrefix.AppFloat, null); + } +} \ No newline at end of file diff --git a/Zenoh/Sample.cs b/Zenoh/Sample.cs new file mode 100644 index 0000000..526a716 --- /dev/null +++ b/Zenoh/Sample.cs @@ -0,0 +1,96 @@ +using System; +using System.Runtime.InteropServices; + +namespace Zenoh; + +// 这是一个引用类型, 不释放引用的内存. +public class Sample +{ + private readonly unsafe ZSample* _native; + + internal unsafe Sample(ZSample* sample) + { + _native = sample; + } + + public string GetKeyexpr() + { + unsafe + { + return ZenohC.ZKeyexprToString(_native->keyexpr); + } + } + + public EncodingPrefix GetEncodingPrefix() + { + unsafe + { + return _native->encoding.prefix; + } + } + + public byte[] GetEncodingSuffix() + { + unsafe + { + nuint len = _native->encoding.suffix.len; + nint start = (nint)_native->encoding.suffix.start; + byte[] data = new byte[len]; + Marshal.Copy(start, data, 0, (int)len); + return data; + } + } + + public SampleKind GetSampleKind() + { + unsafe + { + return _native->kind; + } + } + + public byte[] GetPayload() + { + unsafe + { + if (ZenohC.z_bytes_check(&_native->payload) != 1) + return Array.Empty(); + var len = _native->payload.len; + byte[] data = new byte[len]; + Marshal.Copy((nint)_native->payload.start, data, 0, (int)len); + return data; + } + } + + public string? GetString() + { + unsafe + { + if (ZenohC.z_bytes_check(&_native->payload) != 1) + return null; + return Marshal.PtrToStringUTF8((nint)_native->payload.start, (int)_native->payload.len); + } + } + + public long? GetInteger() + { + var str = GetString(); + if (!Int64.TryParse(str, out long n)) + { + return null; + } + + return n; + } + + public double? GetDouble() + { + var str = GetString(); + if (!Double.TryParse(str, out double n)) + { + return null; + } + + return n; + } +} \ No newline at end of file diff --git a/Zenoh/Session.cs b/Zenoh/Session.cs new file mode 100644 index 0000000..0ac9438 --- /dev/null +++ b/Zenoh/Session.cs @@ -0,0 +1,508 @@ +#pragma warning disable CS8500 + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + + +namespace Zenoh; + +public class Session : IDisposable +{ + internal SortedDictionary subscribersDictionary; + private int _indexSubscriber = 1; + internal SortedDictionary publishersDictionary; + private int _indexPublisher = 1; + internal SortedDictionary queryableDictionary; + private int _indexQueryable = 1; + private bool _disposed; + private readonly unsafe ZOwnedSession* _session; + + private unsafe Session(ZOwnedSession* session) + { + subscribersDictionary = new SortedDictionary(); + publishersDictionary = new SortedDictionary(); + queryableDictionary = new SortedDictionary(); + _disposed = false; + _session = session; + } + + public static Session? Open(Config config) + { + unsafe + { + ZOwnedSession session = ZenohC.z_open(config.ownedConfig); + if (ZenohC.z_session_check(&session) != 1) + { + return null; + } + + nint p = Marshal.AllocHGlobal(Marshal.SizeOf(session)); + Marshal.StructureToPtr(session, p, false); + + return new Session((ZOwnedSession*)p); + } + } + + + public void Close() + { + if (_disposed) return; + + unsafe + { + foreach ((_, Subscriber subscriber) in subscribersDictionary) + { + ZenohC.z_undeclare_subscriber(subscriber.ownedSubscriber); + Marshal.FreeHGlobal((nint)subscriber.ownedSubscriber); + subscriber.ownedSubscriber = null; + } + + subscribersDictionary.Clear(); + + ZenohC.z_close(_session); + Marshal.FreeHGlobal((nint)_session); + } + + _disposed = true; + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + Close(); + } + + public Id LocalId() + { + unsafe + { + ZSession session = ZenohC.z_session_loan(_session); + ZId zid = ZenohC.z_info_zid(session); + return new Id(zid); + } + } + + public Id[] RoutersId() + { + unsafe + { + ZSession session = ZenohC.z_session_loan(_session); + nint pIdBuffer = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.WriteInt64(pIdBuffer, 0); + ZOwnedClosureZId ownedClosureZId = new ZOwnedClosureZId + { + context = (void*)pIdBuffer, + call = ZIdBuffer.z_id_call, + drop = null, + }; + nint pOwnedClosureZId = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(ownedClosureZId, pOwnedClosureZId, false); + ZenohC.z_info_routers_zid(session, (ZOwnedClosureZId*)pOwnedClosureZId); + ZIdBuffer? zIdBuffer = (ZIdBuffer?)Marshal.PtrToStructure(pIdBuffer, typeof(ZIdBuffer)); + + Marshal.FreeHGlobal(pOwnedClosureZId); + Marshal.FreeHGlobal(pIdBuffer); + + return zIdBuffer is null ? Array.Empty() : zIdBuffer.Value.ToIds(); + } + } + + public Id[] PeersId() + { + unsafe + { + ZSession session = ZenohC.z_session_loan(_session); + nint pIdBuffer = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.WriteInt64(pIdBuffer, 0); + ZOwnedClosureZId ownedClosureZId = new ZOwnedClosureZId + { + context = (void*)pIdBuffer, + call = ZIdBuffer.z_id_call, + drop = null, + }; + nint pOwnedClosureZId = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(ownedClosureZId, pOwnedClosureZId, false); + ZenohC.z_info_peers_zid(session, (ZOwnedClosureZId*)pOwnedClosureZId); + ZIdBuffer? zIdBuffer = (ZIdBuffer?)Marshal.PtrToStructure(pIdBuffer, typeof(ZIdBuffer)); + + Marshal.FreeHGlobal(pOwnedClosureZId); + Marshal.FreeHGlobal(pIdBuffer); + + return zIdBuffer is null ? Array.Empty() : zIdBuffer.Value.ToIds(); + } + } + + public bool PutStr(string key, string value) + { + return PutStr(key, value, CongestionControl.Block, Priority.RealTime); + } + + public bool PutStr(string key, string s, CongestionControl congestionControl, Priority priority) + { + byte[] data = Encoding.UTF8.GetBytes(s); + return _put(key, data, congestionControl, priority, EncodingPrefix.TextPlain); + } + + public bool PutJson(string key, string value) + { + return PutJson(key, value, CongestionControl.Block, Priority.RealTime); + } + + public bool PutJson(string key, string s, CongestionControl congestionControl, Priority priority) + { + byte[] data = Encoding.UTF8.GetBytes(s); + return _put(key, data, congestionControl, priority, EncodingPrefix.AppJson); + } + + public bool PutInt(string key, long value) + { + return PutInt(key, value, CongestionControl.Block, Priority.RealTime); + } + + public bool PutInt(string key, long value, CongestionControl congestionControl, Priority priority) + { + string s = value.ToString("G"); + byte[] data = Encoding.UTF8.GetBytes(s); + return _put(key, data, congestionControl, priority, EncodingPrefix.AppInteger); + } + + public bool PutFloat(string key, double value) + { + return PutFloat(key, value, CongestionControl.Block, Priority.RealTime); + } + + public bool PutFloat(string key, double value, CongestionControl congestionControl, Priority priority) + { + string s = value.ToString("G"); + byte[] data = Encoding.UTF8.GetBytes(s); + return _put(key, data, congestionControl, priority, EncodingPrefix.AppFloat); + } + + public bool PutData(string key, byte[] value, EncodingPrefix encodingPrefix, byte[]? encodingSuffix = null) + { + return PutData(key, value, CongestionControl.Block, Priority.RealTime, encodingPrefix, encodingSuffix); + } + + public bool PutData(string key, byte[] value, + CongestionControl congestionControl, Priority priority, + EncodingPrefix encodingPrefix, byte[]? encodingSuffix = null + ) + { + return _put(key, value, congestionControl, priority, encodingPrefix, encodingSuffix); + } + + private bool _put( + string key, byte[] value, + CongestionControl congestionControl, Priority priority, + EncodingPrefix encodingPrefix, byte[]? encodingSuffix = null + ) + { + if (_disposed) return false; + unsafe + { + int r; + + fixed (byte* pv = value) + { + nuint len = (nuint)value.Length; + nint pKey = Marshal.StringToHGlobalAnsi(key); + ZSession session = ZenohC.z_session_loan(_session); + ZKeyexpr keyexpr = ZenohC.z_keyexpr((byte*)pKey); + if (encodingSuffix is null) + { + ZPutOptions options = new ZPutOptions + { + encoding = ZenohC.z_encoding(encodingPrefix, null), + congestionControl = congestionControl, + priority = priority, + }; + r = ZenohC.z_put(session, keyexpr, pv, len, &options); + } + else + { + fixed (byte* pEncodingSuffix = encodingSuffix) + { + ZPutOptions options = new ZPutOptions + { + encoding = ZenohC.z_encoding(encodingPrefix, pEncodingSuffix), + congestionControl = congestionControl, + priority = priority, + }; + r = ZenohC.z_put(session, keyexpr, pv, len, &options); + } + } + + Marshal.FreeHGlobal(pKey); + } + + return r == 0; + } + } + + public bool PubStr(PublisherHandle handle, string value) + { + byte[] data = Encoding.UTF8.GetBytes(value); + return _publisher_put(handle, data, EncodingPrefix.TextPlain); + } + + public bool PubJson(PublisherHandle handle, string value) + { + byte[] data = Encoding.UTF8.GetBytes(value); + return _publisher_put(handle, data, EncodingPrefix.AppJson); + } + + public bool PubInt(PublisherHandle handle, long value) + { + string s = value.ToString("G"); + byte[] data = Encoding.UTF8.GetBytes(s); + return _publisher_put(handle, data, EncodingPrefix.AppInteger); + } + + public bool PubFloat(PublisherHandle handle, double value) + { + string s = value.ToString("G"); + byte[] data = Encoding.UTF8.GetBytes(s); + return _publisher_put(handle, data, EncodingPrefix.AppFloat); + } + + public bool PubData(PublisherHandle handle, byte[] data, EncodingPrefix encodingPrefix, + byte[]? encodingSuffix = null) + { + return _publisher_put(handle, data, encodingPrefix, encodingSuffix); + } + + private bool _publisher_put(PublisherHandle handle, byte[] value, EncodingPrefix encodingPrefix, + byte[]? encodingSuffix = null) + { + if (_disposed) return false; + unsafe + { + if (!publishersDictionary.TryGetValue(handle.handle, out Publisher? publisher)) + return false; + + ZPublisher pub = ZenohC.z_publisher_loan(publisher.ownedPublisher); + int r; + fixed (byte* pv = value) + { + if (encodingSuffix is null) + { + ZPublisherPutOptions options = new ZPublisherPutOptions + { + encoding = ZenohC.z_encoding(encodingPrefix, null), + }; + nuint len = (nuint)value.Length; + r = ZenohC.z_publisher_put(pub, pv, len, &options); + } + else + { + fixed (byte* pSuffix = encodingSuffix) + { + ZPublisherPutOptions options = new ZPublisherPutOptions + { + encoding = ZenohC.z_encoding(encodingPrefix, pSuffix), + }; + nuint len = (nuint)value.Length; + r = ZenohC.z_publisher_put(pub, pv, len, &options); + } + } + } + + return r == 0; + } + } + + public SubscriberHandle? RegisterSubscriber(Subscriber subscriber) + { + unsafe + { + if (subscriber.ownedSubscriber != null) + return null; + + ZSession session = ZenohC.z_session_loan(_session); + nint pKey = Marshal.StringToHGlobalAnsi(subscriber.keyexpr); + ZKeyexpr keyexpr = ZenohC.z_keyexpr((byte*)pKey); + nint pOptions = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(subscriber.options, pOptions, false); + ZOwnedSubscriber sub = + ZenohC.z_declare_subscriber(session, keyexpr, subscriber.closureSample, (ZSubscriberOptions*)pOptions); + Marshal.FreeHGlobal(pOptions); + Marshal.FreeHGlobal(pKey); + + if (ZenohC.z_subscriber_check(&sub) != 1) + return null; + + nint pOwnedSubscriber = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(sub, pOwnedSubscriber, false); + subscriber.ownedSubscriber = (ZOwnedSubscriber*)pOwnedSubscriber; + + _indexSubscriber += 1; + subscribersDictionary.Add(_indexSubscriber, subscriber); + + return new SubscriberHandle + { + handle = _indexSubscriber, + }; + } + } + + public void UnregisterSubscriber(SubscriberHandle handle) + { + UnregisterSubscriber(handle.handle); + } + + private void UnregisterSubscriber(int handle) + { + if (subscribersDictionary.TryGetValue(handle, out Subscriber? subscriber)) + { + unsafe + { + ZenohC.z_undeclare_subscriber(subscriber.ownedSubscriber); + Marshal.FreeHGlobal((nint)subscriber.ownedSubscriber); + subscriber.ownedSubscriber = null; + } + + subscribersDictionary.Remove(handle); + } + } + + public PublisherHandle? RegisterPublisher(Publisher publisher) + { + unsafe + { + if (publisher.ownedPublisher != null) + return null; + + ZSession session = ZenohC.z_session_loan(_session); + nint pKey = Marshal.StringToHGlobalAnsi(publisher.keyexpr); + ZKeyexpr keyexpr = ZenohC.z_keyexpr((byte*)pKey); + nint pOptions = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(publisher.options, pOptions, false); + + ZOwnedPublisher pub = ZenohC.z_declare_publisher(session, keyexpr, (ZPublisherOptions*)pOptions); + + Marshal.FreeHGlobal(pOptions); + Marshal.FreeHGlobal(pKey); + + if (ZenohC.z_publisher_check(&pub) != 1) + return null; + + nint pOwnedPublisher = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(pub, pOwnedPublisher, false); + publisher.ownedPublisher = (ZOwnedPublisher*)pOwnedPublisher; + + _indexPublisher += 1; + publishersDictionary.Add(_indexPublisher, publisher); + + return new PublisherHandle + { + handle = _indexPublisher + }; + } + } + + public void UnregisterPublisher(PublisherHandle handle) + { + UnregisterPublisher(handle.handle); + } + + private void UnregisterPublisher(int handle) + { + if (publishersDictionary.TryGetValue(handle, out Publisher? publisher)) + { + unsafe + { + ZenohC.z_undeclare_publisher(publisher.ownedPublisher); + Marshal.FreeHGlobal((nint)publisher.ownedPublisher); + publisher.ownedPublisher = null; + } + + publishersDictionary.Remove(handle); + } + } + + public Querier? Query(QueryOptions options) + { + if (_disposed) + return null; + + unsafe + { + ZSession session = ZenohC.z_session_loan(_session); + nint pKey = Marshal.StringToHGlobalAnsi(options.keyexpr); + ZKeyexpr keyexpr = ZenohC.z_keyexpr((byte*)pKey); + Querier querier = new Querier(); + ZGetOptions getOptions = new ZGetOptions(); + getOptions.target = options.target; + getOptions.consolidation.mode = options.mode; + getOptions.value.encoding = ZenohC.z_encoding(options.encodingPrefix, null); + getOptions.value.payload.len = (nuint)options.payload.Length; + sbyte r; + fixed (byte* data = options.payload) + { + getOptions.value.payload.start = data; + nint pOptions = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(getOptions, pOptions, false); + r = ZenohC.z_get(session, keyexpr, null, &querier._channel->send, (ZGetOptions*)pOptions); + Marshal.FreeHGlobal(pOptions); + Marshal.FreeHGlobal(pKey); + } + + return r >= 0 ? querier : null; + } + } + + public QueryableHandle? RegisterQueryable(Queryable queryable) + { + unsafe + { + if (queryable.zOwnedQueryable != null) + return null; + + ZSession session = ZenohC.z_session_loan(_session); + nint pKey = Marshal.StringToHGlobalAnsi(queryable.keyexpr); + ZKeyexpr keyexpr = ZenohC.z_keyexpr((byte*)pKey); + + ZOwnedQueryable zOwnedQueryable = + ZenohC.z_declare_queryable(session, keyexpr, queryable.closureQuery, queryable.options); + Marshal.FreeHGlobal(pKey); + + if (ZenohC.z_queryable_check(&zOwnedQueryable) != 1) + return null; + + nint pOwnedQueryable = Marshal.AllocHGlobal(Marshal.SizeOf()); + Marshal.StructureToPtr(zOwnedQueryable, pOwnedQueryable, false); + queryable.zOwnedQueryable = (ZOwnedQueryable*)pOwnedQueryable; + + _indexQueryable += 1; + queryableDictionary.Add(_indexQueryable, queryable); + + return new QueryableHandle + { + handle = _indexQueryable, + }; + } + } + + public void UnregisterQueryable(QueryableHandle handle) + { + UnregisterQueryable(handle.handle); + } + + private void UnregisterQueryable(int handle) + { + if (queryableDictionary.TryGetValue(handle, out Queryable? queryable)) + { + unsafe + { + ZenohC.z_undeclare_queryable(queryable.zOwnedQueryable); + Marshal.FreeHGlobal((nint)queryable.zOwnedQueryable); + queryable.zOwnedQueryable = null; + } + + queryableDictionary.Remove(handle); + } + } +} \ No newline at end of file diff --git a/Zenoh/Subscriber.cs b/Zenoh/Subscriber.cs new file mode 100644 index 0000000..283bc3c --- /dev/null +++ b/Zenoh/Subscriber.cs @@ -0,0 +1,78 @@ +#pragma warning disable CS8500 + +using System; +using System.Runtime.InteropServices; + +namespace Zenoh; + +public struct SubscriberHandle +{ + internal int handle; +} + +public delegate void SubscriberCallback(Sample sample); + +public class Subscriber : IDisposable +{ + internal readonly unsafe ZOwnedClosureSample* closureSample; + internal unsafe ZOwnedSubscriber* ownedSubscriber; + internal readonly string keyexpr; + internal readonly ZSubscriberOptions options; + private readonly ZOwnedClosureSample _ownedClosureSample; + private GCHandle _userCallbackGcHandle; + private bool _disposed; + + public Subscriber(string key, SubscriberCallback userCallback) + : this(key, userCallback, Reliability.Reliable) + { + } + + public Subscriber(string key, SubscriberCallback userCallback, Reliability reliability) + { + unsafe + { + keyexpr = key; + _disposed = false; + options.reliability = reliability; + _userCallbackGcHandle = GCHandle.Alloc(userCallback, GCHandleType.Normal); + _ownedClosureSample = new ZOwnedClosureSample + { + context = (void*)GCHandle.ToIntPtr(_userCallbackGcHandle), + call = Call, + drop = null, + }; + + nint p = Marshal.AllocHGlobal(Marshal.SizeOf(_ownedClosureSample)); + Marshal.StructureToPtr(_ownedClosureSample, p, false); + closureSample = (ZOwnedClosureSample*)p; + ownedSubscriber = null; + } + } + + public void Dispose() => Dispose(true); + + private void Dispose(bool disposing) + { + if (_disposed) return; + + unsafe + { + Marshal.FreeHGlobal((nint)closureSample); + Marshal.FreeHGlobal((nint)ownedSubscriber); + } + + _userCallbackGcHandle.Free(); + _disposed = true; + } + + private static unsafe void Call(ZSample* zSample, void* context) + { + var gch = GCHandle.FromIntPtr((nint)context); + var callback = (SubscriberCallback?)gch.Target; + var sample = new Sample(zSample); + if (callback != null) + { + callback(sample); + } + } +} \ No newline at end of file diff --git a/Zenoh/Types.cs b/Zenoh/Types.cs deleted file mode 100644 index 2eebb44..0000000 --- a/Zenoh/Types.cs +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// -using System; -using System.Runtime.InteropServices; -using System.Collections.Generic; -using System.Linq; - - -namespace Zenoh -{ - [StructLayout(LayoutKind.Sequential)] - internal struct ZString - { - public IntPtr val; // *const c_char - public IntPtr len; // size_t - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ZBytes - { - public IntPtr val; // *const u8 - public IntPtr len; // size_t - } - - internal static class ZTypes - { - internal static string ZStringToString(ZString zs) - { - byte[] managedArray = new byte[(int)zs.len]; - System.Runtime.InteropServices.Marshal.Copy(zs.val, managedArray, 0, (int)zs.len); - string result = System.Text.Encoding.UTF8.GetString(managedArray, 0, (int)zs.len); - // TODO Free ZString ??? - return result; - } - - internal static byte[] ZBytesToBytesArray(ZBytes zb) - { - byte[] managedArray = new byte[(int)zb.len]; - System.Runtime.InteropServices.Marshal.Copy(zb.val, managedArray, 0, (int)zb.len); - // TODO Free ZBytes ??? - return managedArray; - } - - private static char[] _propSeparator = { ';' }; - private static char[] _kvSeparator = { '=' }; - - internal static Dictionary ZStringToProperties(ZString zs) - { - var str = ZTypes.ZStringToString(zs); - - // Parse the properties from the string - var properties = str.Split(_propSeparator, StringSplitOptions.RemoveEmptyEntries) - .Select(x => x.Split(_kvSeparator, 2)) - .ToDictionary(x => x.First(), x => (x.Length == 2) ? x.Last() : ""); - return properties; - } - - } - -} \ No newline at end of file diff --git a/Zenoh/Value.cs b/Zenoh/Value.cs new file mode 100644 index 0000000..5c0a71f --- /dev/null +++ b/Zenoh/Value.cs @@ -0,0 +1,85 @@ +using System; +using System.Runtime.InteropServices; + +namespace Zenoh; + +// 这是一个引用类型, 不释放引用的内存. +public class Value +{ + internal ZValue zValue; + + internal Value(ZValue value) + { + zValue = value; + } + + public EncodingPrefix GetEncodingPrefix() + { + return zValue.encoding.prefix; + } + + public byte[] GetEncodingSuffix() + { + unsafe + { + nuint len = zValue.encoding.suffix.len; + nint start = (nint)zValue.encoding.suffix.start; + byte[] data = new byte[len]; + Marshal.Copy(start, data, 0, (int)len); + return data; + } + } + + public byte[] GetPayload() + { + unsafe + { + fixed (ZBytes* pBytes = &zValue.payload) + { + if (ZenohC.z_bytes_check(pBytes) != 1) + return Array.Empty(); + } + + var len = zValue.payload.len; + byte[] data = new byte[len]; + Marshal.Copy((nint)zValue.payload.start, data, 0, (int)len); + return data; + } + } + + public string? GetString() + { + unsafe + { + fixed (ZBytes* pBytes = &zValue.payload) + { + if (ZenohC.z_bytes_check(pBytes) != 1) + return null; + } + + return Marshal.PtrToStringUTF8((nint)zValue.payload.start, (int)zValue.payload.len); + } + } + + public long? GetInteger() + { + var str = GetString(); + if (!Int64.TryParse(str, out long n)) + { + return null; + } + + return n; + } + + public double? GetDouble() + { + var str = GetString(); + if (!Double.TryParse(str, out double n)) + { + return null; + } + + return n; + } +} \ No newline at end of file diff --git a/Zenoh/Zenoh.cs b/Zenoh/Zenoh.cs deleted file mode 100644 index 9b6d493..0000000 --- a/Zenoh/Zenoh.cs +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// -using System; -using System.Runtime.InteropServices; -using System.Collections.Generic; - - -namespace Zenoh -{ - public class Zenoh - { - - [DllImport("zenohc", EntryPoint = "z_init_logger")] - public static extern void InitLogger(); - - private static char[] _propSeparator = { ';' }; - private static char[] _kvSeparator = { '=' }; - - public static Dictionary ConfigFromFile(string path) - { - var zprops = ZnConfigFromFile(path); - var zstr = ZnConfigToStr(zprops); - return ZTypes.ZStringToProperties(zstr); - } - - [DllImport("zenohc", EntryPoint = "zn_config_from_str", CharSet = CharSet.Ansi)] - internal static extern IntPtr /*zn_properties_t*/ ZnConfigFromStr([MarshalAs(UnmanagedType.LPStr)] string str); - - [DllImport("zenohc", EntryPoint = "zn_config_to_str", CharSet = CharSet.Ansi)] - internal static extern ZString ZnConfigToStr(IntPtr /*zn_properties_t*/ znProps); - - [DllImport("zenohc", EntryPoint = "zn_config_from_file", CharSet = CharSet.Ansi)] - internal static extern IntPtr /*zn_properties_t*/ ZnConfigFromFile([MarshalAs(UnmanagedType.LPStr)] string str); - - } - -} \ No newline at end of file diff --git a/Zenoh/Zenoh.csproj b/Zenoh/Zenoh.csproj index 9ed8c9b..f8dbadd 100644 --- a/Zenoh/Zenoh.csproj +++ b/Zenoh/Zenoh.csproj @@ -1,33 +1,36 @@ - - - Zenoh - Zenoh - 0.0.4 - Julien Enoch - EPL-2.0 OR Apache-2.0 - Zenoh: Zero Overhead Pub/sub, Store/Query and Compute. - false - - https://github.com/eclipse-zenoh/zenoh-csharp - https://github.com/eclipse-zenoh/zenoh-csharp - git - - Library - netstandard2.0 - - true - + + Zenoh + Zenoh-CS + 0.1.4 + sanri + EPL-2.0 OR Apache-2.0 + Zenoh: Zero Overhead Pub/sub, Store/Query and Compute. + false + https://github.com/sanri/zenoh-csharp + https://github.com/sanri/zenoh-csharp + README.md + git + Library + true + 10 + 0.1.4 + zenoh + net7.0;net6.0 + Release;Debug + x64;ARM64 + enable + + + TRACE;PLATFORM_ARM + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + diff --git a/Zenoh/ZenohC.cs b/Zenoh/ZenohC.cs new file mode 100644 index 0000000..3a92eee --- /dev/null +++ b/Zenoh/ZenohC.cs @@ -0,0 +1,1139 @@ +#pragma warning disable CS8500 + +using System.Runtime.InteropServices; + +namespace Zenoh; + +// z_congestion_control_t +public enum CongestionControl +{ + Block, + Drop +} + +// z_encoding_prefix_t +public enum EncodingPrefix +{ + Empty = 0, + AppOctetStream = 1, + AppCustom = 2, + TextPlain = 3, + AppProperties = 4, + AppJson = 5, + AppSql = 6, + AppInteger = 7, + AppFloat = 8, + AppXml = 9, + AppXhtmlXml = 10, + AppXWwwFormUrlencoded = 11, + TextJson = 12, + TextHtml = 13, + TextXml = 14, + TextCss = 15, + TextCsv = 16, + TextJavascript = 17, + ImageJpeg = 18, + ImagePng = 19, + ImageGif = 20 +} + +// z_sample_kind_t +public enum SampleKind +{ + Put = 0, + Delete = 1 +} + +// z_priority_t +public enum Priority +{ + RealTime = 1, + InteractiveHigh = 2, + InteractiveLow = 3, + DataHigh = 4, + Data = 5, + DataLow = 6, + Background = 7 +} + +// z_consolidation_mode_t +public enum ConsolidationMode +{ + Auto = -1, + None = 0, + Monotonic = 1, + Latest = 2, +} + +// z_query_consolidation_t +public enum QueryConsolidation +{ + Auto = -1, + None = 0, + Monotonic = 1, + Latest = 2, +} + +// z_reliability_t +public enum Reliability +{ + BestEffort, + Reliable +} + +// z_query_target_t +public enum QueryTarget +{ + BestMatching, + All, + AllComplete, +}; + +// z_bytes_t +// -------------------------------- +// typedef struct z_bytes_t { +// size_t len; +// const uint8_t *start; +// } z_bytes_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZBytes +{ + internal nuint len; + internal byte* start; +} + +// z_id_t +// -------------------------------- +// typedef struct z_id_t { +// uint8_t id[16]; +// } z_id_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZId +{ + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + internal fixed byte id[16]; +} + +// z_owned_str_t +// -------------------------------- +// typedef struct z_owned_str_t { +// char *_cstr; +// } z_owned_str_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZOwnedStr +{ + internal nint cstr; +} + +// z_owned_str_array_t +// -------------------------------- +// typedef struct z_owned_str_array_t { +// char **val; +// size_t len; +// } z_owned_str_array_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZOwnedStrArray +{ + internal nint val; + internal nuint len; +} + +// z_str_array_t +// -------------------------------- +// typedef struct z_str_array_t { +// size_t len; +// const char *const *val; +// } z_str_array_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZStrArray +{ + internal nuint len; + internal nint val; +} + +// z_owned_encoding_t +// -------------------------------- +// typedef struct z_owned_encoding_t { +// enum z_encoding_prefix_t prefix; +// struct z_bytes_t suffix; +// bool _dropped; +// } z_owned_encoding_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZOwnedEncoding +{ + internal EncodingPrefix prefix; + internal ZBytes suffix; + internal sbyte _dropped; +} + +// z_encoding_t +// -------------------------------- +// typedef struct z_encoding_t { +// enum z_encoding_prefix_t prefix; +// struct z_bytes_t suffix; +// } z_encoding_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZEncoding +{ + internal EncodingPrefix prefix; + internal ZBytes suffix; +} + +// public string PrefixToString() +// { +// return prefix.ToString(); +// } +// +// public static ZEncoding New(EncodingPrefix prefix) +// { +// return FnZEncoding(prefix, IntPtr.Zero); +// } +// +// [DllImport(ZenohC.DllName, EntryPoint = "z_encoding", CallingConvention = CallingConvention.Cdecl)] +// internal static extern ZEncoding FnZEncoding(EncodingPrefix prefix, IntPtr suffix); + +// z_timestamp_t +// -------------------------------- +// typedef struct z_timestamp_t { +// uint64_t time; +// struct z_id_t id; +// } z_timestamp_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZTimestamp +{ + internal ulong time; + internal ZId id; +} + +// z_keyexpr_t +// -------------------------------- +// typedef struct z_keyexpr_t { +// uint64_t _0[4]; +// } z_keyexpr_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal unsafe struct ZKeyexpr +{ + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + private fixed ulong _[4]; +} + +// -------------------------------- +// typedef struct z_owned_keyexpr_t { +// uint64_t _0[4]; +// } z_keyexpr_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal unsafe struct ZOwnedKeyexpr +{ + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + private fixed ulong _[4]; +} + +// z_sample_t +// -------------------------------- +// typedef struct z_sample_t { +// struct z_keyexpr_t keyexpr; +// struct z_bytes_t payload; +// struct z_encoding_t encoding; +// const void *_zc_buf; +// enum z_sample_kind_t kind; +// struct z_timestamp_t timestamp; +// } z_sample_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZSample +{ + internal ZKeyexpr keyexpr; + internal ZBytes payload; + internal ZEncoding encoding; + private nint _zc_buf; + internal SampleKind kind; + internal ZTimestamp timestamp; +} + +// z_owned_config_t +// -------------------------------- +// typedef struct z_owned_config_t { +// void *_0; +// } z_owned_config_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZOwnedConfig +{ + private nint _; +} + +// z_config_t +// -------------------------------- +// typedef struct z_config_t { +// const struct z_owned_config_t *_0; +// } z_config_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZConfig +{ + private nint _; +} + +// z_owned_publisher_t +// -------------------------------- +// typedef struct ALIGN(8) z_owned_publisher_t { +// uint64_t _0[7]; +// } z_owned_publisher_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal unsafe struct ZOwnedPublisher +{ + // [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + private fixed ulong _[7]; +} + +// z_owned_queryable_t +// -------------------------------- +// typedef struct ALIGN(8) z_owned_queryable_t { +// uint64_t _0[4]; +// } z_owned_queryable_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal unsafe struct ZOwnedQueryable +{ + private fixed ulong _[4]; +} + +// z_publisher_t +// -------------------------------- +// typedef struct z_publisher_t { +// const struct z_owned_publisher_t *_0; +// } z_publisher_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPublisher +{ + private nint _; +} + +// z_publisher_options_t +// -------------------------------- +// typedef struct z_publisher_options_t { +// enum z_congestion_control_t congestion_control; +// enum z_priority_t priority; +// } z_publisher_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPublisherOptions +{ + internal CongestionControl congestion_control; + internal Priority priority; +} + +// z_publisher_delete_options_t +// -------------------------------- +// typedef struct z_publisher_delete_options_t { +// uint8_t __dummy; +// } z_publisher_delete_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPublisherDeleteOptions +{ + internal byte dummy; +} + +// z_publisher_put_options_t +// -------------------------------- +// typedef struct z_publisher_put_options_t { +// struct z_encoding_t encoding; +// } z_publisher_put_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPublisherPutOptions +{ + internal ZEncoding encoding; +} + +// z_pull_subscriber_options_t +// -------------------------------- +// typedef struct z_pull_subscriber_options_t { +// enum z_reliability_t reliability; +// } z_pull_subscriber_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPullSubscriberOptions +{ + internal Reliability reliability; +} + +// z_owned_pull_subscriber_t +// -------------------------------- +// typedef struct ALIGN(8) z_owned_pull_subscriber_t { +// uint64_t _0[1]; +// } z_owned_pull_subscriber_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal struct ZOwnedPullSubscriber +{ + private ulong _; +} + +// z_pull_subscriber_t +// -------------------------------- +// typedef struct z_pull_subscriber_t { +// const struct z_owned_pull_subscriber_t *_0; +// } z_pull_subscriber_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPullSubscriber +{ + internal nint _; +} + +// z_queryable_options_t +// -------------------------------- +// typedef struct z_queryable_options_t { +// bool complete; +// } z_queryable_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZQueryableOptions +{ + internal sbyte complete; +} + +// z_subscriber_options_t +// -------------------------------- +// typedef struct z_subscriber_options_t { +// enum z_reliability_t reliability; +// } z_subscriber_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZSubscriberOptions +{ + internal Reliability reliability; +} + +// z_owned_subscriber_t +// -------------------------------- +// typedef struct ALIGN(8) z_owned_subscriber_t { +// uint64_t _0[1]; +// } z_owned_subscriber_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal struct ZOwnedSubscriber +{ + private ulong _; +} + +#if PLATFORM_ARM64 +// -------------------------------- +// typedef struct ALIGN(16) z_owned_reply_t { +// uint64_t _0[24]; +// } z_owned_reply_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 16)] +internal unsafe struct ZOwnedReply{ + private fixed ulong _[24]; +} +#elif PLATFORM_x64 +// -------------------------------- +// typedef struct ALIGN(8) z_owned_reply_t { +// uint64_t _0[22]; +// } z_owned_reply_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential, Pack = 8)] +internal unsafe struct ZOwnedReply +{ + private fixed ulong _[22]; +} +#else +#error PLATFORM_ARM64 or PLATFORM_x64 +#endif + +// z_delete_options_t +// -------------------------------- +// typedef struct z_delete_options_t { +// enum z_congestion_control_t congestion_control; +// enum z_priority_t priority; +// } z_delete_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZDeleteOptions +{ + internal CongestionControl congestion_control; + internal Priority priority; +} + +// z_query_consolidation_t +// -------------------------------- +// typedef struct z_query_consolidation_t { +// enum z_consolidation_mode_t mode; +// } z_query_consolidation_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZQueryConsolidation +{ + internal ConsolidationMode mode; +} + +// z_get_options_t +// -------------------------------- +// typedef struct z_get_options_t { +// enum z_query_target_t target; +// struct z_query_consolidation_t consolidation; +// struct z_value_t value; +// } z_get_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZGetOptions +{ + internal QueryTarget target; + internal ZQueryConsolidation consolidation; + internal ZValue value; +} + +// z_value_t +// -------------------------------- +// typedef struct z_value_t { +// struct z_bytes_t payload; +// struct z_encoding_t encoding; +// } z_value_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZValue +{ + internal ZBytes payload; + internal ZEncoding encoding; +} + +// zc_owned_payload_t +// -------------------------------- +// typedef struct zc_owned_payload_t { +// struct z_bytes_t payload; +// uintptr_t _owner[4]; +// } zc_owned_payload_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZcOwnedPayload +{ + private fixed ulong _[4]; +} + +// zc_owned_shmbuf_t +// -------------------------------- +// typedef struct zc_owned_shmbuf_t { +// uintptr_t _0[9]; +// } zc_owned_shmbuf_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZcOwnedShmbuf +{ + private fixed ulong _[9]; +} + +// zc_owned_shm_manager_t +// -------------------------------- +// typedef struct zc_owned_shm_manager_t { +// uintptr_t _0; +// } zc_owned_shm_manager_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZcOwnedShmManager +{ + private nint _; +} + +// z_put_options_t +// -------------------------------- +// typedef struct z_put_options_t { +// struct z_encoding_t encoding; +// enum z_congestion_control_t congestion_control; +// enum z_priority_t priority; +// } z_put_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZPutOptions +{ + internal ZEncoding encoding; + internal CongestionControl congestionControl; + internal Priority priority; +} + +// z_query_reply_options_t +// -------------------------------- +// typedef struct z_query_reply_options_t { +// struct z_encoding_t encoding; +// } z_query_reply_options_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZQueryReplyOptions +{ + internal ZEncoding encoding; +} + +// z_query_t +// -------------------------------- +// typedef struct z_query_t { +// void *_0; +// } z_query_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZQuery +{ + private nint _; +} + +// z_owned_session_t +// -------------------------------- +// typedef struct z_owned_session_t { +// uintptr_t _0; +// } z_owned_session_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZOwnedSession +{ + private nint _; +} + +// z_session_t +// -------------------------------- +// typedef struct z_session_t { +// uintptr_t _0; +// } z_session_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZSession +{ + private nint _; +} + +// z_owned_closure_sample_t +// -------------------------------- +// typedef struct z_owned_closure_sample_t { +// void *context; +// void (*call)(const struct z_sample_t*, void *context); +// void (*drop)(void*); +// } z_owned_closure_sample_t; +// -------------------------------- +internal unsafe delegate void ZOwnedClosureSampleCall(ZSample* sample, void* context); + +internal unsafe delegate void ZOwnedClosureSampleDrop(void* context); + +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZOwnedClosureSample +{ + internal void* context; + internal ZOwnedClosureSampleCall call; + internal ZOwnedClosureSampleDrop? drop; +} + +// -------------------------------- +// typedef struct z_owned_closure_zid_t { +// void *context; +// void (*call)(const struct z_id_t*, void*); +// void (*drop)(void*); +// } z_owned_closure_zid_t; +// -------------------------------- +internal unsafe delegate void ZOwnedClosureZIdCall(ZId* zId, void* context); + +internal unsafe delegate void ZOwnedClosureZIdDrop(void* context); + +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZOwnedClosureZId +{ + internal void* context; + internal ZOwnedClosureZIdCall call; + internal ZOwnedClosureZIdDrop? drop; +} + +internal unsafe delegate void ZOwnedClosureQueryCall(ZQuery* zQuery, void* context); + +internal unsafe delegate void ZOwnedClosureQueryDrop(void* context); + +// z_owned_closure_query_t +// -------------------------------- +// typedef struct z_owned_closure_query_t { +// void *context; +// void (*call)(const struct z_query_t*, void *context); +// void (*drop)(void*); +// } z_owned_closure_query_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZOwnedClosureQuery +{ + internal void* context; + internal ZOwnedClosureQueryCall call; + internal ZOwnedClosureQueryDrop? drop; +} + +// z_owned_closure_reply_t +// -------------------------------- +// typedef struct z_owned_closure_reply_t { +// void *context; +// void (*call)(struct z_owned_reply_t*, void*); +// void (*drop)(void*); +// } z_owned_closure_reply_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZOwnedClosureReply +{ + internal void* context; + internal delegate* unmanaged[Cdecl] call; + internal delegate* unmanaged[Cdecl] drop; +} + +// z_owned_reply_channel_closure_t +// -------------------------------- +// typedef struct z_owned_reply_channel_closure_t { +// void *context; +// bool (*call)(struct z_owned_reply_t*, void*); +// void (*drop)(void*); +// } z_owned_reply_channel_closure_t; +// -------------------------------- +internal unsafe delegate void ZOwnedReplayChannelClosureCall(ZOwnedReply* zOwnedReply, void* context); + +internal unsafe delegate void ZOwnedReplyChannelClosureDrop(void* context); + +[StructLayout(LayoutKind.Sequential)] +internal unsafe struct ZOwnedReplyChannelClosure +{ + internal void* context; + internal ZOwnedReplayChannelClosureCall call; + internal ZOwnedReplyChannelClosureDrop drop; +} + +// z_owned_reply_channel_t +// -------------------------------- +// typedef struct z_owned_reply_channel_t { +// struct z_owned_closure_reply_t send; +// struct z_owned_reply_channel_closure_t recv; +// } z_owned_reply_channel_t; +// -------------------------------- +[StructLayout(LayoutKind.Sequential)] +internal struct ZOwnedReplyChannel +{ + internal ZOwnedClosureReply send; + internal ZOwnedReplyChannelClosure recv; +} + +[StructLayout(LayoutKind.Sequential)] +public struct ConsolidationStrategy // z_consolidation_strategy_t +{ + public ConsolidationMode firstRouters; + public ConsolidationMode lastRouters; + public ConsolidationMode reception; +} + +internal static unsafe class ZenohC +{ + internal const string DllName = "zenohc"; + internal static uint zRouter = 1; + internal static uint zPeer = 2; + internal static uint zClient = 4; + internal static string zConfigModeKey = "mode"; + internal static string zConfigConnectKey = "connect/endpoints"; + internal static string zConfigListenKey = "listen/endpoints"; + internal static string zConfigUserKey = "transport/auth/usrpwd/user"; + internal static string zConfigPasswordKey = "transport/auth/usrpwd/password"; + internal static string zConfigMulticastScoutingKey = "scouting/multicast/enabled"; + internal static string zConfigMulticastInterfaceKey = "scouting/multicast/interface"; + internal static string zConfigMulticastIpv4AddressKey = "scouting/multicast/address"; + internal static string zConfigScoutingTimeoutKey = "scouting/timeout"; + internal static string zConfigScoutingDelayKey = "scouting/delay"; + internal static string zConfigAddTimestampKey = "add_timestamp"; + + internal static string ZOwnedStrToString(ZOwnedStr* zs) + { + if (z_str_check(zs) != 1) + { + return ""; + } + + return Marshal.PtrToStringUTF8(zs->cstr) ?? ""; + } + + internal static string ZKeyexprToString(ZKeyexpr keyexpr) + { + ZOwnedStr str = z_keyexpr_to_string(keyexpr); + string o = ZOwnedStrToString(&str); + z_str_drop(&str); + return o; + } + + [DllImport(DllName, EntryPoint = "z_bytes_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_bytes_check(ZBytes* b); + + [DllImport(DllName, EntryPoint = "z_str_array_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_str_array_check(ZOwnedStrArray* strs); + + [DllImport(DllName, EntryPoint = "z_str_array_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_str_array_drop(ZOwnedStrArray* strs); + + [DllImport(DllName, EntryPoint = "z_str_array_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZStrArray z_str_array_loan(ZOwnedStrArray* strs); + + [DllImport(DllName, EntryPoint = "z_str_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_str_check(ZOwnedStr* s); + + [DllImport(DllName, EntryPoint = "z_str_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_str_drop(ZOwnedStr* s); + + [DllImport(DllName, EntryPoint = "z_str_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern byte* z_str_loan(ZOwnedStr* s); + + [DllImport(DllName, EntryPoint = "z_str_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedStr z_str_null(); + + [DllImport(DllName, EntryPoint = "z_config_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_config_check(ZOwnedConfig* config); + + [DllImport(DllName, EntryPoint = "z_config_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_config_drop(ZOwnedConfig* config); + + [DllImport(DllName, EntryPoint = "z_config_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZConfig z_config_loan(ZOwnedConfig* config); + + [DllImport(DllName, EntryPoint = "z_config_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig z_config_default(); + + [DllImport(DllName, EntryPoint = "z_config_new", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig z_config_new(); + + [DllImport(DllName, EntryPoint = "z_config_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig z_config_null(); + + [DllImport(DllName, EntryPoint = "z_config_client", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig z_config_client(string[] peers, nuint nPeers); + + [DllImport(DllName, EntryPoint = "z_config_peer", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig z_config_peer(); + + [DllImport(DllName, EntryPoint = "zc_config_from_file", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig zc_config_from_file([MarshalAs(UnmanagedType.LPStr)] string path); + + [DllImport(DllName, EntryPoint = "zc_config_from_str", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedConfig zc_config_from_str([MarshalAs(UnmanagedType.LPStr)] string s); + + [DllImport(DllName, EntryPoint = "zc_config_get", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedStr zc_config_get(ZConfig config, [MarshalAs(UnmanagedType.LPStr)] string key); + + [DllImport(DllName, EntryPoint = "zc_config_insert_json", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte zc_config_insert_json( + ZConfig config, [MarshalAs(UnmanagedType.LPStr)] string key, [MarshalAs(UnmanagedType.LPStr)] string value); + + [DllImport(DllName, EntryPoint = "zc_config_to_string", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedStr zc_config_to_string(ZConfig config); + + [DllImport(DllName, EntryPoint = "z_encoding", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZEncoding z_encoding(EncodingPrefix prefix, byte* suffix); + + [DllImport(DllName, EntryPoint = "z_encoding_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZEncoding z_encoding_default(); + + [DllImport(DllName, EntryPoint = "z_encoding_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_encoding_check(ZOwnedEncoding* encoding); + + [DllImport(DllName, EntryPoint = "z_encoding_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_encoding_drop(ZOwnedEncoding* encoding); + + [DllImport(DllName, EntryPoint = "z_encoding_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZEncoding z_encoding_loan(ZOwnedEncoding* encoding); + + [DllImport(DllName, EntryPoint = "z_encoding_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedEncoding z_encoding_null(); + + [DllImport(DllName, EntryPoint = "z_keyexpr_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_check(ZOwnedKeyexpr* keyexpr); + + [DllImport(DllName, EntryPoint = "z_keyexpr", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZKeyexpr z_keyexpr(byte* name); + // internal static extern ZKeyexpr z_keyexpr([MarshalAs(UnmanagedType.LPStr)] string name); + + [DllImport(DllName, EntryPoint = "z_keyexpr_as_bytes", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZBytes z_keyexpr_as_bytes(ZKeyexpr keyexpr); + + [DllImport(DllName, EntryPoint = "z_keyexpr_canonize", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_canonize(byte* start, nuint* len); + + [DllImport(DllName, EntryPoint = "z_keyexpr_canonize_null_terminated", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_canonize_null_terminated(byte* start); + + [DllImport(DllName, EntryPoint = "z_keyexpr_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_keyexpr_drop(ZOwnedKeyexpr* keyexpr); + + [DllImport(DllName, EntryPoint = "z_keyexpr_concat", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedKeyexpr z_keyexpr_concat(ZKeyexpr left, byte* rightStart, nuint rightLen); + + [DllImport(DllName, EntryPoint = "z_keyexpr_equals", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_equals(ZKeyexpr left, ZKeyexpr right); + + [DllImport(DllName, EntryPoint = "z_keyexpr_includes", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_includes(ZKeyexpr left, ZKeyexpr right); + + [DllImport(DllName, EntryPoint = "z_keyexpr_intersects", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_intersects(ZKeyexpr left, ZKeyexpr right); + + [DllImport(DllName, EntryPoint = "z_keyexpr_is_canon", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_is_canon(byte* start, nuint len); + + [DllImport(DllName, EntryPoint = "z_keyexpr_is_initialized", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_keyexpr_is_initialized(ZKeyexpr* keyexpr); + + [DllImport(DllName, EntryPoint = "z_keyexpr_join", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedKeyexpr z_keyexpr_join(ZKeyexpr left, ZKeyexpr right); + + [DllImport(DllName, EntryPoint = "z_keyexpr_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZKeyexpr z_keyexpr_loan(ZOwnedKeyexpr* keyexpr); + + [DllImport(DllName, EntryPoint = "z_keyexpr_new", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedKeyexpr z_keyexpr_new(byte* name); + + [DllImport(DllName, EntryPoint = "z_keyexpr_unchecked", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZKeyexpr z_keyexpr_unchecked(byte* name); + + [DllImport(DllName, EntryPoint = "z_keyexpr_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedKeyexpr z_keyexpr_null(); + + [DllImport(DllName, EntryPoint = "z_keyexpr_to_string", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedStr z_keyexpr_to_string(ZKeyexpr keyexpr); + + [DllImport(DllName, EntryPoint = "z_declare_keyexpr", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedKeyexpr z_declare_keyexpr(ZSession session, ZKeyexpr keyexpr); + + [DllImport(DllName, EntryPoint = "z_undeclare_keyexpr", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_undeclare_keyexpr(ZSession session, ZOwnedKeyexpr* keyexpr); + + [DllImport(DllName, EntryPoint = "z_timestamp_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_timestamp_check(ZTimestamp ts); + + [DllImport(DllName, EntryPoint = "z_subscriber_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_subscriber_check(ZOwnedSubscriber* sub); + + [DllImport(DllName, EntryPoint = "z_subscriber_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedSubscriber z_subscriber_null(); + + [DllImport(DllName, EntryPoint = "z_subscriber_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZSubscriberOptions z_subscriber_options_default(); + + [DllImport(DllName, EntryPoint = "z_subscriber_pull", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_subscriber_pull(ZPullSubscriber* sub); + + [DllImport(DllName, EntryPoint = "z_declare_subscriber", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedSubscriber z_declare_subscriber( + ZSession session, ZKeyexpr keyexpr, ZOwnedClosureSample* callback, ZSubscriberOptions* options); + + [DllImport(DllName, EntryPoint = "z_undeclare_subscriber", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_undeclare_subscriber(ZOwnedSubscriber* sub); + + [DllImport(DllName, EntryPoint = "z_pull_subscriber_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_pull_subscriber_check(ZOwnedPullSubscriber* sub); + + [DllImport(DllName, EntryPoint = "z_pull_subscriber_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPullSubscriber z_pull_subscriber_loan(ZOwnedPullSubscriber* sub); + + [DllImport(DllName, EntryPoint = "z_pull_subscriber_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedPullSubscriber z_pull_subscriber_null(); + + [DllImport(DllName, EntryPoint = "z_pull_subscriber_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPullSubscriberOptions z_pull_subscriber_options_default(); + + [DllImport(DllName, EntryPoint = "z_declare_pull_subscriber", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedPullSubscriber z_declare_pull_subscriber( + ZSession session, ZKeyexpr keyexpr, ZOwnedClosureSample* callback, ZPullSubscriberOptions* options); + + [DllImport(DllName, EntryPoint = "z_undeclare_pull_subscriber", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_undeclare_pull_subscriber(ZOwnedPullSubscriber* sub); + + [DllImport(DllName, EntryPoint = "z_declare_queryable", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedQueryable z_declare_queryable( + ZSession session, ZKeyexpr keyexpr, ZOwnedClosureQuery* callback, ZQueryableOptions* options); + + [DllImport(DllName, EntryPoint = "z_undeclare_queryable", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_undeclare_queryable(ZOwnedQueryable* queryable); + + [DllImport(DllName, EntryPoint = "z_delete", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_delete(ZSession session, ZKeyexpr keyexpr, ZDeleteOptions* options); + + [DllImport(DllName, EntryPoint = "z_delete_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZDeleteOptions z_delete_options_default(); + + [DllImport(DllName, EntryPoint = "z_get", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_get( + ZSession session, ZKeyexpr keyexpr, byte* parameters, ZOwnedClosureReply* callback, ZGetOptions* options); + + [DllImport(DllName, EntryPoint = "z_get_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZGetOptions z_get_options_default(); + + [DllImport(DllName, EntryPoint = "z_info_peers_zid", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_info_peers_zid(ZSession session, ZOwnedClosureZId* callback); + + [DllImport(DllName, EntryPoint = "z_info_routers_zid", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_info_routers_zid(ZSession session, ZOwnedClosureZId* callback); + + [DllImport(DllName, EntryPoint = "z_info_zid", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZId z_info_zid(ZSession session); + + [DllImport(DllName, EntryPoint = "z_declare_publisher", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedPublisher z_declare_publisher( + ZSession session, ZKeyexpr keyexpr, ZPublisherOptions* options); + + [DllImport(DllName, EntryPoint = "z_undeclare_publisher", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_undeclare_publisher(ZOwnedPublisher* publisher); + + [DllImport(DllName, EntryPoint = "z_publisher_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPublisherOptions z_publisher_options_default(); + + [DllImport(DllName, EntryPoint = "z_publisher_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_publisher_check(ZOwnedPublisher* pbl); + + [DllImport(DllName, EntryPoint = "z_publisher_delete", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_publisher_delete(ZPublisher publisher, ZPublisherDeleteOptions* options); + + [DllImport(DllName, EntryPoint = "z_publisher_delete_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPublisherDeleteOptions z_publisher_delete_options_default(); + + [DllImport(DllName, EntryPoint = "z_publisher_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPublisher z_publisher_loan(ZOwnedPublisher* pbl); + + [DllImport(DllName, EntryPoint = "z_publisher_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedPublisher z_publisher_null(); + + [DllImport(DllName, EntryPoint = "z_publisher_put", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_publisher_put( + ZPublisher publisher, byte* payload, nuint len, ZPublisherPutOptions* options); + + [DllImport(DllName, EntryPoint = "zc_publisher_put_owned", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte zc_publisher_put_owned( + ZPublisher publisher, ZcOwnedPayload* payload, ZPublisherPutOptions* options); + + [DllImport(DllName, EntryPoint = "z_publisher_put_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPublisherOptions z_publisher_put_options_default(); + + [DllImport(DllName, EntryPoint = "z_put", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_put(ZSession session, ZKeyexpr keyexpr, byte* payload, nuint len, ZPutOptions* opts); + + [DllImport(DllName, EntryPoint = "zc_put_owned", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte zc_put_owned( + ZSession session, ZKeyexpr keyexpr, ZcOwnedPayload* payload, ZPutOptions* opts); + + [DllImport(DllName, EntryPoint = "z_put_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZPutOptions z_put_options_default(); + + [DllImport(DllName, EntryPoint = "z_query_consolidation_auto", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryConsolidation z_query_consolidation_auto(); + + [DllImport(DllName, EntryPoint = "z_query_consolidation_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryConsolidation z_query_consolidation_default(); + + [DllImport(DllName, EntryPoint = "z_query_consolidation_latest", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryConsolidation z_query_consolidation_latest(); + + [DllImport(DllName, EntryPoint = "z_query_consolidation_monotonic", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryConsolidation z_query_consolidation_monotonic(); + + [DllImport(DllName, EntryPoint = "z_query_consolidation_none", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryConsolidation z_query_consolidation_none(); + + [DllImport(DllName, EntryPoint = "z_query_keyexpr", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZKeyexpr z_query_keyexpr(ZQuery* query); + + [DllImport(DllName, EntryPoint = "z_query_parameters", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZBytes z_query_parameters(ZQuery* query); + + [DllImport(DllName, EntryPoint = "z_query_reply", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_query_reply( + ZQuery* query, ZKeyexpr key, byte* payload, nuint len, ZQueryReplyOptions* options); + + [DllImport(DllName, EntryPoint = "z_query_parameters", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryReplyOptions z_query_reply_options_default(); + + [DllImport(DllName, EntryPoint = "z_query_target_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern QueryTarget z_query_target_default(); + + [DllImport(DllName, EntryPoint = "z_query_value", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZValue z_query_value(ZQuery* query); + + [DllImport(DllName, EntryPoint = "z_queryable_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_queryable_check(ZOwnedQueryable* queryable); + + [DllImport(DllName, EntryPoint = "z_queryable_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedQueryable z_queryable_null(); + + [DllImport(DllName, EntryPoint = "z_queryable_options_default", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZQueryableOptions z_queryable_options_default(); + + [DllImport(DllName, EntryPoint = "z_reply_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_reply_check(ZOwnedReply* replyData); + + [DllImport(DllName, EntryPoint = "z_reply_is_ok", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_reply_is_ok(ZOwnedReply* reply); + + [DllImport(DllName, EntryPoint = "z_reply_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_reply_drop(ZOwnedReply* replyData); + + [DllImport(DllName, EntryPoint = "z_reply_err", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZValue z_reply_err(ZOwnedReply* replyData); + + [DllImport(DllName, EntryPoint = "z_reply_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedReply z_reply_null(); + + [DllImport(DllName, EntryPoint = "z_reply_ok", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZSample z_reply_ok(ZOwnedReply* reply); + + [DllImport(DllName, EntryPoint = "z_open", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedSession z_open(ZOwnedConfig* config); + + [DllImport(DllName, EntryPoint = "z_close", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_close(ZOwnedSession* session); + + [DllImport(DllName, EntryPoint = "z_session_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_session_check(ZOwnedSession* session); + + [DllImport(DllName, EntryPoint = "z_session_loan", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZSession z_session_loan(ZOwnedSession* session); + + [DllImport(DllName, EntryPoint = "z_session_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedSession z_session_null(); + + [DllImport(DllName, EntryPoint = "zc_session_rcinc", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedSession zc_session_rcinc(ZSession session); + + [DllImport(DllName, EntryPoint = "zc_init_logger", CallingConvention = CallingConvention.Cdecl)] + internal static extern void zc_init_logger(); + + [DllImport(DllName, EntryPoint = "zc_payload_check", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte zc_payload_check(ZcOwnedPayload* payload); + + [DllImport(DllName, EntryPoint = "zc_payload_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void zc_payload_drop(ZcOwnedPayload* payload); + + [DllImport(DllName, EntryPoint = "zc_payload_null", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZcOwnedPayload zc_payload_null(); + + [DllImport(DllName, EntryPoint = "zc_payload_rcinc", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZcOwnedPayload zc_payload_rcinc(ZcOwnedPayload* payload); + + [DllImport(DllName, EntryPoint = "zc_sample_payload_rcinc", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZcOwnedPayload zc_sample_payload_rcinc(ZSample* sample); + + [DllImport(DllName, EntryPoint = "z_closure_sample_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_closure_sample_drop(ZOwnedClosureSample* closure); + + [DllImport(DllName, EntryPoint = "z_closure_reply_call", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_closure_reply_call(ZOwnedClosureReply* closure, ZOwnedReply* sample); + + [DllImport(DllName, EntryPoint = "zc_reply_fifo_new", CallingConvention = CallingConvention.Cdecl)] + internal static extern ZOwnedReplyChannel zc_reply_fifo_new(nuint bound); + + [DllImport(DllName, EntryPoint = "z_reply_channel_drop", CallingConvention = CallingConvention.Cdecl)] + internal static extern void z_reply_channel_drop(ZOwnedReplyChannel* channel); + + [DllImport(DllName, EntryPoint = "z_reply_channel_closure_call", CallingConvention = CallingConvention.Cdecl)] + internal static extern sbyte z_reply_channel_closure_call(ZOwnedReplyChannelClosure* closure, ZOwnedReply* reply); +} \ No newline at end of file diff --git a/Zenoh/example_config.json5 b/Zenoh/example_config.json5 new file mode 100644 index 0000000..f865df9 --- /dev/null +++ b/Zenoh/example_config.json5 @@ -0,0 +1,237 @@ +/// This file attempts to list and document available configuration elements. +/// For a more complete view of the configuration's structure, check out `zenoh/src/config.rs`'s `Config` structure. +/// Note that the values here are correctly typed, but may not be sensible, so copying this file to change only the parts that matter to you is not good practice. +{ + /// Plugins are only loaded if present in the configuration. When starting + /// Once loaded, they may react to changes in the configuration made through the zenoh instance's adminspace. + plugins: { + /// If no `__path__` is given to a plugin, zenohd will automatically search for a shared library matching the plugin's name (here, `libzplugin_rest.so` would be searched for on linux) + rest: { + /// Setting this option to true allows zenohd to panic should it detect issues with this plugin. Setting it to false politely asks the plugin not to panic. + __required__: true, + // defaults to false + http_port: 8000, + }, + storage_manager: { + /// When a path is present, automatic search is disabled, and zenohd will instead select the first path which manages to load. + __path__: [ + "./target/release/libzplugin_storages.so", + "./target/release/libzplugin_storages.dylib", + ], + /// The "memory" volume is always available, but you may create other volumes here, with various backends to support the actual storing. + volumes: { + /// An influxdb backend is also available at https://github.com/eclipse-zenoh/zenoh-backend-influxdb + influxdb: { + url: "https://myinfluxdb.example", + /// Some plugins may need passwords in their configuration. + /// To avoid leaking them through the adminspace, they may be masked behind a privacy barrier. + /// any value held at the key "private" will not be shown in the adminspace. + private: { + username: "user1", + password: "pw1", + }, + }, + influxdb2: { + /// A second backend of the same type can be spawned using `__path__`, for examples when different DBs are needed. + backend: "influxdb", + private: { + username: "user2", + password: "pw2", + }, + url: "https://localhost:8086", + }, + }, + /// + storages: { + demo: { + /// Storages always need to know what set of keys they must work with. These sets are defined by a key expression. + key_expr: "/demo/memory/**", + /// Storages also need to know which volume will be used to actually store their key-value pairs. + /// The "memory" volume is always available, and doesn't require any per-storage options, so requesting "memory" by string is always sufficient. + volume: "memory", + }, + influx_demo: { + key_expr: "/demo/influxdb/**", + /// This prefix will be stripped of the received keys when storing. + strip_prefix: "/demo/influxdb/", + /// influxdb-backed volumes need a bit more configuration, which is passed like-so: + volume: { + id: "influxdb", + db: "example", + }, + }, + influx_demo2: { + key_expr: "/demo/influxdb2/**", + strip_prefix: "/demo/influxdb2/", + volume: { + id: "influxdb2", + db: "example", + }, + }, + }, + }, + }, + /// Directories where plugins configured by name should be looked for. PLugins configured by __path__ are not subject to lookup + plugins_search_dirs: [], + /// The identifier (as hex-string) that zenohd must use. If not set, a random UUIDv4 will be used. + /// WARNING: this id must be unique in your zenoh network. + // id: "5975702c206974277320415343494921", + /// The node's mode (router, peer or client) + mode: "router", + /// Which endpoints to connect to. E.g. tcp/localhost:7447. + /// By configuring the endpoints, it is possible to tell zenoh which router/peer to connect to at startup. + connect: { + endpoints: [ + // "/
" + ], + }, + /// Which endpoints to listen on. E.g. tcp/localhost:7447. + /// By configuring the endpoints, it is possible to tell zenoh which are the endpoints that other routers, + /// peers, or client can use to establish a zenoh session. + listen: { + endpoints: [ + // "/
" + ], + }, + startup: { + subscribe: [ + "/demo/subs/**" + ], + declare_publications: [ + "/demo/pubs/**" + ], + }, + scouting: { + /// In client mode, the period dedicated to scouting for a router before failing + timeout: 3000, + /// In peer mode, the period dedicated to scouting remote peers before attempting other operations + delay: 200, + /// How multicast should behave + multicast: { + /// Whether multicast scouting is enabled or not + enabled: true, + /// The socket which should be used for multicast scouting + address: "224.0.0.224:7447", + /// The network interface which should be used for multicast scouting + interface: "", + // empty string means auto + /// An autoconnection mask (accepted values are bit-or-like combinations of peer, router and client). + /// If the configured instance's mode intersects with this field, zenoh will automatically establish a connection with other nodes discovered through this method of scouting. + autoconnect: "peer|client", + }, + gossip: { + autoconnect: "", + }, + /// If set to `false`, peers will never automatically establish sessions between each-other. + peers_autoconnect: false, + }, + /// Whether data messages should be timestamped + add_timestamp: true, + /// Whether local writes/queries should reach local subscribers/queryables + local_routing: true, + transport: { + unicast: { + /// Timeout in milliseconds when opening a link + accept_timeout: 10000, + /// Maximum number of zenoh session in pending state while accepting + accept_pending: 100, + /// Maximum number of sessions that can be simultaneously alive + max_sessions: 1024, + /// Maximum number of incoming links that are admitted per session + max_links: 1, + }, + multicast: { + /// Link join interval duration in milliseconds + join_interval: 2500, + /// Maximum number of sessions that can be simultaneously alive + max_sessions: 1024, + }, + qos: { + enabled: false, + }, + link: { + tx: { + /// The largest value allowed for Zenoh message sequence numbers (wrappring to 0 when reached). + /// When establishing a session with another Zenoh instance, the lowest value of the two instances will be used. + /// Defaults to 2^28. + sequence_number_resolution: 268435456, + /// Link lease duration in milliseconds to announce to other zenoh nodes + lease: 10000, + /// Number of keep-alive messages in a link lease duration. If no data is sent, keep alive + /// messages will be sent at the configured time interval. + /// NOTE: In order to consider eventual packet loss and transmission latency and jitter, + /// set the actual keep_alive timeout to one fourth of the lease time. + /// This is in-line with the ITU-T G.8013/Y.1731 specification on continous connectivity + /// check which considers a link as failed when no messages are received in 3.5 times the + /// target interval. + keep_alive: 4, + /// Batch size in bytes is expressed as a 16bit unsigned integer. + /// Therefore, the maximum batch size is 2^16-1 (i.e. 65535). + /// The default batch size value is the maximum batch size: 65535. + batch_size: 65535, + queue: { + /// The size of each priority queue indicates the number of batches a given queue can contain. + /// The amount of memory being allocated for each queue is then SIZE_XXX * BATCH_SIZE. + /// In the case of the transport link MTU being smaller than the ZN_BATCH_SIZE, + /// then amount of memory being allocated for each queue is SIZE_XXX * LINK_MTU. + /// If qos is false, then only the DATA priority will be allocated. + size: { + control: 1, + real_time: 1, + interactive_high: 1, + interactive_low: 1, + data_high: 2, + data: 4, + data_low: 4, + background: 4, + }, + /// The initial exponential backoff time in nanoseconds to allow the batching to eventually progress. + /// Higher values lead to a more aggressive batching but it will introduce additional latency. + backoff: 100, + } + }, + rx: { + /// Receiving buffer size in bytes for each link + /// The default the rx_buffer_size value is the same as the default batch size: 65335. + /// For very high throughput scenarios, the rx_buffer_size can be increased to accomodate + /// more in-flight data. This is particularly relevant when dealing with large messages. + /// E.g. for 16MiB rx_buffer_size set the value to: 16777216. + buffer_size: 65535, + /// Maximum size of the defragmentation buffer at receiver end. + /// Fragmented messages that are larger than the configured size will be dropped. + /// The default value is 1GiB. This would work in most scenarios. + /// NOTE: reduce the value if you are operating on a memory constrained device. + max_message_size: 1073741824, + }, + tls: { + root_ca_certificate: null, + server_private_key: null, + server_certificate: null, + client_auth: null, + client_private_key: null, + client_certificate: null, + }, + }, + shared_memory: { + enabled: true, + }, + auth: { + /// The configuration of authentification. + /// A password implies a username is required. + usrpwd: { + user: null, + password: null, + /// The path to a file containing the user password dictionary + dictionary_file: null, + }, + pubkey: { + public_key_pem: null, + private_key_pem: null, + public_key_file: null, + private_key_file: null, + key_size: null, + known_keys_file: null, + }, + }, + }, +} diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..f1c199f --- /dev/null +++ b/examples/README.md @@ -0,0 +1,106 @@ +# Zenoh C# examples + +## Introduce + +Each example accepts the `--help` option that provides a description of its arguments and their default values. + +If you run the tests against the zenoh router running in a Docker container, +you need to add the `-e tcp/localhost:7447` option to your examples. +That's because Docker doesn't support UDP multicast transport, +and therefore the zenoh scouting and discrovery mechanism cannot work with. + +When building, option `--property:Platform=<>` are required. + +## Examples description + +### ZInfo + +Get the ID of each node in the Zenoh network. + +Build +```bash +dotnet build ZInfo/ZInfo.csproj --configuration Release --property:Platform=x64 +``` + +Run +```bash +./ZInfo +``` + +### ZGet + +Sends a query message for a selector. +The queryables with a matching path or selector (for instance ZQueryable ) will receive this query and reply with paths/values that will be received by the receiver stream. + +Build +```bash +dotnet build ZGet/ZGet.csproj --configuration Release --property:Platform=x64 +``` + +Run +```bash +./ZGet +``` + +### ZQueryable + +Declares a queryable function with a path. +This queryable function will be triggered by each call to get with a selector that matches the path, and will return a value to the querier. + +Build +```bash +dotnet build ZQueryable/ZQueryable.csproj --configuration Release --property:Platform=x64 +``` + +Run +```bash +./ZQueryable +``` + + +### ZPut + +Writes a path/value into Zenoh. +The path/value will be received by all matching subscribers, for instance the [ZSub](#ZSub) examples. + +Build +```bash +dotnet build ZPut/ZPut.csproj --configuration Release --property:Platform=x64 +``` + +Run +```bash +./ZPut +``` + +### ZPub +Writes a path/value into Zenoh. +The path/value will be received by all matching subscribers, for instance the [ZSub](#ZSub) examples. +Compared to ZPut, this example is optimized for keys that publish data frequently, reducing some of the overhead. + +Build +```bash +dotnet build ZPub/ZPub.csproj --configuration Release --property:Platform=x64 +``` + +Run +```bash +./ZPub +``` + + +### ZSub + +Registers a subscriber with a selector. +The subscriber will be notified of each write made on any path matching the selector, +and will print this notification. + +Build +```bash +dotnet build ZSub/ZSub.csproj --configuration Release --property:Platform=x64 +``` + +Run +```bash +./ZSub +``` \ No newline at end of file diff --git a/examples/README.zh.md b/examples/README.zh.md new file mode 100644 index 0000000..8dea898 --- /dev/null +++ b/examples/README.zh.md @@ -0,0 +1,101 @@ +# Zenoh C# examples + +## 介绍 +每个示例都接受 `——help` 选项,这些选项提供了对其参数及其默认值的描述. + +如果对运行在Docker容器中的zenoh路由器运行测试, 则需要在示例中添加 `-e tcp/localhost:7447` 选项. +这是因为Docker不支持UDP多播传输, 因此zenoh侦察和发现机制无法工作. + + +构建时, `--property:Platform=<>` 选项是必需的. 可选 `x64` 和 `ARM64`. + +## 示例说明 + +### ZInfo + +获取当前接入的Zenoh网络中, 各个节点的ID. + +构建命令 +```bash +dotnet build ZInfo/ZInfo.csproj --configuration Release --property:Platform=x64 +``` + +启动命令, 在生成产物目录下运行 +```bash +./ZInfo +``` + +### ZGet + +为选择器发送查询消息. +具有匹配路径或选择器的可查询项(例如 ZQueryable)将接收此查询,并使用接收方接收到的路径进行回复. + +构建命令 +```bash +dotnet build ZGet/ZGet.csproj --configuration Release --property:Platform=x64 +``` + +启动命令, 在生成产物目录下运行 +```bash +./ZGet +``` + +### ZQueryable + +声明一个带有路径的可查询函数. +这个可查询的函数将在每次调用get时触发, 调用与路径匹配的选择器, 并将向查询器返回一个值. + +构建命令 +```bash +dotnet build ZQueryable/ZQueryable.csproj --configuration Release --property:Platform=x64 +``` + +启动命令, 在生成产物目录下运行 +```bash +./ZQueryable +``` + + +### ZPut +将 key/value 写入Zenoh网络. +key/value 将被所有匹配的订阅者接收, 例如ZSub示例. + +构建命令 +```bash +dotnet build ZPut/ZPut.csproj --configuration Release --property:Platform=x64 +``` + +启动命令, 在生成产物目录下运行 +```bash +./ZPut +``` + +### ZPub +将 key/value 写入Zenoh网络. +key/value 将被所有匹配的订阅者接收, 例如ZSub示例. +相比于ZPut, 此示例针对经常发布数据的key进行了优化, 减少了部分开销. + +构建命令 +```bash +dotnet build ZPub/ZPub.csproj --configuration Release --property:Platform=x64 +``` + +启动命令, 在生成产物目录下运行 +```bash +./ZPub +``` + +### ZSub + +使用选择器注册订阅服务器. +订阅者将收到与选择器匹配的任何路径上的每次写入的通知, 并将打印此通知. + +构建命令 +```bash +dotnet build ZSub/ZSub.csproj --configuration Release --property:Platform=x64 +``` + +启动命令, 在生成产物目录下运行 +```bash +./ZSub +``` diff --git a/examples/ZGet/ZGet.cs b/examples/ZGet/ZGet.cs new file mode 100644 index 0000000..41a8690 --- /dev/null +++ b/examples/ZGet/ZGet.cs @@ -0,0 +1,144 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using CommandLine; +using Zenoh; + +namespace ZGet; + +class Program +{ + static void Main(string[] args) + { + var r = Parser.Default.ParseArguments(args); + bool ok = true; + r.WithNotParsed(e => { ok = false; }); + if (!ok) return; + + ClArgs clArgs = r.Value; + Config? config = clArgs.ToConfig(); + if (config is null) + return; + + Console.WriteLine("Opening session..."); + var session = Session.Open(config); + if (session is null) + { + Console.WriteLine("Opening session fault!"); + return; + } + + Thread.Sleep(200); + Console.WriteLine("Opening session successful!"); + + string keyexpr = clArgs.GetSelector(); + byte[] data = Encoding.UTF8.GetBytes(clArgs.GetValue()); + QueryOptions queryOptions = new QueryOptions(keyexpr, EncodingPrefix.TextPlain, data); + + Console.WriteLine($"Sending Query '{keyexpr}'"); + Querier? querier = session.Query(queryOptions); + if (querier is null) + { + Console.WriteLine("Session query fault!"); + goto EXIT; + } + + QuerierCallback callback = sample => + { + string key = sample.GetKeyexpr(); + EncodingPrefix encodingPrefix = sample.GetEncodingPrefix(); + string? s = sample.GetString(); + if (s is null) + { + byte[] d = sample.GetPayload(); + Console.WriteLine($">> Received ('{key}' '{encodingPrefix}': '{d}')"); + } + else + { + Console.WriteLine($">> Received ('{key}' '{encodingPrefix}': '{s}')"); + } + }; + + if (!querier.GetSamples(callback)) + { + Console.WriteLine("querier get sample error!"); + } + + EXIT: + session.Close(); + } +} + +class ClArgs +{ + [Option('c', "config", Required = false, HelpText = "A configuration file.")] + public string? ConfigFilePath { get; set; } = null; + + [Option('e', "connect", Required = false, HelpText = "Endpoints to connect to. example: tcp/127.0.0.1:7447")] + public IEnumerable Connects { get; set; } = new List(); + + [Option('l', "listen", Required = false, HelpText = "Endpoints to listen on. example: tcp/127.0.0.1:8447")] + public IEnumerable Listens { get; set; } = new List(); + + [Option('m', "mode", Required = false, + HelpText = "The zenoh session mode (peer by default) [possible values: peer, client]")] + public string Mode { get; set; } = "peer"; + + [Option('s', "selector", Required = false, + HelpText = "The selection of resources to query [default: demo/example/**]")] + public string? Keyexpr { get; set; } = null; + + [Option('v', "value", Required = false, + HelpText = "An optional value to put in the query.")] + public string? Value { get; set; } = null; + + internal Config? ToConfig() + { + if (ConfigFilePath != null) + { + Config? c = Config.LoadFromFile(ConfigFilePath); + if (c is null) + { + Console.WriteLine("load config file error!"); + return null; + } + + return c; + } + + Config config = new Config(); + + config.SetMode(Mode == "client" ? Config.Mode.Client : Config.Mode.Peer); + + List connects = new List(); + foreach (string s in Connects) + { + connects.Add(s); + } + + config.SetConnect(connects.ToArray()); + + List listens = new List(); + foreach (string s in Listens) + { + listens.Add(s); + } + + config.SetListen(listens.ToArray()); + + return config; + } + + public string GetSelector() + { + return Keyexpr ?? "demo/example/**"; + } + + public string GetValue() + { + return Value ?? "hello"; + } +} \ No newline at end of file diff --git a/examples/ZGet/ZGet.csproj b/examples/ZGet/ZGet.csproj new file mode 100644 index 0000000..5059234 --- /dev/null +++ b/examples/ZGet/ZGet.csproj @@ -0,0 +1,31 @@ + + + ZGet + ZGet + Exe + false + 10 + net7.0;net6.0 + Release;Debug + x64;ARM64 + + + TRACE;PLATFORM_ARM + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + + + + + + + + + diff --git a/examples/ZInfo/ZInfo.cs b/examples/ZInfo/ZInfo.cs new file mode 100644 index 0000000..cb8ef5f --- /dev/null +++ b/examples/ZInfo/ZInfo.cs @@ -0,0 +1,110 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Threading; +using CommandLine; +using Zenoh; + +namespace ZInfo; + +class Program +{ + static void Main(string[] args) + { + var r = Parser.Default.ParseArguments(args); + bool ok = true; + r.WithNotParsed(e => { ok = false; }); + if (!ok) return; + + ClArgs clArgs = r.Value; + Config? config = clArgs.ToConfig(); + if (config is null) + return; + + Console.WriteLine("Opening session..."); + var session = Session.Open(config); + if (session is null) + { + Console.WriteLine("Opening session fault!"); + return; + } + + Thread.Sleep(200); + Console.WriteLine("Opening session successful!"); + + string localId = session.LocalId().ToStr(); + Id[] routersId = session.RoutersId(); + List routersIdStr = new List(); + foreach (var id in routersId) + { + routersIdStr.Add(id.ToStr()); + } + + Id[] peerId = session.PeersId(); + List peerIdStr = new List(); + foreach (var id in peerId) + { + peerIdStr.Add(id.ToStr()); + } + + Console.WriteLine($"Local ID: {localId}"); + Console.WriteLine($"PeersPID: {String.Join(',', peerIdStr)}"); + Console.WriteLine($"Routers ID: {String.Join(',', routersIdStr)}"); + + session.Close(); + } +} + +class ClArgs +{ + [Option('c', "config", Required = false, HelpText = "A configuration file.")] + public string? ConfigFilePath { get; set; } = null; + + [Option('e', "connect", Required = false, HelpText = "Endpoints to connect to. example: tcp/127.0.0.1:7447")] + public IEnumerable Connects { get; set; } = new List(); + + [Option('l', "listen", Required = false, HelpText = "Endpoints to listen on. example: tcp/127.0.0.1:8447")] + public IEnumerable Listens { get; set; } = new List(); + + [Option('m', "mode", Required = false, + HelpText = "The zenoh session mode (peer by default) [possible values: peer, client]")] + public string Mode { get; set; } = "peer"; + + internal Config? ToConfig() + { + if (ConfigFilePath != null) + { + Config? c = Config.LoadFromFile(ConfigFilePath); + if (c is null) + { + Console.WriteLine("load config file error!"); + return null; + } + + return c; + } + + Config config = new Config(); + + config.SetMode(Mode == "client" ? Config.Mode.Client : Config.Mode.Peer); + + List connects = new List(); + foreach (string s in Connects) + { + connects.Add(s); + } + + config.SetConnect(connects.ToArray()); + + List listens = new List(); + foreach (string s in Listens) + { + listens.Add(s); + } + + config.SetListen(listens.ToArray()); + + return config; + } +} \ No newline at end of file diff --git a/examples/ZInfo/ZInfo.csproj b/examples/ZInfo/ZInfo.csproj new file mode 100644 index 0000000..9372c12 --- /dev/null +++ b/examples/ZInfo/ZInfo.csproj @@ -0,0 +1,32 @@ + + + ZInfo + ZInfo + Exe + false + 10 + net7.0;net6.0 + Release;Debug + x64;ARM64 + + + TRACE;PLATFORM_ARM + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + + + + + + + + + + diff --git a/examples/ZPub/ZPub.cs b/examples/ZPub/ZPub.cs new file mode 100644 index 0000000..84593b9 --- /dev/null +++ b/examples/ZPub/ZPub.cs @@ -0,0 +1,134 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Threading; +using CommandLine; +using Zenoh; + +namespace ZPub; + +class Program +{ + static void Main(string[] args) + { + var r = Parser.Default.ParseArguments(args); + bool ok = true; + r.WithNotParsed(e => { ok = false; }); + if (!ok) return; + + ClArgs clArgs = r.Value; + Config? config = clArgs.ToConfig(); + if (config is null) + return; + + Console.WriteLine("Opening session..."); + var session = Session.Open(config); + if (session is null) + { + Console.WriteLine("Opening session fault!"); + return; + } + + Thread.Sleep(200); + Console.WriteLine("Opening session successful!"); + + string key = clArgs.GetKey(); + string value = clArgs.GetValue(); + + Publisher publisher = new Publisher(key); + + var handle = session.RegisterPublisher(publisher); + if (handle is null) + { + Console.WriteLine($"Register Publisher1 fault On '{key}'"); + return; + } + + Console.WriteLine($"Registered Publisher1 On '{key}'"); + + for (int i = 0; i < 100; i++) + { + string pubValue = $"[{i}] {value}"; + session.PubStr(handle.Value, pubValue); + Console.WriteLine($"Publishing Data ('{key}': '{pubValue}').."); + + Thread.Sleep(1000); + } + + session.UnregisterPublisher(handle.Value); + + session.Close(); + } +} + +class ClArgs +{ + [Option('c', "config", Required = false, HelpText = "A configuration file.")] + public string? ConfigFilePath { get; set; } = null; + + [Option('e', "connect", Required = false, HelpText = "Endpoints to connect to. example: tcp/127.0.0.1:7447")] + public IEnumerable Connects { get; set; } = new List(); + + [Option('l', "listen", Required = false, HelpText = "Endpoints to listen on. example: tcp/127.0.0.1:8447")] + public IEnumerable Listens { get; set; } = new List(); + + [Option('m', "mode", Required = false, + HelpText = "The zenoh session mode (peer by default) [possible values: peer, client]")] + public string Mode { get; set; } = "peer"; + + [Option('k', "key", Required = false, + HelpText = "The key expression to publish onto. [default: demo/example/zenoh-cs-pub]")] + public string? Keyexpr { get; set; } = null; + + [Option('v', "value", Required = false, + HelpText = "The value to publish. [default: \"Pub from C#!\"]")] + public string? Value { get; set; } = null; + + internal Config? ToConfig() + { + if (ConfigFilePath != null) + { + Config? c = Config.LoadFromFile(ConfigFilePath); + if (c is null) + { + Console.WriteLine("load config file error!"); + return null; + } + + return c; + } + + Config config = new Config(); + + config.SetMode(Mode == "client" ? Config.Mode.Client : Config.Mode.Peer); + + List connects = new List(); + foreach (string s in Connects) + { + connects.Add(s); + } + + config.SetConnect(connects.ToArray()); + + List listens = new List(); + foreach (string s in Listens) + { + listens.Add(s); + } + + config.SetListen(listens.ToArray()); + + return config; + } + + public string GetKey() + { + return Keyexpr ?? "demo/example/zenoh-cs-pub"; + } + + public string GetValue() + { + return Value ?? "Pub from C#!"; + } +} \ No newline at end of file diff --git a/examples/ZPub/ZPub.csproj b/examples/ZPub/ZPub.csproj new file mode 100644 index 0000000..d9f5fc7 --- /dev/null +++ b/examples/ZPub/ZPub.csproj @@ -0,0 +1,32 @@ + + + ZPub + ZPub + Exe + false + 10 + net7.0;net6.0 + Debug;Release + ARM64;x64 + + + + TRACE;PLATFORM_ARM + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + + + + + + + + + diff --git a/examples/ZPut/ZPut.cs b/examples/ZPut/ZPut.cs new file mode 100644 index 0000000..b9ac181 --- /dev/null +++ b/examples/ZPut/ZPut.cs @@ -0,0 +1,122 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Threading; +using CommandLine; +using Zenoh; + +namespace ZPut; + +class Program +{ + static void Main(string[] args) + { + var r = Parser.Default.ParseArguments(args); + bool ok = true; + r.WithNotParsed(e => { ok = false; }); + if (!ok) return; + + ClArgs clArgs = r.Value; + Config? config = clArgs.ToConfig(); + if (config is null) + return; + + Console.WriteLine("Opening session..."); + var session = Session.Open(config); + if (session is null) + { + Console.WriteLine("Opening session unsuccessful!"); + return; + } + + Thread.Sleep(200); + Console.WriteLine("Opening session successful!"); + + string keyStr = "demo/example/zenoh-cs-put/string"; + string dataStr = "Put from csharp !"; + Console.WriteLine(session.PutStr(keyStr, dataStr) + ? $"Putting data string ('{keyStr}': '{dataStr}')" + : "Putting data string fault!"); + + string keyJson = "demo/example/zenoh-cs-put/json"; + string dataJson = "{\"value\": \"Put from csharp\"}"; + Console.WriteLine(session.PutJson(keyJson, dataJson) + ? $"Putting data json ('{keyJson}': {dataJson})" + : "Putting data json fault!"); + + string keyInt = "demo/example/zenoh-cs-put/int"; + long dataInt = 965; + Console.WriteLine(session.PutInt(keyInt, dataInt) + ? $"Putting data int ('{keyInt}': {dataInt})" + : "Putting data int fault!"); + + string keyFloat = "demo/example/zenoh-cs-put/float"; + double dataFloat = 99.6; + Console.WriteLine(session.PutFloat(keyFloat, dataFloat) + ? $"Putting data float ('{keyFloat}': {dataFloat})" + : "Putting data float fault!"); + + string keyBin = "demo/example/zenoh-cs-put/bin"; + byte[] dataBin = { 0x1, 0x2, 0x3, 0x4 }; + Console.WriteLine( + session.PutData(keyBin, dataBin, EncodingPrefix.AppCustom) + ? $"Putting data bin ('{keyBin}': {dataBin.Length} Byte" + : "Putting data bin fault!"); + + session.Close(); + } +} + +class ClArgs +{ + [Option('c', "config", Required = false, HelpText = "A configuration file.")] + public string? ConfigFilePath { get; set; } = null; + + [Option('e', "connect", Required = false, HelpText = "Endpoints to connect to. example: tcp/127.0.0.1:7447")] + public IEnumerable Connects { get; set; } = new List(); + + [Option('l', "listen", Required = false, HelpText = "Endpoints to listen on. example: tcp/127.0.0.1:8447")] + public IEnumerable Listens { get; set; } = new List(); + + [Option('m', "mode", Required = false, + HelpText = "The zenoh session mode (peer by default) [possible values: peer, client]")] + public string Mode { get; set; } = "peer"; + + internal Config? ToConfig() + { + if (ConfigFilePath != null) + { + Config? c = Config.LoadFromFile(ConfigFilePath); + if (c is null) + { + Console.WriteLine("load config file error!"); + return null; + } + + return c; + } + + Config config = new Config(); + + config.SetMode(Mode == "client" ? Config.Mode.Client : Config.Mode.Peer); + + List connects = new List(); + foreach (string s in Connects) + { + connects.Add(s); + } + + config.SetConnect(connects.ToArray()); + + List listens = new List(); + foreach (string s in Listens) + { + listens.Add(s); + } + + config.SetListen(listens.ToArray()); + + return config; + } +} \ No newline at end of file diff --git a/examples/ZPut/ZPut.csproj b/examples/ZPut/ZPut.csproj new file mode 100644 index 0000000..a41407c --- /dev/null +++ b/examples/ZPut/ZPut.csproj @@ -0,0 +1,32 @@ + + + ZPut + ZPut + Exe + false + 10 + net7.0;net6.0 + Release;Debug + x64;ARM64 + + + TRACE;PLATFORM_ARM + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + + + + + + + + + + diff --git a/examples/ZQueryable/ZQueryable.cs b/examples/ZQueryable/ZQueryable.cs new file mode 100644 index 0000000..f62f082 --- /dev/null +++ b/examples/ZQueryable/ZQueryable.cs @@ -0,0 +1,140 @@ +using CommandLine; +using Zenoh; + +namespace ZQueryable; + +class Program +{ + static void Main(string[] args) + { + var r = Parser.Default.ParseArguments(args); + bool ok = true; + r.WithNotParsed(e => { ok = false; }); + if (!ok) return; + + ClArgs clArgs = r.Value; + Config? config = clArgs.ToConfig(); + if (config is null) + return; + + Console.WriteLine("Opening session..."); + var session = Session.Open(config); + if (session is null) + { + Console.WriteLine("Opening session fault!"); + return; + } + + Thread.Sleep(200); + Console.WriteLine("Opening session successful!"); + + QueryableCallback callback = query => + { + string keyexpr = query.GetKeyexpr(); + string payload = query.GetValue().GetString() ?? ""; + Console.WriteLine(payload.Length > 0 + ? $">> [Queryable] Receiver Query '{keyexpr}' with value '{payload}'" + : $">> [Queryable] Receiver Query '{keyexpr}'"); + + query.ReplyStr(clArgs.GetKey(), clArgs.GetValue()); + }; + + Zenoh.Queryable queryable = new Zenoh.Queryable(clArgs.GetKey(), callback); + var handle = session.RegisterQueryable(queryable); + + + if (handle is null) + { + Console.WriteLine($"Register Queryable fault On '{clArgs.GetKey()}'"); + return; + } + + Console.WriteLine($"Registered Queryable On '{clArgs.GetKey()}'"); + + + Console.WriteLine("Enter 'q' to quit..."); + while (true) + { + var input = Console.ReadKey(); + if (input.Key == ConsoleKey.Q) + { + break; + } + } + + session.UnregisterQueryable(handle.Value); + + session.Close(); + } +} + +class ClArgs +{ + [Option('c', "config", Required = false, HelpText = "A configuration file.")] + public string? ConfigFilePath { get; set; } = null; + + [Option('e', "connect", Required = false, HelpText = "Endpoints to connect to. example: tcp/127.0.0.1:7447")] + public IEnumerable Connects { get; set; } = new List(); + + [Option('l', "listen", Required = false, HelpText = "Endpoints to listen on. example: tcp/127.0.0.1:8447")] + public IEnumerable Listens { get; set; } = new List(); + + [Option('m', "mode", Required = false, + HelpText = "The zenoh session mode (peer by default) [possible values: peer, client]")] + public string Mode { get; set; } = "peer"; + + [Option('k', "key", Required = false, + HelpText = "The key expression matching queries to reply to. [default: demo/example/zenoh-cs-queryable]")] + public string? Keyexpr { get; set; } = null; + + [Option('v', "value", Required = false, + HelpText = "The value to reply to queries. [default: \"Queryable from C#!\"]")] + public string? Value { get; set; } = null; + + internal Config? ToConfig() + { + if (ConfigFilePath != null) + { + Config? c = Config.LoadFromFile(ConfigFilePath); + if (c is null) + { + Console.WriteLine("load config file error!"); + return null; + } + + return c; + } + + Config config = new Config(); + + config.SetMode(Mode == "client" ? Config.Mode.Client : Config.Mode.Peer); + + List connects = new List(); + foreach (string s in Connects) + { + connects.Add(s); + } + + config.SetConnect(connects.ToArray()); + + List listens = new List(); + foreach (string s in Listens) + { + listens.Add(s); + } + + config.SetListen(listens.ToArray()); + + return config; + } + + public string GetKey() + { + return Keyexpr ?? "demo/example/zenoh-cs-queryable"; + } + + public string GetValue() + { + return Value ?? "Queryable from Rust!"; + } +} \ No newline at end of file diff --git a/examples/ZQueryable/ZQueryable.csproj b/examples/ZQueryable/ZQueryable.csproj new file mode 100644 index 0000000..c4f929f --- /dev/null +++ b/examples/ZQueryable/ZQueryable.csproj @@ -0,0 +1,29 @@ + + + ZQueryable + ZQueryable + Exe + false + net7.0;net6.0 + enable + Debug;Release + ARM64;x64 + enable + + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + + + + + + + + diff --git a/examples/ZSub/ZSub.cs b/examples/ZSub/ZSub.cs new file mode 100644 index 0000000..c4a15c7 --- /dev/null +++ b/examples/ZSub/ZSub.cs @@ -0,0 +1,136 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.Threading; +using CommandLine; +using Zenoh; + +namespace ZSub; + +class Program +{ + static void Main(string[] args) + { + var r = Parser.Default.ParseArguments(args); + bool ok = true; + r.WithNotParsed(e => { ok = false; }); + if (!ok) return; + + ClArgs clArgs = r.Value; + Config? config = clArgs.ToConfig(); + if (config is null) + return; + + Console.WriteLine("Opening session..."); + var session = Session.Open(config); + if (session is null) + { + Console.WriteLine("Opening session fault!"); + return; + } + + Thread.Sleep(200); + Console.WriteLine("Opening session successful!"); + + + void Callback(Sample sample) + { + string key = sample.GetKeyexpr(); + string value = sample.GetString() ?? ""; + Console.WriteLine($">> [Subscriber] Received PUT ('{key}': '{value}')"); + } + + SubscriberCallback userCallback = Callback; + + string key = clArgs.GetKey(); + + Subscriber subscriber = new Subscriber(key, userCallback); + + var handle = session.RegisterSubscriber(subscriber); + if (handle is null) + { + Console.WriteLine($"Register Subscriber fault On '{key}'"); + return; + } + + Console.WriteLine($"Registered Subscriber On '{key}'"); + + + Console.WriteLine("Enter 'q' to quit..."); + while (true) + { + var input = Console.ReadKey(); + if (input.Key == ConsoleKey.Q) + { + break; + } + } + + session.UnregisterSubscriber(handle.Value); + + session.Close(); + } +} + +class ClArgs +{ + [Option('c', "config", Required = false, HelpText = "A configuration file.")] + public string? ConfigFilePath { get; set; } = null; + + [Option('e', "connect", Required = false, HelpText = "Endpoints to connect to. example: tcp/127.0.0.1:7447")] + public IEnumerable Connects { get; set; } = new List(); + + [Option('l', "listen", Required = false, HelpText = "Endpoints to listen on. example: tcp/127.0.0.1:8447")] + public IEnumerable Listens { get; set; } = new List(); + + [Option('m', "mode", Required = false, + HelpText = "The zenoh session mode (peer by default) [possible values: peer, client]")] + public string Mode { get; set; } = "peer"; + + [Option('k', "key", Required = false, + HelpText = "The key expression to subscribe to. [default: demo/example/**]")] + public string? Keyexpr { get; set; } = null; + + internal Config? ToConfig() + { + if (ConfigFilePath != null) + { + Config? c = Config.LoadFromFile(ConfigFilePath); + if (c is null) + { + Console.WriteLine("load config file error!"); + return null; + } + + return c; + } + + Config config = new Config(); + + config.SetMode(Mode == "client" ? Config.Mode.Client : Config.Mode.Peer); + + List connects = new List(); + foreach (string s in Connects) + { + connects.Add(s); + } + + config.SetConnect(connects.ToArray()); + + List listens = new List(); + foreach (string s in Listens) + { + listens.Add(s); + } + + config.SetListen(listens.ToArray()); + + return config; + } + + public string GetKey() + { + return Keyexpr ?? "demo/example/**"; + } +} \ No newline at end of file diff --git a/examples/ZSub/ZSub.csproj b/examples/ZSub/ZSub.csproj new file mode 100644 index 0000000..72b301b --- /dev/null +++ b/examples/ZSub/ZSub.csproj @@ -0,0 +1,31 @@ + + + ZSub + ZSub + Exe + false + 10 + net7.0;net6.0 + Debug;Release + ARM64;x64 + + + TRACE;PLATFORM_ARM + + + TRACE;PLATFORM_ARM64 + + + TRACE;PLATFORM_x64 + + + + + + + + + + + + diff --git a/examples/Zenoh.Net/README.md b/examples/Zenoh.Net/README.md deleted file mode 100644 index 0d1dbb0..0000000 --- a/examples/Zenoh.Net/README.md +++ /dev/null @@ -1,163 +0,0 @@ -# Zenoh-net C# examples - -## Start instructions - - ```bash - dotnet run -p - ``` - - Each example accepts the `-h` or `--help` option that provides a description of its arguments and their default values. - - :warning: _To pass any options to an example, specify them after the `--`argument. For instance:_ - - ```bash - dotnet run -p ZNInfo.csproj -- -h - ``` - - If you run the tests against the zenoh router running in a Docker container, you need to add the - `-e tcp/localhost:7447` option to your examples. That's because Docker doesn't support UDP multicast - transport, and therefore the zenoh scouting and discrovery mechanism cannot work with. - -## Examples description - - - -### ZNInfo - - Gets information about the zenoh-net session. - - Typical usage: - ```bash - dotnet run -p ZNInfo.csproj - ``` - - -### ZNWrite - - Writes a path/value into Zenoh. - The path/value will be received by all matching subscribers, for instance the [ZNSub](#ZNSub) - and [ZNStorage](#ZNStorage) examples. - - Typical usage: - ```bash - dotnet run -p ZNWrite.csproj - ``` - or - ```bash - dotnet run -p ZNWrite.csproj -- -p /demo/example/test -v 'Hello World' - ``` - - - -### ZNSub - - Registers a subscriber with a selector. - The subscriber will be notified of each write made on any path matching the selector, - and will print this notification. - - Typical usage: - ```bash - dotnet run -p ZNSub.csproj - ``` - or - ```bash - dotnet run -p ZNSub.csproj -- -s /demo/** - ``` - - - - - - - - - - \ No newline at end of file diff --git a/examples/Zenoh.Net/ZNInfo.cs b/examples/Zenoh.Net/ZNInfo.cs deleted file mode 100644 index f78a365..0000000 --- a/examples/Zenoh.Net/ZNInfo.cs +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// -using System; -using System.Diagnostics; -using System.Collections.Generic; -using Zenoh; -using PowerArgs; - -class ZNInfo -{ - static void Main(string[] args) - { - try - { - // initiate logging - Zenoh.Zenoh.InitLogger(); - - // arguments parsing - var arguments = Args.Parse(args); - if (arguments == null) return; - Dictionary conf = arguments.GetConf(); - - Console.WriteLine("Openning session.."); - var s = Zenoh.Net.Session.Open(conf); - - var props = s.Info(); - foreach (KeyValuePair entry in props) - { - Console.WriteLine("{0} : {1}", entry.Key, entry.Value); - } - - s.Dispose(); - } - catch (ArgException) - { - Console.WriteLine(ArgUsage.GenerateUsageFromTemplate()); - } - } -} - - -[ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)] -public class ExampleArgs -{ - [HelpHook, ArgShortcut("h"), ArgDescription("Shows this help")] - public Boolean help { get; set; } - - [ArgShortcut("m"), ArgDescription("The zenoh session mode (peer by default). Possible values [peer|client].")] - public string mode { get; set; } - - [ArgShortcut("e"), ArgDescription("Peer locators used to initiate the zenoh session.")] - public string peer { get; set; } - - [ArgShortcut("l"), ArgDescription("Locators to listen on.")] - public string listener { get; set; } - - [ArgShortcut("c"), ArgDescription("A configuration file.")] - public string config { get; set; } - - public Dictionary GetConf() - { - Dictionary conf; - if (this.config != null) - { - conf = Zenoh.Zenoh.ConfigFromFile(this.config); - } - else - { - conf = new Dictionary(); - } - - if (this.mode != null) - { - conf["mode"] = this.mode; - } - if (this.peer != null) - { - conf["peer"] = this.peer; - } - if (this.listener != null) - { - conf["listener"] = this.listener; - } - return conf; - } -} diff --git a/examples/Zenoh.Net/ZNInfo.csproj b/examples/Zenoh.Net/ZNInfo.csproj deleted file mode 100644 index 3ed3881..0000000 --- a/examples/Zenoh.Net/ZNInfo.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - ZNInfo - ZNInfo - Exe - net5.0 - false - - - - - - - - - - - - diff --git a/examples/Zenoh.Net/ZNSub.cs b/examples/Zenoh.Net/ZNSub.cs deleted file mode 100644 index da0955d..0000000 --- a/examples/Zenoh.Net/ZNSub.cs +++ /dev/null @@ -1,116 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// -using System; -using System.Diagnostics; -using System.Collections.Generic; -using System.Text; -using Zenoh; -using PowerArgs; - -class ZNSub -{ - - public static void SubscriberCallback(Zenoh.Net.Sample sample) - { - Console.WriteLine(">> [Subscription listener] Received ('{0}': '{1}')", - sample.ResName, - BitConverter.ToString(sample.Payload)); - - // Encoding.UTF8.GetString(sample.Payload)); - } - - static void Main(string[] args) - { - try - { - // initiate logging - Zenoh.Zenoh.InitLogger(); - - // arguments parsing - var arguments = Args.Parse(args); - if (arguments == null) return; - Dictionary conf = arguments.GetConf(); - - Console.WriteLine("Openning session..."); - var s = Zenoh.Net.Session.Open(conf); - - Console.WriteLine("Declaring Subscriber on '{0}'...", arguments.selector); - var rkey = Zenoh.Net.ResKey.RName(arguments.selector); - var subInfo = new Zenoh.Net.SubInfo(); - s.DeclareSubscriber(rkey, subInfo, ZNSub.SubscriberCallback); - - char c = ' '; - while (c != 'q') - { - c = Console.ReadKey().KeyChar; - } - - s.Dispose(); - } - catch (ArgException) - { - Console.WriteLine(ArgUsage.GenerateUsageFromTemplate()); - } - } -} - - -[ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)] -public class ExampleArgs -{ - [HelpHook, ArgShortcut("h"), ArgDescription("Shows this help")] - public Boolean help { get; set; } - - [ArgShortcut("m"), ArgDefaultValue("peer"), ArgDescription("The zenoh session mode. Possible values [peer|client].")] - public string mode { get; set; } - - [ArgShortcut("e"), ArgDescription("Peer locators used to initiate the zenoh session.")] - public string peer { get; set; } - - [ArgShortcut("l"), ArgDescription("Locators to listen on.")] - public string listener { get; set; } - - [ArgShortcut("c"), ArgDescription("A configuration file.")] - public string config { get; set; } - - [ArgShortcut("s"), ArgDefaultValue("/demo/example/**"), ArgDescription("The selection of resources to subscribe.")] - public string selector { get; set; } - - public Dictionary GetConf() - { - Dictionary conf; - if (this.config != null) - { - conf = Zenoh.Zenoh.ConfigFromFile(this.config); - } - else - { - conf = new Dictionary(); - } - - if (this.mode != null) - { - conf["mode"] = this.mode; - } - if (this.peer != null) - { - conf["peer"] = this.peer; - } - if (this.listener != null) - { - conf["listener"] = this.listener; - } - return conf; - } -} diff --git a/examples/Zenoh.Net/ZNSub.csproj b/examples/Zenoh.Net/ZNSub.csproj deleted file mode 100644 index 0d08792..0000000 --- a/examples/Zenoh.Net/ZNSub.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - ZNSub - ZNSub - Exe - net5.0 - false - - - - - - - - - - - - diff --git a/examples/Zenoh.Net/ZNWrite.cs b/examples/Zenoh.Net/ZNWrite.cs deleted file mode 100644 index 603df50..0000000 --- a/examples/Zenoh.Net/ZNWrite.cs +++ /dev/null @@ -1,103 +0,0 @@ -// -// Copyright (c) 2021 ADLINK Technology Inc. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// -// Contributors: -// ADLINK zenoh team, -// -using System; -using System.Diagnostics; -using System.Collections.Generic; -using System.Text; -using Zenoh; -using PowerArgs; - -class ZNWrite -{ - static void Main(string[] args) - { - try - { - // initiate logging - Zenoh.Zenoh.InitLogger(); - - // arguments parsing - var arguments = Args.Parse(args); - if (arguments == null) return; - Dictionary conf = arguments.GetConf(); - - Console.WriteLine("Openning session..."); - var s = Zenoh.Net.Session.Open(conf); - - var rkey = Zenoh.Net.ResKey.RName(arguments.path); - - Console.WriteLine("Writing Data ({0}, {1})...", rkey, arguments.value); - s.Write(rkey, Encoding.UTF8.GetBytes(arguments.value)); - - s.Dispose(); - } - catch (ArgException) - { - Console.WriteLine(ArgUsage.GenerateUsageFromTemplate()); - } - } -} - - -[ArgExceptionBehavior(ArgExceptionPolicy.StandardExceptionHandling)] -public class ExampleArgs -{ - [HelpHook, ArgShortcut("h"), ArgDescription("Shows this help")] - public Boolean help { get; set; } - - [ArgShortcut("m"), ArgDefaultValue("peer"), ArgDescription("The zenoh session mode. Possible values [peer|client].")] - public string mode { get; set; } - - [ArgShortcut("e"), ArgDescription("Peer locators used to initiate the zenoh session.")] - public string peer { get; set; } - - [ArgShortcut("l"), ArgDescription("Locators to listen on.")] - public string listener { get; set; } - - [ArgShortcut("c"), ArgDescription("A configuration file.")] - public string config { get; set; } - - [ArgShortcut("p"), ArgDefaultValue("/demo/example/zenoh-csharp-write"), ArgDescription("The name of the resource to write.")] - public string path { get; set; } - - [ArgShortcut("v"), ArgDefaultValue("Write from C#!"), ArgDescription("The value of the resource to write.")] - public string value { get; set; } - - public Dictionary GetConf() - { - Dictionary conf; - if (this.config != null) - { - conf = Zenoh.Zenoh.ConfigFromFile(this.config); - } - else - { - conf = new Dictionary(); - } - - if (this.mode != null) - { - conf["mode"] = this.mode; - } - if (this.peer != null) - { - conf["peer"] = this.peer; - } - if (this.listener != null) - { - conf["listener"] = this.listener; - } - return conf; - } -} diff --git a/examples/Zenoh.Net/ZNWrite.csproj b/examples/Zenoh.Net/ZNWrite.csproj deleted file mode 100644 index 11ea7c1..0000000 --- a/examples/Zenoh.Net/ZNWrite.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - ZNWrite - ZNWrite - Exe - net5.0 - false - - - - - - - - - - - - diff --git a/examples/zenoh-examples.sln b/examples/zenoh-examples.sln index 8a18860..a96f83b 100644 --- a/examples/zenoh-examples.sln +++ b/examples/zenoh-examples.sln @@ -3,60 +3,86 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26124.0 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZNInfo", "Zenoh.Net\ZNInfo.csproj", "{12DDE9FF-E244-4FC5-9061-97F6B600AEBA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zenoh", "..\Zenoh\Zenoh.csproj", "{05075D28-DE9E-4CB4-9976-FCBDD170A7B5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZNWrite", "Zenoh.Net\ZNWrite.csproj", "{B9C668F9-B880-479D-BEB9-7435E5B9742B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZGet", "ZGet\ZGet.csproj", "{7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZNSub", "Zenoh.Net\ZNSub.csproj", "{ECF3EA7C-E5A1-4261-8861-E9A20436BD83}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZPut", "ZPut\ZPut.csproj", "{13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZSub", "ZSub\ZSub.csproj", "{435FE932-CE46-49D0-B921-AC1B11585F13}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZInfo", "ZInfo\ZInfo.csproj", "{B973A563-44AD-4B68-855C-46B5D58DCE32}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZPub", "ZPub\ZPub.csproj", "{D642DF1F-7096-4D47-A5EA-FCF624536993}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZQueryable", "ZQueryable\ZQueryable.csproj", "{C8BACCA5-5B34-4617-B29B-E70A749102C9}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU + Debug|ARM64 = Debug|ARM64 Release|x64 = Release|x64 - Release|x86 = Release|x86 + Release|ARM64 = Release|ARM64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Debug|x64.ActiveCfg = Debug|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Debug|x64.Build.0 = Debug|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Debug|x86.ActiveCfg = Debug|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Debug|x86.Build.0 = Debug|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Release|Any CPU.Build.0 = Release|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Release|x64.ActiveCfg = Release|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Release|x64.Build.0 = Release|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Release|x86.ActiveCfg = Release|Any CPU - {12DDE9FF-E244-4FC5-9061-97F6B600AEBA}.Release|x86.Build.0 = Release|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Debug|x64.ActiveCfg = Debug|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Debug|x64.Build.0 = Debug|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Debug|x86.ActiveCfg = Debug|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Debug|x86.Build.0 = Debug|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Release|Any CPU.Build.0 = Release|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Release|x64.ActiveCfg = Release|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Release|x64.Build.0 = Release|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Release|x86.ActiveCfg = Release|Any CPU - {B9C668F9-B880-479D-BEB9-7435E5B9742B}.Release|x86.Build.0 = Release|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Debug|Any CPU.Build.0 = Debug|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Debug|x64.ActiveCfg = Debug|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Debug|x64.Build.0 = Debug|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Debug|x86.ActiveCfg = Debug|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Debug|x86.Build.0 = Debug|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Release|Any CPU.ActiveCfg = Release|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Release|Any CPU.Build.0 = Release|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Release|x64.ActiveCfg = Release|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Release|x64.Build.0 = Release|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Release|x86.ActiveCfg = Release|Any CPU - {ECF3EA7C-E5A1-4261-8861-E9A20436BD83}.Release|x86.Build.0 = Release|Any CPU + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Debug|x64.ActiveCfg = Debug|x64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Debug|x64.Build.0 = Debug|x64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Release|x64.ActiveCfg = Release|x64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Release|x64.Build.0 = Release|x64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Debug|ARM64.Build.0 = Debug|ARM64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Release|ARM64.ActiveCfg = Release|ARM64 + {05075D28-DE9E-4CB4-9976-FCBDD170A7B5}.Release|ARM64.Build.0 = Release|ARM64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Debug|x64.ActiveCfg = Debug|x64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Debug|x64.Build.0 = Debug|x64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Release|x64.ActiveCfg = Release|x64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Release|x64.Build.0 = Release|x64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Debug|ARM64.Build.0 = Debug|ARM64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Release|ARM64.ActiveCfg = Release|ARM64 + {7CBBC11C-8F9D-40D4-B1A6-AD472FDF99C0}.Release|ARM64.Build.0 = Release|ARM64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Debug|x64.ActiveCfg = Debug|x64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Debug|x64.Build.0 = Debug|x64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Release|x64.ActiveCfg = Release|x64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Release|x64.Build.0 = Release|x64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Debug|ARM64.Build.0 = Debug|ARM64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Release|ARM64.ActiveCfg = Release|ARM64 + {B973A563-44AD-4B68-855C-46B5D58DCE32}.Release|ARM64.Build.0 = Release|ARM64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Debug|x64.ActiveCfg = Debug|x64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Debug|x64.Build.0 = Debug|x64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Release|x64.ActiveCfg = Release|x64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Release|x64.Build.0 = Release|x64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Debug|ARM64.Build.0 = Debug|ARM64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Release|ARM64.ActiveCfg = Release|ARM64 + {13E0FD6C-35D7-4422-A37F-4724D7DCDA2C}.Release|ARM64.Build.0 = Release|ARM64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Debug|x64.ActiveCfg = Debug|x64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Debug|x64.Build.0 = Debug|x64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Release|x64.ActiveCfg = Release|x64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Release|x64.Build.0 = Release|x64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Debug|ARM64.Build.0 = Debug|ARM64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Release|ARM64.ActiveCfg = Release|ARM64 + {435FE932-CE46-49D0-B921-AC1B11585F13}.Release|ARM64.Build.0 = Release|ARM64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Debug|ARM64.Build.0 = Debug|ARM64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Debug|x64.ActiveCfg = Debug|x64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Debug|x64.Build.0 = Debug|x64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Release|ARM64.ActiveCfg = Debug|ARM64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Release|ARM64.Build.0 = Debug|ARM64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Release|x64.ActiveCfg = Release|x64 + {D642DF1F-7096-4D47-A5EA-FCF624536993}.Release|x64.Build.0 = Release|x64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Debug|ARM64.Build.0 = Debug|ARM64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Debug|x64.ActiveCfg = Debug|x64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Debug|x64.Build.0 = Debug|x64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Release|ARM64.ActiveCfg = Release|ARM64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Release|ARM64.Build.0 = Release|ARM64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Release|x64.ActiveCfg = Release|x64 + {C8BACCA5-5B34-4617-B29B-E70A749102C9}.Release|x64.Build.0 = Release|x64 EndGlobalSection EndGlobal