2026-04-28 10:23:58 +08:00
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
|
using System.IO;
|
2026-05-15 17:30:30 +08:00
|
|
|
|
using YY.Admin.Core.Util;
|
2026-04-28 10:23:58 +08:00
|
|
|
|
|
|
|
|
|
|
namespace YY.Admin.Helper
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 服务器连接配置读写工具。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static class ServerSettingsStore
|
|
|
|
|
|
{
|
|
|
|
|
|
private const string DefaultWebSocketPath = "/websocket/scada-sync";
|
|
|
|
|
|
|
2026-05-15 17:30:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 安装目录随包发布的默认配置(只读)。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static string GetBundledAppSettingsPath()
|
|
|
|
|
|
{
|
|
|
|
|
|
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configuration", "appsettings.json");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 用户覆盖配置(可写),仅覆盖 JeecgIntegration 节点时使用。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static string GetUserAppSettingsPath()
|
|
|
|
|
|
{
|
|
|
|
|
|
var dir = AppWritablePaths.EnsureDirectoryExists(AppWritablePaths.ConfigurationDirectory);
|
|
|
|
|
|
return Path.Combine(dir, "appsettings.json");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 兼容旧调用:优先返回用于读取的实际路径(存在用户覆盖则用用户文件)。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static string GetConfigPath()
|
|
|
|
|
|
{
|
|
|
|
|
|
var user = GetUserAppSettingsPath();
|
|
|
|
|
|
if (File.Exists(user))
|
|
|
|
|
|
{
|
|
|
|
|
|
return user;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return GetBundledAppSettingsPath();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-28 10:23:58 +08:00
|
|
|
|
public class ServerSettingsModel
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Ip { get; set; } = "127.0.0.1";
|
|
|
|
|
|
public int Port { get; set; } = 8080;
|
|
|
|
|
|
public string BaseScheme { get; set; } = "http";
|
|
|
|
|
|
public string BasePath { get; set; } = "/jeecg-boot";
|
|
|
|
|
|
public string WebSocketUrl { get; set; } = string.Empty;
|
|
|
|
|
|
public string WebSocketPath { get; set; } = DefaultWebSocketPath;
|
2026-04-30 15:28:20 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否断开连接(true=断开,false=连接)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool DisconnectConnection { get; set; } = false;
|
2026-04-28 10:23:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-15 17:30:30 +08:00
|
|
|
|
private static JObject LoadMergedRoot()
|
2026-04-28 10:23:58 +08:00
|
|
|
|
{
|
2026-05-15 17:30:30 +08:00
|
|
|
|
var bundledPath = GetBundledAppSettingsPath();
|
|
|
|
|
|
if (!File.Exists(bundledPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new FileNotFoundException("未找到安装目录默认配置文件 appsettings.json", bundledPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var root = JObject.Parse(File.ReadAllText(bundledPath));
|
|
|
|
|
|
var userPath = GetUserAppSettingsPath();
|
|
|
|
|
|
if (!File.Exists(userPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
return root;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var userRoot = JObject.Parse(File.ReadAllText(userPath));
|
|
|
|
|
|
var userJeecg = userRoot["JeecgIntegration"] as JObject;
|
|
|
|
|
|
if (userJeecg != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
root["JeecgIntegration"] = userJeecg;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return root;
|
2026-04-28 10:23:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static ServerSettingsModel Load()
|
|
|
|
|
|
{
|
|
|
|
|
|
var model = new ServerSettingsModel();
|
2026-05-15 17:30:30 +08:00
|
|
|
|
var root = LoadMergedRoot();
|
2026-04-28 10:23:58 +08:00
|
|
|
|
var jeecg = root["JeecgIntegration"] as JObject;
|
|
|
|
|
|
if (jeecg == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return model;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var baseUrl = jeecg.Value<string>("BaseUrl") ?? string.Empty;
|
|
|
|
|
|
if (Uri.TryCreate(baseUrl, UriKind.Absolute, out var uri))
|
|
|
|
|
|
{
|
|
|
|
|
|
model.BaseScheme = uri.Scheme;
|
|
|
|
|
|
model.Ip = uri.Host;
|
|
|
|
|
|
model.Port = uri.Port;
|
|
|
|
|
|
model.BasePath = string.IsNullOrWhiteSpace(uri.AbsolutePath) ? string.Empty : uri.AbsolutePath.TrimEnd('/');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
model.WebSocketUrl = jeecg.Value<string>("WebSocketUrl") ?? string.Empty;
|
|
|
|
|
|
model.WebSocketPath = NormalizeWebSocketPath(jeecg.Value<string>("WebSocketPath"));
|
2026-04-30 15:28:20 +08:00
|
|
|
|
model.DisconnectConnection = jeecg.Value<bool?>("DisconnectConnection") ?? false;
|
2026-04-28 10:23:58 +08:00
|
|
|
|
return model;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void Save(ServerSettingsModel model)
|
|
|
|
|
|
{
|
2026-05-15 17:30:30 +08:00
|
|
|
|
var root = LoadMergedRoot();
|
2026-04-28 10:23:58 +08:00
|
|
|
|
var jeecg = root["JeecgIntegration"] as JObject;
|
|
|
|
|
|
if (jeecg == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
jeecg = new JObject();
|
|
|
|
|
|
root["JeecgIntegration"] = jeecg;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var basePath = string.IsNullOrWhiteSpace(model.BasePath) ? string.Empty : model.BasePath.TrimEnd('/');
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(basePath) && !basePath.StartsWith('/'))
|
|
|
|
|
|
{
|
|
|
|
|
|
basePath = "/" + basePath;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var baseUrl = $"{model.BaseScheme}://{model.Ip}:{model.Port}{basePath}";
|
|
|
|
|
|
var webSocketPath = NormalizeWebSocketPath(model.WebSocketPath);
|
|
|
|
|
|
var webSocketUrl = string.IsNullOrWhiteSpace(model.WebSocketUrl)
|
|
|
|
|
|
? BuildDefaultWebSocketUrl(model.BaseScheme, model.Ip, model.Port, basePath, webSocketPath)
|
|
|
|
|
|
: model.WebSocketUrl.Trim();
|
|
|
|
|
|
jeecg["BaseUrl"] = baseUrl;
|
|
|
|
|
|
jeecg["WebSocketUrl"] = webSocketUrl;
|
|
|
|
|
|
jeecg["WebSocketPath"] = webSocketPath;
|
2026-04-30 15:28:20 +08:00
|
|
|
|
jeecg["DisconnectConnection"] = model.DisconnectConnection;
|
2026-04-28 10:23:58 +08:00
|
|
|
|
|
2026-05-15 17:30:30 +08:00
|
|
|
|
var userPath = GetUserAppSettingsPath();
|
|
|
|
|
|
var outRoot = new JObject { ["JeecgIntegration"] = jeecg };
|
|
|
|
|
|
File.WriteAllText(userPath, outRoot.ToString(Formatting.Indented));
|
2026-04-28 10:23:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static string BuildDefaultWebSocketUrl(string baseScheme, string ip, int port, string basePath, string webSocketPath = DefaultWebSocketPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
var safeScheme = string.Equals(baseScheme, "https", StringComparison.OrdinalIgnoreCase) ? "wss" : "ws";
|
|
|
|
|
|
var safeBasePath = string.IsNullOrWhiteSpace(basePath) ? string.Empty : basePath.TrimEnd('/');
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(safeBasePath) && !safeBasePath.StartsWith('/'))
|
|
|
|
|
|
{
|
|
|
|
|
|
safeBasePath = "/" + safeBasePath;
|
|
|
|
|
|
}
|
2026-05-15 17:30:30 +08:00
|
|
|
|
|
2026-04-28 10:23:58 +08:00
|
|
|
|
var safeWsPath = NormalizeWebSocketPath(webSocketPath);
|
|
|
|
|
|
return $"{safeScheme}://{ip}:{port}{safeBasePath}{safeWsPath}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static string NormalizeWebSocketPath(string? webSocketPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
var value = string.IsNullOrWhiteSpace(webSocketPath) ? DefaultWebSocketPath : webSocketPath.Trim();
|
|
|
|
|
|
if (!value.StartsWith('/'))
|
|
|
|
|
|
{
|
|
|
|
|
|
value = "/" + value;
|
|
|
|
|
|
}
|
2026-05-15 17:30:30 +08:00
|
|
|
|
|
2026-04-28 10:23:58 +08:00
|
|
|
|
return value;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|