diff options
Diffstat (limited to 'Net.Messaging.FBM/src/Client/README.md')
-rw-r--r-- | Net.Messaging.FBM/src/Client/README.md | 169 |
1 files changed, 0 insertions, 169 deletions
diff --git a/Net.Messaging.FBM/src/Client/README.md b/Net.Messaging.FBM/src/Client/README.md deleted file mode 100644 index 5aa8e76..0000000 --- a/Net.Messaging.FBM/src/Client/README.md +++ /dev/null @@ -1,169 +0,0 @@ -# VNLib.Net.Messaging.FBM.Client - -Fixed Buffer Messaging Protocol client library. High performance statful messaging -protocol built on top of HTTP web-sockets. Low/no allocation, completely asynchronous -while providing a TPL API. This library provides a simple asynchronous request/response -architecture to web-sockets. This was initially designed to provide an alternative to -complete HTTP request/response overhead, but allow a simple control flow for work -across a network. - -The base of the library relies on creating message objects that allocate fixed size -buffers are configured when the IFBMMessageis constructed. All data is written to the -internal buffer adhering to the format below. - -Messages consist of a 4 byte message id, a collection of headers, and a message body. -The first 4 bytes of a message is the ID (for normal messages a signed integer greater than 0), -0 is reserved for error conditions, and negative numbers are reserved for internal -messages. Headers are identified by a single byte, followed by a variable length UTF8 -encoded character sequence, followed by a termination of 0xFF, 0xF1 (may change). - -### Message structure - 4 byte positive (signed 32-bit integer) message id - 2 byte termination - 1 byte header-id - variable length UTF8 value - 2 byte termination - -- other headers -- - 2 byte termination (extra termination, ie: empty header) - variable length payload - (end of message is the end of the payload) - -Buffer sizes are generally negotiated on initial web-socket upgrade, so to buffer entire messages -in a single read/write from the web-socket. Received messages are read into memory until -the web-socket has no more data available. The message is then parsed and passed for processing -on the server side, or complete a pending request on the client side. Servers may drop the -web-socket connection and return an error if messages exceed the size of the pre-negotiated -buffer. Servers should validate buffer sizes before accepting a connection. - -This client library allows for messages to be streamed to the server, however this library -is optimized for fixed buffers, so streaming will not be the most efficient, and will likely -cause slow-downs in message transmission. However, since FBM relies on a streaming protocol, -so it was silly not to provide it. Streams add overhead of additional buffer allocation, -additional copy, and message fragmentation (multiple writes to the web-socket). Since frames -written to the web-socket must be synchronized, a mutex is held during transmission, which -means the more message overhead, the longer the blocking period on new messages. Mutex -acquisition will wait asynchronously when necessary. - -The goal of the FBM protocol for is to provide efficient use of resources (memory, network, -and minimize GC load) to transfer small messages truly asynchronously, at wire speeds, with -only web-socket and transport overhead. Using web-sockets simplifies implementation, and allows -comparability across platforms, languages, and versions. - -## fundamentals - -The main implementation is the FBMClient class. This class provides the means for creating -the stateful connection to the remote server. It also provides an internal FBMRequest message -rental (object cache) that created initialized FBMRequest messages. This class may be derrived -to provide additional functionality, such as handling control frames that may dynamically -alter the state of the connection (negotiation etc). A mechanism to do so is provided. - -### FBMClient layout - -``` - public class FBMClient : VnDisposeable, IStatefulConnection, ICacheHolder - { - //Raised when an error occurs during receiving or parsing - public event EventHandler<FMBClientErrorEventArgs>? ConnectionClosedOnError; - - //Raised when connection is closed, regardless of the cause - public event EventHandler? ConnectionClosed; - - //Connects to the remote server at the specified websocket address (ws:// or wss://) - public async Task ConnectAsync(Uri address, CancellationToken cancellation = default); - - //When connected, sends the specified message to the remote server - public async Task<FBMResponse> SendAsync(FBMRequest request, CancellationToken cancellationToken = default); - - //When connected, streams a message to the remote server, * the message payload must not be configured * - public async Task<FBMResponse> StreamDataAsync(FBMRequest request, Stream payload, ContentType ct, CancellationToken cancellationToken = default); - - //Disconnects from the remote server - public async Task DisconnectAsync(CancellationToken cancellationToken = default); - - //Releases all held resourses - public void Dispose(); //Inherrited from VnDisposeable - - ICacheHolder.CacheClear(); //Inherited member, clears cached FBMRequest objects - ICacheHolder.CacheHardClear(); //Inherited member, clears cached FBMRequest objects - } -``` - -### Example usage -``` - FBMClientConfig config = new() - { - //The size (in bytes) of the internal buffer to use when receiving messages from the server - RecvBufferSize = 1024, - - //FBMRequest buffer size (expected size of buffers, required for negotiation) - RequestBufferSize = 1024, - - //The size (in chars) of headers the FBMResponse should expect to buffer from the server - ResponseHeaderBufSize = 1024, - - //The absolute maximum message size to buffer from the server - MaxMessageSize = 10 * 1024 * 1024, //10KiB - - //The unmanaged heap the allocate buffers from - BufferHeap = Memory.Shared, - - //Web-socket keepalive frame interval - KeepAliveInterval = TimeSpan.FromSeconds(30), - - //Web-socket sub-protocol header value - SubProtocol = null - }; - - //Craete client from the config - using (FBMClient client = new(config)) - { - //Usually set some type of authentication headers before connecting - - /* - client.ClientSocket.SetHeader("Authorization", "Authorization token"); - */ - - //Connect to server - Uri address = new Uri("wss://localhost:8080/some/fbm/endpoint"); - await client.ConnectAsync(address, CancellationToken.None); - - do - { - //Rent request message - FBMRequest request = client.RentRequest(); - //Some arbitrary header value (or preconfigured header) - request.WriteHeader(0x10, "Hello"); - //Some arbitrary payload - request.WriteBody(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A }, ContentType.Binary); - //Send request message - using (FBMResponse response = await client.SendAsync(request, CancellationToken.None)) - { - //Extension method to raise exception if an invalid response was received (also use the response.IsSet flag) - response.ThrowIfNotSet(); - - //Check headers (using Linq to get first header) - string header1 = response.Headers.First().Value.ToString(); - - //Get payload, data is valid until the response is disposed - ReadOnlySpan<byte> body = response.ResponseBody; - } - //Return request - client.ReturnRequest(request); - //request.Dispose(); //Alternativly dispose message - - await Task.Delay(1000); - } - while(true); - } -``` - -## Final Notes - -XML Documentation is or will be provided for almost all public exports. APIs are intended to -be sensibly public and immutable to allow for easy extensability (via extension methods). I -often use extension libraries to provide additional functionality. (See cache library) - -This library is likely a niche use case, and is probably not for everyone. Unless you care -about reasonably efficient high frequency request/response messaging, this probably isnt -for you. This library provides a reasonable building block for distributed lock mechanisms -and small data caching.
\ No newline at end of file |