This commit is contained in:
Gui.H 2022-11-18 16:34:02 +08:00
commit 5fae2ea387
37 changed files with 608 additions and 261 deletions

View File

@ -50,7 +50,7 @@ csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_before_members_in_anonymous_types = true
# Namespace settings # Namespace settings
csharp_style_namespace_declarations = file_scoped csharp_style_namespace_declarations = file_scoped:warning
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}] [*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
indent_size = 2 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_property = false:suggestion
dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = 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}] [**/{test,samples,perf}/**.{cs,vb}]
# CA1018: Mark attributes with AttributeUsageAttribute # 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_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent csharp_style_expression_bodied_local_functions = false:silent
csharp_style_conditional_delegate_call = true:suggestion 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] [*.vb]
#### ÃüÃûÑùʽ #### #### ÃüÃûÑùʽ ####

View File

@ -3,11 +3,11 @@ name: Build
on: on:
push: push:
branches: branches:
- master - v2
env: env:
# 设置 docker 镜像名 # 设置 docker 镜像名
IMAGE_NAME: fasttunnel IMAGE_NAME: fasttunnel-v2
jobs: jobs:
build: build:
@ -18,8 +18,9 @@ jobs:
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 7.0.* dotnet-version: 7.0.*
include-prerelease: true
- name: Build with dotnet - name: Build with dotnet
run: chmod +x ./publish-win.sh && ./publish-win.sh run: chmod +x ./publish.sh
publish: publish:
name: publish-core name: publish-core
@ -31,7 +32,7 @@ jobs:
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 7.0.* dotnet-version: 7.0.*
include-prerelease: true
# Publish # Publish
- name: publish on version change - name: publish on version change
id: publish_nuget id: publish_nuget
@ -77,6 +78,7 @@ jobs:
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: 7.0.* dotnet-version: 7.0.*
include-prerelease: true
# Publish # Publish
- name: publish on version change - name: publish on version change
@ -102,11 +104,20 @@ jobs:
run: | run: |
IMAGE_ID=springhgui/$IMAGE_NAME IMAGE_ID=springhgui/$IMAGE_NAME
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
VERSION=latest VERSION=$(date "+%Y.%m.%d")
echo IMAGE_ID=$IMAGE_ID echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION echo VERSION=$VERSION
# 设置镜像 id 和版本号 # 设置镜像 id 和版本号
echo [tag] $IMAGE_NAME $IMAGE_ID:$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
# 进行 push # 进行 push
echo [push] $IMAGE_ID:$VERSION
docker 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

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net7.0</TargetFrameworks>
<Version>1.1.0</Version> <Version>1.1.0</Version>
<PackageProjectUrl>https://github.com/FastTunnel/FastTunnel/tree/v2/FastTunnel.Api</PackageProjectUrl> <PackageProjectUrl>https://github.com/FastTunnel/FastTunnel/tree/v2/FastTunnel.Api</PackageProjectUrl>
<RepositoryUrl>https://github.com/FastTunnel/FastTunnel/tree/v2/FastTunnel.Api</RepositoryUrl> <RepositoryUrl>https://github.com/FastTunnel/FastTunnel/tree/v2/FastTunnel.Api</RepositoryUrl>

View File

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
</PropertyGroup> </PropertyGroup>
@ -13,7 +13,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\FastTunnel.Core\FastTunnel.Core.csproj" /> <ProjectReference Include="..\FastTunnel.Core.Client\FastTunnel.Core.Client.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -7,10 +7,9 @@
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Serilog; using Serilog;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Client.Extensions;
namespace FastTunnel.Client; namespace FastTunnel.Client;

View File

@ -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 not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H // Copyright (c) 2019 Gui.H
using FastTunnel.Core.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using System.Collections.Generic; using System.Collections.Generic;
@ -19,4 +20,4 @@ namespace FastTunnel.Core.Config
public IEnumerable<ForwardConfig> Forwards { get; set; } public IEnumerable<ForwardConfig> Forwards { get; set; }
} }
} }

View 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>();
}
}
}

View 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>

View File

@ -17,7 +17,6 @@ using FastTunnel.Core.Handlers.Client;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using FastTunnel.Core.Models.Massage; using FastTunnel.Core.Models.Massage;
using FastTunnel.Core.Utilitys; using FastTunnel.Core.Utilitys;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
@ -141,7 +140,13 @@ public class FastTunnelClient : IFastTunnelClient
throw new Exception($"未处理的消息cmd={cmd}"); 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)); var content = Encoding.UTF8.GetString(line.Slice(1));
#endif
handler.HandlerMsgAsync(this, content, cancellationToken); handler.HandlerMsgAsync(this, content, cancellationToken);
} }
catch (Exception ex) catch (Exception ex)

View File

@ -26,4 +26,5 @@ namespace FastTunnel.Core.Handlers.Client
/// <returns></returns> /// <returns></returns>
Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken); Task HandlerMsgAsync(FastTunnelClient cleint, string msg, CancellationToken cancellationToken);
} }
} }

View File

@ -9,15 +9,16 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FastTunnel.Core.Sockets;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Net.Security; using System.Net.Security;
using FastTunnel.Core.Client.Sockets;
namespace FastTunnel.Core.Handlers.Client namespace FastTunnel.Core.Handlers.Client
{ {
public class SwapHandler : IClientHandler public class SwapHandler : IClientHandler
{ {
readonly ILogger<SwapHandler> _logger; readonly ILogger<SwapHandler> _logger;
static int connectionCount;
public SwapHandler(ILogger<SwapHandler> logger) public SwapHandler(ILogger<SwapHandler> logger)
{ {
@ -37,6 +38,7 @@ namespace FastTunnel.Core.Handlers.Client
{ {
try try
{ {
Interlocked.Increment(ref connectionCount);
_logger.LogDebug($"======Swap {requestId} Start======"); _logger.LogDebug($"======Swap {requestId} Start======");
using (Stream serverStream = await createRemote(requestId, cleint, cancellationToken)) using (Stream serverStream = await createRemote(requestId, cleint, cancellationToken))
using (Stream localStream = await createLocal(requestId, address, cancellationToken)) using (Stream localStream = await createLocal(requestId, address, cancellationToken))
@ -53,7 +55,9 @@ namespace FastTunnel.Core.Handlers.Client
} }
finally finally
{ {
Interlocked.Decrement(ref connectionCount);
_logger.LogDebug($"======Swap {requestId} End======"); _logger.LogDebug($"======Swap {requestId} End======");
_logger.LogDebug($"统计SwapHandler连接数{connectionCount}");
} }
} }

View File

@ -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 not use this file except in compliance with the License.
// You may obtain a copy of the License at // You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H // Copyright (c) 2019 Gui.H
using FastTunnel.Core.Models; using System;
using System.Collections.Generic; 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 public interface IClientConfig
{ {
@ -18,12 +23,5 @@ namespace FastTunnel.Core.Config
public IEnumerable<ForwardConfig> Forwards { get; set; } 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; }
}
} }

View 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; }
}
}

View File

@ -4,9 +4,7 @@
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H // Copyright (c) 2019 Gui.H
using FastTunnel.Core.Config;
using FastTunnel.Core.Client; using FastTunnel.Core.Client;
using FastTunnel.Core.Models;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;

View File

@ -13,16 +13,18 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FastTunnel.Core.Sockets namespace FastTunnel.Core.Client.Sockets
{ {
public class DnsSocketFactory public class DnsSocketFactory
{ {
public static async Task<Socket> ConnectAsync(string host, int port) public static async Task<Socket> ConnectAsync(string host, int port)
{ {
var Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 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); await Socket.ConnectAsync(dnsEndPoint);
return Socket; return Socket;
} }
} }
} }

View File

@ -15,6 +15,7 @@ using Microsoft.Extensions.Options;
using System.IO; using System.IO;
using Yarp.ReverseProxy.Configuration; using Yarp.ReverseProxy.Configuration;
using System.Collections.Generic; using System.Collections.Generic;
using FastTunnel.Core.Forwarder.MiddleWare;
namespace FastTunnel.Core.Client namespace FastTunnel.Core.Client
{ {
@ -51,7 +52,7 @@ namespace FastTunnel.Core.Client
internal void ClientLogin(TunnelClient client) internal void ClientLogin(TunnelClient client)
{ {
Interlocked.Increment(ref ConnectedClientCount); Interlocked.Increment(ref ConnectedClientCount);
logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}"); logger.LogInformation($"客户端连接 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}统计CLIENT连接数{FastTunnelClientHandler.ConnectionCount}");
Clients.Add(client); Clients.Add(client);
} }
@ -63,7 +64,7 @@ namespace FastTunnel.Core.Client
internal void ClientLogout(TunnelClient client) internal void ClientLogout(TunnelClient client)
{ {
Interlocked.Decrement(ref ConnectedClientCount); Interlocked.Decrement(ref ConnectedClientCount);
logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}"); logger.LogInformation($"客户端关闭 {client.RemoteIpAddress} 当前在线数:{ConnectedClientCount}统计CLIENT连接数{FastTunnelClientHandler.ConnectionCount}");
Clients.Remove(client); Clients.Remove(client);
client.Logout(); client.Logout();
} }

View File

@ -3,13 +3,17 @@
// You may obtain a copy of the License at // You may obtain a copy of the License at
// https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE // https://github.com/FastTunnel/FastTunnel/edit/v2/LICENSE
// Copyright (c) 2019 Gui.H // Copyright (c) 2019 Gui.H
#if NETCOREAPP3_1_OR_GREATER
using System.Text.Json; using System.Text.Json;
#else
#endif
namespace FastTunnel.Core.Extensions namespace FastTunnel.Core.Extensions
{ {
public static class ObjectExtensions public static class ObjectExtensions
{ {
#if NETCOREAPP3_1_OR_GREATER
public static string ToJson(this object message) public static string ToJson(this object message)
{ {
if (message == null) if (message == null)
@ -20,5 +24,17 @@ namespace FastTunnel.Core.Extensions
var jsonOptions = new JsonSerializerOptions { WriteIndented = false }; var jsonOptions = new JsonSerializerOptions { WriteIndented = false };
return JsonSerializer.Serialize(message, message.GetType(), jsonOptions); 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
} }
} }

View File

@ -11,9 +11,7 @@ using FastTunnel.Core.Config;
using FastTunnel.Core.Filters; using FastTunnel.Core.Filters;
using FastTunnel.Core.Forwarder; using FastTunnel.Core.Forwarder;
using FastTunnel.Core.Forwarder.MiddleWare; using FastTunnel.Core.Forwarder.MiddleWare;
using FastTunnel.Core.Handlers.Client;
using FastTunnel.Core.Handlers.Server; using FastTunnel.Core.Handlers.Server;
using FastTunnel.Core.Services;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
@ -27,25 +25,6 @@ namespace FastTunnel.Core.Extensions;
public static class ServicesExtensions 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> /// <summary>
/// 添加服务端后台进程 /// 添加服务端后台进程

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<Version>2.1.1</Version> <Version>2.1.1</Version>
<PackageProjectUrl>https://github.com/SpringHgui/FastTunnel</PackageProjectUrl> <PackageProjectUrl>https://github.com/SpringHgui/FastTunnel</PackageProjectUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
@ -17,6 +17,7 @@
<PackageTags>FastTunnel.Core</PackageTags> <PackageTags>FastTunnel.Core</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>FastTunnel.Core</PackageReleaseNotes> <PackageReleaseNotes>FastTunnel.Core</PackageReleaseNotes>
<LangVersion>Preview</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,11 +1,12 @@
// Copyright (c) 2019-2022 Gui.H. https://github.com/FastTunnel/FastTunnel // Licensed under the Apache License, Version 2.0 (the "License").
// The FastTunnel licenses this file to you under the Apache License Version 2.0. // You may not use this file except in compliance with the License.
// For more details,You may obtain License file at: https://github.com/FastTunnel/FastTunnel/blob/v2/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.Client;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using FastTunnel.Core.Sockets;
using Microsoft.AspNetCore.Connections.Features; using Microsoft.AspNetCore.Connections.Features;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -22,100 +23,106 @@ using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
using Yarp.ReverseProxy.Forwarder; 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; this.fastTunnelServer = fastTunnelServer;
readonly FastTunnelServer fastTunnelServer; this.logger = logger;
private readonly IHttpContextAccessor _httpContextAccessor; _httpContextAccessor = httpContextAccessor;
}
public FastTunnelForwarderHttpClientFactory( protected override void ConfigureHandler(ForwarderHttpClientContext context, SocketsHttpHandler handler)
ILogger<FastTunnelForwarderHttpClientFactory> logger, {
IHttpContextAccessor httpContextAccessor, FastTunnelServer fastTunnelServer) 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; Interlocked.Increment(ref connectionCount);
this.logger = logger; var res = await proxyAsync(host, context, contextRequest.RequestAborted);
_httpContextAccessor = httpContextAccessor; return res;
} }
catch (Exception)
protected override void ConfigureHandler(ForwarderHttpClientContext context, SocketsHttpHandler handler)
{ {
base.ConfigureHandler(context, handler); throw;
handler.ConnectCallback = ConnectCallback;
} }
finally
private async ValueTask<Stream> ConnectCallback(SocketsHttpConnectionContext context, CancellationToken cancellationToken)
{ {
var host = context.InitialRequestMessage.RequestUri.Host; Interlocked.Decrement(ref connectionCount);
logger.LogDebug($"统计YARP连接数{connectionCount}");
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));
} }
} }
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));
}
} }

View File

@ -24,6 +24,10 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
readonly Version serverVersion; readonly Version serverVersion;
readonly ILoginHandler loginHandler; readonly ILoginHandler loginHandler;
static int connectionCount;
public static int ConnectionCount => connectionCount;
public FastTunnelClientHandler( public FastTunnelClientHandler(
ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler) ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer, ILoginHandler loginHandler)
{ {
@ -44,7 +48,16 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
return; return;
}; };
await handleClient(context, version); Interlocked.Increment(ref connectionCount);
try
{
await handleClient(context, version);
}
finally
{
Interlocked.Decrement(ref connectionCount);
}
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -16,6 +16,9 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
{ {
ILogger<FastTunnelClientHandler> logger; ILogger<FastTunnelClientHandler> logger;
FastTunnelServer fastTunnelServer; FastTunnelServer fastTunnelServer;
static int connectionCount;
public static int ConnectionCount => connectionCount;
public FastTunnelSwapHandler(ILogger<FastTunnelClientHandler> logger, FastTunnelServer fastTunnelServer) 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) public async Task Handle(HttpContext context, Func<Task> next)
{ {
Interlocked.Increment(ref connectionCount);
try try
{ {
if (context.Request.Method != "PROXY") if (context.Request.Method != "PROXY")
@ -73,10 +78,16 @@ namespace FastTunnel.Core.Forwarder.MiddleWare
await closedAwaiter.Task.WaitAsync(cts.Token); await closedAwaiter.Task.WaitAsync(cts.Token);
logger.LogDebug($"[PROXY]:Closed {requestId}"); logger.LogDebug($"[PROXY]:Closed {requestId}");
} }
catch (TaskCanceledException) { }
catch (Exception ex) catch (Exception ex)
{ {
logger.LogError(ex); logger.LogError(ex);
} }
finally
{
Interlocked.Decrement(ref connectionCount);
logger.LogDebug($"统计SWAP连接数{ConnectionCount}");
}
} }
} }
} }

View File

@ -9,7 +9,6 @@ using FastTunnel.Core.Exceptions;
using FastTunnel.Core.Extensions; using FastTunnel.Core.Extensions;
using FastTunnel.Core.Listener; using FastTunnel.Core.Listener;
using FastTunnel.Core.Models; using FastTunnel.Core.Models;
using FastTunnel.Core.Sockets;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System; using System;

View 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
{
}
}
}
}

View 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;
}
}

View File

@ -22,7 +22,7 @@ namespace FastTunnel.Core.Models
/// 服务端监听的端口号 1~65535 /// 服务端监听的端口号 1~65535
/// </summary> /// </summary>
public int RemotePort { get; set; } public int RemotePort { get; set; }
/// <summary> /// <summary>
/// 协议,内网服务监听的协议 /// 协议,内网服务监听的协议
/// </summary> /// </summary>

View File

@ -12,121 +12,124 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace FastTunnel.Core.Utilitys; namespace FastTunnel.Core.Utilitys
public class WebSocketUtility
{ {
private readonly WebSocket webSocket;
public WebSocketUtility(WebSocket webSocket, Action<ReadOnlySequence<byte>, CancellationToken> processLine)
public class WebSocketUtility
{ {
this.webSocket = webSocket; private readonly WebSocket webSocket;
ProcessLine = processLine;
}
public Action<ReadOnlySequence<byte>, CancellationToken> ProcessLine { get; } public WebSocketUtility(WebSocket webSocket, Action<ReadOnlySequence<byte>, CancellationToken> processLine)
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)
{ {
// Allocate at least 512 bytes from the PipeWriter. this.webSocket = webSocket;
var memory = writer.GetMemory(minimumBufferSize); 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); // Allocate at least 512 bytes from the PipeWriter.
if (bytesRead.Count == 0 || bytesRead.EndOfMessage || bytesRead.MessageType == WebSocketMessageType.Close) 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; 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. // By completing PipeWriter, tell the PipeReader that there's no more data coming.
var result = await writer.FlushAsync(cancellationToken); await writer.CompleteAsync();
if (result.IsCompleted)
{
break;
}
} }
// By completing PipeWriter, tell the PipeReader that there's no more data coming. /// <summary>
await writer.CompleteAsync(); /// 从Pipe中读取收到的消息
} /// </summary>
/// <param name="reader"></param>
/// <summary> /// <param name="cancellationToken"></param>
/// 从Pipe中读取收到的消息 /// <returns></returns>
/// </summary> private async Task ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
/// <param name="reader"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
{
while (true)
{ {
var result = await reader.ReadAsync(cancellationToken); while (true)
var buffer = result.Buffer;
while (TryReadLine(ref buffer, out ReadOnlySequence<byte> line))
{ {
// Process the line. var result = await reader.ReadAsync(cancellationToken);
ProcessLine(line, 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. // Mark the PipeReader as complete.
reader.AdvanceTo(buffer.Start, buffer.End); await reader.CompleteAsync();
// Stop reading if there's no more data coming.
if (result.IsCompleted)
{
break;
}
} }
// Mark the PipeReader as complete. bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
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)
{ {
line = default; // Look for a EOL in the buffer.
return false; SequencePosition? position = buffer.PositionOf((byte)'\n');
}
// Skip the line + the \n. if (position == null)
line = buffer.Slice(0, position.Value); {
buffer = buffer.Slice(buffer.GetPosition(1, position.Value)); line = default;
return true; return false;
}
// Skip the line + the \n.
line = buffer.Slice(0, position.Value);
buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
return true;
}
} }
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -19,8 +19,9 @@ public class Program
CreateHostBuilder(args).Build().Run(); CreateHostBuilder(args).Build().Run();
} }
public static IHostBuilder CreateHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args)
Host.CreateDefaultBuilder(args) {
return Host.CreateDefaultBuilder(args)
.UseSerilog((context, services, configuration) => configuration .UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration) .ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services) .ReadFrom.Services(services)
@ -43,4 +44,5 @@ public class Program
{ {
webBuilder.UseStartup<Startup>(); webBuilder.UseStartup<Startup>();
}); });
}
} }

View File

@ -13,24 +13,10 @@
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "http://localhost:1270/swagger", "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": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
} },
}, "applicationUrl": "http://localhost:1270"
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
"publishAllPorts": true,
"useSSL": true
} }
} }
} }

View File

@ -19,6 +19,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml .github\workflows\dotnetcore.yml = .github\workflows\dotnetcore.yml
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FastTunnel.Core.Client", "FastTunnel.Core.Client\FastTunnel.Core.Client.csproj", "{67DB3ED6-B1DD-49AA-8C5D-34FABC3C643B}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{7D560A9A-E480-40F4-AAF7-398447438255}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -48,6 +54,7 @@ Global
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C} {C8ADFEB1-59DB-4CE3-8D04-5B547107BCCB} = {0E2A9DA2-26AE-4657-B4C5-3A913E2F5A3C}
{7D560A9A-E480-40F4-AAF7-398447438255} = {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3D9C6B44-6706-4EE8-9043-802BBE474A2E} SolutionGuid = {3D9C6B44-6706-4EE8-9043-802BBE474A2E}