Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions Jung.SimpleWebSocket.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35222.181
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{0487DC39-481D-4828-81A5-58CF9BCA2E98}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{68AB7986-ED88-4C74-A447-934ED6D1B657}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jung.SimpleWebSocket", "src\Jung.SimpleWebSocket\Jung.SimpleWebSocket.csproj", "{793B04E9-6326-425A-A29C-A736CFD1E0C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jung.SimpleWebSocket.UnitTests", "tests\Jung.SimpleWebSocket.UnitTests\Jung.SimpleWebSocket.UnitTests.csproj", "{26725C3C-8E90-49AC-9EE4-2A77ADB2229D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jung.SimpleWebSocket.IntegrationTests", "tests\Jung.SimpleWebSocket.IntegrationTests\Jung.SimpleWebSocket.IntegrationTests.csproj", "{D052400A-9F1E-4F2E-98B9-AF74A7A16A2F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicServerExample", "examples\BasicServerExample\BasicServerExample.csproj", "{0C73E461-DE3D-4D14-B81B-732B7C6971A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicClientExample", "examples\BasicClientExample\BasicClientExample.csproj", "{9D4AD09E-B6FF-4E2A-894E-49B97729E190}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicUserHandlingServerExample", "examples\BasicUserHandlingServerExample\BasicUserHandlingServerExample.csproj", "{A538895A-481B-44A5-8E6F-6D617C3F5378}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BasicUserHandlingClientExample", "examples\BasicUserHandlingClientExample\BasicUserHandlingClientExample.csproj", "{C79EBA14-EFA6-424D-9C6E-609C98994473}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -27,10 +41,35 @@ Global
{D052400A-9F1E-4F2E-98B9-AF74A7A16A2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D052400A-9F1E-4F2E-98B9-AF74A7A16A2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D052400A-9F1E-4F2E-98B9-AF74A7A16A2F}.Release|Any CPU.Build.0 = Release|Any CPU
{0C73E461-DE3D-4D14-B81B-732B7C6971A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0C73E461-DE3D-4D14-B81B-732B7C6971A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C73E461-DE3D-4D14-B81B-732B7C6971A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C73E461-DE3D-4D14-B81B-732B7C6971A1}.Release|Any CPU.Build.0 = Release|Any CPU
{9D4AD09E-B6FF-4E2A-894E-49B97729E190}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9D4AD09E-B6FF-4E2A-894E-49B97729E190}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9D4AD09E-B6FF-4E2A-894E-49B97729E190}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9D4AD09E-B6FF-4E2A-894E-49B97729E190}.Release|Any CPU.Build.0 = Release|Any CPU
{A538895A-481B-44A5-8E6F-6D617C3F5378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A538895A-481B-44A5-8E6F-6D617C3F5378}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A538895A-481B-44A5-8E6F-6D617C3F5378}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A538895A-481B-44A5-8E6F-6D617C3F5378}.Release|Any CPU.Build.0 = Release|Any CPU
{C79EBA14-EFA6-424D-9C6E-609C98994473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C79EBA14-EFA6-424D-9C6E-609C98994473}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C79EBA14-EFA6-424D-9C6E-609C98994473}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C79EBA14-EFA6-424D-9C6E-609C98994473}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{793B04E9-6326-425A-A29C-A736CFD1E0C0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{26725C3C-8E90-49AC-9EE4-2A77ADB2229D} = {68AB7986-ED88-4C74-A447-934ED6D1B657}
{D052400A-9F1E-4F2E-98B9-AF74A7A16A2F} = {68AB7986-ED88-4C74-A447-934ED6D1B657}
{0C73E461-DE3D-4D14-B81B-732B7C6971A1} = {0487DC39-481D-4828-81A5-58CF9BCA2E98}
{9D4AD09E-B6FF-4E2A-894E-49B97729E190} = {0487DC39-481D-4828-81A5-58CF9BCA2E98}
{A538895A-481B-44A5-8E6F-6D617C3F5378} = {0487DC39-481D-4828-81A5-58CF9BCA2E98}
{C79EBA14-EFA6-424D-9C6E-609C98994473} = {0487DC39-481D-4828-81A5-58CF9BCA2E98}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F0E3FEC-7DDE-4E02-941B-CEF2DE33DB1C}
EndGlobalSection
Expand Down
14 changes: 14 additions & 0 deletions examples/BasicClientExample/BasicClientExample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Jung.SimpleWebSocket\Jung.SimpleWebSocket.csproj" />
</ItemGroup>

