using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.SqlClient; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.NetworkInformation; using System.Windows.Forms; using System.Net; using System.Security.Cryptography; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Diagnostics; using Microsoft.VisualBasic.Logging; using System.IO.Compression; using SharpCompress.Archives.Rar; using SharpCompress.Common; using SharpCompress.Archives; using System.Diagnostics.Eventing.Reader; using System.ServiceProcess; using static System.Windows.Forms.VisualStyles.VisualStyleElement; using System.Security.Policy; using static System.Windows.Forms.VisualStyles.VisualStyleElement.ToolBar; using System.Data.SqlTypes; namespace Start { public partial class Main : Form { private bool isCanDBConfig = true; private bool isPortTestOk = false; private bool isServiceTestOk=false; private bool isDBNameTestOK=false; public Main() { InitializeComponent(); var physicalAddressList = NetworkInterface.GetAllNetworkInterfaces().Select(t => t.GetPhysicalAddress().ToString()); this.machineTextBox.Text = physicalAddressList.FirstOrDefault()?.ToString(); this.KeySecreteTextBox.Text = Md5($"{this.machineTextBox.Text}_XINGCANG"); } private void Main_Load(object sender, EventArgs e) { portBtn.Enabled = false; activeBtn.Enabled = false; //serverTextBox.DataBindings.Add(new Binding("Enabled", this, "isCanDBConfig")); //usernameTextBox.DataBindings.Add(new Binding("Enabled", this, "isCanDBConfig")); //passwordTextBox.DataBindings.Add(new Binding("Enabled", this, "isCanDBConfig")); //nginxPortTBox.DataBindings.Add(new Binding("Enabled", this, "isCanServerConfig")); //apiPortTBox.DataBindings.Add(new Binding("Enabled", this, "isCanServerConfig")); //dbNameTBox.DataBindings.Add(new Binding("Enabled", this, "isCanServerConfig")); //connectButton.DataBindings.Add(new Binding("Enabled", this, "isCanDBConfig")); } int apiPort = 7100; int vuePort = 9527; private void connectButton_Click(object sender, EventArgs e) { string connectionString = $"Server={serverTextBox.Text};User Id={usernameTextBox.Text};Password={passwordTextBox.Text};"; SqlConnection connection = new SqlConnection(connectionString); try { connection.Open(); Log("数据库连接成功!", Color.Green); isCanDBConfig = false; serverTextBox.Enabled = isCanDBConfig; usernameTextBox.Enabled = isCanDBConfig; passwordTextBox.Enabled = isCanDBConfig; connectButton.Enabled = false; portBtn.Enabled = true; } catch (Exception ex) { Log($"数据库连接失败:{ex.Message}", Color.Red); } finally { connection.Close(); } } private async void portBtn_Click(object sender, EventArgs e) { #region 测试 停止Nginx string nginxPath = Path.Combine(AppContext.BaseDirectory, @$"deploy\nginx-1.20.1\"); var serviceConfig = await File.ReadAllTextAsync("deploy/ServiceConfig.json"); var jObject = JObject.Parse(serviceConfig); #region 创建进程执行命令 Process process = new Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.RedirectStandardInput = true; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; // 不创建新窗口 process.Start(); var proList = Process.GetProcesses().Where(t => t.ProcessName.Contains("nginx") && t.MainModule.FileName.Contains(nginxPath)); foreach (var item in proList) { item.Kill(); } await ProcessStandardInputAsync(process, $"sc stop {jObject["serviceName"].ToString()}"); process.StandardInput.Close(); process.WaitForExit(); #endregion #endregion if (int.TryParse(nginxPortTBox.Text, out vuePort) == false || int.TryParse(apiPortTBox.Text, out apiPort) == false) { Log($"请输入合法的端口", Color.Red); return; } if (IsPortInUse(vuePort)) { Log($"服务设置的前端端口被占用,请选择其他端口", Color.Red); return; } if (IsPortInUse(apiPort)) { Log($"服务设置的后端端口被占用,请选择其他端口", Color.Red); return; } Log("端口测试成功!", Color.Green); isPortTestOk = true; } private void testServicebtn_Click(object sender, EventArgs e) { if (ServiceController.GetServices().Any(t => t.ServiceName == serviceNameTBox.Text)) { Log($"当前服务名称已存在,请更换", Color.Red); return; } isServiceTestOk = true; } private void testDBBtn_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(dbNameTBox.Text)) { Log($"请输入部署的数据库名称", Color.Red); return; } string connectionString = $"Server={serverTextBox.Text};User Id={usernameTextBox.Text};Password={passwordTextBox.Text};"; string sql = $"SELECT COUNT(*) FROM sys.databases WHERE name = '{dbNameTBox.Text.Trim()}';"; // 创建连接对象和命令对象 using (SqlConnection connection = new SqlConnection(connectionString)) using (SqlCommand command = new SqlCommand(sql, connection)) { // 打开连接 connection.Open(); // 执行查询,返回结果行数 int rowCount = (int)command.ExecuteScalar(); // 判断结果是否大于0,即是否存在该数据库 if (rowCount > 0) { Log($"{dbNameTBox.Text.Trim()}该数据库已存在。", Color.Red); return; } } isDBNameTestOK = true; } private void confimDeployBtn_Click(object sender, EventArgs e) { activeBtn.Enabled = true; nginxPortTBox.Enabled = false; apiPortTBox.Enabled = false; portBtn.Enabled = false; dbNameTBox.Enabled = false; } private static bool IsPortInUse(int port) { IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties(); IPEndPoint[] tcpEndPoints = ipProperties.GetActiveTcpListeners(); foreach (IPEndPoint endPoint in tcpEndPoints) { if (endPoint.Port == port) { return true; } } return false; } public static string Md5(string target) { using (MD5 md5 = MD5.Create()) { // MD5非线程安全 byte[] bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(target)); StringBuilder sb = new StringBuilder(32); for (int i = 0; i < bytes.Length; ++i) sb.Append(bytes[i].ToString("x2")); return sb.ToString(); } } private void Log(string message, Color color) { if (InvokeRequired) { Invoke(Log, message, color); return; } logTBox.SelectionColor = color; logTBox.AppendText(message + Environment.NewLine); } private async Task ProcessStandardInputAsync(Process process, string cmd, string workDirectory = "") { if (!string.IsNullOrWhiteSpace(workDirectory)) { process.StartInfo.WorkingDirectory = workDirectory; } await process.StandardInput.WriteLineAsync(cmd); await process.StandardInput.FlushAsync(); } private async void activeBtn_Click(object sender, EventArgs e) { this.activeBtn.Enabled = false; var serviceName = serviceNameTBox.Text; var serviceDisplayName = serviceDisplayNameTBox.Text; var deployFoder = this.folderPathTbox.Text; string nginxExtractName = "nginx-1.20.1"; string apiExtractName = "APIPublish"; string nginxStartPath = Path.Combine(deployFoder, @$"{nginxExtractName}\"); var nginxConfigPath = Path.Combine(nginxStartPath, @$"conf\nginx.conf"); var apiBinPath = Path.Combine(deployFoder, "APIPublish/IRacIS.Core.API.exe"); string nginxRarFilePath = Path.Combine(AppContext.BaseDirectory, $@"deploy\nginx-1.20.1.rar"); // 要解压缩的RAR文件路径 string apiRarFilePath = Path.Combine(AppContext.BaseDirectory, "deploy/net6.0.rar"); // 要解压缩的RAR文件路径 #region 创建进程执行命令 var startInfo = new ProcessStartInfo(); startInfo.FileName = "cmd.exe"; // 指定要启动的应用程序 startInfo.RedirectStandardInput = true; startInfo.UseShellExecute = false; //startInfo.CreateNoWindow = true; // 创建新进程并启动 var process = new Process(); process.StartInfo = startInfo; process.Start(); #endregion #region 解压nginx 和前端部署的文件 Log($"开始解压 nginx 及前端部署 RAR文件", Color.Green); await Task.Run(() => { string extractPath = Path.Combine(deployFoder, nginxExtractName); if (!Directory.Exists(extractPath)) { Directory.CreateDirectory(extractPath); } using (var archive = RarArchive.Open(nginxRarFilePath)) { foreach (var entry in archive.Entries) { if (!entry.IsDirectory) { entry.WriteToDirectory(extractPath, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); } else { string directoryPath = Path.Combine(extractPath, entry.Key); Directory.CreateDirectory(directoryPath); } } } Log($"nginx 及前端部署 RAR文件已成功解压缩到: + {extractPath}", Color.Green); }); #endregion #region 解压后端部署的文件 Log($"开始解压 后端部署 RAR文件", Color.Green); await Task.Run(() => { string extractPath = Path.Combine(deployFoder, apiExtractName); if (!Directory.Exists(extractPath)) { Directory.CreateDirectory(extractPath); } using (var archive = RarArchive.Open(apiRarFilePath)) { foreach (var entry in archive.Entries) { if (!entry.IsDirectory) { entry.WriteToDirectory(extractPath, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); } } } Log($"后端部署 RAR文件已成功解压缩到: + {extractPath}", Color.Green); }); #endregion #region 修改 nginx 配置文件 启动nginx if (!File.Exists(nginxConfigPath)) { MessageBox.Show("预设路径不存在nginx"); } var nginxConfig = File.ReadAllText(nginxConfigPath); nginxConfig = nginxConfig.Replace("9520", vuePort.ToString()); nginxConfig = nginxConfig.Replace("7100", apiPort.ToString()); File.WriteAllText(nginxConfigPath, nginxConfig); // 获取nginx.exe所在的目录 // 创建ProcessStartInfo对象,指定要启动的可执行文件及其参数 ProcessStartInfo psi = new ProcessStartInfo(nginxStartPath + "nginx.exe"); // 指定工作目录,即进入nginx.exe所在的目录 psi.WorkingDirectory = nginxStartPath; Log(" 开始启动 nginx 服务...", Color.Green); // 启动可执行文件 Process.Start(psi); if (Process.GetProcesses().Any(t => t.ProcessName.Contains("nginx") && t.MainModule.FileName.Contains(nginxStartPath))) { Log(" nginx 服务启动成功", Color.Green); } else { Log(" nginx 服务启动失败", Color.Red); return; } #endregion var configObj = new { key = this.machineTextBox.Text, value = this.KeySecreteTextBox.Text.Trim(), user = usernameTextBox.Text, server = serverTextBox.Text, password = passwordTextBox.Text, dbName = dbNameTBox.Text, }; File.WriteAllText($@"C:\ProgramData\.xingcang\config.json", JsonConvert.SerializeObject(configObj)); Log("写入激活秘钥完成", Color.Green); var createStr = $@"sc create {serviceName} binPath= ""{apiBinPath} --urls=""http://127.0.0.1:{apiPort}"" --env CertificateApply"" DisplayName= ""{serviceDisplayName}"" start= auto"; #region 创建服务 // 删除已存在的服务 await ProcessStandardInputAsync(process, $"sc delete {serviceName}"); Log($"删除服务{serviceName}...", Color.Green); // 执行 sc create 命令来创建服务 await ProcessStandardInputAsync(process, createStr); Log($"创建服务{serviceName}...", Color.Green); Log($"执行初始化数据库脚本...", Color.Green); //执行数据库脚本 //await ProcessStandardInputAsync(process, Path.Combine(AppContext.BaseDirectory, "deploy/sql/bin.bat")); await ProcessStandardInputAsync(process, $@" SQLCMD -v dbName = ""{dbNameTBox.Text}"" -i {AppContext.BaseDirectory}deploy\sql\dbo.sql "); await ProcessStandardInputAsync(process, $@" SQLCMD -v dbName = ""{dbNameTBox.Text}"" -i {AppContext.BaseDirectory}deploy\sql\data.sql "); Log($"初始化数据库脚本执行结束", Color.Green); // 执行 sc start 启动服务 Log($"启动部署的后端服务...", Color.Green); await ProcessStandardInputAsync(process, $"sc start {serviceName}"); // 关闭进程流并等待进程退出 process.StandardInput.Close(); process.WaitForExit(); ServiceController sc = new ServiceController(serviceName); if (sc.Status == ServiceControllerStatus.Running) { Log($"后端服务启动成功", Color.Green); try { // Use ProcessStartInfo class var start = new ProcessStartInfo($"http://127.0.0.1:{vuePort}") { UseShellExecute = true, Verb = "open" }; Process.Start(start); } catch (Exception ex) { // Handle exception MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { Log($"后端服务启动失败", Color.Red); } #endregion } private void selectPathBtn_Click(object sender, EventArgs e) { FolderBrowserDialog dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { folderPathTbox.Text = dialog.SelectedPath; } } } }