602 lines
22 KiB
C#
602 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Text;
|
|
using Microsoft.Win32;
|
|
using Lskj.Business;
|
|
using Lskj.Business.Impl;
|
|
using Lskj.Control.Model;
|
|
using Lskj.Core;
|
|
using Lskj.Data;
|
|
using Lskj.Main.Model;
|
|
using Lskj.Model;
|
|
using Lskj.Util;
|
|
|
|
namespace Lskj.Main.Hosting
|
|
{
|
|
public sealed partial class LegacyLoginRuntime
|
|
{
|
|
private const string RegistryFilePath = @"AA_LS_Erp V2.0\File";
|
|
private const string SystemResourcesIniName = "SystemResources.ini";
|
|
private const string SystemResourcesSection = "SystemResources";
|
|
private const string DirectHistoryPrefix = "DownloadAESStr_";
|
|
private const string DirectLastHostKey = "LocalLastIP";
|
|
private const string DirectLastPortKey = "LocalLastPort";
|
|
private const string DirectLastNameKey = "LocalLastPortName";
|
|
private const string ConnectionModeKey = "FrmConfigFlag";
|
|
private const int DirectRequestTimeoutMilliseconds = 5000;
|
|
|
|
public DataSet LoadConnectionSettings()
|
|
{
|
|
var result = new DataSet("LoginConnectionSettings");
|
|
DataTable settings = CreateSettingsTable();
|
|
DataTable savedConnections = CreateSavedConnectionsTable();
|
|
|
|
string directHost = IniHelper.Read(
|
|
SystemResourcesIniName,
|
|
DirectLastHostKey);
|
|
string directPort = IniHelper.Read(
|
|
SystemResourcesIniName,
|
|
DirectLastPortKey);
|
|
string directName = IniHelper.Read(
|
|
SystemResourcesIniName,
|
|
DirectLastNameKey);
|
|
bool directMode = string.Equals(
|
|
IniHelper.Read(SystemResourcesIniName, ConnectionModeKey),
|
|
"1",
|
|
StringComparison.Ordinal);
|
|
|
|
settings.Rows.Add(
|
|
directMode ? "Direct" : "Database",
|
|
ReadRegistryValue("ServerName"),
|
|
ReadRegistryValue("datastr"),
|
|
directHost,
|
|
directPort,
|
|
directName);
|
|
|
|
Dictionary<string, string> entries = IniHelper.GetSectionKeys(
|
|
SystemResourcesIniName,
|
|
SystemResourcesSection);
|
|
foreach (KeyValuePair<string, string> entry in entries)
|
|
{
|
|
if (!entry.Key.StartsWith(
|
|
DirectHistoryPrefix,
|
|
StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string endpoint = entry.Key.Substring(
|
|
DirectHistoryPrefix.Length);
|
|
string host;
|
|
int port;
|
|
if (!TrySplitEndpoint(endpoint, out host, out port))
|
|
continue;
|
|
|
|
string displayName = ReadHistoryDisplayName(entry.Value);
|
|
if (string.IsNullOrWhiteSpace(displayName))
|
|
continue;
|
|
|
|
savedConnections.Rows.Add(
|
|
entry.Key,
|
|
displayName,
|
|
host,
|
|
port);
|
|
}
|
|
|
|
result.Tables.Add(settings);
|
|
result.Tables.Add(savedConnections);
|
|
return result;
|
|
}
|
|
|
|
public string ApplyDatabaseConnection(
|
|
string serverName,
|
|
string databaseName)
|
|
{
|
|
try
|
|
{
|
|
ConnectionCandidate candidate = CreateDatabaseCandidate(
|
|
serverName,
|
|
databaseName);
|
|
return ApplyConnection(
|
|
candidate,
|
|
delegate { CommitDatabaseConnection(); });
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
LogSanitized(exception);
|
|
return ToSafeConnectionError(exception);
|
|
}
|
|
}
|
|
|
|
public string ApplyDirectConnection(
|
|
string host,
|
|
int port,
|
|
string accountBookName)
|
|
{
|
|
try
|
|
{
|
|
Uri resourceUri = BuildDirectResourceUri(host, port);
|
|
string encryptedPayload = DownloadDirectPayload(resourceUri);
|
|
string decryptedPayload = AESUtil.Decrypt(encryptedPayload);
|
|
string[] parts = ParseDirectPayload(decryptedPayload);
|
|
ConnectionCandidate candidate = CreateDirectCandidate(
|
|
parts,
|
|
host,
|
|
port,
|
|
accountBookName,
|
|
encryptedPayload);
|
|
return ApplyConnection(
|
|
candidate,
|
|
delegate { CommitDirectConnection(candidate); });
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
LogSanitized(exception);
|
|
return ToSafeConnectionError(exception);
|
|
}
|
|
}
|
|
|
|
private string ApplyConnection(
|
|
ConnectionCandidate candidate,
|
|
Action commit)
|
|
{
|
|
LegacyConnectionStateSnapshot snapshot =
|
|
LegacyConnectionStateSnapshot.Capture(this);
|
|
try
|
|
{
|
|
ApplyCandidate(candidate);
|
|
ValidateDatabase(candidate);
|
|
ValidateDelphi(candidate);
|
|
SystemInfo.RefreshSystemParam();
|
|
BaseResources.Localization(LocalizationType.CHS);
|
|
commit();
|
|
|
|
_ledgerTable = null;
|
|
SelectedLedgerName = candidate.AccountBookName;
|
|
ERPInfo.Instance.AccountBook = candidate.AccountBookName;
|
|
_connectionInitialized = true;
|
|
return string.Empty;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
snapshot.Restore(this);
|
|
LogSanitized(exception);
|
|
return ToSafeConnectionError(exception);
|
|
}
|
|
}
|
|
|
|
private static ConnectionCandidate CreateDatabaseCandidate(
|
|
string serverName,
|
|
string databaseName)
|
|
{
|
|
serverName = (serverName ?? string.Empty).Trim();
|
|
databaseName = (databaseName ?? string.Empty).Trim();
|
|
if (string.IsNullOrWhiteSpace(serverName))
|
|
throw new ArgumentException("请输入数据库服务器地址。");
|
|
if (string.IsNullOrWhiteSpace(databaseName))
|
|
throw new ArgumentException("请输入数据库名称。");
|
|
|
|
return new ConnectionCandidate
|
|
{
|
|
ServerName = serverName,
|
|
DatabaseName = databaseName,
|
|
AccountBookName = DBConfig.Instance.DataBook ?? string.Empty,
|
|
ServerType = DBConfig.Instance.ServerType ?? "SqlServer",
|
|
ConnectionTemplate = string.Empty,
|
|
DelphiConnectionTemplate = string.Empty
|
|
};
|
|
}
|
|
|
|
private static ConnectionCandidate CreateDirectCandidate(
|
|
string[] parts,
|
|
string host,
|
|
int port,
|
|
string accountBookName,
|
|
string encryptedPayload)
|
|
{
|
|
accountBookName = (accountBookName ?? string.Empty).Trim();
|
|
if (string.IsNullOrWhiteSpace(accountBookName))
|
|
throw new ArgumentException("请输入直连账套名称。");
|
|
|
|
string connectionTemplate =
|
|
"Server={0};Database={1};Persist Security Info=True;" +
|
|
"User ID=" + parts[2] + ";Password=" + parts[3] + ";" +
|
|
"Connection Timeout=5;MultipleActiveResultSets=true";
|
|
string delphiTemplate =
|
|
"Provider=SQLOLEDB.1;Server={0};Database={1};" +
|
|
"Persist Security Info=True;User ID=" + parts[2] +
|
|
";Password=" + parts[3] + ";Connection Timeout=5";
|
|
|
|
return new ConnectionCandidate
|
|
{
|
|
ServerName = parts[0],
|
|
DatabaseName = parts[1],
|
|
AccountBookName = accountBookName,
|
|
ServerType = DBConfig.Instance.ServerType ?? "SqlServer",
|
|
ConnectionTemplate = AESUtil.Encrypt(connectionTemplate),
|
|
DelphiConnectionTemplate = AESUtil.Encrypt(delphiTemplate),
|
|
DirectHost = (host ?? string.Empty).Trim().TrimEnd('/'),
|
|
DirectPort = port,
|
|
DirectEncryptedPayload = encryptedPayload
|
|
};
|
|
}
|
|
|
|
private static void ApplyCandidate(ConnectionCandidate candidate)
|
|
{
|
|
DBConfig.Instance.ServerName = candidate.ServerName;
|
|
DBConfig.Instance.DataBase = candidate.DatabaseName;
|
|
DBConfig.Instance.DataBook = candidate.AccountBookName;
|
|
DBConfig.Instance.ServerType = candidate.ServerType;
|
|
DBConfig.Instance.Connection = candidate.ConnectionTemplate;
|
|
DBConfig.Instance.dephiConnection =
|
|
candidate.DelphiConnectionTemplate;
|
|
}
|
|
|
|
private static void ValidateDatabase(ConnectionCandidate candidate)
|
|
{
|
|
if (!DBConfig.Instance.CreateConnection(
|
|
candidate.ConnectionTemplate))
|
|
{
|
|
throw new LegacyConnectionSettingsException(
|
|
"无法连接数据库,请检查服务器和数据库配置。");
|
|
}
|
|
}
|
|
|
|
private static void ValidateDelphi(ConnectionCandidate candidate)
|
|
{
|
|
if (string.Equals(
|
|
candidate.ServerType,
|
|
"达梦数据库",
|
|
StringComparison.Ordinal))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string connection = DBConfig.Instance.GetDelphiConnection(
|
|
candidate.DelphiConnectionTemplate);
|
|
if (DelphiHelper.Delphi_Init(new StringBuilder(connection)) == 0)
|
|
{
|
|
throw new LegacyConnectionSettingsException(
|
|
"数据库已连接,但 Delphi 组件初始化失败。");
|
|
}
|
|
}
|
|
|
|
private static void CommitDatabaseConnection()
|
|
{
|
|
DBConfig.Instance.WriteConfig();
|
|
IniHelper.Write(
|
|
SystemResourcesIniName,
|
|
ConnectionModeKey,
|
|
"0");
|
|
}
|
|
|
|
private static void CommitDirectConnection(
|
|
ConnectionCandidate candidate)
|
|
{
|
|
string endpoint = candidate.DirectHost + ":" +
|
|
candidate.DirectPort;
|
|
string historyValue = candidate.AccountBookName + "^" +
|
|
candidate.DirectEncryptedPayload;
|
|
|
|
IniHelper.Write(
|
|
SystemResourcesIniName,
|
|
DirectHistoryPrefix + endpoint,
|
|
historyValue);
|
|
IniHelper.Write(
|
|
SystemResourcesIniName,
|
|
DirectLastHostKey,
|
|
candidate.DirectHost);
|
|
IniHelper.Write(
|
|
SystemResourcesIniName,
|
|
DirectLastPortKey,
|
|
candidate.DirectPort.ToString());
|
|
IniHelper.Write(
|
|
SystemResourcesIniName,
|
|
DirectLastNameKey,
|
|
candidate.AccountBookName);
|
|
IniHelper.Write(
|
|
SystemResourcesIniName,
|
|
ConnectionModeKey,
|
|
"1");
|
|
|
|
DBConfig.Instance.WriteConfig(
|
|
DirectLastHostKey,
|
|
candidate.DirectHost);
|
|
DBConfig.Instance.WriteConfig(
|
|
DirectLastPortKey,
|
|
candidate.DirectPort.ToString());
|
|
DBConfig.Instance.WriteConfig(
|
|
DirectLastNameKey,
|
|
candidate.AccountBookName);
|
|
}
|
|
|
|
private static Uri BuildDirectResourceUri(string host, int port)
|
|
{
|
|
host = (host ?? string.Empty).Trim();
|
|
if (string.IsNullOrWhiteSpace(host))
|
|
throw new ArgumentException("请输入直连服务器地址。");
|
|
if (port < 1 || port > 65535)
|
|
throw new ArgumentOutOfRangeException(
|
|
"port",
|
|
"直连端口必须介于 1 和 65535 之间。");
|
|
|
|
if (!host.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
|
|
!host.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
host = "http://" + host;
|
|
}
|
|
|
|
Uri baseUri;
|
|
if (!Uri.TryCreate(host, UriKind.Absolute, out baseUri) ||
|
|
(baseUri.Scheme != Uri.UriSchemeHttp &&
|
|
baseUri.Scheme != Uri.UriSchemeHttps))
|
|
{
|
|
throw new ArgumentException("直连服务器地址格式无效。");
|
|
}
|
|
|
|
var builder = new UriBuilder(baseUri)
|
|
{
|
|
Port = port,
|
|
Path = "/SystemResources.txt",
|
|
Query = string.Empty,
|
|
Fragment = string.Empty
|
|
};
|
|
return builder.Uri;
|
|
}
|
|
|
|
private static string DownloadDirectPayload(Uri resourceUri)
|
|
{
|
|
var request = (HttpWebRequest)WebRequest.Create(resourceUri);
|
|
request.Method = "GET";
|
|
request.Timeout = DirectRequestTimeoutMilliseconds;
|
|
request.ReadWriteTimeout = DirectRequestTimeoutMilliseconds;
|
|
|
|
using (var response = (HttpWebResponse)request.GetResponse())
|
|
using (Stream stream = response.GetResponseStream())
|
|
{
|
|
if (stream == null)
|
|
{
|
|
throw new InvalidDataException(
|
|
"直连服务器未返回连接配置。");
|
|
}
|
|
|
|
using (var reader = new StreamReader(
|
|
stream,
|
|
Encoding.UTF8,
|
|
true))
|
|
{
|
|
string payload = reader.ReadToEnd().Trim();
|
|
if (string.IsNullOrWhiteSpace(payload))
|
|
{
|
|
throw new InvalidDataException(
|
|
"直连服务器返回的连接配置为空。");
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string[] ParseDirectPayload(string decryptedPayload)
|
|
{
|
|
string[] parts = (decryptedPayload ?? string.Empty).Split('^');
|
|
if (parts.Length != 5)
|
|
{
|
|
throw new InvalidDataException(
|
|
"直连服务器返回的连接配置格式无效。");
|
|
}
|
|
|
|
for (int index = 0; index < parts.Length; index++)
|
|
{
|
|
parts[index] = (parts[index] ?? string.Empty).Trim();
|
|
if (string.IsNullOrWhiteSpace(parts[index]))
|
|
{
|
|
throw new InvalidDataException(
|
|
"直连服务器返回的连接配置不完整。");
|
|
}
|
|
}
|
|
|
|
return parts;
|
|
}
|
|
|
|
private static string ToSafeConnectionError(Exception exception)
|
|
{
|
|
if (exception is ArgumentException ||
|
|
exception is InvalidDataException ||
|
|
exception is LegacyConnectionSettingsException)
|
|
{
|
|
return exception.Message;
|
|
}
|
|
if (exception is WebException)
|
|
{
|
|
return "无法读取直连配置,请检查地址、端口和网络连接。";
|
|
}
|
|
|
|
return "连接设置失败,请检查配置和网络连接。";
|
|
}
|
|
|
|
private static void LogSanitized(Exception exception)
|
|
{
|
|
string exceptionType = exception == null
|
|
? "Unknown"
|
|
: exception.GetType().FullName;
|
|
LogHelper.Instance.WriteLog(
|
|
"WPF 登录连接设置失败。异常类型:" + exceptionType);
|
|
}
|
|
|
|
private static DataTable CreateSettingsTable()
|
|
{
|
|
var table = new DataTable("Settings");
|
|
table.Columns.Add("Mode", typeof(string));
|
|
table.Columns.Add("ServerName", typeof(string));
|
|
table.Columns.Add("DatabaseName", typeof(string));
|
|
table.Columns.Add("DirectHost", typeof(string));
|
|
table.Columns.Add("DirectPort", typeof(string));
|
|
table.Columns.Add("DirectAccountBookName", typeof(string));
|
|
return table;
|
|
}
|
|
|
|
private static DataTable CreateSavedConnectionsTable()
|
|
{
|
|
var table = new DataTable("SavedDirectConnections");
|
|
table.Columns.Add("Key", typeof(string));
|
|
table.Columns.Add("DisplayName", typeof(string));
|
|
table.Columns.Add("Host", typeof(string));
|
|
table.Columns.Add("Port", typeof(int));
|
|
return table;
|
|
}
|
|
|
|
private static string ReadRegistryValue(string valueName)
|
|
{
|
|
try
|
|
{
|
|
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(
|
|
RegistryFilePath,
|
|
false))
|
|
{
|
|
object value = key == null
|
|
? null
|
|
: key.GetValue(valueName, string.Empty);
|
|
return value == null ? string.Empty : value.ToString();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
private static bool TrySplitEndpoint(
|
|
string endpoint,
|
|
out string host,
|
|
out int port)
|
|
{
|
|
host = string.Empty;
|
|
port = 0;
|
|
if (string.IsNullOrWhiteSpace(endpoint))
|
|
return false;
|
|
|
|
int separatorIndex = endpoint.LastIndexOf(':');
|
|
if (separatorIndex <= 0 ||
|
|
separatorIndex >= endpoint.Length - 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
host = endpoint.Substring(0, separatorIndex).Trim();
|
|
return !string.IsNullOrWhiteSpace(host) &&
|
|
int.TryParse(endpoint.Substring(separatorIndex + 1), out port) &&
|
|
port >= 1 &&
|
|
port <= 65535;
|
|
}
|
|
|
|
private static string ReadHistoryDisplayName(string value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
return string.Empty;
|
|
|
|
int separatorIndex = value.IndexOf('^');
|
|
return separatorIndex < 0
|
|
? string.Empty
|
|
: value.Substring(0, separatorIndex).Trim();
|
|
}
|
|
|
|
private sealed class ConnectionCandidate
|
|
{
|
|
public string ServerName;
|
|
public string DatabaseName;
|
|
public string AccountBookName;
|
|
public string ServerType;
|
|
public string ConnectionTemplate;
|
|
public string DelphiConnectionTemplate;
|
|
public string DirectHost;
|
|
public int DirectPort;
|
|
public string DirectEncryptedPayload;
|
|
}
|
|
|
|
private sealed class LegacyConnectionStateSnapshot
|
|
{
|
|
private string _serverName;
|
|
private string _databaseName;
|
|
private string _dataBook;
|
|
private string _loginName;
|
|
private string _serverType;
|
|
private string _connectionTemplate;
|
|
private string _delphiConnectionTemplate;
|
|
private string _selectedLedgerName;
|
|
private string _accountBook;
|
|
private bool _connectionInitialized;
|
|
|
|
public static LegacyConnectionStateSnapshot Capture(
|
|
LegacyLoginRuntime runtime)
|
|
{
|
|
return new LegacyConnectionStateSnapshot
|
|
{
|
|
_serverName = DBConfig.Instance.ServerName,
|
|
_databaseName = DBConfig.Instance.DataBase,
|
|
_dataBook = DBConfig.Instance.DataBook,
|
|
_loginName = DBConfig.Instance.LoginName,
|
|
_serverType = DBConfig.Instance.ServerType,
|
|
_connectionTemplate = DBConfig.Instance.Connection,
|
|
_delphiConnectionTemplate =
|
|
DBConfig.Instance.dephiConnection,
|
|
_selectedLedgerName = runtime.SelectedLedgerName,
|
|
_accountBook = ERPInfo.Instance.AccountBook,
|
|
_connectionInitialized = runtime._connectionInitialized
|
|
};
|
|
}
|
|
|
|
public void Restore(LegacyLoginRuntime runtime)
|
|
{
|
|
DBConfig.Instance.ServerName = _serverName;
|
|
DBConfig.Instance.DataBase = _databaseName;
|
|
DBConfig.Instance.DataBook = _dataBook;
|
|
DBConfig.Instance.LoginName = _loginName;
|
|
DBConfig.Instance.ServerType = _serverType;
|
|
DBConfig.Instance.Connection = _connectionTemplate;
|
|
DBConfig.Instance.dephiConnection =
|
|
_delphiConnectionTemplate;
|
|
runtime.SelectedLedgerName = _selectedLedgerName;
|
|
runtime._ledgerTable = null;
|
|
runtime._connectionInitialized = _connectionInitialized;
|
|
ERPInfo.Instance.AccountBook = _accountBook;
|
|
|
|
try
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(_serverName) &&
|
|
!string.IsNullOrWhiteSpace(_databaseName))
|
|
{
|
|
DBConfig.Instance.CreateConnection(
|
|
_connectionTemplate);
|
|
if (!string.Equals(
|
|
_serverType,
|
|
"达梦数据库",
|
|
StringComparison.Ordinal))
|
|
{
|
|
DelphiHelper.Delphi_Init(new StringBuilder(
|
|
DBConfig.Instance.GetDelphiConnection(
|
|
_delphiConnectionTemplate)));
|
|
}
|
|
SystemInfo.RefreshSystemParam();
|
|
}
|
|
}
|
|
catch (Exception restoreException)
|
|
{
|
|
LogSanitized(restoreException);
|
|
}
|
|
}
|
|
}
|
|
|
|
private sealed class LegacyConnectionSettingsException : Exception
|
|
{
|
|
public LegacyConnectionSettingsException(string message)
|
|
: base(message)
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|