mirror of
https://github.com/FastTunnel/FastTunnel.git
synced 2025-02-08 02:39:29 +08:00
Merge branch 'v2' of https://github.com/FastTunnel/FastTunnel into v2
This commit is contained in:
commit
5fae2ea387
|
@ -50,7 +50,7 @@ csharp_new_line_before_members_in_object_initializers = true
|
|||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
|
||||
# Namespace settings
|
||||
csharp_style_namespace_declarations = file_scoped
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
|
||||
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
|
||||
indent_size = 2
|
||||
|
@ -218,6 +218,29 @@ dotnet_style_qualification_for_field = false:suggestion
|
|||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:silent
|
||||
dotnet_style_qualification_for_event = false:silent
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
|
||||
dotnet_code_quality_unused_parameters = all:suggestion
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true:silent
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||
dotnet_style_namespace_match_folder = true:suggestion
|
||||
|
||||
[**/{test,samples,perf}/**.{cs,vb}]
|
||||
# CA1018: Mark attributes with AttributeUsageAttribute
|
||||
|
@ -324,6 +347,21 @@ csharp_style_expression_bodied_accessors = true:silent
|
|||
csharp_style_expression_bodied_lambdas = true:silent
|
||||
csharp_style_expression_bodied_local_functions = false:silent
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_prefer_braces = true:silent
|
||||
csharp_style_prefer_method_group_conversion = true:silent
|
||||
csharp_style_prefer_top_level_statements = true:silent
|
||||
csharp_prefer_static_local_function = true:suggestion
|
||||
csharp_style_prefer_readonly_struct = true:suggestion
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
|
||||
csharp_style_prefer_switch_expression = true:suggestion
|
||||
csharp_style_prefer_pattern_matching = true:silent
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_prefer_not_pattern = true:suggestion
|
||||
csharp_style_prefer_extended_property_pattern = true:suggestion
|
||||
|
||||
[*.vb]
|
||||
#### ÃüÃûÑùʽ ####
|
||||
|
|
21
.github/workflows/dotnetcore.yml
vendored
21
.github/workflows/dotnetcore.yml
vendored
|
@ -3,11 +3,11 @@ name: Build
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- v2
|
||||
|
||||
env:
|
||||
# 设置 docker 镜像名
|
||||
IMAGE_NAME: fasttunnel
|
||||
IMAGE_NAME: fasttunnel-v2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -18,8 +18,9 @@ jobs:
|
|||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 7.0.*
|
||||
include-prerelease: true
|
||||
- name: Build with dotnet
|
||||
run: chmod +x ./publish-win.sh && ./publish-win.sh
|
||||
run: chmod +x ./publish.sh
|
||||
|
||||
publish:
|
||||
name: publish-core
|
||||
|
@ -31,7 +32,7 @@ jobs:
|
|||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 7.0.*
|
||||
|
||||
include-prerelease: true
|
||||
# Publish
|
||||
- name: publish on version change
|
||||
id: publish_nuget
|
||||
|
@ -77,6 +78,7 @@ jobs:
|
|||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: 7.0.*
|
||||
include-prerelease: true
|
||||
|
||||
# Publish
|
||||
- name: publish on version change
|
||||
|
@ -102,11 +104,20 @@ jobs:
|
|||
run: |
|
||||
IMAGE_ID=springhgui/$IMAGE_NAME
|
||||
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
|
||||
VERSION=latest
|
||||
VERSION=$(date "+%Y.%m.%d")
|
||||
|
||||
echo IMAGE_ID=$IMAGE_ID
|
||||
echo VERSION=$VERSION
|
||||
# 设置镜像 id 和版本号
|
||||
echo [tag] $IMAGE_NAME $IMAGE_ID:$VERSION
|
||||
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
|
||||
# 进行 push
|
||||
echo [push] $IMAGE_ID:$VERSION
|
||||
docker push $IMAGE_ID:$VERSION
|
||||
# 再上传一份覆盖latest
|
||||
echo [tag] $IMAGE_ID:$VERSION $IMAGE_ID:latest
|
||||
docker tag $IMAGE_ID:$VERSION $IMAGE_ID:latest
|
||||
|
||||
echo [push] $IMAGE_ID:latest
|
||||
docker push $IMAGE_ID:latest
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net7.0</TargetFrameworks>
|
||||
<Version>1.1.0</Version>
|
||||
<PackageProjectUrl>https://github.com/FastTunnel/FastTunnel/tree/v2/FastTunnel.Api</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/FastTunnel/FastTunnel/tree/v2/FastTunnel.Api</RepositoryUrl>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FastTunnel.Core\FastTunnel.Core.csproj" />
|
||||
<ProjectReference Include="..\FastTunnel.Core.Client\FastTunnel.Core.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Serilog;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Client.Extensions;
|
||||
|
||||
namespace FastTunnel.Client;
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// 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 FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -19,4 +20,4 @@ namespace FastTunnel.Core.Config
|
|||
|
||||
public IEnumerable<ForwardConfig> Forwards { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
33
FastTunnel.Core.Client/Extensions/ServicesExtensions.cs
Normal file
33
FastTunnel.Core.Client/Extensions/ServicesExtensions.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// 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.Config;
|
||||
using FastTunnel.Core.Handlers.Client;
|
||||
using FastTunnel.Core.Services;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FastTunnel.Core.Client.Extensions
|
||||
{
|
||||
public static class ServicesExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端依赖及HostedService
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddFastTunnelClient(this IServiceCollection services, IConfigurationSection configurationSection)
|
||||
{
|
||||
services.Configure<DefaultClientConfig>(configurationSection);
|
||||
|
||||
services.AddTransient<IFastTunnelClient, FastTunnelClient>()
|
||||
.AddSingleton<LogHandler>()
|
||||
.AddSingleton<SwapHandler>();
|
||||
|
||||
services.AddHostedService<ServiceFastTunnelClient>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
39
FastTunnel.Core.Client/FastTunnel.Core.Client.csproj
Normal file
39
FastTunnel.Core.Client/FastTunnel.Core.Client.csproj
Normal file
|
@ -0,0 +1,39 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>2.1.1</Version>
|
||||
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0;net7.0;</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\FastTunnel.Core\Exceptions\SocketClosedException.cs" Link="Exceptions\SocketClosedException.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Extensions\LoggerExtentions.cs" Link="Extensions\LoggerExtentions.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Extensions\ObjectExtensions.cs" Link="Extensions\ObjectExtensions.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Extensions\WebSocketExtensions.cs" Link="Extensions\WebSocketExtensions.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\FastTunnelConst.cs" Link="FastTunnelConst.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Models\ForwardConfig.cs" Link="Models\ForwardConfig.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Models\LogInMassage.cs" Link="Models\LogInMassage.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Models\Message.cs" Link="Models\Message.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Models\TunnelMassage.cs" Link="Models\TunnelMassage.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Models\WebConfig.cs" Link="Models\WebConfig.cs" />
|
||||
<Compile Include="..\FastTunnel.Core\Utilitys\WebSocketUtility.cs" Link="Utilitys\WebSocketUtility.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
|
||||
|
||||
<PackageReference Include="System.IO.Pipelines" Version="5.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Exceptions\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -17,7 +17,6 @@ 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;
|
||||
|
||||
|
@ -141,7 +140,13 @@ public class FastTunnelClient : IFastTunnelClient
|
|||
throw new Exception($"未处理的消息:cmd={cmd}");
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
var content = Encoding.UTF8.GetString(line.Slice(1).ToArray());
|
||||
#endif
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
var content = Encoding.UTF8.GetString(line.Slice(1));
|
||||
#endif
|
||||
handler.HandlerMsgAsync(this, content, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
|
@ -26,4 +26,5 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
/// <returns></returns>
|
||||
Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
}
|
|
@ -9,15 +9,16 @@ using System.Net.Sockets;
|
|||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Net.Security;
|
||||
using FastTunnel.Core.Client.Sockets;
|
||||
|
||||
namespace FastTunnel.Core.Handlers.Client
|
||||
{
|
||||
public class SwapHandler : IClientHandler
|
||||
{
|
||||
readonly ILogger<SwapHandler> _logger;
|
||||
static int connectionCount;
|
||||
|
||||
public SwapHandler(ILogger<SwapHandler> logger)
|
||||
{
|
||||
|
@ -37,6 +38,7 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
{
|
||||
try
|
||||
{
|
||||
Interlocked.Increment(ref connectionCount);
|
||||
_logger.LogDebug($"======Swap {requestId} Start======");
|
||||
using (Stream serverStream = await createRemote(requestId, cleint, cancellationToken))
|
||||
using (Stream localStream = await createLocal(requestId, address, cancellationToken))
|
||||
|
@ -53,7 +55,9 @@ namespace FastTunnel.Core.Handlers.Client
|
|||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref connectionCount);
|
||||
_logger.LogDebug($"======Swap {requestId} End======");
|
||||
_logger.LogDebug($"统计SwapHandler连接数:{connectionCount}");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +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 FastTunnel.Core.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Models;
|
||||
|
||||
namespace FastTunnel.Core.Config
|
||||
namespace FastTunnel.Core.Client
|
||||
{
|
||||
public interface IClientConfig
|
||||
{
|
||||
|
@ -18,12 +23,5 @@ namespace FastTunnel.Core.Config
|
|||
public IEnumerable<ForwardConfig> Forwards { get; set; }
|
||||
}
|
||||
|
||||
public class SuiDaoServer
|
||||
{
|
||||
public string Protocol { get; set; } = "ws";
|
||||
|
||||
public string ServerAddr { get; set; }
|
||||
|
||||
public int ServerPort { get; set; }
|
||||
}
|
||||
}
|
||||
|
20
FastTunnel.Core.Client/Models/SuiDaoServer.cs
Normal file
20
FastTunnel.Core.Client/Models/SuiDaoServer.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
// 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.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FastTunnel.Core.Config
|
||||
{
|
||||
public class SuiDaoServer
|
||||
{
|
||||
public string Protocol { get; set; } = "ws";
|
||||
|
||||
public string ServerAddr { get; set; }
|
||||
|
||||
public int ServerPort { get; set; }
|
||||
}
|
||||
}
|
|
@ -4,9 +4,7 @@
|
|||
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
|
||||
// Copyright (c) 2019 Gui.H
|
||||
|
||||
using FastTunnel.Core.Config;
|
||||
using FastTunnel.Core.Client;
|
||||
using FastTunnel.Core.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
|
@ -13,16 +13,18 @@ using System.Net.Sockets;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FastTunnel.Core.Sockets
|
||||
namespace FastTunnel.Core.Client.Sockets
|
||||
{
|
||||
|
||||
public class DnsSocketFactory
|
||||
{
|
||||
public static async Task<Socket> ConnectAsync(string host, int port)
|
||||
{
|
||||
var Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
||||
DnsEndPoint dnsEndPoint = new DnsEndPoint(host, port);
|
||||
var dnsEndPoint = new DnsEndPoint(host, port);
|
||||
await Socket.ConnectAsync(dnsEndPoint);
|
||||
return Socket;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,7 @@ using Microsoft.Extensions.Options;
|
|||
using System.IO;
|
||||
using Yarp.ReverseProxy.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using FastTunnel.Core.Forwarder.MiddleWare;
|
||||
|
||||
namespace FastTunnel.Core.Client
|
||||
{
|
||||
|
@ -51,7 +52,7 @@ namespace FastTunnel.Core.Client
|
|||
internal void ClientLogin(TunnelClient client)
|
||||
{
|
||||
Interlocked.Increment(ref ConnectedClientCount);
|
||||
logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}");
|
||||
logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount},统计CLIENT连接数:{FastTunnelClientHandler.ConnectionCount}");
|
||||
Clients.Add(client);
|
||||
}
|
||||
|
||||
|
@ -63,7 +64,7 @@ namespace FastTunnel.Core.Client
|
|||
internal void ClientLogout(TunnelClient client)
|
||||
{
|
||||
Interlocked.Decrement(ref ConnectedClientCount);
|
||||
logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}");
|
||||
logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount},统计CLIENT连接数:{FastTunnelClientHandler.ConnectionCount}");
|
||||
Clients.Remove(client);
|
||||
client.Logout();
|
||||
}
|
||||
|
|
|
@ -3,13 +3,17 @@
|
|||
// You may obtain a copy of the License at
|
||||
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
|
||||
// Copyright (c) 2019 Gui.H
|
||||
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
using System.Text.Json;
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
namespace FastTunnel.Core.Extensions
|
||||
{
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
#if NETCOREAPP3_1_OR_GREATER
|
||||
public static string ToJson(this object message)
|
||||
{
|
||||
if (message == null)
|
||||
|
@ -20,5 +24,17 @@ namespace FastTunnel.Core.Extensions
|
|||
var jsonOptions = new JsonSerializerOptions { WriteIndented = false };
|
||||
return JsonSerializer.Serialize(message, message.GetType(), jsonOptions);
|
||||
}
|
||||
#else
|
||||
public static string ToJson(this object message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var jsonOptions = new JsonSerializerOptions { WriteIndented = false };
|
||||
return JsonSerializer.Serialize(message, message.GetType(), jsonOptions);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@ using FastTunnel.Core.Config;
|
|||
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;
|
||||
|
@ -27,25 +25,6 @@ namespace FastTunnel.Core.Extensions;
|
|||
|
||||
public static class ServicesExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端依赖及HostedService
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static void AddFastTunnelClient(this IServiceCollection services, IConfigurationSection configurationSection)
|
||||
{
|
||||
services.Configure<DefaultClientConfig>(configurationSection);
|
||||
services.AddFastTunnelClient();
|
||||
}
|
||||
|
||||
public static void AddFastTunnelClient(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IFastTunnelClient, FastTunnelClient>()
|
||||
.AddSingleton<IExceptionFilter, FastTunnelExceptionFilter>()
|
||||
.AddSingleton<LogHandler>()
|
||||
.AddSingleton<SwapHandler>();
|
||||
|
||||
services.AddHostedService<ServiceFastTunnelClient>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加服务端后台进程
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net6.0</TargetFrameworks>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
<Version>2.1.1</Version>
|
||||
<PackageProjectUrl>https://github.com/SpringHgui/FastTunnel</PackageProjectUrl>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
@ -17,6 +17,7 @@
|
|||
<PackageTags>FastTunnel.Core</PackageTags>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageReleaseNotes>FastTunnel.Core</PackageReleaseNotes>
|
||||
<LangVersion>Preview</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
// 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
|
||||
// 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.Client;
|
||||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Models;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.AspNetCore.Connections.Features;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -22,100 +23,106 @@ using System.Threading.Tasks;
|
|||
using System.Xml.Linq;
|
||||
using Yarp.ReverseProxy.Forwarder;
|
||||
|
||||
namespace FastTunnel.Core.Forwarder
|
||||
namespace FastTunnel.Core.Forwarder;
|
||||
|
||||
public class FastTunnelForwarderHttpClientFactory : ForwarderHttpClientFactory
|
||||
{
|
||||
public class FastTunnelForwarderHttpClientFactory : ForwarderHttpClientFactory
|
||||
readonly ILogger<FastTunnelForwarderHttpClientFactory> logger;
|
||||
readonly FastTunnelServer fastTunnelServer;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
static int connectionCount;
|
||||
|
||||
public FastTunnelForwarderHttpClientFactory(
|
||||
ILogger<FastTunnelForwarderHttpClientFactory> logger,
|
||||
IHttpContextAccessor httpContextAccessor, FastTunnelServer fastTunnelServer)
|
||||
{
|
||||
readonly ILogger<FastTunnelForwarderHttpClientFactory> logger;
|
||||
readonly FastTunnelServer fastTunnelServer;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
this.fastTunnelServer = fastTunnelServer;
|
||||
this.logger = logger;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public FastTunnelForwarderHttpClientFactory(
|
||||
ILogger<FastTunnelForwarderHttpClientFactory> logger,
|
||||
IHttpContextAccessor httpContextAccessor, FastTunnelServer fastTunnelServer)
|
||||
protected override void ConfigureHandler(ForwarderHttpClientContext context, SocketsHttpHandler handler)
|
||||
{
|
||||
base.ConfigureHandler(context, handler);
|
||||
handler.ConnectCallback = ConnectCallback;
|
||||
}
|
||||
|
||||
private async ValueTask<Stream> ConnectCallback(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
|
||||
{
|
||||
var host = context.InitialRequestMessage.RequestUri.Host;
|
||||
|
||||
var contextRequest = _httpContextAccessor.HttpContext;
|
||||
//var lifetime = contextRequest.Features.Get<IConnectionLifetimeFeature>()!;
|
||||
|
||||
try
|
||||
{
|
||||
this.fastTunnelServer = fastTunnelServer;
|
||||
this.logger = logger;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
Interlocked.Increment(ref connectionCount);
|
||||
var res = await proxyAsync(host, context, contextRequest.RequestAborted);
|
||||
return res;
|
||||
}
|
||||
|
||||
protected override void ConfigureHandler(ForwarderHttpClientContext context, SocketsHttpHandler handler)
|
||||
catch (Exception)
|
||||
{
|
||||
base.ConfigureHandler(context, handler);
|
||||
handler.ConnectCallback = ConnectCallback;
|
||||
throw;
|
||||
}
|
||||
|
||||
private async ValueTask<Stream> ConnectCallback(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
|
||||
finally
|
||||
{
|
||||
var host = context.InitialRequestMessage.RequestUri.Host;
|
||||
|
||||
var contextRequest = _httpContextAccessor.HttpContext;
|
||||
//var lifetime = contextRequest.Features.Get<IConnectionLifetimeFeature>()!;
|
||||
|
||||
try
|
||||
{
|
||||
var res = await proxyAsync(host, context, contextRequest.RequestAborted);
|
||||
return res;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Stream> proxyAsync(string host, SocketsHttpConnectionContext context, CancellationToken cancellation)
|
||||
{
|
||||
WebInfo web;
|
||||
if (!fastTunnelServer.WebList.TryGetValue(host, out web))
|
||||
{
|
||||
// 客户端已离线
|
||||
return await OfflinePage(host, context);
|
||||
}
|
||||
|
||||
var msgId = Guid.NewGuid().ToString().Replace("-", "");
|
||||
|
||||
TaskCompletionSource<Stream> tcs = new();
|
||||
logger.LogDebug($"[Http]Swap开始 {msgId}|{host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}");
|
||||
|
||||
cancellation.Register(() =>
|
||||
{
|
||||
logger.LogDebug($"[Proxy TimeOut]:{msgId}");
|
||||
tcs.TrySetCanceled();
|
||||
});
|
||||
|
||||
fastTunnelServer.ResponseTasks.TryAdd(msgId, (tcs, cancellation));
|
||||
|
||||
try
|
||||
{
|
||||
// 发送指令给客户端,等待建立隧道
|
||||
await web.Socket.SendCmdAsync(MessageType.SwapMsg, $"{msgId}|{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}", cancellation);
|
||||
var res = await tcs.Task.WaitAsync(cancellation);
|
||||
|
||||
logger.LogDebug($"[Http]Swap OK {msgId}");
|
||||
return res;
|
||||
}
|
||||
catch (WebSocketException)
|
||||
{
|
||||
// 通讯异常,返回客户端离线
|
||||
return await OfflinePage(host, context);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fastTunnelServer.ResponseTasks.TryRemove(msgId, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async ValueTask<Stream> OfflinePage(string host, SocketsHttpConnectionContext context)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(
|
||||
$"HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n{TunnelResource.Page_Offline}\r\n");
|
||||
|
||||
return await Task.FromResult(new ResponseStream(bytes));
|
||||
Interlocked.Decrement(ref connectionCount);
|
||||
logger.LogDebug($"统计YARP连接数:{connectionCount}");
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Stream> proxyAsync(string host, SocketsHttpConnectionContext context, CancellationToken cancellation)
|
||||
{
|
||||
WebInfo web;
|
||||
if (!fastTunnelServer.WebList.TryGetValue(host, out web))
|
||||
{
|
||||
// 客户端已离线
|
||||
return await OfflinePage(host, context);
|
||||
}
|
||||
|
||||
var msgId = Guid.NewGuid().ToString().Replace("-", "");
|
||||
|
||||
TaskCompletionSource<Stream> tcs = new();
|
||||
logger.LogDebug($"[Http]Swap开始 {msgId}|{host}=>{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}");
|
||||
|
||||
cancellation.Register(() =>
|
||||
{
|
||||
logger.LogDebug($"[Proxy TimeOut]:{msgId}");
|
||||
tcs.TrySetCanceled();
|
||||
});
|
||||
|
||||
fastTunnelServer.ResponseTasks.TryAdd(msgId, (tcs, cancellation));
|
||||
|
||||
try
|
||||
{
|
||||
// 发送指令给客户端,等待建立隧道
|
||||
await web.Socket.SendCmdAsync(MessageType.SwapMsg, $"{msgId}|{web.WebConfig.LocalIp}:{web.WebConfig.LocalPort}", cancellation);
|
||||
var res = await tcs.Task.WaitAsync(cancellation);
|
||||
|
||||
logger.LogDebug($"[Http]Swap OK {msgId}");
|
||||
return res;
|
||||
}
|
||||
catch (WebSocketException)
|
||||
{
|
||||
// 通讯异常,返回客户端离线
|
||||
return await OfflinePage(host, context);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
fastTunnelServer.ResponseTasks.TryRemove(msgId, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async ValueTask<Stream> OfflinePage(string host, SocketsHttpConnectionContext context)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(
|
||||
$"HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n{TunnelResource.Page_Offline}\r\n");
|
||||
|
||||
return await Task.FromResult(new ResponseStream(bytes));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,10 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
|
|||
readonly Version serverVersion;
|
||||
readonly ILoginHandler loginHandler;
|
||||
|
||||
static int connectionCount;
|
||||
|
||||
public static int ConnectionCount => connectionCount;
|
||||
|
||||
public FastTunnelClientHandler(
|
||||
ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler)
|
||||
{
|
||||
|
@ -44,7 +48,16 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
|
|||
return;
|
||||
};
|
||||
|
||||
await handleClient(context, version);
|
||||
Interlocked.Increment(ref connectionCount);
|
||||
|
||||
try
|
||||
{
|
||||
await handleClient(context, version);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref connectionCount);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -16,6 +16,9 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
|
|||
{
|
||||
ILogger<FastTunnelClientHandler> logger;
|
||||
FastTunnelServer fastTunnelServer;
|
||||
static int connectionCount;
|
||||
|
||||
public static int ConnectionCount => connectionCount;
|
||||
|
||||
public FastTunnelSwapHandler(ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer)
|
||||
{
|
||||
|
@ -25,6 +28,8 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
|
|||
|
||||
public async Task Handle(HttpContext context, Func<Task> next)
|
||||
{
|
||||
Interlocked.Increment(ref connectionCount);
|
||||
|
||||
try
|
||||
{
|
||||
if (context.Request.Method != "PROXY")
|
||||
|
@ -73,10 +78,16 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
|
|||
await closedAwaiter.Task.WaitAsync(cts.Token);
|
||||
logger.LogDebug($"[PROXY]:Closed {requestId}");
|
||||
}
|
||||
catch (TaskCanceledException) { }
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref connectionCount);
|
||||
logger.LogDebug($"统计SWAP连接数:{ConnectionCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ using FastTunnel.Core.Exceptions;
|
|||
using FastTunnel.Core.Extensions;
|
||||
using FastTunnel.Core.Listener;
|
||||
using FastTunnel.Core.Models;
|
||||
using FastTunnel.Core.Sockets;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
|
|
106
FastTunnel.Core/Listener/PortProxyListenerV2.cs
Normal file
106
FastTunnel.Core/Listener/PortProxyListenerV2.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
// 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 BeetleX;
|
||||
using BeetleX.EventArgs;
|
||||
using FastTunnel.Core.Handlers.Server;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using IServer = BeetleX.IServer;
|
||||
|
||||
namespace FastTunnel.Core.Listener
|
||||
{
|
||||
public class PortProxyListenerV2
|
||||
{
|
||||
ILogger _logerr;
|
||||
|
||||
public string ListenIp { get; private set; }
|
||||
|
||||
public int ListenPort { get; private set; }
|
||||
|
||||
public IServer Server { get; set; }
|
||||
|
||||
int m_numConnectedSockets;
|
||||
|
||||
private IServer server;
|
||||
|
||||
bool shutdown;
|
||||
ForwardDispatcher _requestDispatcher;
|
||||
WebSocket client;
|
||||
|
||||
// string ip, int port, ILogger logerr, WebSocket client
|
||||
public PortProxyListenerV2()
|
||||
{
|
||||
//IPAddress ipa = IPAddress.Parse(ListenIp);
|
||||
//IPEndPoint localEndPoint = new IPEndPoint(ipa, ListenPort);
|
||||
}
|
||||
|
||||
public void Start(ForwardDispatcher requestDispatcher, string host, int port, ILogger logger, WebSocket webSocket)
|
||||
{
|
||||
this.client = webSocket;
|
||||
this._logerr = logger;
|
||||
this.ListenIp = host;
|
||||
this.ListenPort = port;
|
||||
|
||||
shutdown = false;
|
||||
_requestDispatcher = requestDispatcher;
|
||||
|
||||
server = SocketFactory.CreateTcpServer<TcpServerHandler>();
|
||||
var handler = server.Handler as TcpServerHandler;
|
||||
handler.Sethanler(this);
|
||||
server.Options.DefaultListen.Port = port;
|
||||
server.Options.DefaultListen.Host = host;
|
||||
server.Open();
|
||||
}
|
||||
|
||||
//protected override void OnReceiveMessage(IServer server, ISession session, object message)
|
||||
//{
|
||||
// base.OnReceiveMessage(server, session, message);
|
||||
//}
|
||||
|
||||
private void ProcessAcceptAsync(SocketAsyncEventArgs e)
|
||||
{
|
||||
// 将此客户端交由Dispatcher进行管理
|
||||
}
|
||||
|
||||
internal async void Process(SessionReceiveEventArgs e)
|
||||
{
|
||||
//var pipeStream = e.Session.Stream.ToPipeStream();
|
||||
//if (pipeStream.TryReadLine(out string name))
|
||||
//{
|
||||
// Console.WriteLine(name);
|
||||
// e.Stream.ToPipeStream().WriteLine("hello " + name);
|
||||
// e.Stream.Flush();
|
||||
//}
|
||||
|
||||
await _requestDispatcher.DispatchAsync(e.Stream, client);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (shutdown)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
server.Dispose();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
67
FastTunnel.Core/Listener/TcpServerHandler.cs
Normal file
67
FastTunnel.Core/Listener/TcpServerHandler.cs
Normal file
|
@ -0,0 +1,67 @@
|
|||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BeetleX;
|
||||
using BeetleX.EventArgs;
|
||||
|
||||
namespace FastTunnel.Core.Listener;
|
||||
|
||||
internal class TcpServerHandler : ServerHandlerBase
|
||||
{
|
||||
PortProxyListenerV2 proxyListenerV2;
|
||||
|
||||
public override void Connected(IServer server, ConnectedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[Connected]");
|
||||
}
|
||||
|
||||
public override void Connecting(IServer server, ConnectingEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[Connecting]");
|
||||
}
|
||||
|
||||
public override void Disconnect(IServer server, SessionEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[Disconnect]");
|
||||
}
|
||||
|
||||
public override void Error(IServer server, ServerErrorEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[Error]");
|
||||
}
|
||||
|
||||
public override void Opened(IServer server)
|
||||
{
|
||||
Console.WriteLine("[Opened]");
|
||||
}
|
||||
|
||||
public override void SessionDetection(IServer server, SessionDetectionEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[SessionDetection]");
|
||||
}
|
||||
|
||||
public override void SessionPacketDecodeCompleted(IServer server, PacketDecodeCompletedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[SessionPacketDecodeCompleted]");
|
||||
}
|
||||
|
||||
public override void SessionReceive(IServer server, SessionReceiveEventArgs e)
|
||||
{
|
||||
Console.WriteLine("[SessionReceive]");
|
||||
|
||||
proxyListenerV2.Process(e);
|
||||
}
|
||||
|
||||
internal void Sethanler(PortProxyListenerV2 portProxyListenerV2)
|
||||
{
|
||||
this.proxyListenerV2 = portProxyListenerV2;
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ namespace FastTunnel.Core.Models
|
|||
/// 服务端监听的端口号 1~65535
|
||||
/// </summary>
|
||||
public int RemotePort { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 协议,内网服务监听的协议
|
||||
/// </summary>
|
||||
|
|
|
@ -12,121 +12,124 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FastTunnel.Core.Utilitys;
|
||||
|
||||
public class WebSocketUtility
|
||||
namespace FastTunnel.Core.Utilitys
|
||||
{
|
||||
private readonly WebSocket webSocket;
|
||||
|
||||
public WebSocketUtility(WebSocket webSocket, Action<ReadOnlySequence<byte>, CancellationToken> processLine)
|
||||
|
||||
public class WebSocketUtility
|
||||
{
|
||||
this.webSocket = webSocket;
|
||||
ProcessLine = processLine;
|
||||
}
|
||||
private readonly WebSocket webSocket;
|
||||
|
||||
public Action<ReadOnlySequence<byte>, 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取socket收到的消息写入Pipe
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private async Task FillPipeAsync(WebSocket socket, PipeWriter writer, CancellationToken cancellationToken)
|
||||
{
|
||||
const int minimumBufferSize = 512;
|
||||
|
||||
while (true)
|
||||
public WebSocketUtility(WebSocket webSocket, Action<ReadOnlySequence<byte>, CancellationToken> processLine)
|
||||
{
|
||||
// Allocate at least 512 bytes from the PipeWriter.
|
||||
var memory = writer.GetMemory(minimumBufferSize);
|
||||
this.webSocket = webSocket;
|
||||
ProcessLine = processLine;
|
||||
}
|
||||
|
||||
try
|
||||
public Action<ReadOnlySequence<byte>, 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取socket收到的消息写入Pipe
|
||||
/// </summary>
|
||||
/// <param name="socket"></param>
|
||||
/// <param name="writer"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private async Task FillPipeAsync(WebSocket socket, PipeWriter writer, CancellationToken cancellationToken)
|
||||
{
|
||||
const int minimumBufferSize = 512;
|
||||
|
||||
while (true)
|
||||
{
|
||||
var bytesRead = await socket.ReceiveAsync(memory, cancellationToken);
|
||||
if (bytesRead.Count == 0 || bytesRead.EndOfMessage || bytesRead.MessageType == WebSocketMessageType.Close)
|
||||
// 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;
|
||||
}
|
||||
// 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();
|
||||
}
|
||||
|
||||
// By completing PipeWriter, tell the PipeReader that there's no more data coming.
|
||||
await writer.CompleteAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从Pipe中读取收到的消息
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
while (true)
|
||||
/// <summary>
|
||||
/// 从Pipe中读取收到的消息
|
||||
/// </summary>
|
||||
/// <param name="reader"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
private async Task ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await reader.ReadAsync(cancellationToken);
|
||||
var buffer = result.Buffer;
|
||||
|
||||
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
|
||||
while (true)
|
||||
{
|
||||
// Process the line.
|
||||
ProcessLine(line, cancellationToken);
|
||||
var result = await reader.ReadAsync(cancellationToken);
|
||||
var buffer = result.Buffer;
|
||||
|
||||
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Mark the PipeReader as complete.
|
||||
await reader.CompleteAsync();
|
||||
}
|
||||
|
||||
bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
|
||||
{
|
||||
// Look for a EOL in the buffer.
|
||||
SequencePosition? position = buffer.PositionOf((byte)'\n');
|
||||
|
||||
if (position == null)
|
||||
bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
|
||||
{
|
||||
line = default;
|
||||
return false;
|
||||
}
|
||||
// Look for a EOL in the buffer.
|
||||
SequencePosition? position = buffer.PositionOf((byte)'\n');
|
||||
|
||||
// Skip the line + the \n.
|
||||
line = buffer.Slice(0, position.Value);
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -19,8 +19,9 @@ public class Program
|
|||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||
{
|
||||
return Host.CreateDefaultBuilder(args)
|
||||
.UseSerilog((context, services, configuration) => configuration
|
||||
.ReadFrom.Configuration(context.Configuration)
|
||||
.ReadFrom.Services(services)
|
||||
|
@ -43,4 +44,5 @@ public class Program
|
|||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,24 +13,10 @@
|
|||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:1270/swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
//"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "FastTunnel.Api;FastTunnel.Core"
|
||||
},
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Docker": {
|
||||
"commandName": "Docker",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
||||
"publishAllPorts": true,
|
||||
"useSSL": true
|
||||
},
|
||||
"applicationUrl": "http://localhost:1270"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastTunnel.Core.Client", "FastTunnel.Core.Client\FastTunnel.Core.Client.csproj", "{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -41,6 +43,10 @@ Global
|
|||
{7D560A9A-E480-40F4-AAF7-398447438255}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -48,6 +54,7 @@ Global
|
|||
GlobalSection(NestedProjects) = preSolution
|
||||
{C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
|
||||
{7D560A9A-E480-40F4-AAF7-398447438255} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
|
||||
{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3D9C6B44-6706-4EE8-9043-802BBE474A2E}
|
||||
|
|
Loading…
Reference in New Issue
Block a user