You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
623 lines
21 KiB
623 lines
21 KiB
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Tiobon.PublishHelper
|
|
{
|
|
/// <summary>
|
|
/// 辅助类
|
|
/// </summary>
|
|
public class Utility
|
|
{
|
|
#region 参数
|
|
/// <summary>
|
|
/// 停止发布
|
|
/// </summary>
|
|
public static bool m_StopPublish = false;
|
|
/// <summary>
|
|
/// 替换控制指令
|
|
/// </summary>
|
|
public static System.Text.RegularExpressions.Regex m_RegexUb = new System.Text.RegularExpressions.Regex(@"\u001b\[\d+[A-z]");
|
|
/// <summary>
|
|
/// 测试服务器
|
|
/// </summary>
|
|
public static string m_TestServerIp = "192.168.8.60";
|
|
#endregion
|
|
|
|
#region 事件
|
|
/// <summary>
|
|
/// 记录日志
|
|
/// </summary>
|
|
public static Action<string, string> SendLogHandle;
|
|
public static void SendLog(string msg, bool status = false)
|
|
{
|
|
SendLogHandle("", msg);
|
|
if (status)
|
|
{
|
|
SetStatus(msg);
|
|
}
|
|
lock (m_Logs)
|
|
m_Logs.Add(msg);
|
|
}
|
|
public static void SendLog(string oprate, string msg, bool status = false)
|
|
{
|
|
SendLogHandle(oprate, msg);
|
|
if (status)
|
|
{
|
|
SetStatus(msg);
|
|
}
|
|
lock (m_Logs)
|
|
{
|
|
if (string.IsNullOrEmpty(oprate))
|
|
m_Logs.Add($"{msg}");
|
|
else
|
|
m_Logs.Add($"[{oprate}] {msg}");
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 设置进度条显示/隐藏
|
|
/// </summary>
|
|
public static Action<bool> SetProgressBarVisible;
|
|
/// <summary>
|
|
/// 设置进度条状态
|
|
/// </summary>
|
|
public static Action<long, ulong> SetProgressBarValue;
|
|
/// <summary>
|
|
/// 设置当前状态
|
|
/// </summary>
|
|
public static Action<string> SetStatus;
|
|
#endregion
|
|
|
|
#region 初始化
|
|
public static void Init()
|
|
{
|
|
ReadDevServer();
|
|
ReadPublishServer();
|
|
ReadOprateLog();
|
|
Thread log = new Thread(WriteLogger);
|
|
log.Start();
|
|
}
|
|
#endregion
|
|
|
|
#region 服务器管理
|
|
/// <summary>
|
|
/// 开发服务器列表
|
|
/// </summary>
|
|
public static List<DevServer> m_DevServers = new List<DevServer>();
|
|
/// <summary>
|
|
/// 保存开发服务器配置
|
|
/// </summary>
|
|
public static void SaveDevServer()
|
|
{
|
|
try
|
|
{
|
|
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\DevServers.dat";
|
|
if (File.Exists(fname))
|
|
File.Delete(fname);
|
|
using (FileStream fs = new FileStream(fname, FileMode.Create))
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
//将list序列化到文件中
|
|
bf.Serialize(fs, m_DevServers);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 读取开发服务器配置
|
|
/// </summary>
|
|
public static void ReadDevServer()
|
|
{
|
|
try
|
|
{
|
|
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\DevServers.dat";
|
|
if (File.Exists(fname))
|
|
{
|
|
using (FileStream fs = new FileStream(fname, FileMode.Open))
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
//将list序列化到文件中
|
|
m_DevServers = bf.Deserialize(fs) as List<DevServer>;
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (m_DevServers is null)
|
|
{
|
|
m_DevServers = new List<DevServer>();
|
|
}
|
|
|
|
m_DevServers.ForEach(s =>
|
|
{
|
|
if (s.Hospitals is null)
|
|
{
|
|
s.Hospitals = new List<Hospital>();
|
|
}
|
|
});
|
|
}
|
|
/// <summary>
|
|
/// 发布服务器列表
|
|
/// </summary>
|
|
public static List<PublishServer> m_PublishServers = new List<PublishServer>();
|
|
/// <summary>
|
|
/// 保存发布服务器配置
|
|
/// </summary>
|
|
public static void SavePublishServer()
|
|
{
|
|
try
|
|
{
|
|
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\PublishServers.dat";
|
|
if (File.Exists(fname))
|
|
File.Delete(fname);
|
|
using (FileStream fs = new FileStream(fname, FileMode.Create))
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
//将list序列化到文件中
|
|
bf.Serialize(fs, m_PublishServers);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 读取发布服务器配置
|
|
/// </summary>
|
|
public static void ReadPublishServer()
|
|
{
|
|
try
|
|
{
|
|
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\PublishServers.dat";
|
|
if (File.Exists(fname))
|
|
{
|
|
using (FileStream fs = new FileStream(fname, FileMode.Open))
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
//将list序列化到文件中
|
|
m_PublishServers = bf.Deserialize(fs) as List<PublishServer>;
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (m_PublishServers is null)
|
|
{
|
|
m_PublishServers = new List<PublishServer>();
|
|
}
|
|
|
|
m_PublishServers.ForEach(s =>
|
|
{
|
|
if (s.Folders is null)
|
|
s.Folders = new List<VersionFolder>();
|
|
|
|
s.Folders.ForEach(f =>
|
|
{
|
|
if (f.Files is null)
|
|
f.Files = new List<VersionFile>();
|
|
});
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
#region 操作记录
|
|
/// <summary>
|
|
/// 操作记录
|
|
/// </summary>
|
|
public static OprateLog m_OprateLog = new OprateLog();
|
|
/// <summary>
|
|
/// 保存操作记录
|
|
/// </summary>
|
|
public static void SaveOprateLog()
|
|
{
|
|
try
|
|
{
|
|
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\OprateLog.dat";
|
|
if (File.Exists(fname))
|
|
File.Delete(fname);
|
|
using (FileStream fs = new FileStream(fname, FileMode.Create))
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
//将list序列化到文件中
|
|
bf.Serialize(fs, m_OprateLog);
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 读取操作记录
|
|
/// </summary>
|
|
public static void ReadOprateLog()
|
|
{
|
|
try
|
|
{
|
|
string fname = AppDomain.CurrentDomain.BaseDirectory + "\\OprateLog.dat";
|
|
if (File.Exists(fname))
|
|
{
|
|
using (FileStream fs = new FileStream(fname, FileMode.Open))
|
|
{
|
|
BinaryFormatter bf = new BinaryFormatter();
|
|
//将list序列化到文件中
|
|
m_OprateLog = bf.Deserialize(fs) as OprateLog;
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
if (m_OprateLog is null)
|
|
{
|
|
m_OprateLog = new OprateLog();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Ping测试
|
|
/// <summary>
|
|
/// Ping测试
|
|
/// </summary>
|
|
/// <param name="ip"></param>
|
|
/// <param name="b_log"></param>
|
|
/// <returns></returns>
|
|
public static bool Ping(string ip, bool b_log = true)
|
|
{
|
|
bool b_suc = false;
|
|
try
|
|
{
|
|
using (Ping ping = new Ping())
|
|
{
|
|
b_suc = ping.Send(ip, 2000).Status == IPStatus.Success;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
b_suc = false;
|
|
}
|
|
if (!b_suc && b_log)
|
|
{
|
|
SendLog(ip, "ping失败,不继续执行其他远程操作指令");
|
|
}
|
|
return b_suc;
|
|
}
|
|
#endregion
|
|
|
|
#region 获取临时文件名
|
|
/// <summary>
|
|
/// 获取临时文件名
|
|
/// </summary>
|
|
/// <param name="fname"></param>
|
|
/// <param name="random"></param>
|
|
/// <returns></returns>
|
|
public static string GetTempFileName(string fname, bool random = true)
|
|
{
|
|
return $"{System.Environment.GetEnvironmentVariable("TEMP")}\\{fname}" + (random ? $"_{DateTime.Now.Ticks}" : "");
|
|
}
|
|
#endregion
|
|
|
|
#region 获取服务器状态
|
|
/// <summary>
|
|
/// 获取服务器状态
|
|
/// </summary>
|
|
/// <param name="server"></param>
|
|
/// <returns></returns>
|
|
public static (bool Success, double Cpu, double MemTotal, double MemUsed, double Disk) GetServerStatus(Server server)
|
|
{
|
|
var res = (false, 0, 0, 0, 0);
|
|
try
|
|
{
|
|
var (Success, Result) = SshHelper.ExcuteCmd(server, "cpu=`top -b -n 1 | awk 'NR>7{sum+=$9} END {print sum}'`\n mem=`free -m | awk 'NR==2{print $2,$3}'` \n disk=`df -h | grep \"home\" |awk '{{print $5}}'` \n echo \"$cpu,$mem,$disk\"", false);
|
|
if (Success)
|
|
{
|
|
//87,7981 4369,96%
|
|
var empties = Result.Trim('\n').Trim().Split(new string[] { "%", ",", " " }, StringSplitOptions.RemoveEmptyEntries);
|
|
if (empties.Length == 4)
|
|
{
|
|
return (true, double.Parse(empties[0]), double.Parse(empties[1]), double.Parse(empties[2]), double.Parse(empties[3]));
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{ }
|
|
return res;
|
|
}
|
|
#endregion
|
|
|
|
#region 日志
|
|
/// <summary>
|
|
/// 停止记录日志
|
|
/// </summary>
|
|
public static bool m_LogRun = true;
|
|
private static List<string> m_Logs = new List<string>();
|
|
/// <summary>
|
|
/// 日志线程
|
|
/// </summary>
|
|
private static void WriteLogger()
|
|
{
|
|
var path = AppDomain.CurrentDomain.BaseDirectory + "Log\\";
|
|
if (!Directory.Exists(path))
|
|
Directory.CreateDirectory(path);
|
|
string fname = string.Empty;
|
|
var logs = new List<string>();
|
|
while (m_LogRun)
|
|
{
|
|
try
|
|
{
|
|
lock (m_Logs)
|
|
{
|
|
if (m_Logs.Count > 0)
|
|
{
|
|
m_Logs.ForEach(s => logs.Add(s));
|
|
fname = path + DateTime.Now.ToString("yyyy_MM_dd") + ".txt";
|
|
m_Logs.Clear();
|
|
}
|
|
}
|
|
if (logs.Count > 0)
|
|
{
|
|
WriteLoggerToFile(fname, logs);
|
|
logs.Clear();
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
finally
|
|
{
|
|
System.Threading.Thread.Sleep(3000);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 日志写入文件
|
|
/// </summary>
|
|
/// <param name="fname">文件名</param>
|
|
/// <param name="logs">日志</param>
|
|
private static void WriteLoggerToFile(string fname, List<string> logs)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
logs.ForEach(s => sb.AppendLine(DateTime.Now.ToString("HH:mm:ss") + "\t" + s));
|
|
if (!File.Exists(fname))
|
|
{
|
|
using (StreamWriter sw = File.CreateText(fname))
|
|
{
|
|
sw.Write(sb.ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
using (StreamWriter sw = File.AppendText(fname))
|
|
{
|
|
sw.Write(sb.ToString());
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region 发布与打包锁
|
|
/// <summary>
|
|
/// 查询锁定文件
|
|
/// </summary>
|
|
/// <param name="server"></param>
|
|
/// <param name="hospital"></param>
|
|
/// <param name="oprate"></param>
|
|
/// <returns></returns>
|
|
public static bool LockDevFiles(Server server, string oprate)
|
|
{
|
|
bool b_in = false;
|
|
string lfname = GetTempFileName("lockfile");
|
|
string rfname = $"/tmp/lockfile";
|
|
if (SftpHelper.DownloadFile(server, rfname, lfname))
|
|
{
|
|
if (File.Exists(lfname))
|
|
{
|
|
SendLog(File.ReadAllText(lfname, Encoding.UTF8));
|
|
b_in = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
File.WriteAllText(lfname, $"当前服务器 {server.Ip} 繁忙。用户 [{Environment.MachineName}] 正在 {oprate},请等待 [{Environment.MachineName}] 操作完毕...", Encoding.UTF8);
|
|
SftpHelper.UploadFile(server, lfname, rfname);
|
|
}
|
|
return b_in;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除锁定文件
|
|
/// </summary>
|
|
/// <param name="server"></param>
|
|
public static void RemoveDevFiles(Server server)
|
|
{
|
|
SftpHelper.Delete(server, $"/tmp/lockfile");
|
|
}
|
|
#endregion
|
|
|
|
#region HTTP模板
|
|
public static CookieContainer m_Cookies = new CookieContainer();
|
|
public enum Compression
|
|
{
|
|
GZip,
|
|
Deflate,
|
|
None,
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取HttpWebRequest模板
|
|
/// </summary>
|
|
/// <param name="url">URL地址</param>
|
|
/// <param name="postdata">POST</param>
|
|
/// <param name="cookies">Cookies</param>
|
|
/// <returns></returns>
|
|
public static HttpWebRequest GetHttpRequest(string url, string postdata, CookieContainer cookies, string header = null)
|
|
{
|
|
HttpWebRequest request = WebRequest.Create(new Uri(url)) as HttpWebRequest;
|
|
|
|
request.CookieContainer = cookies;
|
|
request.ContentType = !string.IsNullOrEmpty(header) ? "application/json" : "application/x-www-form-urlencoded";
|
|
request.ServicePoint.ConnectionLimit = 300;
|
|
ServicePointManager.Expect100Continue = false;
|
|
request.Referer = url;
|
|
request.Accept = "*/*";
|
|
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)";
|
|
request.AllowAutoRedirect = true;
|
|
if (!string.IsNullOrEmpty(header))
|
|
request.Headers.Add("Authorization", header);
|
|
if (postdata != null && postdata != "")
|
|
{
|
|
request.Method = "POST";
|
|
byte[] byte_post = Encoding.Default.GetBytes(postdata);
|
|
request.ContentLength = byte_post.Length;
|
|
using (Stream stream = request.GetRequestStream())
|
|
{
|
|
stream.Write(byte_post, 0, byte_post.Length);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
request.Method = "GET";
|
|
}
|
|
return request;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 提取HttpWebResponse文本内容
|
|
/// </summary>
|
|
/// <param name="resp">HttpWebResponse响应包</param>
|
|
/// <returns></returns>
|
|
public static string GetResponseContent(HttpWebResponse resp)
|
|
{
|
|
|
|
if (resp.StatusCode != HttpStatusCode.OK)
|
|
throw new Exception("远程服务器返回状态码: " + resp.StatusCode);
|
|
|
|
Encoding enc = Encoding.UTF8;
|
|
if (resp.CharacterSet != null && resp.CharacterSet != "")
|
|
enc = Encoding.GetEncoding(resp.CharacterSet);
|
|
|
|
Compression comp = Compression.None;
|
|
if (resp.ContentEncoding != null && resp.ContentEncoding.Trim().ToUpper() == "GZIP")
|
|
comp = Compression.GZip;
|
|
else if (resp.ContentEncoding != null && resp.ContentEncoding.Trim().ToUpper() == "DEFLATE")
|
|
comp = Compression.Deflate;
|
|
|
|
MemoryStream ms = new MemoryStream();
|
|
using (StreamWriter sw = new StreamWriter(ms, enc))
|
|
{
|
|
StreamReader sr;
|
|
switch (comp)
|
|
{
|
|
case Compression.GZip:
|
|
sr = new StreamReader(new System.IO.Compression.GZipStream(resp.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress), enc);
|
|
break;
|
|
case Compression.Deflate:
|
|
sr = new StreamReader(new System.IO.Compression.DeflateStream(resp.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress), enc);
|
|
break;
|
|
default:
|
|
sr = new StreamReader(resp.GetResponseStream(), enc);
|
|
break;
|
|
}
|
|
|
|
while (!sr.EndOfStream)
|
|
{
|
|
char[] buf = new char[16000];
|
|
int read = sr.ReadBlock(buf, 0, 16000);
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.Append(buf, 0, read);
|
|
sw.Write(buf, 0, read);
|
|
}
|
|
sr.Close();
|
|
}
|
|
|
|
byte[] mbuf = ms.GetBuffer();
|
|
string sbuf = enc.GetString(mbuf);
|
|
return sbuf;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取HttpWebRequest返回值
|
|
/// </summary>
|
|
/// <param name="url">URL地址</param>
|
|
/// <param name="postdata">PostData</param>
|
|
/// <returns></returns>
|
|
public static string GetHttpResult(string url, string postdata, string header = null)
|
|
{
|
|
try
|
|
{
|
|
HttpWebRequest request = GetHttpRequest(url, postdata, m_Cookies, header);
|
|
|
|
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
|
|
|
m_Cookies.Add(response.Cookies);
|
|
|
|
return GetResponseContent(response);
|
|
}
|
|
catch
|
|
{
|
|
//Utilities.sendLog("连接 " + url + " 失败" + ex.Message);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取HttpWebRequest返回值
|
|
/// </summary>
|
|
/// <param name="url">URL地址</param>
|
|
/// <param name="postdata">PostData</param>
|
|
/// <returns></returns>
|
|
public static Stream GetHttpResponse(string url, string postdata)
|
|
{
|
|
try
|
|
{
|
|
HttpWebRequest request = GetHttpRequest(url, postdata, m_Cookies);
|
|
|
|
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
|
|
|
|
return response.GetResponseStream();
|
|
}
|
|
catch
|
|
{
|
|
//Utilities.sendLog("连接 " + url + " 失败" + ex.Message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 去除HTML标记
|
|
/// </summary>
|
|
/// <param name="NoHTML">包括HTML的源码 </param>
|
|
/// <returns>已经去除后的文字</returns>
|
|
public static string RemoveHTMLFlag(string input)
|
|
{
|
|
input = Regex.Replace(input, @"<script[^>]*?>.*?</script>", "", RegexOptions.IgnoreCase);
|
|
|
|
Regex regex = new Regex("<.+?>", RegexOptions.IgnoreCase);
|
|
input = regex.Replace(input, "");
|
|
input = Regex.Replace(input, @"<(.[^>]*)>", "", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"([\r\n])[\s]+", "", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"-->", "", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"<!--.*", "", RegexOptions.IgnoreCase);
|
|
|
|
input = Regex.Replace(input, @"&(quot|#34);", "\"", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(amp|#38);", "&", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(lt|#60);", "<", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(gt|#62);", ">", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(nbsp|#160);", " ", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(iexcl|#161);", "\xa1", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(cent|#162);", "\xa2", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(pound|#163);", "\xa3", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&(copy|#169);", "\xa9", RegexOptions.IgnoreCase);
|
|
input = Regex.Replace(input, @"&#(\d+);", "", RegexOptions.IgnoreCase);
|
|
|
|
input.Replace("<", "");
|
|
input.Replace(">", "");
|
|
input.Replace("\r\n", "");
|
|
|
|
return input;
|
|
}
|
|
#endregion
|
|
}
|
|
}
|
|
|