From 4ef6ac1402437423695e6b7dded4422846974333 Mon Sep 17 00:00:00 2001 From: "Gui.H" Date: Sun, 10 Jul 2022 22:34:13 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BD=BF=E7=94=A8pipline.io?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastTunnel.Client/FastTunnel.Client.csproj | 8 +- FastTunnel.Client/Program.cs | 14 +- .../appsettings.Development.json | 7 + FastTunnel.Client/appsettings.json | 27 +- FastTunnel.Core/Client/FastTunnelClient.cs | 263 +++++++++--------- FastTunnel.Core/Client/FastTunnelServer.cs | 4 +- FastTunnel.Core/Client/IFastTunnelClient.cs | 7 +- .../Extensions/ServicesExtensions.cs | 170 +++++------ .../Extensions/WebSocketExtensions.cs | 3 - FastTunnel.Core/FastTunnelConst.cs | 2 - .../FastTunnelForwarderHttpClientFactory.cs | 5 - .../MiddleWare/FastTunnelClientHandler.cs | 20 +- .../Handlers/Client/IClientHandler.cs | 7 + FastTunnel.Core/Handlers/Client/LogHandler.cs | 35 +-- .../Handlers/Client/SwapHandler.cs | 12 +- .../Handlers/Server/ILoginHandler.cs | 12 +- .../Handlers/Server/LoginHandler.cs | 212 +++++++------- FastTunnel.Core/Models/TunnelClient.cs | 164 +++++------ FastTunnel.Core/Protocol/TunnelProtocol.cs | 44 --- .../Services/ServiceFastTunnelClient.cs | 8 +- FastTunnel.Core/Utilitys/WebSocketUtility.cs | 132 +++++++++ FastTunnel.Server/FastTunnel.Server.csproj | 2 + FastTunnel.Server/Program.cs | 14 +- .../config/appsettings.Development.json | 13 +- FastTunnel.Server/config/appsettings.json | 23 +- 25 files changed, 657 insertions(+), 551 deletions(-) create mode 100644 FastTunnel.Client/appsettings.Development.json delete mode 100644 FastTunnel.Core/Protocol/TunnelProtocol.cs create mode 100644 FastTunnel.Core/Utilitys/WebSocketUtility.cs 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&客户端通讯端口 From e67045166514d675d1dd7e085cb88e123290364a Mon Sep 17 00:00:00 2001 From: "Gui.H" Date: Mon, 11 Jul 2022 14:37:12 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9yarp=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E7=BA=A7=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FastTunnel.Server/config/appsettings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/FastTunnel.Server/config/appsettings.json b/FastTunnel.Server/config/appsettings.json index 44a22a6..0c9fd29 100644 --- a/FastTunnel.Server/config/appsettings.json +++ b/FastTunnel.Server/config/appsettings.json @@ -5,6 +5,7 @@ "Default": "Information", "Override": { "Microsoft": "Warning", + "Yarp.ReverseProxy": "Warning", "Microsoft.Hosting.Lifetime": "Information" } },