aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Net.Messaging.FBM/README.md38
-rw-r--r--lib/Net.Messaging.FBM/src/Client/FBMClientConfig.cs2
-rw-r--r--lib/Net.Messaging.FBM/src/Client/README.md140
-rw-r--r--lib/Net.Messaging.FBM/src/Server/readme.md38
4 files changed, 93 insertions, 125 deletions
diff --git a/lib/Net.Messaging.FBM/README.md b/lib/Net.Messaging.FBM/README.md
index 9d3cd7a..19e925c 100644
--- a/lib/Net.Messaging.FBM/README.md
+++ b/lib/Net.Messaging.FBM/README.md
@@ -2,5 +2,41 @@
High performance structured web-socket based asynchronous request/response messaging library for .NET.
-#### Builds
+[**Client Lib**](src/Client/#) - FBM Fixed Buffer Messaging client library
+
+[**Server Lib**](src/Server/#) - FBM Fixed Buffer Messaging server/listener helper library
+
+## Fixed Buffer Message protocol overview
+FBM is a simple binary message protocol that supports asynchronous messaging between clients-servers that is built atop HTTP and web-sockets. It client and server architecture uses fixed sized buffers and assumes all messages sent/received will fit those buffers, this helps reduce copying and allocations. Streaming is minimally supported for clients but servers will still have a fixed max message size, so it cannot stream arbitrary length data. Servers will always buffer request messages into memory, so a max message size is the only guard for resource abuse.
+
+#### FBM Message frames
+Message frames consist of a 4-byte message id, a collection of key-value encoded headers, and a message body/payload. 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).
+```
+ 4 byte positive (big endian signed 32-bit integer) message id
+ 2 byte termination [0xFF,0xF1]
+ 1 byte header-id
+ variable length UTF8 value
+ 2 byte termination [0xFF,0xF1]
+ <-- other headers -->
+ 2 byte termination (extra termination, ie: empty header) [0xFF,0xF1]
+ variable length payload
+ <end of message is the end of the payload>
+Example:
+id=0x8EB26 term Action cmd utf8 "read" End header End header section
+[0x00,0x08, 0xEB, 0x26, 0xFF, 0xF1, 0x04, 0x72, 0x65, 0x61, 0x64, 0xFF, 0xF1, 0xFF, 0xF1]
+
+```
+
+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.
+
+#### Architecture goal
+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 compatibility across platforms, programming languages, and versions.
+
+## Final Notes
+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 isn't for you. This library provides a reasonable building block for distributed lock mechanisms and small data caching.
+
+## License
+The software in this repository is licensed under the GNU Affero General Public License (or any later version). See the [LICENSE](LICENSE.txt) file for more information.
+
+## Builds
Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file. \ No newline at end of file
diff --git a/lib/Net.Messaging.FBM/src/Client/FBMClientConfig.cs b/lib/Net.Messaging.FBM/src/Client/FBMClientConfig.cs
index fb5f32f..30e9a95 100644
--- a/lib/Net.Messaging.FBM/src/Client/FBMClientConfig.cs
+++ b/lib/Net.Messaging.FBM/src/Client/FBMClientConfig.cs
@@ -33,7 +33,7 @@ namespace VNLib.Net.Messaging.FBM.Client
/// <summary>
/// A structure that defines readonly constants for the <see cref="FBMClient"/> to use
/// </summary>
- public readonly struct FBMClientConfig
+ public readonly record struct FBMClientConfig
{
/// <summary>
/// The size (in bytes) of the internal buffer used to buffer incomming messages,
diff --git a/lib/Net.Messaging.FBM/src/Client/README.md b/lib/Net.Messaging.FBM/src/Client/README.md
index 35f49ff..ea76a46 100644
--- a/lib/Net.Messaging.FBM/src/Client/README.md
+++ b/lib/Net.Messaging.FBM/src/Client/README.md
@@ -1,65 +1,18 @@
# 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 (big endian 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.
+Fixed Buffer Messaging Protocol client library. High performance stateful 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 [FBM protocol](../../#)
+
+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.
+
+## 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 derived 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
-```
+``` C#
public class FBMClient : VnDisposeable, IStatefulConnection, ICacheHolder
{
//Raised when an error occurs during receiving or parsing
@@ -69,13 +22,16 @@ alter the state of the connection (negotiation etc). A mechanism to do so is pro
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);
+ public 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, sends the specified message to the remote server, with the default timeout
+ public Task<FBMResponse> SendAsync(FBMRequest request, CancellationToken cancellationToken = default);
+
+ //When connected, sends the specified message to the remote server, with the specified timeout, -1 or 0 to disable timeout
+ public Task<FBMResponse> SendAsync(FBMRequest request, TimeSpan timeout, 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);
+ public Task<FBMResponse> StreamDataAsync(FBMRequest request, Stream payload, ContentType ct, CancellationToken cancellationToken = default);
//Disconnects from the remote server
public async Task DisconnectAsync(CancellationToken cancellationToken = default);
@@ -83,38 +39,39 @@ alter the state of the connection (negotiation etc). A mechanism to do so is pro
//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
+ ICacheHolder.CacheClear(); //Inherited member, clears cached FBMRequest objects
+ ICacheHolder.CacheHardClear(); //Inherited member, clears cached FBMRequest objects
}
```
### Example usage
-```
+``` C#
+
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
+ //The unmanaged heap the allocate buffers from
+ BufferHeap = MemoryUtil.Shared,
+ //The absolute maximum message size to buffer from the server
+ MaxMessageSize = 10 * 1024 * 1024, //10KiB,
+ //The size of the buffer used for buffering incoming messages server messages
+ RecvBufferSize = maxExtra,
+ //The FBMRequest internal buffer size, should be max message + headers
+ MessageBufferSize = (int)Helpers.ToNearestKb(maxMessageSize + MAX_FBM_MESSAGE_HEADER_SIZE),
+ //The space reserved in the FBM request buffer used for header storage
+ MaxHeaderBufferSize = 1024,
+ //Set the web-socket subprotocol
+ SubProtocol = "object-cache",
+ //Use the default encoding (UTF-8)
+ HeaderEncoding = Helpers.DefaultEncoding,
+ //How frequently to send web-socket keepalive messages
+ KeepAliveInterval = TimeSpan.FromSeconds(30),
+ //The default request message timeout
+ RequestTimeout = TimeSpan.FromSeconds(10),
+ //optional debug log, write message debug information if set
+ DebugLog = null
};
- //Craete client from the config
+ //Create client from the config
using (FBMClient client = new(config))
{
//Usually set some type of authentication headers before connecting
@@ -157,16 +114,9 @@ alter the state of the connection (negotiation etc). A mechanism to do so is pro
await Task.Delay(1000);
}
while(true);
+ //You should probably cleanup by asynchronously closing the connection before disposing
}
```
-## 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
+## Builds
+Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file. \ No newline at end of file
diff --git a/lib/Net.Messaging.FBM/src/Server/readme.md b/lib/Net.Messaging.FBM/src/Server/readme.md
index 68eb505..cd6f53e 100644
--- a/lib/Net.Messaging.FBM/src/Server/readme.md
+++ b/lib/Net.Messaging.FBM/src/Server/readme.md
@@ -1,35 +1,17 @@
# VNLib.Net.Messaging.FBM.Server
-Fixed Buffer Messaging Protocol server 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.
+Please see [FBM Protocol spec](../../#) for architecture details
-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).
+## Usage
+This library exports a main type called `FBMListener` it is the "entry point" so to speak for your server development. It listens on an active web-socket session that has been accepted an negotiated by your http server and passed to the `FBMListener.ListenAsync()` method. This call only returns once the connection is disconnected, has an error, or the session is closed. The listener listens for FBM messages on the web-socket, buffers them, and when message has been pre-processed, calls your request handler delegate if the message is valid. If the message exceeds the maximum size, the socket is gracefully closed and the method returns.
-### Message structure
- 4 byte positive (big endian 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)
+Your `RequestHandler` delegate method accepts a type `FBMContext` that holds the request instance, and the `FBMResponseMessage` instance you will use to respond to the client. **Context instances are pooled, so you may not save them or any of their properties once your request handler returns.** Response objects implement the `IFBMMessage` interface, for your consumption. You may also use the "streaming" api, to reduce buffering and copying, implementing your own `IAsyncMessageBody` objects which allows reading data into a buffer asynchronously. Keep in mind a mutex is held while this streaming process occurs, and can cause performance issues, you should generally write a copy of your data to the internal response buffer.
+A `FBMListenerSessionParams` structure must be passed on every call `ListenAsync()` to define the buffer sizes and limits per-session.
-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)
+The `FBMListenerBase` is an abstract type that provides some scaffolding for implementing your own message handler, by handling some plumbing and giving you an abstract method to process incoming messages.
-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
+Calls to your `RequestHandler` method are invoked on a background queuing task, to avoid blocking, or delaying the receive task. However it is still task, not a background thread, so you should try **not** to synchronously block in your request handling routine to avoid blocking a threadpool thread.
+
+## Builds
+Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my [website](https://www.vaughnnugent.com/resources/software). All tar-gzip (.tgz) files will have an associated .sha384 appended checksum of the desired download file. \ No newline at end of file