> ###### Active development occurs on the [_'dev'_](https://github.com/alec1o/Netly/tree/dev) branch. For the stable release, refer to the [_'main'_](https://github.com/alec1o/Netly/tree/main) branch.


> <sup>Netly version 4 will be released soon, help validating the new way of interacting with netly. [_See
more_](https://github.com/alec1o/Netly/discussions/36#discussion-6204441)<sup>

<div align="right">
  <table>
    <td align="left">
      <p>
        <sup>⭐ Your star on <a href="https://github.com/alec1o/Netly">Netly</a> brightens our journey and makes a real impact!<br> ✨ Every like/star is a powerful boost that drives us forward.<br> 💙 Thank you for your incredible support!
</sup>
      </p>
    </td>
  </table>
</div>

<br>

<h1 align="center"><a href="https://github.com/alec1o/Netly">Netly</a></h1>

<h6 align="center"><sub>
powered by <a href="https://github.com/alec1o">ALEC1O</a><sub/>
</h6>

<div align="center">
  <a href="#">
    <img align="center" src="static/logo/netly-logo-3.png" width="128px" alt="netly logo">
  </a>
</div>

> ###### Version 4 Development Roadmap

<table>
  <tr>
    <th align="left" valign="center">🚀 <sub>Fully Implemented</sub></th>
    <td>
      <sub><strong>Byter 3</strong> • <strong>TCP</strong> <i>Client</i> • <strong>TCP</strong> <i>Server</i> • <strong>UDP</strong> <i>Client</i> • <strong>UDP</strong> <i>Server</i> • <strong>HTTP</strong> <i>Client</i> • <strong>HTTP</strong> <i>Server</i> • <strong>HTTP</strong> <i>WebSocket</i> • <strong>RUDP</strong> <i>Client</i> • <strong>RUDP</strong> <i>Server</i></sub>
    </td>
  </tr>
  <tr>
    <th align="left" valign="center">🔧 <sub>Work in Progress</sub></th>
    <td>
      <sub><strong>Documentation <sup>v4</sup></strong> <i><a href="https://github.com/alec1o/Netly/issues/63">#63 (New docs website)</a></i> <br> <strong>HTTP</strong> <i>Body (Enctype Detector and Parser) <a href="https://github.com/alec1o/Netly/issues/67">#67 (Body Parser as Middleware)</a></i></sub> 
    </td>
  </tr>
  <tr>
    <th align="left" valign="center">🔜 <sub>Pending Features</sub></th>
    <td><sub>Adding <a href="https://github.com/alec1o/Byter">Byter</a> v4 <sup>*In development</sup> <br> Adding RUDP tests <br> Adding HTTP tests <br> Adding Websocket tests</sub></td>
  </tr>
</table>



<br>

##### Project

> <sub>Get basic information about this project called [Netly](https://github.com/alec1o/Netly)</sub>

<table>
    <tr>
      <th align="center" valign="center"><sub><strong>Overview</strong></sub></th>
<td>
<br>
<sub>Netly is a robust C# socket library designed to streamline network communication. It offers comprehensive support for multiple protocols, including HTTP, TCP, SSL/TLS, UDP, Reliable UDP (RUDP), and WebSocket. This versatility makes Netly an excellent choice for developing a wide range of applications, from multiplayer games and chat systems to real-time data exchanges.</sub>
<br>
<br>
</td>
    </tr>
    <tr>
      <th align="center" valign="center"><sub><strong>Website</strong></sub></th>
<td>
<br>
<sub>Repository: <a href="https://github.com/alec1o/Netly"><i>github.com/alec1o/netly</i></a></sub>
<br>
<sub>Documentation: <a href="https://netly.docs.kezero.com"><i>netly.docs.kezero.com</i></a></sub>
<br>
<br>
</td>
    </tr>
    <tr>
        <th align="center" valign="center"><sub><strong>Sponsor</strong></sub></th>
<td>
<br>
<div>
    <a href="https://www.kezero.com/?invite_user='Netly'"><img alt="KeZero sponsor notice" src="/static/KeZero%20sponsor.png" height="35px" /></a>
    <br>
    <a href="https://www.jetbrains.com/community/opensource/"><img alt="JetBrains sponsor notice" src="/static/JetBrains%20sponsor.png" height="35px" /></a>
</div>
<br>
</td>
    </tr>
    <tr>
        <th align="center" valign="center"><sup><strong>Supporter</strong></sup></th>
<td>
<h6>Why Contribute to Netly?</h6>

- <sub><strong>Transform Network Communication:</strong> <br>Join us in revolutionizing how software communicates. Your contributions will help build a library that sets new standards for efficiency and reliability.</sub>
- <sub><strong>Advance Your Career:</strong> <br>Engage with innovative projects, solve complex problems, and collaborate with experts. Your involvement will sharpen your skills and expand your professional network.</sub>
- <sub><strong>Share Your Ideas:</strong> <br>Whether you're a seasoned developer or just starting out, your ideas are valuable. Contribute thoughts and suggestions to shape the future of Netly and drive innovation.</sub>

<br>

</td>
    </tr>
</table>

<br>

##### Installing

> <sub>Official publisher</sub>

| <sub>Nuget</sub>                                                    | <sub>Unity Asset Store</sub>                                                                     |
|---------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| <sub>Install on [Nuget](https://www.nuget.org/packages/Netly)</sub> | <sub>Install on [Asset Store ](https://assetstore.unity.com/packages/tools/network/225473)</sub> |

<br>

##### Versions

> <sub>Notable changes</sub>

<table>
<tr> <!-- title -->
<th><sub>v1.x.x</sub></th>
<th><sub>v2.x.x</sub></th>
<th><sub>v3.x.x</sub></th>
<th><sub>v4.x.x</sub></th>
</tr>
<tr> <!-- status -->
<td valign="center" align="center"><sup><sub><i>Legacy</i></sub></sup></td>
<td valign="center" align="center"><sup><sub><i>Legacy</i></sub></sup></td>
<td valign="center" align="center"><sup><sub><i>Stable</i></sub></sup></td>
<td valign="center" align="center"><sup><sub><i>Development</i></sub></sup></td>
</tr>
<tr> <!-- row #1 -->
<td valign="top" align="left"><sub>TCP Support</sub></td>
<td valign="top" align="left"><sub>TCP with <a href="https://bit.ly/message-framing">Message Framing support</a></sub></td>
<td valign="top" align="left"><sub>TCP with TLS/SSL support</sub></td>
<td valign="top" align="left"><sub>HTTP client and server support</sub></td>
</tr>
<tr> <!-- row #2 -->
<td valign="top" align="left"><sub>UDP Support</sub></td>
<td valign="top" align="left"><sub>TCP and UDP performance increase</sub></td>
<td valign="top" align="left"><sub>UDP with connection (timeout response)</sub></td>
<td valign="top" align="left"><sub>Reliable UDP (RUDP) client and server support</sub></td>
</tr>
<tr> <!-- row #3 -->
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"><sub>New <a href="https://bit.ly/message-framing">Message Framing</a> protocol and performance increase</sub></td>
<td valign="top" align="left"><sub>WebSocket client and server support</sub></td>
</tr>
<tr> <!-- row #4 -->
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"><sub>Upgrade to <a href="https://github.com/alec1o/Byter">Byter 2.0</a></sub></td>
<td valign="top" align="left"><sub>Upgrade to <a href="https://github.com/alec1o/Byter">Byter 3.0</a></sub></td>
</tr>
<tr> <!-- row #4 -->
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"><sub><a href="https://github.com/docsifyjs/docsify">Docsify</a> as documentation framework</sub></td>
<td valign="top" align="left"><sub>Documentation improvement by <a href="https://github.com/facebook/docusaurus">Docusaurus</a> and <a href="https://github.com/Jan0660/DocFxMarkdownGen">DocFxMarkdownGen</a></sub></td>
</tr>
<tr> <!-- row #5 -->
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"><sub>Syntax and internal improvement</sub></td>
</tr>
<tr> <!-- row #6 -->
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"></td>
<td valign="top" align="left"><sub>XML comments improvement</sub></td>
</tr>
</table>

<br>

##### Integrations

> <sub>Technical descriptions about integrations</sub>

<table>
    <tr valign="top" align="left">
        <th><sub>List of tested platforms</sub></th>
<td valign="top" align="left">
<br>

- <sub>[.NET](https://dotnet.microsoft.com) (SDK)</sub>
- <sub>[Mono](https://mono-project.com) (SDK)</sub>
- <sub>[Unity](https://unity.com) (Engine)</sub>
- <sub>[Operating system](https://en.wikipedia.org/wiki/Operating_system) (OS)</sub>
    - <sub>Linux</sub>
    - <sub>Windows</sub>
    - <sub>Android</sub>
    - <sub>iOS</sub>
    - <sub>macOS</sub><br><br>
<sub><strong>Notice</strong>: <i>This library might run on all devices. If it doesn't work on any device, it
      should be considered a bug and reported.<i><sub>

<br>
</td>
    </tr>
    <tr valign="top" align="left">
        <th><sub>Dependencies</sub></th>
<td valign="top" align="left">
<br>
<a href="https://github.com/alec1o/Byter"><img alt="byter logo" src="static/Byter-logo-512/sprite_1.png" width="24px"> <sup><strong>
Byter</strong></sup></a>
<br>
</td>
    </tr>
    <tr valign="top" align="left">
        <th><sub>Build</sub></th>
<td valign="top" align="left">
<br>

> ###### Build dependencies

- <sub>[Git](http://git-scm.com/)</sub>
- <sub>[.NET](http://dot.net)</sub>

> ###### Build step-by-step

```rb
# 1. clone project
$ git clone "https://github.com/alec1o/Netly" netly 

# 2. build project
$ dotnet build "netly/" -c Release -o "netly/bin/"

# NOTE:
# Netly.dll require Byter.dll because is Netly dependency
# Netly.dll and Byter.dll have on build folder <netly-path>/bin/
```

<br>
</td>
    </tr>
    <tr valign="top" align="left">
        <th><sub>Features</sub></th>
<td valign="top" align="left">
<br>

> <sub>Below are some missing features that are planned to be added in later versions.</sub><br>

- <sub>``N/A``</sub>

<br>
</td>
    </tr>
</table>

<br>

##### Examples

> <sub>Code highlights</sub>

<table>
<tr>
<th align="center" valign="top"><sub>TCP<strong></strong></sub></th>
<td width="100%">
<details><summary>📄 <strong><sup><sub>Client</sub></sup></strong></summary>

```csharp
using Netly;

TCP.Client client = new TCP.Client(framing: true);
```

```csharp
client.On.Open(() =>
{   
    printf("connection opened");
});

client.On.Close(() =>
{
    printf("connetion closed");
});

client.On.Error((exception) =>
{
    printf("connection erro on open");
});

client.On.Data((bytes) =>
{
    printf("connection receive a raw data");
});

client.On.Event((name, data) =>
{
    printf("connection receive a event");
});

client.On.Modify((socket) =>
{
    printf("called before try open connection.");
});

client.On.Encryption((certificate, chain, errors) =>
{
    // Only if client.IsEncrypted is enabled
    printf("validate ssl/tls certificate");
    // return true if certificate is valid
    return true;
});
```

```csharp
// open connection if closed
client.To.Open(new Host("127.0.0.1", 8080));

// close connection if opened
client.To.Close();

// send raw data if connected
client.To.Data(new byte[2] { 128, 255 });
client.To.Data("hello world", NE.Encoding.UTF8);

// send event if connected
client.To.Event("name", new byte[2] { 128, 255 });
client.To.Event("name", "hello world", NE.Encoding.UTF8); 

// enable encryption (must call before client.To.Open)
client.To.Encryption(true); 
```

</details>
<details><summary>📄 <strong><sup><sub>Server</sub></sup></strong></summary>

```csharp
using Netly;

TCP.Server server = new TCP.Server(framing: true);
```

```csharp
server.On.Open(() =>
{   
    printf("connection opened");
});

server.On.Close(() =>
{
    printf("connection closed");
});

server.On.Error((exception) =>
{
    printf("connection error on open");
});

server.On.Accept((client) =>
{
    client.On.Modify((socket) =>
    {
        printf("modify client socket e.g Enable NoDelay");
    });

    client.On.Open(() =>
    {
        printf("client connected");
    });
    
    client.On.Data((bytes) =>
    {
        printf("client receive a raw data");
    });
    
    client.On.Event((name, bytes) =>
    {
        printf("client receive a event");
    });
    
    client.On.Close(() =>
    {
        printf("client disconnected");
    });
});

server.On.Modify((socket) =>
{
    printf("called before try open connection.");
});
```

```csharp
// open connection
server.To.Open(new Host("1.1.1.1", 1111)); 

// close connection
server.To.Close();

// enable encryption support (must called before server.To.Open)
server.To.Encryption(enable: true, @mypfx, @mypfxpassword, SslProtocols.Tls12);

// broadcast raw data for all connected client
server.To.DataBroadcast("text buffer");
server.To.DataBroadcast(new byte[] { 1, 2, 3 });

// broadcast event (netly event) for all connected client
server.To.EventBroadcast("event name", "text buffer");
server.To.EventBroadcast("event name", new byte[] { 1, 2, 3 });
```

</details>
</td>
</tr>

<tr><th></th></tr>

<tr>
<th align="center" valign="top"><sub>UDP<strong></strong></sub></th>
<td>
<details><summary>📄 <strong><sup><sub>Client</sub></sup></strong></summary>

```csharp
using Netly;

UDP.Client client = new UDP.Client();
```

```csharp
client.On.Open(() =>
{
    printf("connection opened");
});

client.On.Close(() =>
{
    printf("connection closed");
});

client.On.Error((exception) =>
{
    printf("connection error on open");
});

client.On.Data((bytes) =>
{
    printf("connection received a raw data");
});

client.On.Event((name, eventBytes) =>
{
    printf("connection received a event");
});

client.On.Modify((socket) =>
{
   printf("called before try open connection.");
});
```

```csharp 
// open connection if closed
client.To.Open(new Host("127.0.0.1", 8080));

// close connection if opened
client.To.Close();

// send raw data if connected
client.To.Data(new byte[2] { 128, 255 });
client.To.Data("hello world", NE.Encoding.UTF8);

// send event if connected
client.To.Event("name", new byte[2] { 128, 255 });
client.To.Event("name", "hello world", NE.Encoding.UTF8); 
```

</details>
<details><summary>📄 <strong><sup><sub>Server</sub></sup></strong></summary>

```csharp
using Netly;

UDP.Server server = new UDP.Server();
```

```csharp
server.On.Open(() =>
{
    printf("connection opened");
});

server.On.Close(() =>
{
    printf("connection closed");
});

server.On.Error((exception) =>
{
    printf("connection error on open");
});

server.On.Accept((client) =>
{
    client.On.Open(() =>
    {
        printf("client connected");
    });
    
    client.On.Close(() =>
    {
        // Only if use connection is enabled.
        printf("client disconnected");
    });
    
    client.On.Data((bytes) =>
    {
        printf("client received a raw data");
    });
    
    client.On.Event((name, bytes) =>
    {
        printf("client received a event");
    });
});
```

```csharp
// open connection
server.To.Open(new Host("127.0.0.1", 8080));

// close connection
server.To.Close();

// broadcast raw data for all connected client
server.To.DataBroadcast("text buffer");
server.To.DataBroadcast(new byte[] { 1, 2, 3 });

// broadcast event (netly event) for all connected client
server.To.EventBroadcast("event name", "text buffer");
server.To.EventBroadcast("event name", new byte[] { 1, 2, 3 });
 
```

</details>
</td>
</tr>

<tr><th></th></tr>

<tr>
<th align="center" valign="top"><sub>HTTP<strong></strong></sub></th>
<td>
<details><summary>📄 <strong><sup><sub>Client</sub></sup></strong></summary>

```csharp
using Netly;

HTTP.Client client = new HTTP.Client();

// add http header for request
client.Headers.Add("Content-Type", "json");
client.Headers.Add("Token", "ImGui.h");

// add http url queries e.g: https://www.alec1o.com/?page=about&version=4
client.Queries.Add("page", "about");
client.Queries.Add("version", "4");

// set request timeout (ms) default 15s (15000ms), 0 or negative value means infinite timeout.
client.Timeout = 6000; // 6s

// is opened: while is requesting
bool isFetching = client.IsOpened;
```

```csharp
HttpClient http = null;

// called before try connect to server
// modify the HttpClient object
client.On.Modify((HttpClient instance) =>
{
    http = instance;
});

// connection is opened and fetch server.
client.On.Open((response) =>
{
    // you can use "http" instance on this scope (isn't null)
    if (http.<foo> == <bar>) { ... }
});

// erro on fetch, it can be timeout or whatever error
// but if you receives error it mean the operation is called or done
client.On.Error((Exception exception) =>
{
    Ny.Logger.PushError(exception);
});

// connection is closed with fetch server.
client.On.Close(() =>
{
     if (http.<bar> == <foo>) { ... }
});
```

```csharp

// used to fetch a server
client.To.Open("method e.g GET", "url", "body, allow null");

// used for cancel opened request
client.To.Close();

```

</details>
<details><summary>📄 <strong><sup><sub>Server</sub></sup></strong></summary>

```csharp
using Netly;

HTTP.Server server = new HTTP.Server();

// return true if server is serve http context
bool isServe = server.IsOpened;

```

```csharp

server.On.Open(() =>
{
    // http server opened 
});
server.On.Close(() =>
{
    // http server closed 
});

server.On.Error((exception) =>
{
    // http server open error
});

server.On.Modify((httpListener) =>
{
    // HttpListener instance, called before try open connection.    
});

// Open http server connection
server.To.Open(new Uri("http://127.0.0.1:8080/"));

// Close http server connection
server.To.Close();
```

##### Map

```csharp
// Map path
server.Map.Get("/", async (req, res) => {
    // Handle async: GET
})

server.Map.Post("/user", (req, res) => {
    // Handle sync: POST
});

// map using dynamic URL
server.Map.Delete("/post/{userId}/group/{groupId}", async (req, res)) => 
{
    string userId = req.Param["userId"];
    string groupId = req.Param["groupId"];
    
    // Handle async: Delete from dynamic URL path 
});

server.Map.WebSocket("/echo", (req, ws) =>
{
    // Handle websocket connection from path
});

/*
You can map: 
 * Get     # get request
 * Post    # post request
 * Delete  # delete request
 * Put     # put request
 * Patch   # patch request
 * Trace   # trace request
 * Options # options request
 * Head    # head request, (only head)
 * All     # all http nethod request
 * WebSocket   # websocket request
*/
    
```

##### Middleware

```csharp
/*
    Note: Middlewares is executed in added order
*/

// Global Middleware (*don't have workflow path)
server.Middleware.Add(async (req, res, next) => {
    // verify request timer
    Stopwatch watch = new Stopwatch(); // init timer

    next(); // call another middleware.

    watch.Stop(); // stop timer

    res.Header.Add("Request-Timer", watch.ElapsedMilliseconds.ToString());
});


// Local middleware (have workflow path)
server.Middleware.Add("/admin", async (req, res, next) => {

    if (MyApp.CheckAdminByHeader(req.Header))
    {       
        res.Header.Add("Admin-Token", MyApp.RefreshAdminHeaderToken(req));
        // call next middleware
        next();
        // now. all middleware is executed. (because this is two way middleware)
        res.Header.Add("Request-Delay", (DateTime.UtcNow - timer)());
    }
    else
    {
        res.Header.Add("Content-Type", "application/json;charset=UTF-8");
        await res.Send(404, "{ 'error': 'invalid request.' }");
        // skip other middlewares:
        // next();
    }
});
```

</details>
</td>
</tr>


<tr><th></th></tr>

<tr>
<th align="center" valign="top"><sub>RUDP<strong></strong></sub></th>
<td>
<details><summary>📄 <strong><sup><sub>Client</sub></sup></strong></summary>

```csharp
using Netly;

RUDP.Client client = new RUDP.Client();
```

```csharp
client.On.Open(() =>
{
    printf("connection opened");
});

client.On.Close(() =>
{
    printf("connection closed");
});

client.On.Error((exception) =>
{
    printf("connection error on open");
});

client.On.Data((bytes, type) =>
{
    printf("connection received a raw data");
});

client.On.Event((name, bytes, type) =>
{
    printf("connection received a event");
});

client.On.Modify((socket) =>
{
    printf("called before try open connection.");
});
```

```csharp
// open connection if closed
client.To.Open(new Host("127.0.0.1", 8080));

// close connection if opened
client.To.Close();

// send raw data if connected
client.To.Data(new byte[2] { 128, 255 }, RUDP.Unreliable);
client.To.Data("hello world", NE.Encoding.UTF8, RUDP.Reliable);

// send event if connected
client.To.Event("name", new byte[2] { 128, 255 }, RUDP.Unreliable);
client.To.Event("name", "hello world", NE.Encoding.UTF8, RUDP.Reliable);
```

</details>
<details><summary>📄 <strong><sup><sub>Server</sub></sup></strong></summary>

```csharp
using Netly;

RUDP.Server server = new RUDP.Server();
```

```csharp
server.On.Open(() =>
{
    printf("connection opened");
});

server.On.Close(() =>
{
    printf("connection closed");
});

server.On.Error((exception) =>
{
    printf("connection error on open");
});

server.On.Accept((client) =>
{
    client.On.Open(() =>
    {
        printf("client connected");
    });
    
    client.On.Close(() =>
    {
        // Only if use connection is enabled.
        printf("client disconnected");
    });
    
    client.On.Data((bytes, type) =>
    {
        if (type == RUDP.Reliable) { ... }
        else if (type == RUDP.Unreliable) { ... }
        else {  ... } /* type == RUDP.Sequenced */

        
        printf("client received a raw data");
    });
    
    client.On.Event((name, type) =>
    
        if (type == RUDP.Reliable) { ... }
        else if (type == RUDP.Unreliable) { ... }
        else {  ... } /* type == RUDP.Sequenced */
        
        printf("client received a event");
    });    
});
```

```csharp
// open connection
server.To.Open(new Host("127.0.0.1", 8080));

// close connection
server.To.Close();

// broadcast raw data for all connected client
server.To.DataBroadcast("text buffer", RUDP.Unreliable);
server.To.DataBroadcast(new byte[] { 1, 2, 3 }, RUDP.Reliable);
server.To.DataBroadcast(new byte[] { 3, 2, 1 }, RUDP.Sequenced);

// broadcast event (netly event) for all connected client
server.To.EventBroadcast("event name", "text buffer", RUDP.Unreliable);
server.To.EventBroadcast("event name", new byte[] { 1, 2, 3 }, RUDP.Reliable);
server.To.EventBroadcast("event name", new byte[] { 3, 2, 1 }, RUDP.Sequenced);
```

</details>
</td>
</tr>

<tr><th></th></tr>

<tr>
<th align="center" valign="top"><sub>WebSocket<strong></strong></sub></th>
<td>
<details><summary>📄 <strong><sup><sub>Client</sub></sup></strong></summary>

```csharp
using Netly;

HTTP.WebSocket client = new HTTP.WebSocket();
```

```csharp
client.On.Open(() =>
{
    // websocket connection opened
});

client.On.Close(() =>
{
    // websocket connection closed
});

client.On.Error((exception) =>
{
    // error on open websocket connectin
});

client.On.Data((bytes, type) =>
{
    if (type == HTTP.Binary) { ... }
    else if (type == HTTP.Text) { ... }
    else { /* NOTE: it's imposible */ }
    
    // raw data received from server
});

client.On.Event((name, bytes, type) =>
{
    if (type == HTTP.Binary) { ... }
    else if (type == HTTP.Text) { ... }
    else { /* NOTE: it's imposible */ }
    
    // event received from server
});

client.On.Modify((wsSocket) =>
{
    // modify websocket socket
});
```

```csharp
// open websocket client connection
client.To.Open(new Uri("ws://127.0.0.1:8080/echo"));

// close websocket client connection
client.To.Close();

// send raw data for server
//      text message
client.To.Data("my message", HTTP.Text);
//      binnary message
client.To.Data(NE.GetBytes("my buffer"), HTTP.Binary);

// send event (netly event) for server
//      text message
client.To.Event("event name", "my message", HTTP.Text);
//      binnary message
client.To.Data("event name", NE.GetBytes("my buffer"), HTTP.Binary); 
```

</details>
<details><summary>📄 <strong><sup><sub>Server</sub></sup></strong></summary>

```csharp
using Netly;
using Netly.Interfaces;

HTTP.Server server = new HTTP.Server();

IHTTP.WebSocket[] Clients = server.WebSocketClients;
```

```csharp
server.Map.WebSocket("/chat/{token}", async (req, ws) =>
{
    // Accept websocket from dynamic path
    string token = req.Params["token"];
    
    // validate websocket connection from params
    if (Foo.Bar(token) == false)
    {
        ws.To.Close();
    }
    
    ws.On.Modify(...);
    ws.On.Open(...);
    ws.On.Close(...);
    ws.On.Data(...);
    ws.On.Event(...);
});


server.Map.Websocket("/echo", (req, ws) =>
{
    // Handle websocket on /echo path
    
    ws.On.Modify((wsSocket) =>
    {
        // modify server-side websocket ocket
    });
    
    ws.On.Open(() =>
    {
        // server-side websocket connection opened
    });
    
    ws.On.Close(() =>
    {
        // server-side websocket connection closed
    });
    
    ws.On.Data((bytes, type) =>
    {
        if (type == HTTP.Binary) { ... }
        else if (type == HTTP.Text) { ... }
        else { /* NOTE: it's imposible */ }
        
        // server-side websocket received raw data
    });
    
    ws.On.Event((name, bytes, type) =>
    {
        if (type == HTTP.Binary) { ... }
        else if (type == HTTP.Text) { ... }
        else { /* NOTE: it's imposible */ }
        
        // server-side websocket received event
    });
});
```

```csharp
server.On.Open(() =>
{
    // http server opened 
});
server.On.Close(() =>
{
    // http server closed 
});

server.On.Error((exception) =>
{
    // http server open error
});

server.On.Modify((httpListener) =>
{
    // HttpListener instance, called before try open connection.    
});

// Open http server connection
server.To.Open(new Uri("http://127.0.0.1:8080/"));

// Close http server connection
server.To.Close();
```

```csharp
// open websocket client connection
server.To.Open(new Uri("ws://127.0.0.1:8080/echo"));

// close websocket client connection
server.To.Close();

// broadcast raw data for all connected websocket socket
//      text message
server.To.WebsocketDataBroadcast("my message", HTTP.Text);
//      binnary message
server.To.WebsocketDataBroadcast(NE.GetBytes("my buffer"), HTTP.Binary);

// broadcast event (netly event) for all connected websocket socket
//      text message
server.To.WebsocketEventBroadcast("event name", "my message", HTTP.Text);
//      binnary message
server.To.WebsocketEventBroadcast("event name", NE.GetBytes("my buffer"), HTTP.Binary); 
```

</details>

</td>

</tr>

<tr><th></th></tr>

<tr>
<th align="center" valign="top"><a href="https://github.com/alec1o/Byter"><sub>Byter<strong></strong></sub></a></th>
<td>

###### For more information and details see [Byter's](https://github.com/alec1o/Byter) official information

> <sub>Byter documentation: [alec1o/Byter](https://github.com/alec1o/Byter)</sub>
<details><summary>📄 <strong><sup><sub>Primitive</sub></sup></strong></summary>

```csharp
using Byter;
```

- <strong><sub>Serialize</sub></strong>  <sub>_(have +20 types of data supported, e.g. enum, bool, array, list, class,
  struct,... [see official docs](https://github.com/alec1o/Byter)_</sub>
    ```csharp
    Primitive primitive = new();
    
    // add element
    
    primitive.Add.ULong(1024);                 // e.g. Id
    primitive.Add.DateTime(DateTime.UtcNow);   // e.g. Sent Time
    primitive.Add.Struct(new Student() {...}); // e.g Student
    primitive.Add.Class(new Employee() {...}); // e.g Employee
    ...
    
    // get buffer
    byte[] buffer = primitive.GetBytes();
    ```

- <strong><sub>Deserialize</sub></strong>
    ```csharp
    // WARNING: Need primitive buffer to deserialize
    Primitive primitive = new(...buffer);
    
    ulong id = primitive.Get.ULong();
    DateTime sentTime = primitive.Get.DateTime();
    Student student = primitive.Get.Struct<Student>();
    Employee employee = primitive.Get.Class<Employee>();
    
    /*
        * NOTE: Primitive don't make exception when diserialize error,
        * don't need try/catch block
    */
    if (primitive.IsValid is false)
    {
        // discart this. +1/all failed on deserialize
        return;
    }
    
    // deserialized sucessful
    ```
- <strong><sub>*Dynamic Read Technical</sub></strong>
    ```csharp
    Primitive primitive = new(...buffer);
    
    var topic = primitive.Get.Enum<Topic>();
    
    if(!primitive.IsValid) return; // discart this, topic not found.
    
    switch(topic)
    {
        case Topic.Student:
        {
            // read student info e.g.
            var student = primitive.Get.Struct<Student>();
            ...
            return;
        }
        
        case Topic.Employee:
        {
            // read employee info e.g.
            var employee = primitive.Get.Class<Employee>();
            ...
            return;
        }
        
        default:
        {        
            // discart this, topic not found. 
            ...
            return;
        }
    }
    ```

___

###### Warning
Primitive can serialize/deserialize complex data, e.g. (T[], List<T>, Class, Struct, Enum).<br>
But when you want to deserialize your (Class, Structure, List<Class/Struct>, Class/Struct[]), It must have:
- (generic and public constructor: is a public constructor with no arguments, e.g. which allows:
  ```csharp
  Human human = new Human();
  ```
- And the class/struct property must have public access and { get; set; } or not private
for example. (In byter programming, _ONLY PROPERTIES THAT CAN BE READ AND WRITTEN WILL BE SERIALIZED AND DESERIALIZED)_
  ```csharp
  // valid
  public string Name;
  public string Name { get; set; }
  internal string Name; // !!! if visible from Byter
  internal string Name { get; set; }; // !!! if visible from Byter
  
  // invalid
  private string Name;
  private string Name { get; set; }
  internal string Name; // !!! if unvisible from Byter
  internal string Name { get; set; }; // !!! if unvisible from Byter
  ```

___

###### Example

- <strong><sub>Sample of complex data</sub></strong>
    ```cs
    public class Human
    {
        public BigInteger IdNumber { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public DateTime DateOfBirth { get; set; }
        public GenderType Gender { get; set; } // enum
        public byte[] Picture { get; set; }
        
    }
    
    public class Employee
    {
        public Human Human { get; set; }
        public string Position { get; set; }
        public DateTime HireDate { get; set; }
        public int YearsOfService { get; set; }
    }
    
    public struct Student 
    {
        public string Major { get; set; }
        public DateTime EnrollmentDate { get; set; }
        public List<Book> Books { get; set; }   
        
    }
    
    public class Book
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public string ISBN { get; set; }
        public int PublicationYear { get; set; }
        public string Publisher { get; set; }
        public decimal Price { get; set; }
    }
    ```

</details>
<details><summary>📄 <strong><sup><sub>Extension</sub></sup></strong></summary>

```csharp
using Byter;
```

- <strong><sub>Global Default
  Encoding</sub></strong> [<i><sub>(source code spec)</sub></i>](https://github.com/alec1o/Byter/blob/main/src/src/extension/StringExtension.cs#L8)
   ```csharp
   // update global defaut encoding. Default is UTF8
   StringExtension.Default = Encoding.Unicode; // Unicode is UTF16
   ```

- <strong><sub>Convert string to byte[]</sub></strong>
    ```csharp
    // using global encoding (*UTF8)
    byte[] username  = "@alec1o".GetBytes(); 
    
    // using UNICODE (*UTF16) encoding
    byte[] message = "Hello 👋 World 🌎".GetBytes(Encoding.Unicode); 
    
    // using UTF32 encoding
    string secreatWord = "I'm not human, I'm  a concept.";
    byte[] secreat = secreatWord.GetBytes(Encoding.UTF32);
    ```

- <strong><sub>Convert byte[] to string</sub></strong>
    ```csharp
    // using global encoding (*UTF8)
    string username  = new byte[] { ... }.GetString(); 
    
    // using UNICODE (*UTF16) encoding
    string message = new byte[] { ... }.GetString(Encoding.Unicode); 
    
    // using UTF32 encoding
    byte[] secreat = new byte[] { ... };
    string secreatWord = secreat.GetString(Encoding.UTF32);
    ```

- <strong><sub>Capitalize string</sub></strong>
    ```rb
    string name = "alECio furanZE".ToCapitalize();
    # Alecio Furanze
    
    string title = "i'M noT humAn";
    title = title.ToCapitalize();
    # I'm Not Human
    ```

- <strong><sub>UpperCase string</sub></strong>
    ```rb
    string name = "alECio furanZE".ToUpperCase();
    # ALECIO FURANZE
    
    string title = "i'M noT humAn";
    title = title.ToUpperCase();
    # I'M NOT HUMAN
    ```

- <strong><sub>LowerCase string</sub></strong>
    ```rb
    string name = "ALEciO FUraNZE".ToLowerCase();
    # alecio furanze
    
    string title = "i'M Not huMAN";
    title = title.ToLowerCase();
    # i'm not human
    ```

</details>

<a href="###"><img src="/static/transparent-horizontal-1px-2048px.png" width="100%"><a/>

</td>

</tr>
</table>

<br>

##### Usage

> <sub>Integration and interaction example codes</sub>


<table>

<tr>
<th align="center" valign="top"><sub><strong>Standard</strong></sub></th>
<td>
<details><summary>📄 <strong><sup><sub>Console</sub></sup></strong></summary>

```csharp
using System;
using Netly;

public class Program
{
    private static void Main(string[] args)
    {
        UDP.Client client = new UDP.Client();
        
        client.On.Open(() =>
        {
            Console.WriteLine(<some-text-here>);
        };
            
        client.On.Close(() =>
        {
            Console.WriteLine(<some-text-here>);
        };
            
        client.On.Error((exception) =>
        {
            Console.WriteLine(<some-text-here>);
        };
        
        while(true)
        {
            if(!client.IsOpened)
            {
                client.To.Open(new Host("1.1.1.1", 1111));
            }
            else
            {
                Console.WriteLine("Message: ");
                string message = Console.ReadLine();
                client.To.Data(message ?? "No message.", NE.Encoding.UTF8);
            }
        }
    }
}
```

</details>
</td>
</tr>

<tr><th></th></tr>

<tr>
<th align="center" valign="top"><sub><strong>Flax Engine</strong></sub></th>
<td>
<details><summary>📄 <strong><sup><sub>Script</sub></sup></strong></summary>

```csharp
using System;
using FlaxEngine;
using Netly;

public class Example : Script
{
    public string message;
    
    internal UDP.Client client;
    
    public override void Awake()
    {
        client = new UDP.Client();        
        
        client.On.Open(() =>
        {
            Debug.Log(<some-text-here>);
        };
            
        client.On.Close(() =>
        {
            Debug.Log(<some-text-here>);
        };
            
        client.On.Error((exception) =>
        {
            Debug.Log(<some-text-here>);
        };
    }
    
    public override void Start()
    {
        client.To.Open(new Host("1.1.1.1", 1111));
    }
    
    public override void Update()
    {
        if(!client.IsOpened)
        {
             client.To.Open(new Host("1.1.1.1", 1111));
        }
        else
        {            
            if (Input.GetKeyDown(KeyCode.Space))
            {
                client.To.Data(message ?? "No message.", NE.Encoding.UTF8);
            }
        }
    }
}
```

</details>
</td>
</tr>

<tr><th></th></tr>

<tr>
<th align="center" valign="top"><sub><strong>Unity Engine</strong></sub></th>
<td>

<details><summary>📄 <strong><sup><sub>MonoBehaviour</sub></sup></strong></summary>

```csharp
using System;
using FlaxEngine;
using Netly;

public class Example : MonoBehaviour
{
    public string message;
    
    internal UDP.Client client;
    
    private void Awake()
    {
        client = new UDP.Client();        
        
        client.On.Open(() =>
        {
            Debug.Log(<some-text-here>);
        };
            
        client.On.Close(() =>
        {
            Debug.Log(<some-text-here>);
        };
            
        client.On.Error((exception) =>
        {
            Debug.Log(<some-text-here>);
        };
    }
    
    private void Start()
    {
        client.To.Open(new Host("1.1.1.1", 1111));
    }
    
    private void Update()
    {
        if(!client.IsOpened)
        {
             client.To.Open(new Host("1.1.1.1", 1111));
        }
        else
        {            
            if (Input.GetKeyDown(KeyCode.Space))
            {
                client.To.Data(message ?? "No message.", NE.Encoding.UTF8);
            }
        }
    }
}
```

</details>
</td>
</tr>

<tr><th></th></tr>
<tr>
<tr>
<th align="center" valign="top"><sub><i>WARNING:</i></sub></th>
<td>

<sub>
<strong>Initialize event handlers once, not in loops</strong>. Set up handlers with `<protocol>.<client|server>.On.<event>` methods in initialization methods like `Awake()` or `Start()`. Avoid repeatedly setting these up in update loops to maintain performance.
</sub>
<br>
<br>
<sub>
<strong>Handle protocol actions wisely</strong>. Use `<protocol>.<client|server>.To.<action>` methods, such as `<protocol>.<client|server>.To.Open()`, `<protocol>.<client|server>.To.Data()`, and `<protocol>.<client|server>.To.Close()`, with careful management. Ensure you only open a connection when it's not already open and send data only when the connection is confirmed as active. Avoid calling these methods in tight loops.
</sub>

<br><br>
  
```csharp
// OK 100% Recommended 
private void Start()
{
    var client = ...;

    client.On.Open(() => ...); // e.g generic handler
    client.On.Open(() => ...); // e.g only to send "Hi"
    client.On.Event((name, bytes, ?) => ...); // e.g generic event handler
    client.On.Event((name, bytes, ?) => ...); // e.g only to handle A event
    client.On.Event((name, bytes, ?) => ...); // e.g only to handle B event

    client.To.Open(...);
}
```

```csharp
public void Update()
{
    client.To.Open(...);                 // [OK? - May Not In Loop?]
    client.To.Data(...);                 // [OK? - May Not In Loop?]
    client.To.Event(...);                // [OK? - May Not In Loop?]
    client.To.Close(...);                // [OK? - May Not In Loop?]   
    
    ws.On.Open(() => ...);               // [BAD - Never In Loop]
    ws.On.Close(() => ... );             // [BAD - Never In Loop]
    ws.On.Data((bytes) => ... );         // [BAD - Never In Loop]
    ws.On.Error((exception) => ... );    // [BAD - Never In Loop]
    ws.On.Event((name, bytes) =>  ... ); // [BAD - Never In Loop]
}
```

<br>
</td>
</tr>
</table>
