https://github.com/kekyo/fluorite
Simplest and fully-customizable RPC standalone infrastructure.
https://github.com/kekyo/fluorite
async bidirectional complementary dotnet full-duplex json rpc-client rpc-server standalone transport websocket
Last synced: 5 months ago
JSON representation
Simplest and fully-customizable RPC standalone infrastructure.
- Host: GitHub
- URL: https://github.com/kekyo/fluorite
- Owner: kekyo
- License: apache-2.0
- Created: 2021-03-16T00:24:47.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2021-09-14T12:38:20.000Z (over 4 years ago)
- Last Synced: 2025-10-04T21:33:59.433Z (5 months ago)
- Topics: async, bidirectional, complementary, dotnet, full-duplex, json, rpc-client, rpc-server, standalone, transport, websocket
- Language: C#
- Homepage:
- Size: 510 KB
- Stars: 5
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Fluorite

Fluorite - Simplest and fully-customizable RPC standalone infrastructure on .NET
[](https://www.repostatus.org/#wip)
## NuGet
|Package|main|devel|Description|
|:--|:--|:--|:--|
|Fluorite|[](https://www.nuget.org/packages/Fluorite)|[](https://www.myget.org/feed/fluorite/package/nuget/Fluorite)|Meta-package (Provides automated generating static proxy / **Experimental**)|
|Fluorite.Dynamic|[](https://www.nuget.org/packages/Fluorite.Dynamic)|[](https://www.myget.org/feed/fluorite/package/nuget/Fluorite.Dynamic)|Meta-package (Provides automated generating dynamic proxy)|
### Sub packages
|Package|main|devel|Description|
|:--|:--|:--|:--|
|Fluorite.Core|[](https://www.nuget.org/packages/Fluorite.Core)|[](https://www.myget.org/feed/fluorite/package/nuget/Fluorite.Core)|Independed core engine|
|Fluorite.Serializer|[](https://www.nuget.org/packages/Fluorite.Serializer)|[](https://www.myget.org/feed/fluorite/package/nuget/Fluorite.Serializer)|Default serializer implementation (Newtonsoft.Json)|
|Fluorite.Transport|[](https://www.nuget.org/packages/Fluorite.Transport)|[](https://www.myget.org/feed/fluorite/package/nuget/Fluorite.Transport)|Default transport implementation (System.Net.WebSockets)|
|Fluorite.Build|[](https://www.nuget.org/packages/Fluorite.Build)|[](https://www.myget.org/feed/fluorite/package/nuget/Fluorite.Build)|Automated static proxy generator at building time|
## CI
|main|devel|
|:--|:--|
|[](https://github.com/kekyo/Fluorite/actions?query=branch%3Amain)|[](https://github.com/kekyo/Fluorite/actions?query=branch%3Adevel)|
-----
## What is this ?
An implementation of bi-directional/complementary/asynchronous RPC (remote procedure call) controller with customizable serializer/transport interface.
This is simple diagram for user side Fluorite architecture:

Fluorite doesn't have any depending other large libraries (For example: ASP.NET).
You can easy integrate flexible RPC messaging system on your own application.
### Features
* Can do truly bi-directional operation between server and client.
* Complementary interface.
* With overlapping calls and will do non-blocking (if transport has capability).
* Fully asynchronous sending/receiving operation with `ValueTask` type.
* RPC form on custom interface definition.
* You can choose static proxy (at building time) or dynamic proxy (at runtime).
* Or you can attach your own custom proxy generator.
* Can attach your own custom serializer likes Json or another form by simple interface.
* Json, Bson, XML, Message Pack, Protocol Buffer and etc...
* Will make simpler logical message format.
* Can attach your own custom transport likes WebSocket or another protocol by simple interface.
* WebSocket, TCP/UDP direct, Pipe, IPC, MQ, Persistence data and etc...
-----
## Getting started
Default configuration (meta-package) is applied with:
* Will use serializer `Newtonsoft.Json`.
* Will use transport `System.Net.WebSockets`.
* Client side: `ClientWebSocket`.
* Server side: `WebSocket` on `HttpListener`.
NOTE: When running on Windows platform, you have to configure `HttpListener`/`HTTP.SYS` related setup protocol on server side. For example:
1. `netsh http add urlacl url=http://+:4649/ user=everyone`
2. `netsh advfirewall firewall add rule name="Fluorite HTTP" dir=in action=allow`
3. `netsh advfirewall firewall set rule name="Fluorite HTTP" new program=system profile=private protocol=tcp localport=4649`
### Custom RPC interface definition
We can use independent platform such as `netstandard2.0` or likes.
```csharp
// nuget install Fluorite
// (or Fluorite.Build using static proxy generator)
using Fluorite;
// You can use custom types each arguments/return value, constraint depending used serializer.
// (Default serializer is Newtonsoft.Json)
public sealed class Item
{
public int Id;
public string Label;
public int Price;
}
// Require inherits `IHost` and method returns ValueTask or ValueTask.
public interface IPartsShop : IHost
{
ValueTask GetItemsAsync(string category, int max);
ValueTask PurchaseAsync(params int[] itemIds);
}
```
### Client side
```csharp
// nuget install Fluorite
using Fluorite;
// Initialize
Nest.Factory.Initialize();
// Connect to server with default WebSocket/Json transport.
// (Optional: You can register client side expose object at last arguments same as server side)
var nest = await Nest.Factory.ConnectAsync("server.example.com", 4649, false);
try
{
// Get transparent proxy instance from the client nest.
var partsShop = nest.GetPeer();
// Manipulate via transparent proxy.
var items = await shop.GetItemsAsync("FPGA", 100);
await shop.PurchaseAsync(items[3].Id);
}
finally
{
// Shutdown client nest
await nest.ShutdownAsync();
}
```
### Server side
```csharp
// nuget install Fluorite
using Fluorite;
// The exposed interface implementer.
internal sealed class PartsShop : IPartsShop
{
public async ValueTask GetItemsAsync(string category, int max)
{
// ...
}
public async ValueTask PurchaseAsync(int[] itemIds)
{
// ...
}
}
// Initialize
Nest.Factory.Initialize();
// Start default WebSocket/Json server (at background)
// with expose objects at last arguments.
var nest = await Nest.Factory.StartServer(4649, false, new PartsShop());
try
{
// ...
}
finally
{
// Shutdown server nest
await nest.ShutdownAsync();
}
```
-----
## Transparent proxy
Fluorite requires transparent proxy implementation. You can choice few implementation ways:
* Automatic static proxy generator:
* `Fluorite.Build` (or `Fluorite`) package will generate automatically static transparent proxy class on your project.
* It's easy way and recommended.
* AOT environment friendly and fastest at runtime.
* But some .NET development environemnt couldn't use. Unity (Game engine) and others have unique way to build environment.
* Dynamic proxy generator:
* `Fluorite.Dynamic` package will generate automatically dynamic transparent proxy class at on demand (runtime).
* Stable mostly environments.
* It's better performance, will use CIL/MSIL generator.
* Maybe couldn't use on AOT platform.
* Self implements static proxy:
* Flexible and customizable.
* You dodge referring meta-package `Fluorite` or `Fluorite.Dynamic`. Will make decrease dependency only referring `Fluorite.Core`.
* Tired :)
## Automatic static proxy generator (Fluorite.Build)
You don't need anything. It's an example result:
```csharp
// It's automatically generated, you can see it by ILSpy and others.
internal sealed class IPartsShopProxy__ :
GeneratedProxyBase, IPartsShop
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask GetItemsAsync(string category, int max)
{
return base.InvokeAsync("ExamplePartsShop.IPartsShop.GetItems", new object[2] { category, max });
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ValueTask PurchaseAsync(int[] itemIds)
{
return base.InvokeAsync("ExamplePartsShop.IPartsShop.Purchase", new object[1] { itemIds });
}
}
```
## Automatic dynamic proxy generator (use Fluorite.Dynamic)
## Self implements static proxy
You have to implement likes:
```csharp
// Hand coded static proxy class.
internal sealed class PartsShopProxy :
StaticProxyBase, IPartsShop
{
public ValueTask GetItemsAsync(string category, int max)
{
return base.InvokeAsync("GetItems", category, max);
}
public ValueTask PurchaseAsync(int[] itemIds)
{
// HACK: Requires cast expression because will convert implicitly param array.
return base.InvokeAsync("Purchase", (object)itemIds);
}
}
// Register proxy class.
Nest.Register();
```
-----
## Advanced topic
### Customize with your own serializer
TODO:
### Customize with your own transport
TODO:
### Customize with your own proxy factory
TODO:
-----
## License
Apache-v2
## History
* 0.6.0:
* Reconstruct transport architecture overall transferring data with `Stream` asynchronously.
* Reconstruct transport architecture enabling truly full-duplex on WebSocket.
* 0.5.0:
* Implemented static proxy generator at running build time (Fluorite.Build)
* 0.2.0:
* Passed full-duplex, bi-directional tests.
* 0.1.0:
* Initial version.