diff --git a/Tunnelite.sln b/Tunnelite.sln index 7db3f9d..8c1a902 100644 --- a/Tunnelite.sln +++ b/Tunnelite.sln @@ -17,7 +17,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.TcpServer", "test\Test EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.TcpForwarder", "test\Test.TcpForwarder\Test.TcpForwarder.csproj", "{BCC3AD29-688B-4482-B952-F0095D104020}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test.WebApi", "test\Test.WebApi\Test.WebApi.csproj", "{B2656A6C-79E5-41A1-93B2-F87D550FB02E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.WebApi", "test\Test.WebApi\Test.WebApi.csproj", "{B2656A6C-79E5-41A1-93B2-F87D550FB02E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tunnelite.Sdk", "src\Tunnelite.Sdk\Tunnelite.Sdk.csproj", "{BCC85AF5-8BD0-4E4E-AB0E-306FF640537D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tunnelite.AspNetCore", "src\Tunnelite.AspNetCore\Tunnelite.AspNetCore.csproj", "{E66B7CBA-88CB-41EF-B0B2-8A57F2F9CE81}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -49,6 +53,14 @@ Global {B2656A6C-79E5-41A1-93B2-F87D550FB02E}.Debug|Any CPU.Build.0 = Debug|Any CPU {B2656A6C-79E5-41A1-93B2-F87D550FB02E}.Release|Any CPU.ActiveCfg = Release|Any CPU {B2656A6C-79E5-41A1-93B2-F87D550FB02E}.Release|Any CPU.Build.0 = Release|Any CPU + {BCC85AF5-8BD0-4E4E-AB0E-306FF640537D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BCC85AF5-8BD0-4E4E-AB0E-306FF640537D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BCC85AF5-8BD0-4E4E-AB0E-306FF640537D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BCC85AF5-8BD0-4E4E-AB0E-306FF640537D}.Release|Any CPU.Build.0 = Release|Any CPU + {E66B7CBA-88CB-41EF-B0B2-8A57F2F9CE81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E66B7CBA-88CB-41EF-B0B2-8A57F2F9CE81}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E66B7CBA-88CB-41EF-B0B2-8A57F2F9CE81}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E66B7CBA-88CB-41EF-B0B2-8A57F2F9CE81}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -60,6 +72,8 @@ Global {9E529D00-D5E7-4E2E-80AD-83B793B77DF8} = {230DD554-CD20-4A77-874B-E9BA59A2DC18} {BCC3AD29-688B-4482-B952-F0095D104020} = {230DD554-CD20-4A77-874B-E9BA59A2DC18} {B2656A6C-79E5-41A1-93B2-F87D550FB02E} = {230DD554-CD20-4A77-874B-E9BA59A2DC18} + {BCC85AF5-8BD0-4E4E-AB0E-306FF640537D} = {AFD8CF9B-F8B9-47C9-BEAB-FC0161D2AFB8} + {E66B7CBA-88CB-41EF-B0B2-8A57F2F9CE81} = {AFD8CF9B-F8B9-47C9-BEAB-FC0161D2AFB8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E385A6C3-BECA-4888-B12B-31AA9984F86F} diff --git a/src/Tunnelite.AspNetCore/Tunnelite.AspNetCore.csproj b/src/Tunnelite.AspNetCore/Tunnelite.AspNetCore.csproj new file mode 100644 index 0000000..346111b --- /dev/null +++ b/src/Tunnelite.AspNetCore/Tunnelite.AspNetCore.csproj @@ -0,0 +1,37 @@ + + + + net8.0 + enable + enable + Tunnelite.AspNetCore + tunnel;tunneling;websockets;signalr;reverse-proxy;proxy; + Cristi Pufu + MIT + git + README.md + SDK for tunneling AspNetCore apps + https://github.com/cristipufu/ws-tunnel-signalr + https://github.com/cristipufu/ws-tunnel-signalr + 1.0.0 + true + true + snupkg + + + + + True + \ + + + + + + + + + + + + diff --git a/src/Tunnelite.AspNetCore/TunneliteExtensions.cs b/src/Tunnelite.AspNetCore/TunneliteExtensions.cs new file mode 100644 index 0000000..ca8d942 --- /dev/null +++ b/src/Tunnelite.AspNetCore/TunneliteExtensions.cs @@ -0,0 +1,68 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Hosting.Server.Features; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Tunnelite.Sdk; + +#nullable disable +namespace Tunnelite.AspNetCore; + +public static class TunneliteExtensions +{ + private static readonly Guid ClientId = Guid.NewGuid(); + + public static IApplicationBuilder UseTunnelite(this IApplicationBuilder app) + { + var lifetime = app.ApplicationServices.GetRequiredService(); + var server = app.ApplicationServices.GetRequiredService(); + + lifetime.ApplicationStarted.Register(() => + { + var addressFeature = server.Features.Get(); + var localUrl = addressFeature?.Addresses.FirstOrDefault(); + + if (string.IsNullOrEmpty(localUrl)) + { + throw new InvalidOperationException("Unable to determine the local URL of the application."); + } + + Task.Run(async () => + { + var httpTunnel = new HttpTunnelRequest + { + ClientId = ClientId, + LocalUrl = localUrl, + PublicUrl = "https://tunnelite.com", + }; + + var client = new HttpTunnelClient(httpTunnel, null); + + client.Log += x => Console.WriteLine(x); + client.LogRequest += (method, path) => Console.WriteLine($"{DateTimeOffset.Now:HH:mm:ss} [{method}]: {path}"); + client.LogFailedRequest += (method, path) => Console.Write($"{DateTimeOffset.Now:HH:mm:ss} [{method}]: {path}"); + client.LogError += x => Console.WriteLine(x); + client.LogException += x => Console.WriteLine(x.Message); + + await client.ConnectAsync(); + + LogTunnelInfo(client.TunnelUrl); + + }, CancellationToken.None); + + }); + + return app; + } + + private static void LogTunnelInfo(string tunnelUrl) + { + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("╔══════════════════════════════════════════════════════════════════════════════╗"); + Console.WriteLine($" Tunnelite URL: {tunnelUrl,-67}"); + Console.WriteLine("╚══════════════════════════════════════════════════════════════════════════════╝"); + Console.ResetColor(); + Console.WriteLine(); + } +} diff --git a/src/Tunnelite.Client/ITunnelClient.cs b/src/Tunnelite.Client/ITunnelClient.cs deleted file mode 100644 index b8e59dd..0000000 --- a/src/Tunnelite.Client/ITunnelClient.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.AspNetCore.SignalR.Client; - -namespace Tunnelite.Client; - -public interface ITunnelClient -{ - event Func? Connected; - - HubConnection Connection { get; } - - string? TunnelUrl { get; } - - Task ConnectAsync(); -} diff --git a/src/Tunnelite.Client/Program.cs b/src/Tunnelite.Client/Program.cs index 3e1508a..3d87374 100644 --- a/src/Tunnelite.Client/Program.cs +++ b/src/Tunnelite.Client/Program.cs @@ -2,8 +2,7 @@ using Microsoft.Extensions.Logging; using Spectre.Console; using System.CommandLine; -using Tunnelite.Client.HttpTunnel; -using Tunnelite.Client.TcpTunnel; +using Tunnelite.Sdk; namespace Tunnelite.Client; @@ -100,6 +99,9 @@ private static async Task InitializeTcpTunnel(string localUrl, string publicUrl, ctx.Status("Connecting to TCP tunnel..."); Client = new TcpTunnelClient(tcpTunnel, logLevel); + + AddLogging(Client); + await Client.ConnectAsync(); ctx.Status("TCP tunnel established."); @@ -117,6 +119,9 @@ private static async Task InitializeHttpTunnel(string localUrl, string publicUrl ctx.Status("Connecting to HTTP tunnel..."); Client = new HttpTunnelClient(httpTunnel, logLevel); + + AddLogging(Client); + await Client.ConnectAsync(); ctx.Status("HTTP tunnel established."); @@ -176,7 +181,7 @@ private static async Task RunMainLoop(string localUrl) } } - public static Table WriteStatusTable(string localUrl, string? tunnelUrl, string color, string currentStatus) + private static Table WriteStatusTable(string localUrl, string? tunnelUrl, string color, string currentStatus) { AnsiConsole.Clear(); @@ -199,32 +204,41 @@ private static void WriteHelp() AnsiConsole.WriteLine(); } - public static void Log(string log) + private static void Log(string log) { string entry = $"[yellow] {DateTimeOffset.Now:HH:mm:ss}[/]: {Markup.Escape(log)}"; AnsiConsole.MarkupLine(entry); } - public static void LogRequest(string method, string path) + private static void LogRequest(string method, string path) { string entry = $"[green] {DateTimeOffset.Now:HH:mm:ss} [[{method}]][/]: {Markup.Escape(path)}"; AnsiConsole.MarkupLine(entry); } - public static void LogFailedRequest(string method, string path) + private static void LogFailedRequest(string method, string path) { string entry = $"[red] {DateTimeOffset.Now:HH:mm:ss} [[{method}]][/]: {Markup.Escape(path)}"; AnsiConsole.MarkupLine(entry); } - public static void LogError(string message) + private static void LogError(string message) { string entry = $"[red] {DateTimeOffset.Now:HH:mm:ss}[/]: {Markup.Escape(message)}"; AnsiConsole.MarkupLine(entry); } - public static void LogException(Exception ex) + private static void LogException(Exception ex) { AnsiConsole.WriteException(ex); } + + private static void AddLogging(ITunnelClient client) + { + client.Log += Log; + client.LogRequest += LogRequest; + client.LogFailedRequest += LogFailedRequest; + client.LogError += LogError; + client.LogException += LogException; + } } \ No newline at end of file diff --git a/src/Tunnelite.Client/Tunnelite.Client.csproj b/src/Tunnelite.Client/Tunnelite.Client.csproj index 4755455..e7e7c6b 100644 --- a/src/Tunnelite.Client/Tunnelite.Client.csproj +++ b/src/Tunnelite.Client/Tunnelite.Client.csproj @@ -16,7 +16,8 @@ Tool for tunneling URLs https://github.com/cristipufu/ws-tunnel-signalr https://github.com/cristipufu/ws-tunnel-signalr - 1.1.5 + 1.1.6 + true @@ -27,11 +28,12 @@ - - - + + + + diff --git a/src/Tunnelite.Client/HttpTunnel/HttpConnection.cs b/src/Tunnelite.Sdk/HttpTunnel/HttpConnection.cs similarity index 89% rename from src/Tunnelite.Client/HttpTunnel/HttpConnection.cs rename to src/Tunnelite.Sdk/HttpTunnel/HttpConnection.cs index 4c61c1e..4b0eebe 100644 --- a/src/Tunnelite.Client/HttpTunnel/HttpConnection.cs +++ b/src/Tunnelite.Sdk/HttpTunnel/HttpConnection.cs @@ -1,5 +1,5 @@ #nullable disable -namespace Tunnelite.Client.HttpTunnel; +namespace Tunnelite.Sdk; public class HttpConnection { diff --git a/src/Tunnelite.Client/HttpTunnel/HttpTunnelClient.cs b/src/Tunnelite.Sdk/HttpTunnel/HttpTunnelClient.cs similarity index 89% rename from src/Tunnelite.Client/HttpTunnel/HttpTunnelClient.cs rename to src/Tunnelite.Sdk/HttpTunnel/HttpTunnelClient.cs index 78ee4b2..ae742e9 100644 --- a/src/Tunnelite.Client/HttpTunnel/HttpTunnelClient.cs +++ b/src/Tunnelite.Sdk/HttpTunnel/HttpTunnelClient.cs @@ -7,11 +7,17 @@ using System.Net.WebSockets; using System.Runtime.CompilerServices; -namespace Tunnelite.Client.HttpTunnel; +namespace Tunnelite.Sdk; public class HttpTunnelClient : ITunnelClient { public event Func? Connected; + public event Action? LogRequest; + public event Action? LogFailedRequest; + public event Action? LogException; + public event Action? Log; + public event Action? LogError; + public HubConnection Connection { get; } public string? TunnelUrl { @@ -51,7 +57,7 @@ public HttpTunnelClient(HttpTunnelRequest tunnel, LogLevel? logLevel) Connection.On("NewHttpConnection", (httpConnection) => { - Program.LogRequest(httpConnection.Method, httpConnection.Path); + LogRequest?.Invoke(httpConnection.Method, httpConnection.Path); _ = TunnelHttpConnectionAsync(httpConnection); @@ -60,7 +66,7 @@ public HttpTunnelClient(HttpTunnelRequest tunnel, LogLevel? logLevel) Connection.On("NewWsConnection", (wsConnection) => { - Program.LogRequest("WS", wsConnection.Path); + LogRequest?.Invoke("WS", wsConnection.Path); _ = TunnelWsConnectionAsync(wsConnection); @@ -157,8 +163,8 @@ private async Task TunnelHttpConnectionAsync(HttpConnection httpConnection) } catch (Exception ex) { - Program.LogFailedRequest(httpConnection.Method, httpConnection.Path); - Program.LogException(ex); + LogFailedRequest?.Invoke(httpConnection.Method, httpConnection.Path); + LogException?.Invoke(ex); using var errorRequest = new HttpRequestMessage(HttpMethod.Delete, requestUrl); using var response = await ServerHttpClient.SendAsync(errorRequest); } @@ -181,14 +187,14 @@ private async Task TunnelWsConnectionAsync(WsConnection wsConnection) } catch (Exception ex) { - Program.LogFailedRequest("WS", wsConnection.Path); - Program.LogException(ex); + LogFailedRequest?.Invoke("WS", wsConnection.Path); + LogException?.Invoke(ex); } finally { await cts.CancelAsync(); - Program.Log($"[WS] Connection {wsConnection.RequestId} closed."); + Log?.Invoke($"[WS] Connection {wsConnection.RequestId} closed."); } } @@ -217,7 +223,7 @@ private async Task StreamIncomingWsAsync(WebSocket webSocket, WsConnection wsCon } finally { - Program.Log($"[WS] Writing data to connection {wsConnection.RequestId} finished."); + Log?.Invoke($"[WS] Writing data to connection {wsConnection.RequestId} finished."); } } @@ -226,7 +232,7 @@ private async Task StreamOutgoingWsAsync(WebSocket localWebSocket, WsConnection await Connection.InvokeAsync("StreamOutgoingWsAsync", StreamLocalWsAsync(localWebSocket, wsConnection, cancellationToken), wsConnection, cancellationToken: cancellationToken); } - private static async IAsyncEnumerable<(ReadOnlyMemory, WebSocketMessageType)> StreamLocalWsAsync(WebSocket webSocket, WsConnection wsConnection, [EnumeratorCancellation] CancellationToken cancellationToken) + private async IAsyncEnumerable<(ReadOnlyMemory, WebSocketMessageType)> StreamLocalWsAsync(WebSocket webSocket, WsConnection wsConnection, [EnumeratorCancellation] CancellationToken cancellationToken) { const int chunkSize = 32 * 1024; @@ -248,7 +254,7 @@ private async Task StreamOutgoingWsAsync(WebSocket localWebSocket, WsConnection } finally { - Program.Log($"[WS] Reading data from connection {wsConnection.RequestId} finished."); + Log?.Invoke($"[WS] Reading data from connection {wsConnection.RequestId} finished."); ArrayPool.Shared.Return(buffer); } @@ -270,13 +276,13 @@ private async Task StreamOutgoingWsAsync(WebSocket localWebSocket, WsConnection if (!response.IsSuccessStatusCode) { - Program.LogError($"{tunnelResponse!.Message}:{tunnelResponse.Error}"); + LogError?.Invoke($"{tunnelResponse!.Message}:{tunnelResponse.Error}"); } } catch (Exception ex) { - Program.LogError($"[HTTP] An error occurred while registering the tunnel:"); - Program.LogException(ex); + LogError?.Invoke($"[HTTP] An error occurred while registering the tunnel:"); + LogException?.Invoke(ex); await Task.Delay(5000); } @@ -303,7 +309,7 @@ private async Task ConnectWithRetryAsync(HubConnection connection, Cancell } catch { - Program.LogError($"[HTTP] Cannot connect to the public server on {Tunnel.PublicUrl}."); + LogError?.Invoke($"[HTTP] Cannot connect to the public server on {Tunnel.PublicUrl}."); await Task.Delay(5000, token); } diff --git a/src/Tunnelite.Client/HttpTunnel/HttpTunnelRequest.cs b/src/Tunnelite.Sdk/HttpTunnel/HttpTunnelRequest.cs similarity index 85% rename from src/Tunnelite.Client/HttpTunnel/HttpTunnelRequest.cs rename to src/Tunnelite.Sdk/HttpTunnel/HttpTunnelRequest.cs index d981010..f77b920 100644 --- a/src/Tunnelite.Client/HttpTunnel/HttpTunnelRequest.cs +++ b/src/Tunnelite.Sdk/HttpTunnel/HttpTunnelRequest.cs @@ -1,5 +1,5 @@ #nullable disable -namespace Tunnelite.Client.HttpTunnel; +namespace Tunnelite.Sdk; public class HttpTunnelRequest { diff --git a/src/Tunnelite.Client/HttpTunnel/HttpTunnelResponse.cs b/src/Tunnelite.Sdk/HttpTunnel/HttpTunnelResponse.cs similarity index 84% rename from src/Tunnelite.Client/HttpTunnel/HttpTunnelResponse.cs rename to src/Tunnelite.Sdk/HttpTunnel/HttpTunnelResponse.cs index aa6a1ce..86e9cca 100644 --- a/src/Tunnelite.Client/HttpTunnel/HttpTunnelResponse.cs +++ b/src/Tunnelite.Sdk/HttpTunnel/HttpTunnelResponse.cs @@ -1,5 +1,5 @@ #nullable disable -namespace Tunnelite.Client.HttpTunnel; +namespace Tunnelite.Sdk; public class HttpTunnelResponse { diff --git a/src/Tunnelite.Sdk/ITunnelClient.cs b/src/Tunnelite.Sdk/ITunnelClient.cs new file mode 100644 index 0000000..d8dae46 --- /dev/null +++ b/src/Tunnelite.Sdk/ITunnelClient.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.SignalR.Client; + +namespace Tunnelite.Sdk; + +public interface ITunnelClient +{ + event Func? Connected; + event Action? LogRequest; + event Action? LogFailedRequest; + event Action? LogException; + event Action? Log; + event Action? LogError; + + HubConnection Connection { get; } + + string? TunnelUrl { get; } + + Task ConnectAsync(); +} diff --git a/src/Tunnelite.Client/TcpTunnel/TcpConnection.cs b/src/Tunnelite.Sdk/TcpTunnel/TcpConnection.cs similarity index 70% rename from src/Tunnelite.Client/TcpTunnel/TcpConnection.cs rename to src/Tunnelite.Sdk/TcpTunnel/TcpConnection.cs index 12a72cf..7a1e987 100644 --- a/src/Tunnelite.Client/TcpTunnel/TcpConnection.cs +++ b/src/Tunnelite.Sdk/TcpTunnel/TcpConnection.cs @@ -1,5 +1,5 @@ #nullable disable -namespace Tunnelite.Client.TcpTunnel; +namespace Tunnelite.Sdk; public class TcpConnection { diff --git a/src/Tunnelite.Client/TcpTunnel/TcpTunnelClient.cs b/src/Tunnelite.Sdk/TcpTunnel/TcpTunnelClient.cs similarity index 85% rename from src/Tunnelite.Client/TcpTunnel/TcpTunnelClient.cs rename to src/Tunnelite.Sdk/TcpTunnel/TcpTunnelClient.cs index ce53e7e..5d9dbb7 100644 --- a/src/Tunnelite.Client/TcpTunnel/TcpTunnelClient.cs +++ b/src/Tunnelite.Sdk/TcpTunnel/TcpTunnelClient.cs @@ -5,12 +5,19 @@ using System.Net.Sockets; using System.Runtime.CompilerServices; -namespace Tunnelite.Client.TcpTunnel; +namespace Tunnelite.Sdk; public class TcpTunnelClient : ITunnelClient { public event Func? Connected; + public event Action? LogRequest; + public event Action? LogFailedRequest; + public event Action? LogException; + public event Action? Log; + public event Action? LogError; + public HubConnection Connection { get; } + public string? TunnelUrl { get @@ -42,7 +49,7 @@ public TcpTunnelClient(TcpTunnelRequest tunnel, LogLevel? logLevel) Connection.On("NewTcpConnection", (tcpConnection) => { - Program.LogRequest("TCP", $"New Connection {tcpConnection.RequestId}"); + LogRequest?.Invoke("TCP", $"New Connection {tcpConnection.RequestId}"); _ = HandleNewTcpConnectionAsync(tcpConnection); @@ -51,7 +58,7 @@ public TcpTunnelClient(TcpTunnelRequest tunnel, LogLevel? logLevel) Connection.On("TcpTunnelClosed", async (errorMessage) => { - Program.LogError($"[TCP] Tunnel closed by server: {errorMessage}."); + LogError?.Invoke($"[TCP] Tunnel closed by server: {errorMessage}."); _currentTunnel = await RegisterTunnelAsync(tunnel); }); @@ -94,13 +101,13 @@ public async Task ConnectAsync() if (!string.IsNullOrEmpty(tunnelResponse.Error)) { - Program.LogError($"[TCP] {tunnelResponse!.Message}:{tunnelResponse.Error}"); + LogError?.Invoke($"[TCP] {tunnelResponse!.Message}:{tunnelResponse.Error}"); } } catch (Exception ex) { - Program.LogError($"[TCP] An error occurred while registering the tunnel:"); - Program.LogException(ex); + LogError?.Invoke($"[TCP] An error occurred while registering the tunnel:"); + LogException?.Invoke(ex); await Task.Delay(5000); } @@ -125,13 +132,13 @@ private async Task HandleNewTcpConnectionAsync(TcpConnection tcpConnection) } catch (Exception ex) { - Program.LogException(ex); + LogException?.Invoke(ex); } finally { await cts.CancelAsync(); - Program.Log($"[TCP] Connection {tcpConnection.RequestId} closed."); + Log?.Invoke($"[TCP] Connection {tcpConnection.RequestId} closed."); } } @@ -162,7 +169,7 @@ private async Task StreamIncomingAsync(TcpClient localClient, TcpConnection tcpC } finally { - Program.Log($"[TCP] Writing data to connection {tcpConnection.RequestId} finished."); + Log?.Invoke($"[TCP] Writing data to connection {tcpConnection.RequestId} finished."); } } @@ -171,7 +178,7 @@ private async Task StreamOutgoingAsync(TcpClient localClient, TcpConnection tcpC await Connection.InvokeAsync("StreamOutgoingAsync", StreamLocalTcpAsync(localClient, tcpConnection, cancellationToken), tcpConnection, cancellationToken: cancellationToken); } - private static async IAsyncEnumerable> StreamLocalTcpAsync(TcpClient localClient, TcpConnection tcpConnection, [EnumeratorCancellation] CancellationToken cancellationToken) + private async IAsyncEnumerable> StreamLocalTcpAsync(TcpClient localClient, TcpConnection tcpConnection, [EnumeratorCancellation] CancellationToken cancellationToken) { const int chunkSize = 32 * 1024; @@ -190,7 +197,7 @@ private static async IAsyncEnumerable> StreamLocalTcpAsync( } finally { - Program.Log($"[TCP] Reading data from connection {tcpConnection.RequestId} finished."); + Log?.Invoke($"[TCP] Reading data from connection {tcpConnection.RequestId} finished."); ArrayPool.Shared.Return(buffer); } @@ -212,7 +219,7 @@ private async Task ConnectWithRetryAsync(HubConnection connection, Cancell } catch { - Program.LogError($"[TCP] Cannot connect to the public server on {Tunnel.PublicUrl}"); + LogError?.Invoke($"[TCP] Cannot connect to the public server on {Tunnel.PublicUrl}"); await Task.Delay(5000, token); } diff --git a/src/Tunnelite.Client/TcpTunnel/TcpTunnelRequest.cs b/src/Tunnelite.Sdk/TcpTunnel/TcpTunnelRequest.cs similarity index 88% rename from src/Tunnelite.Client/TcpTunnel/TcpTunnelRequest.cs rename to src/Tunnelite.Sdk/TcpTunnel/TcpTunnelRequest.cs index 3bb218f..89331d7 100644 --- a/src/Tunnelite.Client/TcpTunnel/TcpTunnelRequest.cs +++ b/src/Tunnelite.Sdk/TcpTunnel/TcpTunnelRequest.cs @@ -1,5 +1,5 @@ #nullable disable -namespace Tunnelite.Client.TcpTunnel; +namespace Tunnelite.Sdk; public class TcpTunnelRequest { diff --git a/src/Tunnelite.Client/TcpTunnel/TcpTunnelResponse.cs b/src/Tunnelite.Sdk/TcpTunnel/TcpTunnelResponse.cs similarity index 84% rename from src/Tunnelite.Client/TcpTunnel/TcpTunnelResponse.cs rename to src/Tunnelite.Sdk/TcpTunnel/TcpTunnelResponse.cs index 9496e2a..5879150 100644 --- a/src/Tunnelite.Client/TcpTunnel/TcpTunnelResponse.cs +++ b/src/Tunnelite.Sdk/TcpTunnel/TcpTunnelResponse.cs @@ -1,5 +1,5 @@ #nullable disable -namespace Tunnelite.Client.TcpTunnel; +namespace Tunnelite.Sdk; public class TcpTunnelResponse { diff --git a/src/Tunnelite.Sdk/Tunnelite.Sdk.csproj b/src/Tunnelite.Sdk/Tunnelite.Sdk.csproj new file mode 100644 index 0000000..b4a53de --- /dev/null +++ b/src/Tunnelite.Sdk/Tunnelite.Sdk.csproj @@ -0,0 +1,35 @@ + + + + net8.0 + enable + enable + Tunnelite.Sdk + tunnel;tunneling;websockets;signalr;reverse-proxy;proxy; + Cristi Pufu + MIT + git + README.md + SDK for tunneling URLs + https://github.com/cristipufu/ws-tunnel-signalr + https://github.com/cristipufu/ws-tunnel-signalr + 1.0.0 + true + true + snupkg + + + + + True + \ + + + + + + + + + + diff --git a/src/Tunnelite.Server/Tunnelite.Server.csproj b/src/Tunnelite.Server/Tunnelite.Server.csproj index 988b8ee..cfa2a20 100644 --- a/src/Tunnelite.Server/Tunnelite.Server.csproj +++ b/src/Tunnelite.Server/Tunnelite.Server.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/test/Test.WebApi/Program.cs b/test/Test.WebApi/Program.cs index d0a1942..2f86cdc 100644 --- a/test/Test.WebApi/Program.cs +++ b/test/Test.WebApi/Program.cs @@ -1,4 +1,4 @@ -using Test.WebApi; +using Tunnelite.AspNetCore; var builder = WebApplication.CreateBuilder(args); diff --git a/test/Test.WebApi/Test.WebApi.csproj b/test/Test.WebApi/Test.WebApi.csproj index 8342502..47bc4c4 100644 --- a/test/Test.WebApi/Test.WebApi.csproj +++ b/test/Test.WebApi/Test.WebApi.csproj @@ -7,7 +7,7 @@ - + diff --git a/test/Test.WebApi/TunneliteExtensions.cs b/test/Test.WebApi/TunneliteExtensions.cs deleted file mode 100644 index 3115651..0000000 --- a/test/Test.WebApi/TunneliteExtensions.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Microsoft.AspNetCore.Hosting.Server; -using Microsoft.AspNetCore.Hosting.Server.Features; -using Spectre.Console; -using Tunnelite.Client.HttpTunnel; - -namespace Test.WebApi -{ - public static class TunneliteExtensions - { - private static readonly Guid ClientId = Guid.NewGuid(); - - public static IApplicationBuilder UseTunnelite(this IApplicationBuilder app) - { - var lifetime = app.ApplicationServices.GetRequiredService(); - var server = app.ApplicationServices.GetRequiredService(); - var logger = app.ApplicationServices.GetRequiredService>(); - - lifetime.ApplicationStarted.Register(() => - { - var addressFeature = server.Features.Get(); - var localUrl = addressFeature?.Addresses.FirstOrDefault(); - - if (string.IsNullOrEmpty(localUrl)) - { - throw new InvalidOperationException("Unable to determine the local URL of the application."); - } - - var httpTunnel = new HttpTunnelRequest - { - ClientId = ClientId, - LocalUrl = localUrl, - PublicUrl = "https://tunnelite.com", - }; - - var client = new HttpTunnelClient(httpTunnel, null); - - client.ConnectAsync().GetAwaiter().GetResult(); - - Table statusTable = Tunnelite.Client.Program.WriteStatusTable(localUrl, client.TunnelUrl, "green", "Connected"); - - }); - - return app; - } - } -}