</Project>
59 changes: 59 additions & 0 deletions examples/BasicClientExample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// This file is part of the Jung SimpleWebSocket project.
// The project is licensed under the MIT license.

using Jung.SimpleWebSocket;

namespace BasicClientExample
{
internal class Program
{
/// <summary>
/// An example of a basic WebSocket client using the Jung.SimpleWebSocket library.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// Create the WebSocket client and connect to the server at ws://127.0.0.1:8085/chat
using var simpleWebSocketClient = new SimpleWebSocketClient("127.0.0.1", 8085, "/chat");

// Subscribe to client events
simpleWebSocketClient.Disconnected += (s, e) => Console.WriteLine($"Disconnected from the server. Reason: {e.ClosingStatusDescription}");
simpleWebSocketClient.MessageReceived += (s, e) => Console.WriteLine($"Message received from server: {e.Message}");
simpleWebSocketClient.BinaryMessageReceived += (s, e) => Console.WriteLine($"Binary message received from server: {BitConverter.ToString(e.Message)}");

try
{
// Connect to the server
simpleWebSocketClient.ConnectAsync().GetAwaiter().GetResult();

// Simulate any delay
Thread.Sleep(1000);

// Send a message to the server
Console.WriteLine("Sending message to the server: Hello, Server!");
simpleWebSocketClient.SendMessageAsync("Hello, Server!").GetAwaiter().GetResult();

// Keep the server running until a key is pressed
Console.WriteLine("Press Enter to stop the server...");
Console.ReadKey();

// You do not have to explicitly disconnect the client because of the using statement
// simpleWebSocketClient.DisconnectAsync("Client is shutting down").Wait();
}
catch (Exception exception)
{

var exceptionMessage = exception.Message;
if (exception.InnerException != null)
{
exceptionMessage += $" Inner exception: {exception.InnerException.Message}";
}
Console.WriteLine($"An error occurred: {exceptionMessage}");

// Keep the console application running until a key is pressed
Console.WriteLine("Press Enter close this window...");
Console.ReadKey();
}
}
}
}
14 changes: 14 additions & 0 deletions examples/BasicServerExample/BasicServerExample.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Jung.SimpleWebSocket\Jung.SimpleWebSocket.csproj" />
</ItemGroup>

</Project>
93 changes: 93 additions & 0 deletions examples/BasicServerExample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// This file is part of the Jung SimpleWebSocket project.
// The project is licensed under the MIT license.

using Jung.SimpleWebSocket;
using Jung.SimpleWebSocket.Models;
using Jung.SimpleWebSocket.Models.EventArguments;

