mirror of
https://github.com/snltty/linker.git
synced 2025-09-27 05:25:57 +08:00
182
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
release_name: v1.8.2.${{ steps.date.outputs.today }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: "1. 一些累计更新\r\n2. 测试发布,请使用1.8.2"
|
||||
body: "1. 一些累计更新\r\n2. 重建权限存储,ulong改为BitArray,同组所有客户端需保持版本一致\r\n3. 增加唤醒功能,支持WOL,COM继电器,HID继电器\r\n4. 基于One-KVM包装docker镜像集成linker\r\n5. 管理端口改为1804,一个端口托管Web+Websocket"
|
||||
- name: publish projects
|
||||
run: ./publish.bat "C:\\Android\\android-sdk"
|
||||
- name: upload-win-x86-oss
|
||||
|
@@ -20,7 +20,7 @@ namespace linker.app
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
IApiStore apiStore = LinkerMessengerEntry.GetService<IApiStore>();
|
||||
webview.Source = new Uri($"http://127.0.0.1:{apiStore.Info.WebPort}?t={DateTime.Now.Ticks}/#/?api={apiStore.Info.ApiPort}&psd={Helper.GlobalString}");
|
||||
webview.Source = new Uri($"http://127.0.0.1:{apiStore.Info.WebPort}?t={DateTime.Now.Ticks}/#/?api={apiStore.Info.WebPort}&psd={Helper.GlobalString}");
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@ sidebar_position: 0
|
||||
:::
|
||||
|
||||
:::tip[客户端]
|
||||
1. 客户端模式 监听端口 `1803(TCP)`websocket管理接口,`1804(TCP)`管理UI端口
|
||||
1. 客户端模式 管理接口`1804(TCP)`
|
||||
2. 运行起来后可以使用`http://127.0.0.1:1804`打开管理页面,如果是windows,也可以在`linker.tray.win.exe`托盘程序里打开管理页面
|
||||
:::
|
||||
|
||||
|
@@ -31,7 +31,7 @@ sc delete 服务名
|
||||
|
||||
1. 由于linker使用当前目录下的`configs`文件夹里的配置文件,所以不能使用同一程序多开,需要使用多份程序,**不要把`configs`文件夹也复制过去**
|
||||
2. 客户端托盘无法多开,所以需要客户端多开时,**需要你手动安装服务**,不能使用托盘安装服务
|
||||
3. 客户端会监听两个端口,默认为`1803` 管理接口,`1804`网页服务,所以,在初始化时,你需要各个客户端**使用不同的端口**
|
||||
3. 客户端会监听`1804` 管理接口,所以,在初始化时,你需要各个客户端**使用不同的端口**
|
||||
|
||||
#### 在初始化时,`接口端口`,和`网页端口`,需要各个客户端设置为不一样的端口
|
||||

|
||||
|
@@ -25,19 +25,16 @@ chmod +x linker-install.sh
|
||||
|
||||
:::tip[说明]
|
||||
|
||||
1. 服务端端口 `1802` TCP+UDP
|
||||
2. 客户端端口 `1804`、`1803` TCP
|
||||
3. 配置文件夹 `./configs`
|
||||
4. 日志文件夹 `./logs`
|
||||
5. 镜像清单 `snltty/linker-debian`、`snltty/linker-musl`、`snltty/linker-kvm`
|
||||
6. 特定平台 `snltty/linker-debian-{arch}`、`snltty/linker-musl-{arch}`、`snltty/linker-kvm-{arch}`,`{arch}`可以是`x64`、`arm64`、`arm`
|
||||
7. `bridge`模式,需要映射一些端口比如`-p 18000-18010:18000-18010`,用于端口转发
|
||||
8. `host`模式,或者直接使用host`--network host`,**建议使用host,点对网,网对网,端口转发都方便**
|
||||
1. 服务端端口 `1802` TCP+UDP、客户端端口 `1804` TCP
|
||||
2. 配置文件夹 `./configs`、日志文件夹 `./logs`
|
||||
3. 镜像清单 `snltty/linker-debian`、`snltty/linker-musl`、`snltty/linker-kvm` 或者 `snltty/linker-debian-{arch}`、`snltty/linker-musl-{arch}`、`snltty/linker-kvm-{arch}`,`{arch}`可以是`x64`、`arm64`、`arm`
|
||||
4. `bridge`模式,需要映射一些端口比如`-p 18000-18010:18000-18010`,用于端口转发,或者直接使用host`--network host`,**建议使用host,点对网,网对网,端口转发都方便**
|
||||
5. 如果你使用的是KVM镜像,那么会多需要几个端口`1806 http`、`1807 https`、`5900 VNC`、`623 ipmi`
|
||||
|
||||
#### 客户端-bridge
|
||||
```
|
||||
docker run -it -d --name linker \
|
||||
-p 1804:1804/tcp -p 1803:1803/tcp \
|
||||
-p 1804:1804/tcp \
|
||||
-p 18000-18010:18000-18010/tcp \
|
||||
-p 18000-18010:18000-18010/udp \
|
||||
-v /usr/local/linker-docker/configs:/app/configs \
|
||||
@@ -47,6 +44,41 @@ docker run -it -d --name linker \
|
||||
--privileged=true \
|
||||
snltty/linker-musl
|
||||
```
|
||||
#### 客户端-bridge-kvm
|
||||
|
||||
1. 基于[One-KVM](https://one-kvm.mofeng.run/start_install/docker_install/)的docker镜像包装,集成linker
|
||||
2. 在linker参数的基础上,再加上KVM的参数,根据自己的需求修改一下参数即可
|
||||
3. 使用 1806 端口打开KVM管理页面
|
||||
|
||||
```
|
||||
docker run --name linker-kvm -itd \
|
||||
-p 1804:1804/tcp \
|
||||
-p 18000-18010:18000-18010/tcp \
|
||||
-p 18000-18010:18000-18010/udp \
|
||||
-v /usr/local/linker-docker/configs:/app/configs \
|
||||
-v /usr/local/linker-docker/logs:/app/logs \
|
||||
--device /dev/net/tun \
|
||||
--restart=always \
|
||||
--privileged=true \
|
||||
--network host \
|
||||
-p 1806:1806/tcp -p 1806:1806/udp \ #网页http端口
|
||||
-p 1807:1807/tcp -p 1807:1807/udp \ #网页https端口
|
||||
-p 5900:5900/tcp -p 5900:5900/udp \ #vnc端口
|
||||
-p 623:623/tcp -p 623:623/udp \ #ipmi端口
|
||||
--device /dev/video0:/dev/video0 \ #采集卡
|
||||
--device /dev/snd:/dev/snd -e AUDIONUM=0 \ #声卡
|
||||
--device /dev/hidraw1:/dev/hidraw1 -e ATX=USBRELAY_HID \ #HID继电器
|
||||
--device /dev/ttyUSB0:/dev/ttyUSB0 -e CH9329SPEED=9600 \ #CH9329键盘鼠标
|
||||
-v /usr/local/linker-docker/kvmd:/etc/kvmd \ #映射配置目录
|
||||
-e USERNAME=snltty -e PASSWORD=snltty -e NOAUTH=1 \ #账号密码,禁用认证
|
||||
-e NOVNC=1 \ #禁用vnc
|
||||
-e NOIPMI=1 \ #禁用ipmi
|
||||
-e NOWEBTERM=1 -e NOWEBTERMWRITE=1 \ #禁用webterm
|
||||
-e NOSSL=1 \ #禁用ssl
|
||||
snltty/linker-kvm
|
||||
```
|
||||
|
||||
|
||||
#### 客户端-host
|
||||
```
|
||||
docker run -it -d --name linker \
|
||||
@@ -58,6 +90,32 @@ docker run -it -d --name linker \
|
||||
--network host \
|
||||
snltty/linker-musl
|
||||
```
|
||||
#### 客户端-host-kvm
|
||||
|
||||
1. 基于[One-KVM](https://one-kvm.mofeng.run/start_install/docker_install/)的docker镜像包装,集成linker
|
||||
2. 在linker参数的基础上,再加上KVM的参数,根据自己的需求修改一下参数即可
|
||||
3. 使用 1806 端口打开KVM管理页面
|
||||
|
||||
```
|
||||
docker run --name linker-kvm -itd \
|
||||
-v /usr/local/linker-docker/configs:/app/configs \
|
||||
-v /usr/local/linker-docker/logs:/app/logs \
|
||||
--device /dev/net/tun \
|
||||
--restart=always \
|
||||
--privileged=true \
|
||||
--network host \
|
||||
--device /dev/video0:/dev/video0 \ #采集卡
|
||||
--device /dev/snd:/dev/snd -e AUDIONUM=0 \ #声卡
|
||||
--device /dev/hidraw1:/dev/hidraw1 -e ATX=USBRELAY_HID \ #HID继电器
|
||||
--device /dev/ttyUSB0:/dev/ttyUSB0 -e CH9329SPEED=9600 \ #CH9329键盘鼠标
|
||||
-v /usr/local/linker-docker/kvmd:/etc/kvmd \ #映射配置目录
|
||||
-e USERNAME=snltty -e PASSWORD=snltty -e NOAUTH=1 \ #账号密码,禁用认证
|
||||
-e NOVNC=1 \ #禁用vnc
|
||||
-e NOIPMI=1 \ #禁用ipmi
|
||||
-e NOWEBTERM=1 -e NOWEBTERMWRITE=1 \ #禁用webterm
|
||||
-e NOSSL=1 \ #禁用ssl
|
||||
snltty/linker-kvm
|
||||
```
|
||||
|
||||
#### 服务端-bridge
|
||||
```
|
||||
|
@@ -19,9 +19,8 @@ sidebar_position: 8
|
||||
```
|
||||
{
|
||||
"Name": "A", //客户端名
|
||||
"Access": 4503599627370495, //权限值,可以看`src/linker.messenger.api/Config.cs`里的`AccessValue`枚举
|
||||
"AccessBits": '11111111111', //按下标,1有权限,0无权限,可以看`src/linker.messenger.api/Config.cs`里的`AccessValue`枚举
|
||||
"CApi": {
|
||||
"ApiPort": 1803, //api接口
|
||||
"ApiPassword": "snltty", //api密码
|
||||
"WebPort": 1804, //web端口
|
||||
"WebRoot": "./web/" //web根目录
|
||||
|
@@ -17,7 +17,7 @@ sidebar_position: 6
|
||||
### 1.2、动态配置示例
|
||||
以javascript 为例,设置参数方法:
|
||||
```
|
||||
const ws = new WebSocket(`ws://127.0.0.1:1803`, ['接口密钥']);
|
||||
const ws = new WebSocket(`ws://127.0.0.1:1804`, ['接口密钥']);
|
||||
ws.onopen = () => {
|
||||
const json = {Key:'token',Value:'snltty'}; //你的参数内容,json格式,任意内容,将原样post到ActionUrl
|
||||
ws.send(JSON.stringify({
|
||||
|
@@ -1,202 +0,0 @@
|
||||
using linker.libs.extends;
|
||||
using linker.libs.websocket;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace linker.libs.api
|
||||
{
|
||||
/// <summary>
|
||||
/// 前段接口服务
|
||||
/// </summary>
|
||||
public class ApiServer : IApiServer
|
||||
{
|
||||
protected readonly Dictionary<string, PluginPathCacheInfo> plugins = new();
|
||||
protected readonly ConcurrentDictionary<uint, ConnectionTimeInfo> connectionTimes = new();
|
||||
public uint OnlineNum = 0;
|
||||
private string password = string.Empty;
|
||||
|
||||
private WebSocketServer server;
|
||||
|
||||
public ApiServer()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启websockt
|
||||
/// </summary>
|
||||
public void Websocket(int port, string password = "")
|
||||
{
|
||||
this.password = password;
|
||||
server = new WebSocketServer();
|
||||
try
|
||||
{
|
||||
server.Start(port);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
server.OnConnecting = (connection, header) =>
|
||||
{
|
||||
bool res = string.IsNullOrWhiteSpace(this.password) || (header.TryGetHeaderValue(WebsocketHeaderKey.SecWebSocketProtocol, out string _password) && string.Equals(_password, this.password));
|
||||
if (res)
|
||||
{
|
||||
header.SetHeaderValue(WebsocketHeaderKey.SecWebSocketExtensions, string.Empty);
|
||||
}
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
header.TryGetHeaderValue(WebsocketHeaderKey.SecWebSocketProtocol, out string _password1);
|
||||
LoggerHelper.Instance.Info($"websocket client password {_password1} eq {password}");
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
server.OnOpen = (connection) =>
|
||||
{
|
||||
Interlocked.Increment(ref OnlineNum);
|
||||
connectionTimes.TryAdd(connection.Id, new ConnectionTimeInfo());
|
||||
};
|
||||
server.OnDisConnectd = (connection) =>
|
||||
{
|
||||
Interlocked.Decrement(ref OnlineNum);
|
||||
if (OnlineNum < 0) Interlocked.Exchange(ref OnlineNum, 0);
|
||||
connectionTimes.TryRemove(connection.Id, out _);
|
||||
};
|
||||
server.OnMessage = (connection, frame, message) =>
|
||||
{
|
||||
if (connectionTimes.TryGetValue(connection.Id, out ConnectionTimeInfo timeInfo))
|
||||
{
|
||||
timeInfo.DateTime = DateTime.Now;
|
||||
}
|
||||
var req = message.DeJson<ApiControllerRequestInfo>();
|
||||
req.Connection = connection;
|
||||
OnMessage(req).ContinueWith((result) =>
|
||||
{
|
||||
var resp = result.Result.ToJson().ToBytes();
|
||||
connection.SendFrameText(resp);
|
||||
});
|
||||
};
|
||||
}
|
||||
public void SetPassword(string password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收到消息
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ApiControllerResponseInfo> OnMessage(ApiControllerRequestInfo model)
|
||||
{
|
||||
model.Path = model.Path.ToLower();
|
||||
if (plugins.TryGetValue(model.Path, out PluginPathCacheInfo plugin) == false)
|
||||
{
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Content = $"{model.Path} not exists",
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
Code = ApiControllerResponseCodes.NotFound
|
||||
};
|
||||
}
|
||||
if (plugin.HasAccess(plugin.Access) == false)
|
||||
{
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Content = "no permission",
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
Code = ApiControllerResponseCodes.Error
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ApiControllerParamsInfo param = new ApiControllerParamsInfo
|
||||
{
|
||||
RequestId = model.RequestId,
|
||||
Content = model.Content,
|
||||
Connection = model.Connection
|
||||
};
|
||||
dynamic resultAsync = plugin.Method.Invoke(plugin.Target, new object[] { param });
|
||||
object resultObject = null;
|
||||
if (plugin.IsVoid == false)
|
||||
{
|
||||
if (plugin.IsTask)
|
||||
{
|
||||
await resultAsync.ConfigureAwait(false);
|
||||
if (plugin.IsTaskResult)
|
||||
{
|
||||
resultObject = resultAsync.Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultObject = resultAsync;
|
||||
}
|
||||
}
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Code = param.Code,
|
||||
Content = param.Code != ApiControllerResponseCodes.Error ? resultObject : param.ErrorMessage,
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Error($"{model.Path} -> {ex.Message}");
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Content = ex.Message,
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
Code = ApiControllerResponseCodes.Error
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed class ConnectionTimeInfo
|
||||
{
|
||||
public DateTime DateTime { get; set; } = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 前段接口缓存
|
||||
/// </summary>
|
||||
public struct PluginPathCacheInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象
|
||||
/// </summary>
|
||||
public object Target { get; set; }
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
public MethodInfo Method { get; set; }
|
||||
/// <summary>
|
||||
/// 是否void
|
||||
/// </summary>
|
||||
public bool IsVoid { get; set; }
|
||||
/// <summary>
|
||||
/// 是否task
|
||||
/// </summary>
|
||||
public bool IsTask { get; set; }
|
||||
/// <summary>
|
||||
/// 是否task result
|
||||
/// </summary>
|
||||
public bool IsTaskResult { get; set; }
|
||||
|
||||
public int Access { get; set; }
|
||||
public Func<int, bool> HasAccess { get; set; }
|
||||
}
|
||||
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
namespace linker.libs.api
|
||||
{
|
||||
/// <summary>
|
||||
/// 前端接口服务
|
||||
/// </summary>
|
||||
public interface IApiServer
|
||||
{
|
||||
/// <summary>
|
||||
/// websocket
|
||||
/// </summary>
|
||||
public void Websocket(int port,string password);
|
||||
public void SetPassword(string password);
|
||||
}
|
||||
|
||||
}
|
@@ -1,8 +1,9 @@
|
||||
using linker.libs.websocket;
|
||||
using System;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace linker.libs.api
|
||||
namespace linker.libs.web
|
||||
{
|
||||
/// <summary>
|
||||
/// 前段接口
|
||||
@@ -38,7 +39,7 @@ namespace linker.libs.api
|
||||
public sealed class ApiControllerRequestInfo
|
||||
{
|
||||
[JsonIgnore]
|
||||
public WebsocketConnection Connection { get; set; }
|
||||
public WebSocket Connection { get; set; }
|
||||
/// <summary>
|
||||
/// 路径
|
||||
/// </summary>
|
||||
@@ -58,7 +59,7 @@ namespace linker.libs.api
|
||||
/// </summary>
|
||||
public sealed class ApiControllerParamsInfo
|
||||
{
|
||||
public WebsocketConnection Connection { get; set; }
|
||||
public WebSocket Connection { get; set; }
|
||||
/// <summary>
|
||||
/// 请求id
|
||||
/// </summary>
|
@@ -1,4 +1,6 @@
|
||||
namespace linker.libs.web
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace linker.libs.web
|
||||
{
|
||||
/// <summary>
|
||||
/// web服务
|
||||
@@ -8,7 +10,8 @@
|
||||
/// <summary>
|
||||
/// 开始
|
||||
/// </summary>
|
||||
public void Start(int port, string root);
|
||||
public void Start(int port, string root,string password);
|
||||
public void SetPassword(string password);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,12 @@
|
||||
using System;
|
||||
using linker.libs.extends;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace linker.libs.web
|
||||
@@ -12,6 +17,8 @@ namespace linker.libs.web
|
||||
public class WebServer : IWebServer
|
||||
{
|
||||
private string root = "";
|
||||
private string password = Helper.GlobalString;
|
||||
protected readonly Dictionary<string, PluginPathCacheInfo> plugins = new();
|
||||
|
||||
private readonly IWebServerFileReader fileReader;
|
||||
public WebServer(IWebServerFileReader fileReader)
|
||||
@@ -22,10 +29,11 @@ namespace linker.libs.web
|
||||
/// <summary>
|
||||
/// 开启web
|
||||
/// </summary>
|
||||
public void Start(int port, string root)
|
||||
public void Start(int port, string root, string password)
|
||||
{
|
||||
this.root = root;
|
||||
Task.Factory.StartNew(() =>
|
||||
this.password = password;
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -34,7 +42,25 @@ namespace linker.libs.web
|
||||
http.Prefixes.Add($"http://+:{port}/");
|
||||
http.Start();
|
||||
|
||||
http.BeginGetContext(Callback, http);
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpListenerContext context = await http.GetContextAsync();
|
||||
if (context.Request.IsWebSocketRequest)
|
||||
{
|
||||
HttpListenerWebSocketContext wsContext = await context.AcceptWebSocketAsync(null);
|
||||
HandleWs(wsContext.WebSocket);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleWeb(context);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -42,13 +68,11 @@ namespace linker.libs.web
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}
|
||||
private void Callback(IAsyncResult result)
|
||||
|
||||
private void HandleWeb(HttpListenerContext context)
|
||||
{
|
||||
HttpListener http = result.AsyncState as HttpListener;
|
||||
HttpListenerContext context = http.EndGetContext(result);
|
||||
HttpListenerRequest request = context.Request;
|
||||
HttpListenerResponse response = context.Response;
|
||||
|
||||
try
|
||||
{
|
||||
response.Headers.Set("Server", Helper.GlobalString);
|
||||
@@ -99,11 +123,7 @@ namespace linker.libs.web
|
||||
}
|
||||
|
||||
response.Close();
|
||||
|
||||
http.BeginGetContext(Callback, http);
|
||||
}
|
||||
|
||||
|
||||
private Dictionary<string, string> types = new Dictionary<string, string> {
|
||||
{ ".webp","image/webp"},
|
||||
{ ".png","image/png"},
|
||||
@@ -127,6 +147,133 @@ namespace linker.libs.web
|
||||
}
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
public void SetPassword(string password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
private async void HandleWs(WebSocket websocket)
|
||||
{
|
||||
byte[] buffer = new byte[8 * 1024];
|
||||
try
|
||||
{
|
||||
WebSocketReceiveResult result = await websocket.ReceiveAsync(buffer, CancellationToken.None);
|
||||
if (result.MessageType != WebSocketMessageType.Text)
|
||||
{
|
||||
await websocket.CloseAsync(WebSocketCloseStatus.ProtocolError, "password fail", CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
ApiControllerRequestInfo req = Encoding.UTF8.GetString(buffer.AsMemory(0, result.Count).Span).DeJson<ApiControllerRequestInfo>();
|
||||
if (req.Path != "password" || req.Content != this.password)
|
||||
{
|
||||
await websocket.CloseAsync(WebSocketCloseStatus.ProtocolError, "password fail", CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
await websocket.SendAsync(new ApiControllerResponseInfo
|
||||
{
|
||||
Code = ApiControllerResponseCodes.Success,
|
||||
Path = req.Path,
|
||||
RequestId = req.RequestId,
|
||||
Content = "password ok",
|
||||
}.ToJson().ToBytes(), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
|
||||
while (websocket.State == WebSocketState.Open)
|
||||
{
|
||||
result = await websocket.ReceiveAsync(buffer, CancellationToken.None);
|
||||
switch (result.MessageType)
|
||||
{
|
||||
case WebSocketMessageType.Text:
|
||||
{
|
||||
req = Encoding.UTF8.GetString(buffer.AsMemory(0, result.Count).Span).DeJson<ApiControllerRequestInfo>();
|
||||
req.Connection = websocket;
|
||||
ApiControllerResponseInfo resp = await OnMessage(req);
|
||||
await websocket.SendAsync(resp.ToJson().ToBytes(), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
break;
|
||||
case WebSocketMessageType.Binary:
|
||||
break;
|
||||
case WebSocketMessageType.Close:
|
||||
await websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closed by client", CancellationToken.None);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Error(ex);
|
||||
}
|
||||
}
|
||||
private async Task<ApiControllerResponseInfo> OnMessage(ApiControllerRequestInfo model)
|
||||
{
|
||||
model.Path = model.Path.ToLower();
|
||||
if (plugins.TryGetValue(model.Path, out PluginPathCacheInfo plugin) == false)
|
||||
{
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Content = $"{model.Path} not exists",
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
Code = ApiControllerResponseCodes.NotFound
|
||||
};
|
||||
}
|
||||
if (plugin.HasAccess(plugin.Access) == false)
|
||||
{
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Content = "no permission",
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
Code = ApiControllerResponseCodes.Error
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ApiControllerParamsInfo param = new ApiControllerParamsInfo
|
||||
{
|
||||
RequestId = model.RequestId,
|
||||
Content = model.Content,
|
||||
Connection = model.Connection
|
||||
};
|
||||
dynamic resultAsync = plugin.Method.Invoke(plugin.Target, new object[] { param });
|
||||
object resultObject = null;
|
||||
if (plugin.IsVoid == false)
|
||||
{
|
||||
if (plugin.IsTask)
|
||||
{
|
||||
await resultAsync.ConfigureAwait(false);
|
||||
if (plugin.IsTaskResult)
|
||||
{
|
||||
resultObject = resultAsync.Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultObject = resultAsync;
|
||||
}
|
||||
}
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Code = param.Code,
|
||||
Content = param.Code != ApiControllerResponseCodes.Error ? resultObject : param.ErrorMessage,
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.Instance.Error($"{model.Path} -> {ex.Message}");
|
||||
return new ApiControllerResponseInfo
|
||||
{
|
||||
Content = ex.Message,
|
||||
RequestId = model.RequestId,
|
||||
Path = model.Path,
|
||||
Code = ApiControllerResponseCodes.Error
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,4 +290,31 @@ namespace linker.libs.web
|
||||
return File.ReadAllBytes(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
public struct PluginPathCacheInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象
|
||||
/// </summary>
|
||||
public object Target { get; set; }
|
||||
/// <summary>
|
||||
/// 方法
|
||||
/// </summary>
|
||||
public MethodInfo Method { get; set; }
|
||||
/// <summary>
|
||||
/// 是否void
|
||||
/// </summary>
|
||||
public bool IsVoid { get; set; }
|
||||
/// <summary>
|
||||
/// 是否task
|
||||
/// </summary>
|
||||
public bool IsTask { get; set; }
|
||||
/// <summary>
|
||||
/// 是否task result
|
||||
/// </summary>
|
||||
public bool IsTaskResult { get; set; }
|
||||
|
||||
public int Access { get; set; }
|
||||
public Func<int, bool> HasAccess { get; set; }
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,10 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using linker.libs;
|
||||
using linker.messenger.signin;
|
||||
using linker.messenger.api;
|
||||
using IApiServer = linker.messenger.api.IApiServer;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.access
|
||||
{
|
||||
@@ -18,9 +17,10 @@ namespace linker.messenger.access
|
||||
private readonly ISerializer serializer;
|
||||
private readonly IAccessStore accessStore;
|
||||
private readonly IApiStore apiStore;
|
||||
private readonly IApiServer apiServer;
|
||||
private readonly linker.messenger.api.IWebServer apiServer;
|
||||
|
||||
public AccessApiController(IMessengerSender sender, SignInClientState signInClientState, AccessDecenter accessDecenter, ISignInClientStore signInClientStore, ISerializer serializer, IAccessStore accessStore, IApiStore apiStore, IApiServer apiServer)
|
||||
public AccessApiController(IMessengerSender sender, SignInClientState signInClientState, AccessDecenter accessDecenter,
|
||||
ISignInClientStore signInClientStore, ISerializer serializer, IAccessStore accessStore, IApiStore apiStore, linker.messenger.api.IWebServer apiServer)
|
||||
{
|
||||
this.sender = sender;
|
||||
this.signInClientState = signInClientState;
|
||||
|
@@ -1,8 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.signin;
|
||||
using IApiServer = linker.messenger.api.IApiServer;
|
||||
|
||||
namespace linker.messenger.access
|
||||
{
|
||||
@@ -96,8 +94,8 @@ namespace linker.messenger.access
|
||||
private readonly IAccessStore accessStore;
|
||||
private readonly ISerializer serializer;
|
||||
private readonly IApiStore apiStore;
|
||||
private readonly IApiServer apiServer;
|
||||
public AccessClientMessenger(IAccessStore accessStore, ISerializer serializer, IApiStore apiStore, IApiServer apiServer)
|
||||
private readonly linker.messenger.api.IWebServer apiServer;
|
||||
public AccessClientMessenger(IAccessStore accessStore, ISerializer serializer, IApiStore apiStore, linker.messenger.api.IWebServer apiServer)
|
||||
{
|
||||
this.accessStore = accessStore;
|
||||
this.serializer = serializer;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.messenger.access;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.access;
|
||||
using linker.messenger.decenter;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
namespace linker.messenger.api
|
||||
@@ -14,8 +15,8 @@ namespace linker.messenger.api
|
||||
}
|
||||
public static ServiceProvider UseAccessClient(this ServiceProvider serviceProvider)
|
||||
{
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<AccessApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<AccessApiController>() });
|
||||
|
||||
DecenterClientTransfer decenterClientTransfer = serviceProvider.GetService<DecenterClientTransfer>();
|
||||
decenterClientTransfer.AddDecenters(new List<IDecenter> { serviceProvider.GetService<AccessDecenter>() });
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
|
||||
namespace linker.messenger.action
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.messenger.action;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.action;
|
||||
using linker.messenger.relay.server.validator;
|
||||
using linker.messenger.sforward.server.validator;
|
||||
using linker.messenger.signin.args;
|
||||
@@ -17,8 +18,8 @@ namespace linker.messenger.api
|
||||
}
|
||||
public static ServiceProvider UseActionClient(this ServiceProvider serviceProvider)
|
||||
{
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<ActionApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<ActionApiController>() });
|
||||
|
||||
SignInArgsTransfer signInArgsTransfer = serviceProvider.GetService<SignInArgsTransfer>();
|
||||
signInArgsTransfer.AddArgs(new List<ISignInArgs> { serviceProvider.GetService<SignInArgsAction>() });
|
||||
|
@@ -1,62 +0,0 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using System.Reflection;
|
||||
|
||||
namespace linker.messenger.api
|
||||
{
|
||||
/// <summary>
|
||||
/// 前段接口服务
|
||||
/// </summary>
|
||||
public sealed partial class ApiServer : libs.api.ApiServer, IApiServer
|
||||
{
|
||||
private readonly IAccessStore accessStore;
|
||||
public ApiServer(IAccessStore accessStore)
|
||||
{
|
||||
this.accessStore = accessStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载插件
|
||||
/// </summary>
|
||||
public void AddPlugins(List<IApiController> list)
|
||||
{
|
||||
Type voidType = typeof(void);
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Info($"add api {string.Join(",", list.Select(c => c.GetType().Name))}");
|
||||
|
||||
foreach (IApiController obj in list)
|
||||
{
|
||||
Type type = obj.GetType();
|
||||
string path = type.Name.Replace("ApiController", "").Replace("ApiController", "");
|
||||
foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
string key = $"{path}/{method.Name}".ToLower();
|
||||
if (plugins.ContainsKey(key) == false)
|
||||
{
|
||||
bool istask = method.ReturnType.GetProperty("IsCompleted") != null && method.ReturnType.GetMethod("GetAwaiter") != null;
|
||||
bool isTaskResult = method.ReturnType.GetProperty("Result") != null;
|
||||
|
||||
AccessAttribute accessAttr = method.GetCustomAttribute<AccessAttribute>();
|
||||
int access = (int)(accessAttr?.Value ?? 0);
|
||||
|
||||
plugins.TryAdd(key, new PluginPathCacheInfo
|
||||
{
|
||||
IsVoid = method.ReturnType == voidType,
|
||||
Method = method,
|
||||
Target = obj,
|
||||
IsTask = istask,
|
||||
IsTaskResult = isTaskResult,
|
||||
Access = access,
|
||||
HasAccess = HasAccess,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool HasAccess(int access)
|
||||
{
|
||||
return accessStore.HasAccess((AccessValue)access);
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,7 +7,6 @@ namespace linker.messenger.api
|
||||
{
|
||||
public static ServiceCollection AddApiClient(this ServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection.AddSingleton<IApiServer, ApiServer>();
|
||||
serviceCollection.AddSingleton<IWebServer, WebServer>();
|
||||
|
||||
serviceCollection.AddSingleton<IWebServerFileReader, WebServerFileReader>();
|
||||
@@ -18,21 +17,12 @@ namespace linker.messenger.api
|
||||
{
|
||||
IApiStore apiStore = serviceProvider.GetService<IApiStore>();
|
||||
IAccessStore accessStore = serviceProvider.GetService<IAccessStore>();
|
||||
if (apiStore.Info.ApiPort > 0 && accessStore.HasAccess(AccessValue.Api))
|
||||
{
|
||||
LoggerHelper.Instance.Info($"start client api");
|
||||
IApiServer server = serviceProvider.GetService<IApiServer>();
|
||||
server.Websocket(apiStore.Info.ApiPort, apiStore.Info.ApiPassword);
|
||||
LoggerHelper.Instance.Warning($"client api listen:{apiStore.Info.ApiPort}");
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Warning($"client api password:{apiStore.Info.ApiPassword}");
|
||||
}
|
||||
|
||||
if (apiStore.Info.WebPort > 0 && accessStore.HasAccess(AccessValue.Web))
|
||||
{
|
||||
LoggerHelper.Instance.Info($"start client web");
|
||||
IWebServer webServer = serviceProvider.GetService<IWebServer>();
|
||||
webServer.Start(apiStore.Info.WebPort, apiStore.Info.WebRoot);
|
||||
webServer.Start(apiStore.Info.WebPort, apiStore.Info.WebRoot, apiStore.Info.ApiPassword);
|
||||
LoggerHelper.Instance.Warning($"client web listen:{apiStore.Info.WebPort}");
|
||||
}
|
||||
return serviceProvider;
|
||||
|
@@ -1,10 +0,0 @@
|
||||
using linker.libs.api;
|
||||
|
||||
namespace linker.messenger.api
|
||||
{
|
||||
public interface IApiServer : libs.api.IApiServer
|
||||
{
|
||||
public void AddPlugins(List<IApiController> list);
|
||||
}
|
||||
|
||||
}
|
@@ -3,15 +3,10 @@ namespace linker.messenger.api
|
||||
{
|
||||
public sealed class ApiClientInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 管理接口端口
|
||||
/// </summary>
|
||||
public int ApiPort { get; set; } = 1803;
|
||||
/// <summary>
|
||||
/// 管理接口密码
|
||||
/// </summary>
|
||||
public string ApiPassword { get; set; } = Helper.GlobalString;
|
||||
|
||||
/// <summary>
|
||||
/// 网站端口
|
||||
/// </summary>
|
||||
@@ -33,12 +28,6 @@ namespace linker.messenger.api
|
||||
/// <returns></returns>
|
||||
public bool Set(ApiClientInfo info);
|
||||
/// <summary>
|
||||
/// 设置接口端口
|
||||
/// </summary>
|
||||
/// <param name="port"></param>
|
||||
/// <returns></returns>
|
||||
public bool SetApiPort(int port);
|
||||
/// <summary>
|
||||
/// 设置接口密码
|
||||
/// </summary>
|
||||
/// <param name="password"></param>
|
||||
|
@@ -1,15 +1,69 @@
|
||||
using linker.libs.web;
|
||||
using linker.libs;
|
||||
using linker.libs.web;
|
||||
using System.Reflection;
|
||||
|
||||
namespace linker.messenger.api
|
||||
{
|
||||
public interface IWebServer : libs.web.IWebServer
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载插件
|
||||
/// </summary>
|
||||
void AddPlugins(List<IApiController> list);
|
||||
}
|
||||
/// <summary>
|
||||
/// 本地web管理端服务器
|
||||
/// </summary>
|
||||
public sealed class WebServer : libs.web.WebServer, IWebServer
|
||||
{
|
||||
public WebServer(IWebServerFileReader webServerFileReader) : base(webServerFileReader)
|
||||
private readonly IAccessStore accessStore;
|
||||
public WebServer(IWebServerFileReader webServerFileReader, IAccessStore accessStore) : base(webServerFileReader)
|
||||
{
|
||||
this.accessStore = accessStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载插件
|
||||
/// </summary>
|
||||
public void AddPlugins(List<IApiController> list)
|
||||
{
|
||||
Type voidType = typeof(void);
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Info($"add api {string.Join(",", list.Select(c => c.GetType().Name))}");
|
||||
|
||||
foreach (IApiController obj in list)
|
||||
{
|
||||
Type type = obj.GetType();
|
||||
string path = type.Name.Replace("ApiController", "").Replace("ApiController", "");
|
||||
foreach (MethodInfo method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
|
||||
{
|
||||
string key = $"{path}/{method.Name}".ToLower();
|
||||
if (plugins.ContainsKey(key) == false)
|
||||
{
|
||||
bool istask = method.ReturnType.GetProperty("IsCompleted") != null && method.ReturnType.GetMethod("GetAwaiter") != null;
|
||||
bool isTaskResult = method.ReturnType.GetProperty("Result") != null;
|
||||
|
||||
AccessAttribute accessAttr = method.GetCustomAttribute<AccessAttribute>();
|
||||
int access = (int)(accessAttr?.Value ?? 0);
|
||||
|
||||
plugins.TryAdd(key, new PluginPathCacheInfo
|
||||
{
|
||||
IsVoid = method.ReturnType == voidType,
|
||||
Method = method,
|
||||
Target = obj,
|
||||
IsTask = istask,
|
||||
IsTaskResult = isTaskResult,
|
||||
Access = access,
|
||||
HasAccess = HasAccess,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private bool HasAccess(int access)
|
||||
{
|
||||
return accessStore.HasAccess(AccessValue.Api) && accessStore.HasAccess((AccessValue)access);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.snat;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace linker.messenger.firewall
|
||||
IMessengerResolver messengerResolver = serviceProvider.GetService<IMessengerResolver>();
|
||||
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<FirewallClientMessenger>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<FirewallApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<FirewallApiController>() });
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using linker.libs;
|
||||
using linker.messenger.signin;
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.firewall
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.flow.messenger;
|
||||
using linker.messenger.relay.server;
|
||||
using linker.messenger.tunnel;
|
||||
@@ -22,8 +23,8 @@ namespace linker.messenger.flow
|
||||
}
|
||||
public static ServiceProvider UseFlowClient(this ServiceProvider serviceProvider)
|
||||
{
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<FlowApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<FlowApiController>() });
|
||||
|
||||
FlowTransfer flowTransfer = serviceProvider.GetService<FlowTransfer>();
|
||||
flowTransfer.AddFlows(new List<IFlow> { serviceProvider.GetService<MessengerFlow>() });
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.flow.messenger;
|
||||
using linker.messenger.relay.client;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.decenter;
|
||||
using linker.messenger.forward.proxy;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -23,8 +24,8 @@ namespace linker.messenger.forward
|
||||
}
|
||||
public static ServiceProvider UseForwardClient(this ServiceProvider serviceProvider)
|
||||
{
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<ForwardApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<ForwardApiController>() });
|
||||
|
||||
ForwardTransfer forwardTransfer = serviceProvider.GetService<ForwardTransfer>();
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using System.Net;
|
||||
using linker.libs;
|
||||
using linker.tunnel.connection;
|
||||
@@ -7,6 +6,7 @@ using System.Collections.Concurrent;
|
||||
using linker.messenger.signin;
|
||||
using linker.messenger.forward.proxy;
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.forward
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.timer;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
namespace linker.messenger.logger
|
||||
@@ -25,8 +26,8 @@ namespace linker.messenger.logger
|
||||
}
|
||||
public static ServiceProvider UseLoggerClient(this ServiceProvider serviceProvider)
|
||||
{
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<LoggerApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<LoggerApiController>() });
|
||||
|
||||
IAccessStore accessStore= serviceProvider.GetService<IAccessStore>();
|
||||
ILoggerStore loggerStore= serviceProvider.GetService<ILoggerStore>();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using linker.libs.extends;
|
||||
using linker.libs.api;
|
||||
using linker.libs;
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.logger
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
@@ -21,8 +22,8 @@ namespace linker.messenger.plan
|
||||
IMessengerResolver messengerResolver = serviceProvider.GetService<IMessengerResolver>();
|
||||
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<PlanClientMessenger>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<PlanApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<PlanApiController>() });
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.signin;
|
||||
|
||||
namespace linker.messenger.plan
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.relay.client;
|
||||
using linker.messenger.relay.messenger;
|
||||
using linker.messenger.relay.server;
|
||||
@@ -31,8 +31,8 @@ namespace linker.messenger.relay
|
||||
SyncTreansfer syncTreansfer = serviceProvider.GetService<SyncTreansfer>();
|
||||
syncTreansfer.AddSyncs(new List<ISync> { serviceProvider.GetService<RelaySyncSecretKey>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<RelayApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<RelayApiController>() });
|
||||
|
||||
RelayClientTestTransfer relayClientTestTransfer = serviceProvider.GetService<RelayClientTestTransfer>();
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.relay.client;
|
||||
using linker.messenger.relay.client.transport;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.decenter;
|
||||
using linker.messenger.plan;
|
||||
using linker.messenger.sforward.client;
|
||||
@@ -33,8 +34,8 @@ namespace linker.messenger.sforward
|
||||
}
|
||||
public static ServiceProvider UseSForwardClient(this ServiceProvider serviceProvider)
|
||||
{
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<SForwardApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<SForwardApiController>() });
|
||||
|
||||
SForwardClientTransfer sForwardClientTransfer = serviceProvider.GetService<SForwardClientTransfer>();
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using linker.plugins.sforward.messenger;
|
||||
using System.Collections.Concurrent;
|
||||
using linker.messenger.signin;
|
||||
using linker.libs;
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.sforward.client
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.exroute;
|
||||
using linker.messenger.signin.args;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -36,7 +36,7 @@ namespace linker.messenger.signin
|
||||
serviceProvider.GetService<SignInArgsVersionClient>(),
|
||||
});
|
||||
|
||||
linker.messenger.api.IApiServer apiServer = serviceProvider.GetService<linker.messenger.api.IApiServer>();
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> {
|
||||
serviceProvider.GetService<SignInApiController>()
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
|
||||
namespace linker.messenger.signin
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.decenter;
|
||||
using linker.messenger.exroute;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -28,8 +29,8 @@ namespace linker.messenger.socks5
|
||||
IMessengerResolver messengerResolver = serviceProvider.GetService<IMessengerResolver>();
|
||||
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<Socks5ClientMessenger>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<Socks5ApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<Socks5ApiController>() });
|
||||
|
||||
DecenterClientTransfer decenterClientTransfer = serviceProvider.GetService<DecenterClientTransfer>();
|
||||
decenterClientTransfer.AddDecenters(new List<IDecenter> { serviceProvider.GetService<Socks5Decenter>() });
|
||||
|
@@ -1,10 +1,10 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using System.Collections.Concurrent;
|
||||
using linker.tunnel.connection;
|
||||
using linker.messenger.signin;
|
||||
using linker.libs;
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.socks5
|
||||
{
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using System.IO.Compression;
|
||||
using linker.libs;
|
||||
using linker.messenger.signin;
|
||||
@@ -8,6 +7,7 @@ using System.Text;
|
||||
using linker.messenger.relay.client.transport;
|
||||
using System.Text.Json;
|
||||
using System.Collections;
|
||||
using linker.libs.web;
|
||||
namespace linker.messenger.store.file
|
||||
{
|
||||
public sealed class ConfigApiController : IApiController
|
||||
@@ -48,7 +48,6 @@ namespace linker.messenger.store.file
|
||||
config.Data.Client.Name = info.Client.Name;
|
||||
config.Data.Client.Groups = new SignInClientGroupInfo[] { new SignInClientGroupInfo { Id = info.Client.GroupId, Name = info.Client.GroupId, Password = info.Client.GroupPassword } };
|
||||
config.Data.Client.CApi.WebPort = info.Client.Web;
|
||||
config.Data.Client.CApi.ApiPort = info.Client.Api;
|
||||
config.Data.Client.CApi.ApiPassword = info.Client.Password;
|
||||
|
||||
if (info.Client.HasServer)
|
||||
@@ -258,7 +257,6 @@ namespace linker.messenger.store.file
|
||||
client.CApi.ApiPassword = configExportInfo.ApiPassword;
|
||||
}
|
||||
client.CApi.WebPort = configExportInfo.WebPort;
|
||||
client.CApi.ApiPort = configExportInfo.ApiPort;
|
||||
|
||||
client.AccessBits = accessStore.AssignAccess(configExportInfo.Access);
|
||||
|
||||
@@ -321,7 +319,6 @@ namespace linker.messenger.store.file
|
||||
public string GroupId { get; set; }
|
||||
public string GroupPassword { get; set; }
|
||||
|
||||
public int Api { get; set; }
|
||||
public int Web { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
@@ -370,7 +367,6 @@ namespace linker.messenger.store.file
|
||||
public string Name { get; set; }
|
||||
public string ApiPassword { get; set; }
|
||||
public int WebPort { get; set; }
|
||||
public int ApiPort { get; set; }
|
||||
public bool Single { get; set; }
|
||||
public BitArray Access { get; set; }
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using linker.libs;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.action;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.firewall;
|
||||
@@ -126,8 +127,8 @@ namespace linker.messenger.store.file
|
||||
fileConfig.Save(config);
|
||||
RunningConfig runningConfig = serviceProvider.GetService<RunningConfig>();
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<ConfigApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<ConfigApiController>() });
|
||||
|
||||
SyncTreansfer syncTreansfer = serviceProvider.GetService<SyncTreansfer>();
|
||||
syncTreansfer.AddSyncs(new List<ISync> {
|
||||
|
@@ -24,12 +24,6 @@ namespace linker.messenger.store.file.api
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetApiPort(int port)
|
||||
{
|
||||
fileConfig.Data.Client.CApi.ApiPort = port;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SetApiPassword(string password)
|
||||
{
|
||||
fileConfig.Data.Client.CApi.ApiPassword = password;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.web;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using IApiServer = linker.messenger.api.IApiServer;
|
||||
namespace linker.messenger.sync
|
||||
{
|
||||
public static class Entry
|
||||
@@ -17,7 +16,7 @@ namespace linker.messenger.sync
|
||||
IMessengerResolver messengerResolver= serviceProvider.GetService<IMessengerResolver>();
|
||||
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<SyncClientMessenger>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<SyncApiController>() });
|
||||
|
||||
return serviceProvider;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
namespace linker.messenger.sync
|
||||
{
|
||||
|
@@ -8,6 +8,7 @@ using System.Text.Json;
|
||||
using linker.tunnel.connection;
|
||||
using linker.messenger.signin.args;
|
||||
using linker.messenger.sync;
|
||||
using linker.libs.web;
|
||||
namespace linker.messenger.tunnel
|
||||
{
|
||||
public static class Entry
|
||||
@@ -55,8 +56,8 @@ namespace linker.messenger.tunnel
|
||||
DecenterClientTransfer decenterClientTransfer = serviceProvider.GetService<DecenterClientTransfer>();
|
||||
decenterClientTransfer.AddDecenters(new List<IDecenter> { serviceProvider.GetService<TunnelDecenter>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<TunnelApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<TunnelApiController>() });
|
||||
|
||||
|
||||
ExRouteTransfer exRouteTransfer = serviceProvider.GetService<ExRouteTransfer>();
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using linker.tunnel.transport;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using System.Collections.Concurrent;
|
||||
using linker.messenger.signin;
|
||||
@@ -7,6 +6,7 @@ using linker.libs;
|
||||
using linker.messenger.api;
|
||||
using linker.tunnel.connection;
|
||||
using linker.tunnel;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.tunnel
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using linker.libs;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.decenter;
|
||||
using linker.messenger.exroute;
|
||||
@@ -61,8 +62,8 @@ namespace linker.messenger.tuntap
|
||||
IMessengerResolver messengerResolver = serviceProvider.GetService<IMessengerResolver>();
|
||||
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<TuntapClientMessenger>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<TuntapApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<TuntapApiController>() });
|
||||
|
||||
ExRouteTransfer exRouteTransfer = serviceProvider.GetService<ExRouteTransfer>();
|
||||
exRouteTransfer.AddExRoutes(new List<IExRoute> { serviceProvider.GetService<TuntapExRoute>() });
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using System.Collections.Concurrent;
|
||||
using linker.tunnel.connection;
|
||||
using System.Net;
|
||||
@@ -8,6 +7,7 @@ using linker.messenger.signin;
|
||||
using linker.messenger.tuntap.lease;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.tuntap.messenger;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.tuntap
|
||||
{
|
||||
|
@@ -1,4 +1,4 @@
|
||||
using linker.messenger.api;
|
||||
using linker.libs.web;
|
||||
using linker.messenger.sync;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
namespace linker.messenger.updater
|
||||
@@ -30,8 +30,8 @@ namespace linker.messenger.updater
|
||||
SyncTreansfer syncTransfer = serviceProvider.GetService<SyncTreansfer>();
|
||||
syncTransfer.AddSyncs(new List<ISync> { serviceProvider.GetService<UpdaterConfigSyncSecretKey>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<UpdaterApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<UpdaterApiController>() });
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.extends;
|
||||
using linker.libs;
|
||||
using linker.messenger.signin;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.updater
|
||||
{
|
||||
|
@@ -1,4 +1,5 @@
|
||||
|
||||
using linker.libs.web;
|
||||
using linker.messenger.api;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
namespace linker.messenger.wakeup
|
||||
@@ -21,8 +22,8 @@ namespace linker.messenger.wakeup
|
||||
IMessengerResolver messengerResolver = serviceProvider.GetService<IMessengerResolver>();
|
||||
messengerResolver.AddMessenger(new List<IMessenger> { serviceProvider.GetService<WakeupClientMessenger>() });
|
||||
|
||||
IApiServer apiServer = serviceProvider.GetService<IApiServer>();
|
||||
apiServer.AddPlugins(new List<libs.api.IApiController> { serviceProvider.GetService<WakeupApiController>() });
|
||||
linker.messenger.api.IWebServer apiServer = serviceProvider.GetService<linker.messenger.api.IWebServer>();
|
||||
apiServer.AddPlugins(new List<IApiController> { serviceProvider.GetService<WakeupApiController>() });
|
||||
|
||||
return serviceProvider;
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs;
|
||||
using linker.libs;
|
||||
using linker.messenger.signin;
|
||||
using linker.messenger.api;
|
||||
using linker.libs.extends;
|
||||
using linker.libs.web;
|
||||
|
||||
namespace linker.messenger.wakeup
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.281" ProductVersion="0.0.0.281" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
||||
<project ver="10" name="linker.tray.win" libEmbed="true" icon="..\linker\favicon.ico" ui="win" output="linker.tray.win.exe" CompanyName="snltty" FileDescription="linker.tray.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="linker.tray.win" InternalName="linker.install.win" FileVersion="0.0.0.283" ProductVersion="0.0.0.283" publishDir="/dist/" dstrip="false" local="false" ignored="false">
|
||||
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
|
||||
<folder name="资源文件" path="res" embed="true" local="false" ignored="false">
|
||||
<file name="favicon.ico" path="res\favicon.ico" comment="res\favicon.ico"/>
|
||||
@@ -51,5 +51,6 @@
|
||||
<file name="app.842662e0.js" path="web\js\app.842662e0.js" comment="web\js\app.842662e0.js"/>
|
||||
<file name="chunk-vendors.710dc716.js" path="web\js\chunk-vendors.710dc716.js" comment="web\js\chunk-vendors.710dc716.js"/>
|
||||
</folder>
|
||||
<file name="test.html" path="web\test.html" comment="web\test.html"/>
|
||||
</folder>
|
||||
</project>
|
||||
|
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
BIN
src/linker.tray.win/dist/linker.tray.win.exe
vendored
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
import win.ui;
|
||||
/*DSG{{*/
|
||||
var winform = win.form(text="linker 管理";right=849;bottom=739;max=false;min=1;topmost=1)
|
||||
var winform = win.form(text="linker 管理";right=849;bottom=739;max=false;topmost=1)
|
||||
winform.add()
|
||||
/*}}*/
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import win.ui;
|
||||
/*DSG{{*/
|
||||
var winform = win.form(text="linker 管理(简单)";right=399;bottom=639;border="thin";max=false;min=1;topmost=1)
|
||||
var winform = win.form(text="linker 管理(简单)";right=399;bottom=639;border="thin";max=false;topmost=1)
|
||||
winform.add()
|
||||
/*}}*/
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.81af7d4e.js"></script><script defer="defer" src="js/app.2201faad.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.bb3197c7.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
||||
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="favicon.ico"><title>linker.web</title><link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/><script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script><script defer="defer" src="js/chunk-vendors.81af7d4e.js"></script><script defer="defer" src="js/app.ca5c5474.js"></script><link href="css/chunk-vendors.d8267b33.css" rel="stylesheet"><link href="css/app.af897554.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but linker.web doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>
|
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/226.e53f663b.js
Normal file
1
src/linker.tray.win/web/js/226.e53f663b.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[663],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(56768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(44114);var u=a(24232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(53830),m=a(90144),b=a(57477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(71241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(98104),X=a(27985),y=a(39383),N=a(62956),U=a(27569),Q=a(57671),W=a(99983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(24722),M=a(81387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);
|
||||
"use strict";(self["webpackChunklinker_web"]=self["webpackChunklinker_web"]||[]).push([[519],{7332:function(e,n,a){a.r(n),a.d(n,{default:function(){return O}});var t=a(56768);const s={class:"net-wrap app-wrap"},l={class:"inner absolute flex flex-column flex-nowrap"},i={class:"head"},o={class:"body flex-1 relative"},c={class:"status"};function r(e,n,a,r,u,d){const g=(0,t.g2)("Head"),p=(0,t.g2)("List"),v=(0,t.g2)("Status");return(0,t.uX)(),(0,t.CE)("div",s,[(0,t.Lk)("div",l,[(0,t.Lk)("div",i,[(0,t.bF)(g)]),(0,t.Lk)("div",o,[(0,t.bF)(p)]),(0,t.Lk)("div",c,[(0,t.bF)(v,{config:!1})])])])}a(44114);var u=a(24232);const d=e=>((0,t.Qi)("data-v-6bfe19a3"),e=e(),(0,t.jt)(),e),g={class:"head-wrap"},p={class:"tools flex"},v={class:"label"},h=d((()=>(0,t.Lk)("span",{class:"flex-1"},null,-1))),f={style:{"margin-left":"1rem"}};function k(e,n,a,s,l,i){const o=(0,t.g2)("Refresh"),c=(0,t.g2)("el-icon"),r=(0,t.g2)("el-button"),d=(0,t.g2)("Background");return(0,t.uX)(),(0,t.CE)("div",g,[(0,t.Lk)("div",p,[(0,t.Lk)("span",v,"分组 : "+(0,u.v_)(s.state.group),1),h,(0,t.bF)(r,{size:"small",onClick:s.handleRefresh},{default:(0,t.k6)((()=>[(0,t.eW)(" 刷新(F5)"),(0,t.bF)(c,null,{default:(0,t.k6)((()=>[(0,t.bF)(o)])),_:1})])),_:1},8,["onClick"]),(0,t.Lk)("div",f,[(0,t.bF)(d,{name:"net"})])])])}var C=a(53830),m=a(90144),b=a(57477),L=a(5096),_={components:{Edit:b.ffu,Refresh:b.C42,Background:L.A},setup(){const e=(0,C.B)(),n=(0,m.Kh)({server:(0,t.EW)((()=>e.value.config.Client.Server.Host)),group:(0,t.EW)((()=>e.value.config.Client.Group.Name))}),a=()=>{window.location.reload()};return{state:n,handleRefresh:a}}},w=a(71241);const S=(0,w.A)(_,[["render",k],["__scopeId","data-v-6bfe19a3"]]);var F=S;const x=e=>((0,t.Qi)("data-v-68d1c30a"),e=e(),(0,t.jt)(),e),T={class:"net-list-wrap flex flex-column absolute"},z={class:"flex-1 scrollbar"},E={class:"flex"},A=x((()=>(0,t.Lk)("div",{class:"flex-1"},null,-1))),I={class:"tuntap"},P={class:"page t-c"},B={class:"page-wrap t-c"};function R(e,n,a,s,l,i){const o=(0,t.g2)("DeviceName"),c=(0,t.g2)("UpdaterBtn"),r=(0,t.g2)("TuntapShow"),u=(0,t.g2)("el-pagination");return(0,t.uX)(),(0,t.CE)("div",T,[(0,t.Lk)("div",z,[(0,t.Lk)("ul",null,[((0,t.uX)(!0),(0,t.CE)(t.FK,null,(0,t.pI)(s.devices.page.List,((e,n)=>((0,t.uX)(),(0,t.CE)("li",{key:n},[(0,t.Lk)("dl",null,[(0,t.Lk)("dt",E,[(0,t.Lk)("div",null,[(0,t.bF)(o,{item:e},null,8,["item"])]),A,(0,t.Lk)("div",null,[(0,t.bF)(c,{config:!1,item:e},null,8,["item"])])]),(0,t.Lk)("dd",I,[s.tuntap.list[e.MachineId]?((0,t.uX)(),(0,t.Wv)(r,{key:0,item:e},null,8,["item"])):(0,t.Q3)("",!0)])])])))),128))])]),(0,t.Lk)("div",P,[(0,t.Lk)("div",B,[(0,t.bF)(u,{size:"small",background:"",layout:"prev,pager, next","pager-count":5,total:s.devices.page.Count,"page-size":s.devices.page.Request.Size,"current-page":s.devices.page.Request.Page,onCurrentChange:s.handlePageChange,onSizeChange:s.handlePageSizeChange,"page-sizes":[10,20,50,100,255]},null,8,["total","page-size","current-page","onCurrentChange","onSizeChange"])])])])}var D=a(98104),X=a(27985),y=a(39383),N=a(62956),U=a(27569),Q=a(57671),W=a(99983),H={components:{StarFilled:b.BQ2,UpdaterBtn:N.A,DeviceName:U.A,TuntapShow:Q.A},setup(e){(0,C.B)();const n=(0,m.Kh)({}),{devices:a,machineId:s,_getSignList:l,_getSignList1:i,handleDeviceEdit:o,handlePageChange:c,handlePageSizeChange:r,handleDel:u,clearDevicesTimeout:d}=(0,X.r)(),{tuntap:g,_getTuntapInfo:p,handleTuntapRefresh:v,clearTuntapTimeout:h,handleTuntapEdit:f,sortTuntapIP:k}=(0,D.O)(),{_getUpdater:b,_subscribeUpdater:L,clearUpdaterTimeout:_}=(0,y.d)(),{connections:w,forwardConnections:S,_getForwardConnections:F,tuntapConnections:x,_getTuntapConnections:T,socks5Connections:z,_getSocks5Connections:E,handleTunnelConnections:A,clearConnectionsTimeout:I}=(0,W.L2)();return(0,t.sV)((()=>{c(),v(),l(),i(),p(),b(),L()})),(0,t.hi)((()=>{d(),h(),_()})),{state:n,devices:a,machineId:s,handlePageChange:c,handlePageSizeChange:r,tuntap:g}}};const K=(0,w.A)(H,[["render",R],["__scopeId","data-v-68d1c30a"]]);var j=K,q=a(44453),M=a(81387),V={components:{Head:F,List:j,Status:q.A},setup(){document.addEventListener("contextmenu",(function(e){e.preventDefault()}));const e=(0,C.B)(),n=(0,M.rd)();return(0,t.sV)((()=>{0==e.value.hasAccess("NetManager")&&n.push({name:"NoPermission"})})),{}}};const G=(0,w.A)(V,[["render",r],["__scopeId","data-v-6a3f3b43"]]);var O=G}}]);
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/linker.tray.win/web/js/app.ca5c5474.js
Normal file
1
src/linker.tray.win/web/js/app.ca5c5474.js
Normal file
File diff suppressed because one or more lines are too long
@@ -1,28 +1,15 @@
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
let requestId = 0, ws = null, wsUrl = '', index = 1, apiPassword = '';
|
||||
//请求缓存,等待回调
|
||||
let requestId = 0, ws = null, wsUrl = '', index = 1, apiPassword = 'snltty';
|
||||
const requests = {};
|
||||
const queues = [];
|
||||
export const websocketState = { connected: false, connecting: false };
|
||||
|
||||
const sendQueueMsg = () => {
|
||||
if (queues.length > 0 && websocketState.connected && ws && ws.readyState == 1) {
|
||||
try {
|
||||
ws.send(queues.shift());
|
||||
} catch (e) { }
|
||||
}
|
||||
setTimeout(sendQueueMsg, 1000 / 60);
|
||||
}
|
||||
//sendQueueMsg();
|
||||
|
||||
|
||||
const sendTimeout = () => {
|
||||
const time = Date.now();
|
||||
for (let j in requests) {
|
||||
const item = requests[j];
|
||||
if (time - item.time > item.timeout) {
|
||||
item.reject('超时~');
|
||||
item.reject(`超时:${JSON.stringify(item)}`);
|
||||
delete requests[j];
|
||||
}
|
||||
}
|
||||
@@ -30,8 +17,6 @@ const sendTimeout = () => {
|
||||
}
|
||||
sendTimeout();
|
||||
|
||||
|
||||
//发布订阅
|
||||
export const pushListener = {
|
||||
subs: {
|
||||
},
|
||||
@@ -59,10 +44,10 @@ export const pushListener = {
|
||||
}
|
||||
}
|
||||
|
||||
//消息处理
|
||||
const onWebsocketOpen = () => {
|
||||
websocketState.connected = true;
|
||||
websocketState.connecting = false;
|
||||
sendWebsocketMsg('password',apiPassword || 'snltty');
|
||||
pushListener.push(websocketStateChangeKey, websocketState.connected);
|
||||
}
|
||||
const onWebsocketClose = (e) => {
|
||||
@@ -125,8 +110,7 @@ export const initWebsocket = (url = wsUrl, password = apiPassword) => {
|
||||
ws.close();
|
||||
}
|
||||
websocketState.connecting = true;
|
||||
const protocol = password || 'snltty';
|
||||
ws = new WebSocket(wsUrl, [protocol]);
|
||||
ws = new WebSocket(wsUrl);
|
||||
ws.iddd = ++index;
|
||||
ws.onopen = onWebsocketOpen;
|
||||
ws.onclose = onWebsocketClose
|
||||
@@ -140,8 +124,6 @@ export const closeWebsocket = () => {
|
||||
ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
//发送消息
|
||||
export const sendWebsocketMsg = (path, msg = {}, errHandle = false, timeout = 15000) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let id = ++requestId;
|
||||
@@ -165,7 +147,6 @@ export const sendWebsocketMsg = (path, msg = {}, errHandle = false, timeout = 15
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const websocketStateChangeKey = Symbol();
|
||||
export const subWebsocketState = (callback) => {
|
||||
pushListener.add(websocketStateChangeKey, callback);
|
||||
|
@@ -66,9 +66,9 @@ export default {
|
||||
'status.exportSingle': '单设备',
|
||||
'status.exportName': '设备名',
|
||||
'status.exportNamePlease': '请输入设备名',
|
||||
'status.exportApiPassword': '接口密码',
|
||||
'status.exportApiPassword': '管理密码',
|
||||
'status.exportApiPasswordPlease': '请输入接口密码',
|
||||
'status.exportWebport': '网页端口',
|
||||
'status.exportWebport': '管理端口',
|
||||
'status.exportWebportPlease': '请输入网页端口',
|
||||
'status.exportApiport': '接口端口',
|
||||
'status.exportApiportPlease': '请输入接口端口',
|
||||
|
@@ -33,7 +33,8 @@ export default {
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const defaultInfo = {api:`${window.location.hostname}:1803`,psd:'snltty'};
|
||||
const api = process.env.NODE_ENV == 'development' ? `${window.location.hostname}:1804` : window.location.host;
|
||||
const defaultInfo = {api:api,psd:'snltty'};
|
||||
const queryCache = JSON.parse(sessionStorage.getItem('api-cache') || localStorage.getItem('api-cache') || JSON.stringify(defaultInfo));
|
||||
const state = reactive({
|
||||
api:queryCache.api,
|
||||
|
@@ -7,35 +7,30 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0">
|
||||
<el-row>
|
||||
<el-row class="w-100">
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="机器名" prop="name">
|
||||
<el-input v-model="state.form.name" maxlength="32" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :sm="12" :xs="24" v-if="globalData.isPc">
|
||||
<el-form-item label="网页端口" prop="web">
|
||||
<el-input v-model="state.form.web" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0" v-if="globalData.isPc">
|
||||
<el-row>
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="接口端口" prop="api">
|
||||
<el-input v-model="state.form.api" />
|
||||
<el-row class="w-100">
|
||||
<el-col :sm="12" :xs="24" v-if="globalData.isPc">
|
||||
<el-form-item label="管理端口" prop="web">
|
||||
<el-input v-model="state.form.web" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="接口密码" prop="password">
|
||||
<el-form-item label="管理密码" prop="password">
|
||||
<el-input type="password" v-model="state.form.password" show-password maxlength="36" show-word-limit/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0">
|
||||
<el-row>
|
||||
<el-row class="w-100">
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="分组名" prop="groupid">
|
||||
<el-input v-model="state.form.groupid" maxlength="36" show-word-limit />
|
||||
@@ -49,7 +44,7 @@
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0">
|
||||
<el-row>
|
||||
<el-row class="w-100">
|
||||
<el-col :span="24">
|
||||
<el-form-item label-width="8rem" prop="hasServer">
|
||||
<el-checkbox v-model="state.form.hasServer" label="我有服务器(私有部署)" size="large" />
|
||||
@@ -59,7 +54,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="" label-width="0" v-if="state.form.hasServer">
|
||||
<el-row>
|
||||
<el-row class="w-100">
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="信标服务" prop="server">
|
||||
<el-input v-model="state.form.server"/>
|
||||
@@ -74,7 +69,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="" label-width="0" v-if="state.form.hasServer">
|
||||
<el-row>
|
||||
<el-row class="w-100">
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="穿透密钥" prop="sForwardSecretKey">
|
||||
<el-input v-model="state.form.sForwardSecretKey" maxlength="36" show-word-limit />
|
||||
@@ -88,7 +83,7 @@
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item label="" label-width="0" v-if="state.form.hasServer">
|
||||
<el-row>
|
||||
<el-row class="w-100">
|
||||
<el-col :sm="12" :xs="24">
|
||||
<el-form-item label="更新密钥" prop="updaterSecretKey">
|
||||
<el-input v-model="state.form.updaterSecretKey" maxlength="36" show-word-limit />
|
||||
@@ -118,7 +113,6 @@ export default {
|
||||
name:step.value.form.client.name || globalData.value.config.Client.Name,
|
||||
groupid: step.value.form.client.groupid ||globalData.value.config.Client.Group.Id,
|
||||
groupPassword: step.value.form.client.groupPassword ||globalData.value.config.Client.Group.Password,
|
||||
api: step.value.form.client.api ||globalData.value.config.Client.CApi.ApiPort,
|
||||
web: step.value.form.client.web ||globalData.value.config.Client.CApi.WebPort,
|
||||
password:step.value.form.client.password || globalData.value.config.Client.CApi.ApiPassword,
|
||||
|
||||
@@ -134,19 +128,6 @@ export default {
|
||||
groupid: [{ required: true, message: "必填", trigger: "blur" }],
|
||||
groupPassword: [{ required: true, message: "必填", trigger: "blur" }],
|
||||
password: [{ required: true, message: "必填", trigger: "blur" }],
|
||||
api: [
|
||||
{ required: true, message: "必填", trigger: "blur" },
|
||||
{
|
||||
type: "number",
|
||||
min: 0,
|
||||
max: 65535,
|
||||
message: "数字 0-65535",
|
||||
trigger: "blur",
|
||||
transform(value) {
|
||||
return Number(value);
|
||||
},
|
||||
},
|
||||
],
|
||||
web: [
|
||||
{ required: true, message: "必填", trigger: "blur" },
|
||||
{
|
||||
@@ -173,7 +154,6 @@ export default {
|
||||
name: state.form.name,
|
||||
groupid: state.form.groupid,
|
||||
groupPassword: state.form.groupPassword,
|
||||
api: +state.form.api,
|
||||
web: +state.form.web,
|
||||
password: state.form.password,
|
||||
|
||||
|
@@ -15,21 +15,16 @@
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="24"><el-checkbox :disabled="onlyNode" v-model="state.single" :label="$t('status.exportSingle')" /></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="12"><el-checkbox :disabled="onlyNode" v-model="state.single" :label="$t('status.exportSingle')" /></el-col>
|
||||
<el-col :span="12">
|
||||
<div class="flex flex-nowrap">
|
||||
<span style="width: 11rem;">{{$t('status.exportName')}} : </span><el-input :disabled="!state.single" v-model="state.name" maxlength="32" show-word-limit></el-input>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="flex flex-nowrap">
|
||||
<span style="width: 11rem;">{{$t('status.exportApiPassword')}} : </span><el-input type="password" show-password :disabled="onlyNode" v-model="state.apipassword" maxlength="36" show-word-limit></el-input>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<div class="flex flex-nowrap mgt-1">
|
||||
<span style="width: 11rem;">{{$t('status.exportWebport')}} : </span><el-input :disabled="onlyNode" v-model="state.webport"></el-input>
|
||||
@@ -37,7 +32,7 @@
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="flex flex-nowrap mgt-1">
|
||||
<span style="width: 11rem;">{{$t('status.exportApiport')}} : </span><el-input :disabled="onlyNode" v-model="state.apiport"></el-input>
|
||||
<span style="width: 11rem;">{{$t('status.exportApiPassword')}} : </span><el-input type="password" show-password :disabled="onlyNode" v-model="state.apipassword" maxlength="36" show-word-limit></el-input>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
@@ -112,7 +107,6 @@ export default {
|
||||
single:true,
|
||||
name:'',
|
||||
apipassword:onlyNode.value? globalData.value.config.Client.CApi.ApiPassword :'',
|
||||
apiport: globalData.value.config.Client.CApi.ApiPort,
|
||||
webport: globalData.value.config.Client.CApi.WebPort,
|
||||
|
||||
relay:true,
|
||||
@@ -143,7 +137,6 @@ export default {
|
||||
name:state.name,
|
||||
apipassword:state.apipassword,
|
||||
webport:+state.webport,
|
||||
apiport:+state.apiport,
|
||||
relay:state.relay,
|
||||
sforward:state.sforward,
|
||||
updater:state.updater,
|
||||
@@ -168,10 +161,6 @@ export default {
|
||||
ElMessage.error(t('status.exportWebportPlease'));
|
||||
return;
|
||||
}
|
||||
if(!json.apiport || isNaN(json.apiport) || json.apiport<=0 || json.apiport>65535){
|
||||
ElMessage.error(t('status.exportApiportPlease'));
|
||||
return;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
const download = ()=>{
|
||||
|
@@ -20,8 +20,6 @@ RUN apt update \
|
||||
|
||||
EXPOSE 1802/tcp
|
||||
EXPOSE 1802/udp
|
||||
EXPOSE 1803/tcp
|
||||
EXPOSE 1803/udp
|
||||
EXPOSE 1804/tcp
|
||||
EXPOSE 1804/udp
|
||||
|
||||
|
@@ -20,8 +20,6 @@ RUN apt update \
|
||||
|
||||
EXPOSE 1802/tcp
|
||||
EXPOSE 1802/udp
|
||||
EXPOSE 1803/tcp
|
||||
EXPOSE 1803/udp
|
||||
EXPOSE 1804/tcp
|
||||
EXPOSE 1804/udp
|
||||
EXPOSE 1806/tcp
|
||||
|
@@ -10,8 +10,6 @@ RUN echo "https://mirrors.ustc.edu.cn/alpine/latest-stable/main/" > /etc/apk/rep
|
||||
|
||||
EXPOSE 1802/tcp
|
||||
EXPOSE 1802/udp
|
||||
EXPOSE 1803/tcp
|
||||
EXPOSE 1803/udp
|
||||
EXPOSE 1804/tcp
|
||||
EXPOSE 1804/udp
|
||||
|
||||
|
@@ -21,7 +21,10 @@
|
||||
<Authors>snltty</Authors>
|
||||
<Company>snltty</Company>
|
||||
<Description>1. 一些累计更新
|
||||
2. 测试发布,请使用1.8.2</Description>
|
||||
2. 重建权限存储,ulong改为BitArray,同组所有客户端需保持版本一致
|
||||
3. 增加唤醒功能,支持WOL,COM继电器,HID继电器
|
||||
4. 基于One-KVM包装docker镜像集成linker
|
||||
5. 管理端口改为1804,一个端口托管Web+Websocket</Description>
|
||||
<Copyright>snltty</Copyright>
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
|
@@ -1,4 +1,7 @@
|
||||
v1.8.2
|
||||
2025-06-05 10:48:49
|
||||
2025-06-05 17:13:06
|
||||
1. 一些累计更新
|
||||
2. 测试发布,请使用1.8.2
|
||||
2. 重建权限存储,ulong改为BitArray,同组所有客户端需保持版本一致
|
||||
3. 增加唤醒功能,支持WOL,COM继电器,HID继电器
|
||||
4. 基于One-KVM包装docker镜像集成linker
|
||||
5. 管理端口改为1804,一个端口托管Web+Websocket
|
Reference in New Issue
Block a user