diff --git a/FastTunnel.Client/FastTunnel.Client.csproj b/FastTunnel.Client/FastTunnel.Client.csproj
index 60cbf9d..71f2df0 100644
--- a/FastTunnel.Client/FastTunnel.Client.csproj
+++ b/FastTunnel.Client/FastTunnel.Client.csproj
@@ -7,6 +7,7 @@
+
@@ -16,6 +17,9 @@
+
+ Always
+
Always
@@ -28,9 +32,7 @@
-
-
-
+
diff --git a/FastTunnel.Client/Program.cs b/FastTunnel.Client/Program.cs
index e964643..4e8dff1 100644
--- a/FastTunnel.Client/Program.cs
+++ b/FastTunnel.Client/Program.cs
@@ -30,20 +30,18 @@ class Program
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
- .UseSerilog((hostBuilderContext, services, loggerConfiguration) =>
+ .UseSerilog((context, services, loggerConfiguration) =>
{
- var enableFileLog = (bool)(hostBuilderContext.Configuration.GetSection("EnableFileLog")?.Get(typeof(bool)) ?? false);
- loggerConfiguration.WriteTo.Console();
- if (enableFileLog)
- {
- loggerConfiguration.WriteTo.File("Logs/log.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7);
- }
+ loggerConfiguration.ReadFrom.Configuration(context.Configuration)
+ .ReadFrom.Services(services)
+ .Enrich.FromLogContext()
+ .WriteTo.Console();
})
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
// -------------------FastTunnel START------------------
- services.AddFastTunnelClient(hostContext.Configuration.GetSection("ClientSettings"));
+ services.AddFastTunnelClient(hostContext.Configuration.GetSection("FastTunnel"));
// -------------------FastTunnel EDN--------------------
});
}
diff --git a/FastTunnel.Client/appsettings.Development.json b/FastTunnel.Client/appsettings.Development.json
new file mode 100644
index 0000000..a576829
--- /dev/null
+++ b/FastTunnel.Client/appsettings.Development.json
@@ -0,0 +1,7 @@
+{
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug"
+ }
+ }
+}
diff --git a/FastTunnel.Client/appsettings.json b/FastTunnel.Client/appsettings.json
index 5573d35..4a8ca03 100644
--- a/FastTunnel.Client/appsettings.json
+++ b/FastTunnel.Client/appsettings.json
@@ -1,15 +1,24 @@
{
- "Logging": {
- "LogLevel": {
- // Trace Debug Information Warning Error
+ "Serilog": {
+ "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
+ "MinimumLevel": {
"Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
- }
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "WriteTo": [
+ //{
+ // "Name": "File",
+ // "Args": {
+ // "path": "Logs/log-.log",
+ // "rollingInterval": 3
+ // }
+ //}
+ ]
},
- // 是否启用文件日志输出
- "EnableFileLog": true,
- "ClientSettings": {
+ "FastTunnel": {
"Server": {
// [必选] 服务端ip/域名(来自服务端配置文件的urls参数)
"ServerAddr": "127.0.0.1",
diff --git a/FastTunnel.Core/Client/FastTunnelClient.cs b/FastTunnel.Core/Client/FastTunnelClient.cs
index b42947b..b1ce625 100644
--- a/FastTunnel.Core/Client/FastTunnelClient.cs
+++ b/FastTunnel.Core/Client/FastTunnelClient.cs
@@ -4,153 +4,158 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
-using FastTunnel.Core.Config;
-using FastTunnel.Core.Models;
using System;
-using System.Text;
-using System.Threading.Tasks;
-using FastTunnel.Core.Extensions;
-using System.Threading;
-using Microsoft.Extensions.Logging;
-using FastTunnel.Core.Handlers.Client;
-using Microsoft.Extensions.Options;
+using System.Buffers;
+using System.Net.Sockets;
using System.Net.WebSockets;
-using FastTunnel.Core.Utilitys;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using FastTunnel.Core.Config;
+using FastTunnel.Core.Extensions;
+using FastTunnel.Core.Handlers.Client;
+using FastTunnel.Core.Models;
using FastTunnel.Core.Models.Massage;
+using FastTunnel.Core.Utilitys;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
-namespace FastTunnel.Core.Client
+namespace FastTunnel.Core.Client;
+
+public class FastTunnelClient : IFastTunnelClient
{
- public class FastTunnelClient : IFastTunnelClient
+ private ClientWebSocket socket;
+
+ protected readonly ILogger _logger;
+ protected DefaultClientConfig ClientConfig { get; private set; }
+
+ private readonly SwapHandler swapHandler;
+ private readonly LogHandler logHandler;
+
+ private static ReadOnlySpan EndSpan => new ReadOnlySpan(new byte[] { (byte)'\n' });
+
+ public SuiDaoServer Server { get; protected set; }
+
+ public FastTunnelClient(
+ ILogger logger,
+ SwapHandler newCustomerHandler,
+ LogHandler logHandler,
+ IOptionsMonitor configuration)
{
- private ClientWebSocket socket;
+ ReadOnlySpan span = new ReadOnlySpan();
+ _logger = logger;
+ swapHandler = newCustomerHandler;
+ this.logHandler = logHandler;
+ ClientConfig = configuration.CurrentValue;
+ Server = ClientConfig.Server;
+ }
- protected readonly ILogger _logger;
- private readonly SwapHandler _newCustomerHandler;
- private readonly LogHandler _logHandler;
+ ///
+ /// 启动客户端
+ ///
+ public virtual async Task StartAsync(CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("===== FastTunnel Client Start =====");
- public DefaultClientConfig ClientConfig { get; private set; }
-
- public SuiDaoServer Server { get; protected set; }
-
- public FastTunnelClient(
- ILogger logger,
- SwapHandler newCustomerHandler,
- LogHandler logHandler,
- IOptionsMonitor configuration)
- {
- _logger = logger;
- _newCustomerHandler = newCustomerHandler;
- _logHandler = logHandler;
- ClientConfig = configuration.CurrentValue;
- Server = ClientConfig.Server;
- }
-
- ///
- /// 启动客户端
- ///
- ///
- /// 自定义登录信息,可进行扩展业务
- public async void StartAsync(CancellationToken cancellationToken)
- {
- _logger.LogInformation("===== FastTunnel Client Start =====");
-
- while (!cancellationToken.IsCancellationRequested)
- {
- try
- {
- await loginAsync(cancellationToken);
- await ReceiveServerAsync(cancellationToken);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex.Message);
- await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
- }
- }
-
- _logger.LogInformation("===== FastTunnel Client End =====");
- }
-
- private async Task loginAsync(CancellationToken cancellationToken)
+ while (!cancellationToken.IsCancellationRequested)
{
try
{
- var logMsg = GetLoginMsg(cancellationToken);
-
- // 连接到的目标IP
- socket = new ClientWebSocket();
- socket.Options.RemoteCertificateValidationCallback = delegate { return true; };
- socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_VERSION, AssemblyUtility.GetVersion().ToString());
- socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_TOKEN, ClientConfig.Token);
-
- _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
- await socket.ConnectAsync(
- new Uri($"{Server.Protocol}://{Server.ServerAddr}:{Server.ServerPort}"), cancellationToken);
-
- _logger.LogDebug("连接服务端成功");
-
- // 登录
- await socket.SendCmdAsync(MessageType.LogIn, logMsg, cancellationToken);
- }
- catch (Exception)
- {
- throw;
- }
- }
-
- public virtual string GetLoginMsg(CancellationToken cancellationToken)
- {
- Server = ClientConfig.Server;
- return new LogInMassage
- {
- Webs = ClientConfig.Webs,
- Forwards = ClientConfig.Forwards,
- }.ToJson();
- }
-
- private async Task ReceiveServerAsync(CancellationToken cancellationToken)
- {
- byte[] buffer = new byte[FastTunnelConst.MAX_CMD_LENGTH];
- while (!cancellationToken.IsCancellationRequested)
- {
- var res = await socket.ReceiveAsync(buffer, cancellationToken);
- var type = buffer[0];
- var content = Encoding.UTF8.GetString(buffer, 1, res.Count - 1);
- HandleServerRequestAsync(type, content, cancellationToken);
- }
- }
-
- private async void HandleServerRequestAsync(byte cmd, string ctx, CancellationToken cancellationToken)
- {
- await Task.Yield();
-
- try
- {
- IClientHandler handler;
- switch ((MessageType)cmd)
- {
- case MessageType.SwapMsg:
- case MessageType.Forward:
- handler = _newCustomerHandler;
- break;
- case MessageType.Log:
- handler = _logHandler;
- break;
- default:
- throw new Exception($"未处理的消息:cmd={cmd}");
- }
-
- await handler.HandlerMsgAsync(this, ctx, cancellationToken);
+ await loginAsync(cancellationToken);
+ await ReceiveServerAsync(cancellationToken);
}
catch (Exception ex)
{
- _logger.LogError(ex);
+ _logger.LogError(ex.Message);
+ await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
}
}
- public void Stop(CancellationToken cancellationToken)
+ _logger.LogInformation("===== FastTunnel Client End =====");
+ }
+
+ private async Task loginAsync(CancellationToken cancellationToken)
+ {
+ var logMsg = GetLoginMsg(cancellationToken);
+ if (socket != null)
{
- _logger.LogInformation("===== FastTunnel Client Stoping =====");
+ socket.Abort();
+ }
+
+ // 连接到的目标IP
+ socket = new ClientWebSocket();
+ socket.Options.RemoteCertificateValidationCallback = delegate { return true; };
+ socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_VERSION, AssemblyUtility.GetVersion().ToString());
+ socket.Options.SetRequestHeader(FastTunnelConst.FASTTUNNEL_TOKEN, ClientConfig.Token);
+
+ _logger.LogInformation($"正在连接服务端 {Server.ServerAddr}:{Server.ServerPort}");
+ await socket.ConnectAsync(
+ new Uri($"{Server.Protocol}://{Server.ServerAddr}:{Server.ServerPort}"), cancellationToken);
+
+ _logger.LogDebug("连接服务端成功");
+
+ // 登录
+ await socket.SendCmdAsync(MessageType.LogIn, logMsg, cancellationToken);
+ }
+
+ protected virtual string GetLoginMsg(CancellationToken cancellationToken)
+ {
+ Server = ClientConfig.Server;
+ return new LogInMassage
+ {
+ Webs = ClientConfig.Webs,
+ Forwards = ClientConfig.Forwards,
+ }.ToJson();
+ }
+
+
+ protected async Task ReceiveServerAsync(CancellationToken cancellationToken)
+ {
+ var utility = new WebSocketUtility(socket, ProcessLine);
+ await utility.ProcessLinesAsync(cancellationToken);
+ }
+
+ private void ProcessLine(ReadOnlySequence line, CancellationToken cancellationToken)
+ {
+ HandleServerRequestAsync(line, cancellationToken);
+ }
+
+ private void HandleServerRequestAsync(ReadOnlySequence line, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var row = line.ToArray();
+ var cmd = row[0];
+ IClientHandler handler;
+ switch ((MessageType)cmd)
+ {
+ case MessageType.SwapMsg:
+ case MessageType.Forward:
+ handler = swapHandler;
+ break;
+ case MessageType.Log:
+ handler = logHandler;
+ break;
+ default:
+ throw new Exception($"未处理的消息:cmd={cmd}");
+ }
+
+ var content = Encoding.UTF8.GetString(line.Slice(1));
+ handler.HandlerMsgAsync(this, content, cancellationToken);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex);
+ }
+ }
+
+ public async Task StopAsync(CancellationToken cancellationToken)
+ {
+ _logger.LogInformation("===== FastTunnel Client Stoping =====");
+ if (socket != null)
+ {
+ socket.Abort();
}
}
}
diff --git a/FastTunnel.Core/Client/FastTunnelServer.cs b/FastTunnel.Core/Client/FastTunnelServer.cs
index 6612a20..ebb5184 100644
--- a/FastTunnel.Core/Client/FastTunnelServer.cs
+++ b/FastTunnel.Core/Client/FastTunnelServer.cs
@@ -48,7 +48,7 @@ namespace FastTunnel.Core.Client
/// 客户端登录
///
///
- internal void OnClientLogin(TunnelClient client)
+ internal void ClientLogin(TunnelClient client)
{
Interlocked.Increment(ref ConnectedClientCount);
logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}");
@@ -60,7 +60,7 @@ namespace FastTunnel.Core.Client
///
///
///
- internal void OnClientLogout(TunnelClient client)
+ internal void ClientLogout(TunnelClient client)
{
Interlocked.Decrement(ref ConnectedClientCount);
logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}");
diff --git a/FastTunnel.Core/Client/IFastTunnelClient.cs b/FastTunnel.Core/Client/IFastTunnelClient.cs
index a3952f9..805ca88 100644
--- a/FastTunnel.Core/Client/IFastTunnelClient.cs
+++ b/FastTunnel.Core/Client/IFastTunnelClient.cs
@@ -1,17 +1,18 @@
-// Licensed under the Apache License, Version 2.0 (the "License").
+// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
using System.Threading;
+using System.Threading.Tasks;
namespace FastTunnel.Core.Client
{
public interface IFastTunnelClient
{
- void StartAsync(CancellationToken cancellationToken);
+ Task StartAsync(CancellationToken cancellationToken);
- void Stop(CancellationToken cancellationToken);
+ Task StopAsync(CancellationToken cancellationToken);
}
}
diff --git a/FastTunnel.Core/Extensions/ServicesExtensions.cs b/FastTunnel.Core/Extensions/ServicesExtensions.cs
index 91824d1..2c13031 100644
--- a/FastTunnel.Core/Extensions/ServicesExtensions.cs
+++ b/FastTunnel.Core/Extensions/ServicesExtensions.cs
@@ -4,113 +4,97 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
+using System.Threading;
+using System.Threading.Tasks;
using FastTunnel.Core.Client;
using FastTunnel.Core.Config;
-using FastTunnel.Core.Forwarder.MiddleWare;
+using FastTunnel.Core.Filters;
using FastTunnel.Core.Forwarder;
+using FastTunnel.Core.Forwarder.MiddleWare;
using FastTunnel.Core.Handlers.Client;
+using FastTunnel.Core.Handlers.Server;
using FastTunnel.Core.Services;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
-using Yarp.ReverseProxy.Forwarder;
-using Microsoft.AspNetCore.Builder;
-using FastTunnel.Core.Filters;
-using Microsoft.AspNetCore.Mvc.Filters;
-using FastTunnel.Core.Models;
-using FastTunnel.Core.Handlers.Server;
-using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
-using System.Threading.Tasks;
-using System.Threading;
+using Yarp.ReverseProxy.Forwarder;
-/* 项目“FastTunnel.Core (net5.0)”的未合并的更改
-在此之前:
-using Microsoft.AspNetCore.Http;
+namespace FastTunnel.Core.Extensions;
-namespace FastTunnel.Core
-在此之后:
-using Microsoft.AspNetCore.Http;
-using FastTunnel.Core.Extensions;
-using FastTunnel;
-using FastTunnel.Core;
-
-namespace FastTunnel.Core
-*/
-using Microsoft.AspNetCore.Http;
-
-namespace FastTunnel.Core.Extensions
+public static class ServicesExtensions
{
- public static class ServicesExtensions
+ ///
+ /// 客户端依赖及HostedService
+ ///
+ ///
+ public static void AddFastTunnelClient(this IServiceCollection services, IConfigurationSection configurationSection)
{
- ///
- /// 客户端依赖及HostedService
- ///
- ///
- public static void AddFastTunnelClient(this IServiceCollection services, IConfigurationSection configurationSection)
+ services.Configure(configurationSection);
+ services.AddFastTunnelClient();
+ }
+
+ public static void AddFastTunnelClient(this IServiceCollection services)
+ {
+ services.AddTransient()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton();
+
+ services.AddHostedService();
+ }
+
+ ///
+ /// 添加服务端后台进程
+ ///
+ ///
+ public static void AddFastTunnelServer(this IServiceCollection services, IConfigurationSection configurationSection)
+ {
+ services.AddReverseProxy().LoadFromMemory();
+ services.AddSingleton();
+ services.AddHttpContextAccessor();
+
+ services.Configure(configurationSection)
+ .AddSingleton()
+ .AddTransient()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton();
+ }
+
+ ///
+ /// 服务端中间件
+ ///
+ ///
+ public static void UseFastTunnelServer(this IApplicationBuilder app)
+ {
+ app.UseWebSockets();
+
+ var swapHandler = app.ApplicationServices.GetRequiredService();
+ var clientHandler = app.ApplicationServices.GetRequiredService();
+ app.Use(clientHandler.Handle);
+ app.Use(swapHandler.Handle);
+ }
+
+ public static void MapFastTunnelServer(this IEndpointRouteBuilder endpoints)
+ {
+ endpoints.MapReverseProxy();
+ endpoints.MapFallback(context =>
{
- services.Configure(configurationSection);
- services.AddFastTunnelClient();
- }
-
- public static void AddFastTunnelClient(this IServiceCollection services)
- {
- services.AddTransient()
- .AddSingleton()
- .AddSingleton()
- .AddSingleton();
-
- services.AddHostedService();
- }
-
- ///
- /// 添加服务端后台进程
- ///
- ///
- public static void AddFastTunnelServer(this IServiceCollection services, IConfigurationSection configurationSection)
- {
- services.AddReverseProxy().LoadFromMemory();
- services.AddSingleton();
- services.AddHttpContextAccessor();
-
- services.Configure(configurationSection)
- .AddSingleton()
- .AddTransient()
- .AddSingleton()
- .AddSingleton()
- .AddSingleton();
- }
-
- ///
- /// 服务端中间件
- ///
- ///
- public static void UseFastTunnelServer(this IApplicationBuilder app)
- {
- app.UseWebSockets();
-
- var swapHandler = app.ApplicationServices.GetRequiredService();
- var clientHandler = app.ApplicationServices.GetRequiredService();
- app.Use(clientHandler.Handle);
- app.Use(swapHandler.Handle);
- }
-
- public static void MapFastTunnelServer(this IEndpointRouteBuilder endpoints)
- {
- endpoints.MapReverseProxy();
- endpoints.MapFallback(context =>
+ var options = context.RequestServices.GetRequiredService>();
+ var host = context.Request.Host.Host;
+ if (!host.EndsWith(options.CurrentValue.WebDomain) || host.Equals(options.CurrentValue.WebDomain))
{
- var options = context.RequestServices.GetRequiredService>();
- var host = context.Request.Host.Host;
- if (!host.EndsWith(options.CurrentValue.WebDomain) || host.Equals(options.CurrentValue.WebDomain))
- {
- context.Response.StatusCode = 404;
- return Task.CompletedTask;
- }
-
- context.Response.StatusCode = 200;
- context.Response.WriteAsync(TunnelResource.Page_NotFound, CancellationToken.None);
+ context.Response.StatusCode = 404;
return Task.CompletedTask;
- });
- }
+ }
+
+ context.Response.StatusCode = 200;
+ context.Response.WriteAsync(TunnelResource.Page_NotFound, CancellationToken.None);
+ return Task.CompletedTask;
+ });
}
}
diff --git a/FastTunnel.Core/Extensions/WebSocketExtensions.cs b/FastTunnel.Core/Extensions/WebSocketExtensions.cs
index 62ae2a8..8b95400 100644
--- a/FastTunnel.Core/Extensions/WebSocketExtensions.cs
+++ b/FastTunnel.Core/Extensions/WebSocketExtensions.cs
@@ -27,9 +27,6 @@ namespace FastTunnel.Core.Extensions
}
var buffer = Encoding.UTF8.GetBytes($"{(char)type}{content}\n");
- if (type != MessageType.LogIn && buffer.Length > FastTunnelConst.MAX_CMD_LENGTH)
- throw new ArgumentOutOfRangeException(nameof(content));
-
await socket.SendAsync(buffer, WebSocketMessageType.Binary, false, cancellationToken);
}
}
diff --git a/FastTunnel.Core/FastTunnelConst.cs b/FastTunnel.Core/FastTunnelConst.cs
index c67f839..0210d76 100644
--- a/FastTunnel.Core/FastTunnelConst.cs
+++ b/FastTunnel.Core/FastTunnelConst.cs
@@ -17,7 +17,5 @@ namespace FastTunnel.Core
public const string FASTTUNNEL_VERSION = "FT_VERSION";
public const string FASTTUNNEL_MSGID = "FT_MSGID";
public const string FASTTUNNEL_TOKEN = "FT_TOKEN";
-
- public const int MAX_CMD_LENGTH = 100;
}
}
diff --git a/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs b/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs
index 816d612..06b9209 100644
--- a/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs
+++ b/FastTunnel.Core/Forwarder/FastTunnelForwarderHttpClientFactory.cs
@@ -52,11 +52,6 @@ namespace FastTunnel.Core.Forwarder
var contextRequest = _httpContextAccessor.HttpContext;
//var lifetime = contextRequest.Features.Get()!;
- contextRequest.RequestAborted.Register(() =>
- {
- logger.LogDebug($"[ConnectionClosed]");
- });
-
try
{
var res = await proxyAsync(host, context, contextRequest.RequestAborted);
diff --git a/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs b/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs
index 3046b34..85711e9 100644
--- a/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs
+++ b/FastTunnel.Core/Forwarder/MiddleWare/FastTunnelClientHandler.cs
@@ -7,6 +7,8 @@ using FastTunnel.Core.Extensions;
using FastTunnel.Core.Handlers.Server;
using FastTunnel.Core.Models;
using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Server.Kestrel.Core;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Net.WebSockets;
@@ -66,19 +68,23 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
return;
}
- var client = new TunnelClient(webSocket, fastTunnelServer, loginHandler, context.Connection.RemoteIpAddress);
+ var loggerFactory = context.RequestServices.GetRequiredService();
+ var log = loggerFactory.CreateLogger();
+ var client = new TunnelClient(webSocket, fastTunnelServer, loginHandler, context.Connection.RemoteIpAddress, log);
client.ConnectionPort = context.Connection.LocalPort;
try
{
- fastTunnelServer.OnClientLogin(client);
- await client.ReviceAsync(CancellationToken.None);
-
- fastTunnelServer.OnClientLogout(client);
+ fastTunnelServer.ClientLogin(client);
+ await client.ReviceAsync(context.RequestAborted);
}
- catch (Exception)
+ catch (Exception ex)
{
- fastTunnelServer.OnClientLogout(client);
+ logger.LogError(ex, "客户端异常");
+ }
+ finally
+ {
+ fastTunnelServer.ClientLogout(client);
}
}
diff --git a/FastTunnel.Core/Handlers/Client/IClientHandler.cs b/FastTunnel.Core/Handlers/Client/IClientHandler.cs
index 8520213..51916f9 100644
--- a/FastTunnel.Core/Handlers/Client/IClientHandler.cs
+++ b/FastTunnel.Core/Handlers/Client/IClientHandler.cs
@@ -17,6 +17,13 @@ namespace FastTunnel.Core.Handlers.Client
{
public interface IClientHandler
{
+ ///
+ /// 处理消息
+ ///
+ ///
+ ///
+ ///
+ ///
Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken);
}
}
diff --git a/FastTunnel.Core/Handlers/Client/LogHandler.cs b/FastTunnel.Core/Handlers/Client/LogHandler.cs
index 0d41b58..c84db62 100644
--- a/FastTunnel.Core/Handlers/Client/LogHandler.cs
+++ b/FastTunnel.Core/Handlers/Client/LogHandler.cs
@@ -4,30 +4,25 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
-using FastTunnel.Core.Config;
-using FastTunnel.Core.Models;
-using Microsoft.Extensions.Logging;
-using System;
-using FastTunnel.Core.Extensions;
-using FastTunnel.Core.Client;
-using System.Threading.Tasks;
using System.Threading;
+using System.Threading.Tasks;
+using FastTunnel.Core.Client;
+using Microsoft.Extensions.Logging;
-namespace FastTunnel.Core.Handlers.Client
+namespace FastTunnel.Core.Handlers.Client;
+
+public class LogHandler : IClientHandler
{
- public class LogHandler : IClientHandler
+ private readonly ILogger _logger;
+
+ public LogHandler(ILogger logger)
{
- ILogger _logger;
+ _logger = logger;
+ }
- public LogHandler(ILogger logger)
- {
- _logger = logger;
- }
-
- public async Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken)
- {
- _logger.LogInformation(msg.Replace("\n", string.Empty));
- await Task.CompletedTask;
- }
+ public async Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken)
+ {
+ _logger.LogInformation(msg);
+ await Task.CompletedTask;
}
}
diff --git a/FastTunnel.Core/Handlers/Client/SwapHandler.cs b/FastTunnel.Core/Handlers/Client/SwapHandler.cs
index 224f492..4e078f2 100644
--- a/FastTunnel.Core/Handlers/Client/SwapHandler.cs
+++ b/FastTunnel.Core/Handlers/Client/SwapHandler.cs
@@ -1,4 +1,4 @@
-// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel
+// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel
// The FastTunnel licenses this file to you under the Apache License Version 2.0.
// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/LICENSE
@@ -30,8 +30,14 @@ namespace FastTunnel.Core.Handlers.Client
var requestId = msgs[0];
var address = msgs[1];
+ await swap(cleint, requestId, address, cancellationToken);
+ }
+
+ private async Task swap(FastTunnelClient cleint, string requestId, string address, CancellationToken cancellationToken)
+ {
try
{
+ _logger.LogDebug($"======Swap {requestId} Start======");
using (Stream serverStream = await createRemote(requestId, cleint, cancellationToken))
using (Stream localStream = await createLocal(requestId, address, cancellationToken))
{
@@ -45,6 +51,10 @@ namespace FastTunnel.Core.Handlers.Client
{
_logger.LogError(ex, $"Swap error {requestId}");
}
+ finally
+ {
+ _logger.LogDebug($"======Swap {requestId} End======");
+ }
}
private async Task createLocal(string requestId, string localhost, CancellationToken cancellationToken)
diff --git a/FastTunnel.Core/Handlers/Server/ILoginHandler.cs b/FastTunnel.Core/Handlers/Server/ILoginHandler.cs
index fabe52e..aaeb896 100644
--- a/FastTunnel.Core/Handlers/Server/ILoginHandler.cs
+++ b/FastTunnel.Core/Handlers/Server/ILoginHandler.cs
@@ -4,14 +4,14 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
+using System.Threading;
+using System.Threading.Tasks;
using FastTunnel.Core.Client;
using FastTunnel.Core.Models;
-using System.Threading.Tasks;
-namespace FastTunnel.Core.Handlers.Server
+namespace FastTunnel.Core.Handlers.Server;
+
+public interface ILoginHandler
{
- public interface ILoginHandler
- {
- Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd);
- }
+ Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd, CancellationToken cancellationToken);
}
diff --git a/FastTunnel.Core/Handlers/Server/LoginHandler.cs b/FastTunnel.Core/Handlers/Server/LoginHandler.cs
index 8a1215c..5bfeb9f 100644
--- a/FastTunnel.Core/Handlers/Server/LoginHandler.cs
+++ b/FastTunnel.Core/Handlers/Server/LoginHandler.cs
@@ -4,6 +4,12 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
using FastTunnel.Core.Client;
using FastTunnel.Core.Extensions;
using FastTunnel.Core.Forwarder;
@@ -11,134 +17,126 @@ using FastTunnel.Core.Listener;
using FastTunnel.Core.Models;
using FastTunnel.Core.Models.Massage;
using Microsoft.Extensions.Logging;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.Json;
-using System.Threading;
-using System.Threading.Tasks;
using Yarp.ReverseProxy.Configuration;
-namespace FastTunnel.Core.Handlers.Server
-{
- public class LoginHandler : ILoginHandler
- {
- readonly ILogger logger;
- readonly IProxyConfigProvider proxyConfig;
- public const bool NeedRecive = true;
+namespace FastTunnel.Core.Handlers.Server;
- public LoginHandler(ILogger logger, IProxyConfigProvider proxyConfig)
+public class LoginHandler : ILoginHandler
+{
+ private readonly ILogger logger;
+ private readonly IProxyConfigProvider proxyConfig;
+ public const bool NeedRecive = true;
+
+ public LoginHandler(ILogger logger, IProxyConfigProvider proxyConfig)
+ {
+ this.proxyConfig = proxyConfig;
+ this.logger = logger;
+ }
+
+ protected async Task HandleLoginAsync(FastTunnelServer server, TunnelClient client, LogInMassage requet, CancellationToken cancellationToken)
+ {
+ var hasTunnel = false;
+
+ var tips = new List();
+
+ await client.webSocket.SendCmdAsync(MessageType.Log, $"穿透协议 | 映射关系(公网=>内网)", cancellationToken);
+ Thread.Sleep(300);
+
+ if (requet.Webs != null && requet.Webs.Any())
{
- this.proxyConfig = proxyConfig;
- this.logger = logger;
+ hasTunnel = true;
+ foreach (var item in requet.Webs)
+ {
+ var hostName = $"{item.SubDomain}.{server.ServerOption.CurrentValue.WebDomain}".Trim().ToLower();
+ var info = new WebInfo { Socket = client.webSocket, WebConfig = item };
+
+ logger.LogDebug($"new domain '{hostName}'");
+ server.WebList.AddOrUpdate(hostName, info, (key, oldInfo) => { return info; });
+ (proxyConfig as FastTunnelInMemoryConfigProvider).AddWeb(hostName);
+
+ await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{hostName}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None);
+ client.AddWeb(info);
+
+ if (item.WWW != null)
+ {
+ foreach (var www in item.WWW)
+ {
+ // TODO:validateDomain
+ hostName = www.Trim().ToLower();
+ server.WebList.AddOrUpdate(www, info, (key, oldInfo) => { return info; });
+ (proxyConfig as FastTunnelInMemoryConfigProvider).AddWeb(www);
+
+ await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{www}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None);
+ client.AddWeb(info);
+ }
+ }
+ }
}
- protected async Task HandleLoginAsync(FastTunnelServer server, TunnelClient client, LogInMassage requet)
+ if (requet.Forwards != null && requet.Forwards.Any())
{
- bool hasTunnel = false;
-
- List tips = new List();
-
- await client.webSocket.SendCmdAsync(MessageType.Log, $"穿透协议 | 映射关系(公网=>内网)", CancellationToken.None);
- Thread.Sleep(300);
-
- if (requet.Webs != null && requet.Webs.Any())
+ if (server.ServerOption.CurrentValue.EnableForward)
{
hasTunnel = true;
- foreach (var item in requet.Webs)
+
+ foreach (var item in requet.Forwards)
{
- var hostName = $"{item.SubDomain}.{server.ServerOption.CurrentValue.WebDomain}".Trim().ToLower();
- var info = new WebInfo { Socket = client.webSocket, WebConfig = item };
-
- logger.LogDebug($"new domain '{hostName}'");
- server.WebList.AddOrUpdate(hostName, info, (key, oldInfo) => { return info; });
- (proxyConfig as FastTunnelInMemoryConfigProvider).AddWeb(hostName);
-
- await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{hostName}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None);
- client.AddWeb(info);
-
- if (item.WWW != null)
+ try
{
- foreach (var www in item.WWW)
- {
- // TODO:validateDomain
- hostName = www.Trim().ToLower();
- server.WebList.AddOrUpdate(www, info, (key, oldInfo) => { return info; });
- (proxyConfig as FastTunnelInMemoryConfigProvider).AddWeb(www);
+ if (item.LocalPort == 3389)
+ tips.Add("您已将3389端口暴露,请确保您的PC密码足够安全。");
- await client.webSocket.SendCmdAsync(MessageType.Log, $" HTTP | http://{www}:{client.ConnectionPort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None);
- client.AddWeb(info);
+ if (item.LocalPort == 22)
+ tips.Add("您已将22端口暴露,请确保您的PC密码足够安全。");
+
+ if (server.ForwardList.TryGetValue(item.RemotePort, out var old))
+ {
+ logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}");
+ old.Listener.Stop();
+ server.ForwardList.TryRemove(item.RemotePort, out var _);
}
+
+ // TODO: 客户端离线时销毁
+ var ls = new PortProxyListener("0.0.0.0", item.RemotePort, logger, client.webSocket);
+ ls.Start(new ForwardDispatcher(logger, server, item));
+
+ var forwardInfo = new ForwardInfo { Listener = ls, Socket = client.webSocket, SSHConfig = item };
+
+ // TODO: 客户端离线时销毁
+ server.ForwardList.TryAdd(item.RemotePort, forwardInfo);
+ logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
+
+ client.AddForward(forwardInfo);
+ await client.webSocket.SendCmdAsync(MessageType.Log, $" TCP | {server.ServerOption.CurrentValue.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None);
+ }
+ catch (Exception ex)
+ {
+ logger.LogError($"SSH proxy error: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
+ logger.LogError(ex.Message);
+ await client.webSocket.SendCmdAsync(MessageType.Log, ex.Message, CancellationToken.None);
+ continue;
}
}
}
-
- if (requet.Forwards != null && requet.Forwards.Any())
+ else
{
- if (server.ServerOption.CurrentValue.EnableForward)
- {
- hasTunnel = true;
-
- foreach (var item in requet.Forwards)
- {
- try
- {
- if (item.LocalPort == 3389)
- tips.Add("您已将3389端口暴露,请确保您的PC密码足够安全。");
-
- if (item.LocalPort == 22)
- tips.Add("您已将22端口暴露,请确保您的PC密码足够安全。");
-
- ForwardInfo old;
- if (server.ForwardList.TryGetValue(item.RemotePort, out old))
- {
- logger.LogDebug($"Remove Listener {old.Listener.ListenIp}:{old.Listener.ListenPort}");
- old.Listener.Stop();
- server.ForwardList.TryRemove(item.RemotePort, out ForwardInfo _);
- }
-
- // TODO: 客户端离线时销毁
- var ls = new PortProxyListener("0.0.0.0", item.RemotePort, logger, client.webSocket);
- ls.Start(new ForwardDispatcher(logger, server, item));
-
- var forwardInfo = new ForwardInfo { Listener = ls, Socket = client.webSocket, SSHConfig = item };
-
- // TODO: 客户端离线时销毁
- server.ForwardList.TryAdd(item.RemotePort, forwardInfo);
- logger.LogDebug($"SSH proxy success: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
-
- client.AddForward(forwardInfo);
- await client.webSocket.SendCmdAsync(MessageType.Log, $" TCP | {server.ServerOption.CurrentValue.WebDomain}:{item.RemotePort} => {item.LocalIp}:{item.LocalPort}", CancellationToken.None);
- }
- catch (Exception ex)
- {
- logger.LogError($"SSH proxy error: {item.RemotePort} => {item.LocalIp}:{item.LocalPort}");
- logger.LogError(ex.Message);
- await client.webSocket.SendCmdAsync(MessageType.Log, ex.Message, CancellationToken.None);
- continue;
- }
- }
- }
- else
- {
- await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.ForwardDisabled, CancellationToken.None);
- }
+ await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.ForwardDisabled, CancellationToken.None);
}
-
- foreach (var item in tips)
- {
- await client.webSocket.SendCmdAsync(MessageType.Log, item, CancellationToken.None);
- }
-
- if (!hasTunnel)
- await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.NoTunnel, CancellationToken.None);
}
- public virtual async Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd)
+ foreach (var item in tips)
{
- var msg = JsonSerializer.Deserialize(lineCmd);
- await HandleLoginAsync(fastTunnelServer, tunnelClient, msg);
- return NeedRecive;
+ await client.webSocket.SendCmdAsync(MessageType.Log, item, CancellationToken.None);
}
+
+ if (!hasTunnel)
+ await client.webSocket.SendCmdAsync(MessageType.Log, TunnelResource.NoTunnel, CancellationToken.None);
+ }
+
+ public virtual async Task HandlerMsg(FastTunnelServer fastTunnelServer, TunnelClient tunnelClient, string lineCmd, CancellationToken cancellationToken)
+ {
+ var msg = JsonSerializer.Deserialize(lineCmd);
+ await HandleLoginAsync(fastTunnelServer, tunnelClient, msg, cancellationToken);
+ return NeedRecive;
}
}
diff --git a/FastTunnel.Core/Models/TunnelClient.cs b/FastTunnel.Core/Models/TunnelClient.cs
index 05dd119..d6688da 100644
--- a/FastTunnel.Core/Models/TunnelClient.cs
+++ b/FastTunnel.Core/Models/TunnelClient.cs
@@ -4,104 +4,108 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H
-using FastTunnel.Core.Client;
-using FastTunnel.Core.Handlers.Server;
-using FastTunnel.Core.Protocol;
using System;
+using System.Buffers;
using System.Collections.Generic;
-using System.Linq;
+using System.IO.Pipelines;
using System.Net;
+using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using FastTunnel.Core.Client;
+using FastTunnel.Core.Handlers.Server;
+using FastTunnel.Core.Utilitys;
+using Microsoft.Extensions.Logging;
-namespace FastTunnel.Core.Models
+namespace FastTunnel.Core.Models;
+
+public class TunnelClient
{
- public class TunnelClient
+ public WebSocket webSocket { get; private set; }
+
+ ///
+ /// 服务端端口号
+ ///
+ public int ConnectionPort { get; set; }
+
+ private readonly FastTunnelServer fastTunnelServer;
+ private readonly ILoginHandler loginHandler;
+ private readonly ILogger logger;
+
+ public IPAddress RemoteIpAddress { get; private set; }
+
+ private readonly IList webInfos = new List();
+ private readonly IList> forwardInfos = new List>();
+
+ public TunnelClient(
+ WebSocket webSocket, FastTunnelServer fastTunnelServer,
+ ILoginHandler loginHandler, IPAddress remoteIpAddress, ILogger logger)
{
- public WebSocket webSocket { get; private set; }
+ this.logger = logger;
+ this.webSocket = webSocket;
+ this.fastTunnelServer = fastTunnelServer;
+ this.loginHandler = loginHandler;
+ this.RemoteIpAddress = remoteIpAddress;
+ }
- ///
- /// 服务端端口号
- ///
- public int ConnectionPort { get; set; }
+ internal void AddWeb(WebInfo info)
+ {
+ webInfos.Add(info);
+ }
- readonly FastTunnelServer fastTunnelServer;
- readonly ILoginHandler loginHandler;
+ internal void AddForward(ForwardInfo forwardInfo)
+ {
+ forwardInfos.Add(forwardInfo);
+ }
- public IPAddress RemoteIpAddress { get; private set; }
+ ///
+ /// 接收客户端的消息
+ ///
+ ///
+ ///
+ public async Task ReviceAsync(CancellationToken cancellationToken)
+ {
+ var utility = new WebSocketUtility(webSocket, ProcessLine);
+ await utility.ProcessLinesAsync(cancellationToken);
+ }
- readonly IList webInfos = new List();
- readonly IList> forwardInfos = new List>();
- public TunnelClient(WebSocket webSocket, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler, IPAddress remoteIpAddress)
+ private async void ProcessLine(ReadOnlySequence line, CancellationToken cancellationToken)
+ {
+ var cmd = Encoding.UTF8.GetString(line);
+ await HandleCmdAsync(this, cmd, cancellationToken);
+ }
+
+ private async Task HandleCmdAsync(TunnelClient tunnelClient, string lineCmd, CancellationToken cancellationToken)
+ {
+ try
{
- this.webSocket = webSocket;
- this.fastTunnelServer = fastTunnelServer;
- this.loginHandler = loginHandler;
- this.RemoteIpAddress = remoteIpAddress;
+ return await loginHandler.HandlerMsg(fastTunnelServer, tunnelClient, lineCmd.Substring(1), cancellationToken);
}
-
- internal void AddWeb(WebInfo info)
+ catch (Exception ex)
{
- webInfos.Add(info);
- }
-
- internal void AddForward(ForwardInfo forwardInfo)
- {
- forwardInfos.Add(forwardInfo);
- }
-
- public async Task ReviceAsync(CancellationToken cancellationToken)
- {
- var buffer = new byte[FastTunnelConst.MAX_CMD_LENGTH];
- var tunnelProtocol = new TunnelProtocol();
-
- while (true)
- {
- var res = await webSocket.ReceiveAsync(buffer, cancellationToken);
- var cmds = tunnelProtocol.HandleBuffer(buffer, 0, res.Count);
- if (cmds == null) continue;
-
- foreach (var item in cmds)
- {
- if (!await HandleCmdAsync(this, item))
- {
- return;
- };
- }
- }
- }
- private async Task HandleCmdAsync(TunnelClient tunnelClient, string lineCmd)
- {
- try
- {
- return await loginHandler.HandlerMsg(fastTunnelServer, tunnelClient, lineCmd.Substring(1));
- }
- catch (Exception ex)
- {
- Console.WriteLine($"处理客户端消息失败:cmd={lineCmd} {ex}");
- return false;
- }
- }
-
- internal void Logout()
- {
- // forward监听终止
- if (forwardInfos != null)
- {
- foreach (var item in forwardInfos)
- {
- try
- {
- item.Listener.Stop();
- }
- catch { }
- }
- }
-
- webSocket.CloseAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None);
+ Console.WriteLine($"处理客户端消息失败:cmd={lineCmd} {ex}");
+ return false;
}
}
+
+ internal void Logout()
+ {
+ // forward监听终止
+ if (forwardInfos != null)
+ {
+ foreach (var item in forwardInfos)
+ {
+ try
+ {
+ item.Listener.Stop();
+ }
+ catch { }
+ }
+ }
+
+ webSocket.CloseAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None);
+ }
}
diff --git a/FastTunnel.Core/Protocol/TunnelProtocol.cs b/FastTunnel.Core/Protocol/TunnelProtocol.cs
deleted file mode 100644
index e1df723..0000000
--- a/FastTunnel.Core/Protocol/TunnelProtocol.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License").
-// You may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
-// Copyright (c) 2019 Gui.H
-
-using FastTunnel.Core.Extensions;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace FastTunnel.Core.Protocol
-{
- public class TunnelProtocol
- {
- string massgeTemp;
- string m_sectionFlag = "\n";
-
- public IEnumerable HandleBuffer(byte[] buffer, int offset, int count)
- {
- var words = buffer.GetString(offset, count);
- var sum = massgeTemp + words;
-
- if (sum.Contains(m_sectionFlag))
- {
- var array = (sum).Split(m_sectionFlag);
- massgeTemp = null;
- var fullMsg = words.EndsWith(m_sectionFlag);
-
- if (!fullMsg)
- {
- massgeTemp = array[array.Length - 1];
- }
-
- return array.Take(array.Length - 1);
- }
- else
- {
- massgeTemp = sum;
- return null;
- }
- }
- }
-}
diff --git a/FastTunnel.Core/Services/ServiceFastTunnelClient.cs b/FastTunnel.Core/Services/ServiceFastTunnelClient.cs
index d49ec09..52ad9e9 100644
--- a/FastTunnel.Core/Services/ServiceFastTunnelClient.cs
+++ b/FastTunnel.Core/Services/ServiceFastTunnelClient.cs
@@ -33,14 +33,12 @@ namespace FastTunnel.Core.Services
public async Task StartAsync(CancellationToken cancellationToken)
{
- _fastTunnelClient.StartAsync(cancellationToken);
- await Task.CompletedTask;
+ await _fastTunnelClient.StartAsync(cancellationToken);
}
- public Task StopAsync(CancellationToken cancellationToken)
+ public async Task StopAsync(CancellationToken cancellationToken)
{
- _fastTunnelClient.Stop(cancellationToken);
- return Task.CompletedTask;
+ await _fastTunnelClient.StopAsync(cancellationToken);
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
diff --git a/FastTunnel.Core/Utilitys/WebSocketUtility.cs b/FastTunnel.Core/Utilitys/WebSocketUtility.cs
new file mode 100644
index 0000000..89e599e
--- /dev/null
+++ b/FastTunnel.Core/Utilitys/WebSocketUtility.cs
@@ -0,0 +1,132 @@
+// Licensed under the Apache License, Version 2.0 (the "License").
+// You may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
+// Copyright (c) 2019 Gui.H
+
+using System;
+using System.Buffers;
+using System.IO.Pipelines;
+using System.Net.WebSockets;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace FastTunnel.Core.Utilitys;
+
+public class WebSocketUtility
+{
+ private readonly WebSocket webSocket;
+
+ public WebSocketUtility(WebSocket webSocket, Action, CancellationToken> processLine)
+ {
+ this.webSocket = webSocket;
+ ProcessLine = processLine;
+ }
+
+ public Action, CancellationToken> ProcessLine { get; }
+
+ public async Task ProcessLinesAsync(CancellationToken cancellationToken)
+ {
+ var pipe = new Pipe();
+ var writing = FillPipeAsync(webSocket, pipe.Writer, cancellationToken);
+ var reading = ReadPipeAsync(pipe.Reader, cancellationToken);
+
+ await Task.WhenAll(reading, writing);
+ }
+
+ ///
+ /// 读取socket收到的消息写入Pipe
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private async Task FillPipeAsync(WebSocket socket, PipeWriter writer, CancellationToken cancellationToken)
+ {
+ const int minimumBufferSize = 512;
+
+ while (true)
+ {
+ // Allocate at least 512 bytes from the PipeWriter.
+ var memory = writer.GetMemory(minimumBufferSize);
+
+ try
+ {
+ var bytesRead = await socket.ReceiveAsync(memory, cancellationToken);
+ if (bytesRead.Count == 0 || bytesRead.EndOfMessage || bytesRead.MessageType == WebSocketMessageType.Close)
+ {
+ break;
+ }
+ // Tell the PipeWriter how much was read from the Socket.
+ writer.Advance(bytesRead.Count);
+ }
+ catch (Exception)
+ {
+ break;
+ }
+
+ // Make the data available to the PipeReader.
+ var result = await writer.FlushAsync(cancellationToken);
+
+ if (result.IsCompleted)
+ {
+ break;
+ }
+ }
+
+ // By completing PipeWriter, tell the PipeReader that there's no more data coming.
+ await writer.CompleteAsync();
+ }
+
+ ///
+ /// 从Pipe中读取收到的消息
+ ///
+ ///
+ ///
+ ///
+ private async Task ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
+ {
+ while (true)
+ {
+ var result = await reader.ReadAsync(cancellationToken);
+ var buffer = result.Buffer;
+
+ while (TryReadLine(ref buffer, out ReadOnlySequence line))
+ {
+ // Process the line.
+ ProcessLine(line, cancellationToken);
+ }
+
+ // Tell the PipeReader how much of the buffer has been consumed.
+ reader.AdvanceTo(buffer.Start, buffer.End);
+
+ // Stop reading if there's no more data coming.
+ if (result.IsCompleted)
+ {
+ break;
+ }
+ }
+
+ // Mark the PipeReader as complete.
+ await reader.CompleteAsync();
+ }
+
+ bool TryReadLine(ref ReadOnlySequence buffer, out ReadOnlySequence line)
+ {
+ // Look for a EOL in the buffer.
+ SequencePosition? position = buffer.PositionOf((byte)'\n');
+
+ if (position == null)
+ {
+ line = default;
+ return false;
+ }
+
+ // Skip the line + the \n.
+ line = buffer.Slice(0, position.Value);
+ buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
+ return true;
+ }
+}
diff --git a/FastTunnel.Server/FastTunnel.Server.csproj b/FastTunnel.Server/FastTunnel.Server.csproj
index b9a2a58..c7bd9ba 100644
--- a/FastTunnel.Server/FastTunnel.Server.csproj
+++ b/FastTunnel.Server/FastTunnel.Server.csproj
@@ -36,4 +36,6 @@
Always
+
+
diff --git a/FastTunnel.Server/Program.cs b/FastTunnel.Server/Program.cs
index d3fd758..8a5c61a 100644
--- a/FastTunnel.Server/Program.cs
+++ b/FastTunnel.Server/Program.cs
@@ -21,15 +21,11 @@ public class Program
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
- .UseSerilog((hostBuilderContext, services, loggerConfiguration) =>
- {
- var enableFileLog = (bool)(hostBuilderContext.Configuration.GetSection("EnableFileLog")?.Get(typeof(bool)) ?? false);
- loggerConfiguration.WriteTo.Console();
- if (enableFileLog)
- {
- loggerConfiguration.WriteTo.File("Logs/log.txt", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7);
- }
- })
+ .UseSerilog((context, services, configuration) => configuration
+ .ReadFrom.Configuration(context.Configuration)
+ .ReadFrom.Services(services)
+ .Enrich.FromLogContext()
+ .WriteTo.Console())
.UseWindowsService()
.ConfigureWebHost(webHostBuilder =>
{
diff --git a/FastTunnel.Server/config/appsettings.Development.json b/FastTunnel.Server/config/appsettings.Development.json
index 834acb9..a576829 100644
--- a/FastTunnel.Server/config/appsettings.Development.json
+++ b/FastTunnel.Server/config/appsettings.Development.json
@@ -1,12 +1,7 @@
{
- "Logging": {
- "LogLevel": {
- // Trace Debug Information Warning Error
- "Default": "Debug",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
+ "Serilog": {
+ "MinimumLevel": {
+ "Default": "Debug"
}
- },
- "AllowedHosts": "*",
- "EnableFileLog": false
+ }
}
diff --git a/FastTunnel.Server/config/appsettings.json b/FastTunnel.Server/config/appsettings.json
index 3306654..44a22a6 100644
--- a/FastTunnel.Server/config/appsettings.json
+++ b/FastTunnel.Server/config/appsettings.json
@@ -1,11 +1,22 @@
{
- "Logging": {
- "LogLevel": {
- // Trace Debug Information Warning Error
+ "Serilog": {
+ "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
+ "MinimumLevel": {
"Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information"
- }
+ "Override": {
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "WriteTo": [
+ //{
+ // "Name": "File",
+ // "Args": {
+ // "path": "Logs/log-.log",
+ // "rollingInterval": 3
+ // }
+ //}
+ ]
},
"AllowedHosts": "*",
// Http&客户端通讯端口