feat: local server 添加连接
This commit is contained in:
parent
bff3e114fc
commit
02c162ee8f
8 changed files with 479 additions and 6 deletions
128
Server/Common/AES.cs
Normal file
128
Server/Common/AES.cs
Normal file
|
@ -0,0 +1,128 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace Common;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 与目标服务器通信将会加密
|
||||
/// </summary>
|
||||
public class AESHelper
|
||||
{
|
||||
static readonly byte[] Key =
|
||||
[
|
||||
0x11,
|
||||
0xF2,
|
||||
0xAF,
|
||||
0xCF,
|
||||
0xFF,
|
||||
0x8B,
|
||||
0x4C,
|
||||
0x7D,
|
||||
0x23,
|
||||
0x96,
|
||||
0x1B,
|
||||
0x32,
|
||||
0x43,
|
||||
0xA4,
|
||||
0x55,
|
||||
0xF6,
|
||||
0x29,
|
||||
0x1C,
|
||||
0x1B,
|
||||
0x92,
|
||||
0x23,
|
||||
0x44,
|
||||
0xB5,
|
||||
0xF6,
|
||||
];
|
||||
static readonly byte[] IV =
|
||||
[
|
||||
0xD1,
|
||||
0xF7,
|
||||
0xAB,
|
||||
0xCA,
|
||||
0xBC,
|
||||
0x7B,
|
||||
0x2C,
|
||||
0x3D,
|
||||
0xFA,
|
||||
0xAA,
|
||||
0xFC,
|
||||
0xA8,
|
||||
0x28,
|
||||
0x19,
|
||||
0x9C,
|
||||
0xB6,
|
||||
];
|
||||
|
||||
public static byte[] EncryptStringToBytes_Aes(string plainText)
|
||||
{
|
||||
// Check arguments.
|
||||
if (plainText == null || plainText.Length <= 0)
|
||||
throw new ArgumentNullException(nameof(plainText), "can't be null");
|
||||
byte[] encrypted;
|
||||
|
||||
// Create an Aes object
|
||||
// with the specified key and IV.
|
||||
using (Aes aesAlg = Aes.Create())
|
||||
{
|
||||
aesAlg.Key = Key;
|
||||
aesAlg.IV = IV;
|
||||
|
||||
// Create an encryptor to perform the stream transform.
|
||||
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
// Create the streams used for encryption.
|
||||
using MemoryStream msEncrypt = new();
|
||||
using CryptoStream csEncrypt = new(
|
||||
msEncrypt,
|
||||
encryptor,
|
||||
CryptoStreamMode.Write
|
||||
);
|
||||
using (StreamWriter swEncrypt = new(csEncrypt))
|
||||
{
|
||||
//Write all data to the stream.
|
||||
swEncrypt.Write(plainText);
|
||||
}
|
||||
encrypted = msEncrypt.ToArray();
|
||||
}
|
||||
|
||||
// Return the encrypted bytes from the memory stream.
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
public static string DecryptStringFromBytes_Aes(byte[] cipherText)
|
||||
{
|
||||
// Check arguments.
|
||||
if (cipherText == null || cipherText.Length <= 0)
|
||||
throw new ArgumentNullException(nameof(cipherText), "can't be null");
|
||||
|
||||
// Declare the string used to hold
|
||||
// the decrypted text.
|
||||
string plaintext = string.Empty;
|
||||
|
||||
// Create an Aes object
|
||||
// with the specified key and IV.
|
||||
using (Aes aesAlg = Aes.Create())
|
||||
{
|
||||
aesAlg.Key = Key;
|
||||
aesAlg.IV = IV;
|
||||
|
||||
// Create a decryptor to perform the stream transform.
|
||||
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
// Create the streams used for decryption.
|
||||
using MemoryStream msDecrypt = new(cipherText);
|
||||
using CryptoStream csDecrypt = new(msDecrypt, decryptor, CryptoStreamMode.Read);
|
||||
using StreamReader srDecrypt = new(csDecrypt);
|
||||
// Read the decrypted bytes from the decrypting stream
|
||||
// and place them in a string.
|
||||
plaintext = srDecrypt.ReadToEnd();
|
||||
}
|
||||
|
||||
return plaintext;
|
||||
}
|
||||
}
|
7
Server/Common/Message.cs
Normal file
7
Server/Common/Message.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Common;
|
||||
|
||||
public class SyncMsg(bool isSuccess, string body)
|
||||
{
|
||||
public bool IsSuccess { get; set; } = isSuccess;
|
||||
public string Body { get; set; } = body;
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -28,6 +29,19 @@ namespace LocalServer.Controllers
|
|||
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
}
|
||||
}
|
||||
|
||||
[Route("/macaddr")]
|
||||
public string GetMacAddress()
|
||||
{
|
||||
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
|
||||
string macaddrs = "";
|
||||
foreach (NetworkInterface nic in nics)
|
||||
{
|
||||
PhysicalAddress physicalAddress = nic.GetPhysicalAddress();
|
||||
macaddrs += physicalAddress.ToString() + ";";
|
||||
}
|
||||
return macaddrs;
|
||||
}
|
||||
//TODO 是否在本地记载同步日志?
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,4 +10,8 @@
|
|||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,19 +1,108 @@
|
|||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Common;
|
||||
using LocalServer.Models;
|
||||
|
||||
namespace LocalServer;
|
||||
|
||||
public class LocalSyncServer
|
||||
{
|
||||
public readonly WebSocket Socket;
|
||||
public StateHelpBase StateHelper;
|
||||
|
||||
public Config? SyncConfig;
|
||||
|
||||
/// <summary>
|
||||
/// 发布源连接
|
||||
/// </summary>
|
||||
public readonly WebSocket LocalSocket;
|
||||
|
||||
/// <summary>
|
||||
/// 发布源-缓冲区,存储数据 最大1MB
|
||||
/// </summary>
|
||||
public byte[] Buffer = new byte[1024 * 1024];
|
||||
|
||||
/// <summary>
|
||||
/// 发布目标-连接
|
||||
/// </summary>
|
||||
public readonly ClientWebSocket RemoteSocket = new();
|
||||
|
||||
/// <summary>
|
||||
/// 发布开始时间
|
||||
/// </summary>
|
||||
private readonly DateTime StartTime = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// 发布名称
|
||||
/// </summary>
|
||||
public readonly string Name;
|
||||
|
||||
/// <summary>
|
||||
/// 父工程,用于释放资源
|
||||
/// </summary>
|
||||
public readonly LocalSyncServerFactory Factory;
|
||||
|
||||
public LocalSyncServer(WebSocket socket, string name, LocalSyncServerFactory factory)
|
||||
{
|
||||
Socket = socket;
|
||||
LocalSocket = socket;
|
||||
Name = name;
|
||||
Factory = factory;
|
||||
|
||||
StateHelper = new LocalAuthorityState(this);
|
||||
}
|
||||
|
||||
public async Task Start()
|
||||
{
|
||||
//最大1MB
|
||||
var buffer = new byte[1024 * 1024];
|
||||
var receiveResult = await LocalSocket.ReceiveAsync(
|
||||
new ArraySegment<byte>(buffer),
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
while (!receiveResult.CloseStatus.HasValue)
|
||||
{
|
||||
await LocalSocket.SendAsync(
|
||||
new ArraySegment<byte>(buffer, 0, receiveResult.Count),
|
||||
receiveResult.MessageType,
|
||||
receiveResult.EndOfMessage,
|
||||
CancellationToken.None
|
||||
);
|
||||
|
||||
receiveResult = await LocalSocket.ReceiveAsync(
|
||||
new ArraySegment<byte>(buffer),
|
||||
CancellationToken.None
|
||||
);
|
||||
}
|
||||
Factory.RemoveLocalSyncServer(this);
|
||||
await LocalSocket.CloseAsync(
|
||||
receiveResult.CloseStatus.Value,
|
||||
receiveResult.CloseStatusDescription,
|
||||
CancellationToken.None
|
||||
);
|
||||
}
|
||||
|
||||
public async void LocalSocketSendMsg(object msgOb)
|
||||
{
|
||||
string msg = JsonSerializer.Serialize(msgOb);
|
||||
await LocalSocket.SendAsync(
|
||||
new ArraySegment<byte>(Encoding.UTF8.GetBytes(msg)),
|
||||
WebSocketMessageType.Text,
|
||||
true,
|
||||
CancellationToken.None
|
||||
);
|
||||
}
|
||||
|
||||
public async void RemoteSocketSendMsg(object msgOb)
|
||||
{
|
||||
string msg = JsonSerializer.Serialize(msgOb);
|
||||
var buffer = AESHelper.EncryptStringToBytes_Aes(msg);
|
||||
await RemoteSocket.SendAsync(
|
||||
buffer,
|
||||
WebSocketMessageType.Text,
|
||||
true,
|
||||
CancellationToken.None
|
||||
);
|
||||
}
|
||||
|
||||
public void Close() { }
|
||||
}
|
||||
|
|
|
@ -4,19 +4,29 @@ namespace LocalServer;
|
|||
|
||||
public class LocalSyncServerFactory
|
||||
{
|
||||
public void CreateLocalSyncServer(WebSocket socket, string name)
|
||||
private readonly object Lock = new();
|
||||
|
||||
public async void CreateLocalSyncServer(WebSocket socket, string name)
|
||||
{
|
||||
if (Servers.Select(x => x.Name == name).Any())
|
||||
{
|
||||
throw new Exception("there already is a server with that name is Runing!");
|
||||
}
|
||||
Servers.Add(new LocalSyncServer(socket, name, this));
|
||||
var server = new LocalSyncServer(socket, name, this);
|
||||
lock (Lock)
|
||||
{
|
||||
Servers.Add(server);
|
||||
}
|
||||
await server.Start();
|
||||
}
|
||||
|
||||
private readonly List<LocalSyncServer> Servers = [];
|
||||
|
||||
public void RemoveLocalSyncServer(LocalSyncServer server)
|
||||
{
|
||||
lock (Lock)
|
||||
{
|
||||
Servers.Remove(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
32
Server/LocalServer/Models/Config.cs
Normal file
32
Server/LocalServer/Models/Config.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
namespace LocalServer.Models;
|
||||
|
||||
public class DirFileConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 本地-源根目录
|
||||
/// </summary>
|
||||
public required string LocalRootPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 远程-目标根目录
|
||||
/// </summary>
|
||||
public required string RemoteRootPath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排除的文件,它是根目录的相对路径
|
||||
/// </summary>
|
||||
public List<string>? ExcludeFiles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 除此外全部忽略,最高优先级,若有值,ExcludeFiles 将被忽略,它是根目录的相对路径
|
||||
/// </summary>
|
||||
public List<DirFileConfig>? CherryPickFiles { get; set; }
|
||||
}
|
||||
|
||||
public class Config
|
||||
{
|
||||
public required string Name { get; set; }
|
||||
public required string RemoteUrl { get; set; }
|
||||
|
||||
public List<DirFileConfig>? DirFileConfigs { get; set; }
|
||||
}
|
189
Server/LocalServer/StateHelper.cs
Normal file
189
Server/LocalServer/StateHelper.cs
Normal file
|
@ -0,0 +1,189 @@
|
|||
using System.Net.NetworkInformation;
|
||||
using System.Net.WebSockets;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using System.Security.AccessControl;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Common;
|
||||
using LocalServer.Models;
|
||||
|
||||
namespace LocalServer;
|
||||
|
||||
// enum StateWhenMsg
|
||||
// {
|
||||
// Authority = 0,
|
||||
// ConfigInfo = 1,
|
||||
// LocalPackAndUpload = 2,
|
||||
// RemoteUnPackAndRelease = 3,
|
||||
// }
|
||||
|
||||
public abstract class StateHelpBase(LocalSyncServer context)
|
||||
{
|
||||
protected readonly LocalSyncServer Context = context;
|
||||
|
||||
public abstract void HandleRemoteMsg(SyncMsg? msg);
|
||||
|
||||
public abstract void HandleLocalMsg(SyncMsg? msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 0. 发布源验证密码
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public class LocalAuthorityState(LocalSyncServer context) : StateHelpBase(context)
|
||||
{
|
||||
public override void HandleRemoteMsg(SyncMsg? msg)
|
||||
{
|
||||
throw new NotImplementedException("error usage!");
|
||||
}
|
||||
|
||||
public override void HandleLocalMsg(SyncMsg? msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
string Pwd = msg.Body;
|
||||
if (Pwd == "Xfs1%$@_fdYU.>>")
|
||||
{
|
||||
Context.LocalSocketSendMsg(new SyncMsg(true, "源服务密码校验成功!"));
|
||||
Context.StateHelper = new WaitingConfigInfoState(Context);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new UnauthorizedAccessException("pwd error!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 1. 获取配置信息,它包含目标的服务器的配置信息
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public class WaitingConfigInfoState(LocalSyncServer context) : StateHelpBase(context)
|
||||
{
|
||||
public override void HandleRemoteMsg(SyncMsg? msg) { }
|
||||
|
||||
public override void HandleLocalMsg(SyncMsg? msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
string ConfigInfo = msg.Body;
|
||||
Context.SyncConfig =
|
||||
JsonSerializer.Deserialize<Config>(ConfigInfo)
|
||||
?? throw new NullReferenceException("ConfigInfo is null");
|
||||
var task = Context.RemoteSocket.ConnectAsync(
|
||||
new Uri(Context.SyncConfig.RemoteUrl),
|
||||
CancellationToken.None
|
||||
);
|
||||
if (task.Wait(10000))
|
||||
{
|
||||
if (Context.RemoteSocket.State == WebSocketState.Open)
|
||||
{
|
||||
var state = new RemoteAuthorityState(Context);
|
||||
state.SendPwdToRemoteServer();
|
||||
Context.StateHelper = state;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("connect remote server failed!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new TimeoutException("connect remote server timeout");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2. 目标服务器权限校验
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public class RemoteAuthorityState(LocalSyncServer context) : StateHelpBase(context)
|
||||
{
|
||||
public override void HandleRemoteMsg(SyncMsg? msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else { }
|
||||
}
|
||||
|
||||
public override void HandleLocalMsg(SyncMsg? msg) { }
|
||||
|
||||
public void SendPwdToRemoteServer()
|
||||
{
|
||||
var authorityInfo = new
|
||||
{
|
||||
Pwd = "xfs@#123hd??1>>|12#4",
|
||||
MacAdr = new LocalServer.Controllers.LocalServerController(
|
||||
Context.Factory
|
||||
).GetMacAddress()
|
||||
};
|
||||
Context.RemoteSocketSendMsg(authorityInfo);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 3. 文件比较
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public class DirFilesDiffState(LocalSyncServer context) : StateHelpBase(context)
|
||||
{
|
||||
public override void HandleRemoteMsg(SyncMsg? msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else { }
|
||||
}
|
||||
|
||||
public override void HandleLocalMsg(SyncMsg? msg) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 4. 本地打包并上传
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public class LocalPackAndUploadState(LocalSyncServer context) : StateHelpBase(context)
|
||||
{
|
||||
public override void HandleRemoteMsg(SyncMsg? msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else { }
|
||||
}
|
||||
|
||||
public override void HandleLocalMsg(SyncMsg? msg) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 5. 目标服务器解包并发布
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public class RemoteUnPackAndReleaseState(LocalSyncServer context) : StateHelpBase(context)
|
||||
{
|
||||
public override void HandleRemoteMsg(SyncMsg? msg)
|
||||
{
|
||||
if (msg == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else { }
|
||||
}
|
||||
|
||||
public override void HandleLocalMsg(SyncMsg? msg) { }
|
||||
}
|
Loading…
Reference in a new issue