namespace BasicServerExample
{
internal class Program
{
/// <summary>
/// An example of a basic WebSocket server using the Jung.SimpleWebSocket library.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// Create server options
var serverOptions = new SimpleWebSocketServerOptions()
{
// Set the server to listen on port 8085 and localhost
Port = 8085,
LocalIpAddress = new System.Net.IPAddress([127, 0, 0, 1])
};

// Create the WebSocket server
using var simpleWebSocketServer = new SimpleWebSocketServer(serverOptions);

// Subscribe to the server events
simpleWebSocketServer.ClientConnected += (s, e) => Console.WriteLine($"Client connected: {e.ClientId}");
simpleWebSocketServer.ClientDisconnected += (s, e) => Console.WriteLine($"Client disconnected: {e.Client.Id}, Reason: {e.ClosingStatusDescription}");
simpleWebSocketServer.MessageReceived += (s, e) => Console.WriteLine($"Message received from {e.ClientId}: {e.Message}");
simpleWebSocketServer.BinaryMessageReceived += SimpleWebSocketServer_BinaryMessageReceived;
simpleWebSocketServer.ClientUpgradeRequestReceivedAsync += SimpleWebSocketServer_ClientUpgradeRequestReceivedAsync;

// Start the server
simpleWebSocketServer.Start();
Console.WriteLine("Server started on ws://127.0.0.1:8085");

// Keep the server running until a key is pressed
Console.WriteLine("Press Enter to stop the server...");
Console.ReadKey();

// You do not have to explicitly shutdown the server because of the using statement
// simpleWebSocketServer.ShutdownServer().Wait();
}

/// <summary>
/// This event is triggered when a client sends a binary message to the server.
/// </summary>
/// <param name="sender">The server that received the binary message.</param>
/// <param name="e">The event arguments containing the client ID and the binary message.</param>
private static void SimpleWebSocketServer_BinaryMessageReceived(object? sender, ClientBinaryMessageReceivedArgs e)
{
// Convert the binary message to a hex string
string hex = BitConverter.ToString(e.Message);
Console.WriteLine($"Binary message received from {e.ClientId}: {hex}");
}

/// <summary>
/// This event is triggered when a client sends an upgrade request to the server.
/// </summary>
/// <param name="sender">The server that received the upgrade request.</param>
/// <param name="e">The event arguments containing the client and the request details.</param>
/// <param name="cancellationToken">The cancellation token of the server.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
private static Task SimpleWebSocketServer_ClientUpgradeRequestReceivedAsync(object sender, ClientUpgradeRequestReceivedArgs e, CancellationToken cancellationToken)
{
Console.WriteLine($"Upgrade request received from {e.Client.Id} for {e.WebContext.RequestPath}");

// Do something with the upgrade request
// For example save request path to client properties
e.Client.Properties["RequestPath"] = e.WebContext.RequestPath;

// Or reject the upgrade request if the request path is not /chat
if (e.WebContext.RequestPath != "/chat")
{
// It is recommended to set a status code higher than 400 to reject the upgrade request.
e.ResponseContext.StatusCode = System.Net.HttpStatusCode.Forbidden; // 403 Forbidden
// Handle the request and reject it
e.AcceptRequest = false;
}
else
{
// Handle the request and accept it
e.AcceptRequest = true;
}

// Because this is an async event, we need to return a completed task.
return Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Jung.SimpleWebSocket\Jung.SimpleWebSocket.csproj" />
</ItemGroup>

</Project>
77 changes: 77 additions & 0 deletions examples/BasicUserHandlingClientExample/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// This file is part of the Jung SimpleWebSocket project.
// The project is licensed under the MIT license.

using Jung.SimpleWebSocket;
using Jung.SimpleWebSocket.Models.EventArguments;

namespace BasicUserHandlingClientExample
{
internal class Program
{
/// <summary>
/// An example of a basic WebSocket client using the Jung.SimpleWebSocket library.
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// Create the WebSocket client and connect to the server at ws://127.0.0.1:8085/chat
using var simpleWebSocketClient = new SimpleWebSocketClient("127.0.0.1", 8085, "/chat");

// Subscribe to client events
simpleWebSocketClient.Disconnected += (s, e) => Console.WriteLine($"Disconnected from the server. Reason: {e.ClosingStatusDescription}");
simpleWebSocketClient.MessageReceived += (s, e) => Console.WriteLine($"Message received from server: {e.Message}");
simpleWebSocketClient.BinaryMessageReceived += (s, e) => Console.WriteLine($"Binary message received from server: {BitConverter.ToString(e.Message)}");
simpleWebSocketClient.SendingUpgradeRequestAsync += SimpleWebSocketClient_SendingUpgradeRequestAsync;

try
{
// Connect to the server
simpleWebSocketClient.ConnectAsync().GetAwaiter().GetResult();

// Simulate any delay
Thread.Sleep(1000);

// Send a message to the server
Console.WriteLine("Sending message to the server: Hello, Server!");
simpleWebSocketClient.SendMessageAsync("Hello, Server!").GetAwaiter().GetResult();

// Keep the server running until a key is pressed
Console.WriteLine("Press Enter to stop the server...");
Console.ReadKey();

// You do not have to explicitly disconnect the client because of the using statement
// simpleWebSocketClient.DisconnectAsync("Client is shutting down").GetAwaiter().GetResult();
}
catch (Exception exception)
{
var exceptionMessage = exception.Message;
if (exception.InnerException != null)
{
exceptionMessage += $" Inner exception: {exception.InnerException.Message}";
}
Console.WriteLine($"An error occurred: {exceptionMessage}");

// Keep the console application running until a key is pressed
Console.WriteLine("Press Enter close this window...");
Console.ReadKey();
}
}

/// <summary>
/// Handles the event triggered before a WebSocket upgrade request is sent, allowing customization of the
/// request.
/// </summary>
/// <param name="sender">The source of the event, the WebSocket client instance.</param>
/// <param name="e">The event arguments containing details about the upgrade request, including headers and other context.</param>
/// <param name="cancellationToken">The cancellation token of the client.</param>
/// <returns>A completed task, as this method performs its operation synchronously.</returns>
private static Task SimpleWebSocketClient_SendingUpgradeRequestAsync(object sender, SendingUpgradeRequestArgs e, CancellationToken cancellationToken)
{
// Add a custom header to the upgrade request
e.WebContext.Headers["User-Name"] = "Alice";

// Because this is a synchronous method, we return a completed task.
return Task.CompletedTask;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Jung.SimpleWebSocket\Jung.SimpleWebSocket.csproj" />
</ItemGroup>

</Project>
Loading