内网穿透测试

This commit is contained in:
snltty
2024-05-09 10:58:56 +08:00
parent b997c970eb
commit a9f7da8f3c
51 changed files with 1489 additions and 3166 deletions

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
processorArchitecture="x86"
version="5.1.0.0"
type="win32"
name="cmonitor.install.win.exe"/>
<description>cmonitor.install.win</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="x86"/>
</dependentAssembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10, Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<!--
可任选以下配置之一指定一个进程权限:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
requireAdministrator 为管理员权限,
highestAvailable 为可以获取到的最高权限,
asInvoker 为默认值,即调用进程当前权限,一般不需要显式指定,指定后会禁用虚拟化。
虚拟化指Vista以后系统禁止写 Program File目录,启用虚拟化则重定向到%localappdata%\VirtualStore目录
而注册表 HKEY_LOCAL_MACHINE\Software 则重定向到HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\Software
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@@ -0,0 +1,2 @@
//发布前触发
import ide;

View File

@@ -0,0 +1,6 @@
//此触发器在生成EXE以后执行
import ide;
import fsys;
//获取生成的EXE文件路径
var publishFile = ide.getPublishPath();

View File

@@ -1,194 +0,0 @@
using common.libs;
using common.libs.extends;
using System.Net;
using System.Text.Json.Serialization;
namespace cmonitor.install.win
{
public sealed class Config
{
FileStream fs = null;
StreamWriter writer = null;
StreamReader reader = null;
SemaphoreSlim slim = new SemaphoreSlim(1);
public Config()
{
if (Directory.Exists(ConfigPath) == false)
{
Directory.CreateDirectory(ConfigPath);
}
string path = Path.Join(ConfigPath, "config.json");
fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read);
reader = new StreamReader(fs, System.Text.Encoding.UTF8);
writer = new StreamWriter(fs, System.Text.Encoding.UTF8);
Load();
}
public ConfigCommonInfo Common { get; set; } = new ConfigCommonInfo();
public ConfigClientInfo Client { get; set; } = new ConfigClientInfo();
public ConfigServerInfo Server { get; set; } = new ConfigServerInfo();
public string ConfigPath { get; } = "./configs/";
private Dictionary<string, Dictionary<string, object>> JsonDic = new Dictionary<string, Dictionary<string, object>>();
public T Get<T>(T defaultValue)
{
return Get<T>(typeof(T).Name, defaultValue);
}
public T Get<T>(string name, T defaultValue)
{
if (JsonDic.ContainsKey(name))
{
return JsonDic[name].ToJson().DeJson<T>();
}
return defaultValue;
}
public void Set<T>(T value)
{
Set<T>(typeof(T).Name, value);
}
public void Set<T>(string name, T value)
{
JsonDic[name] = value.ToJson().DeJson<Dictionary<string, object>>();
Save();
}
private void Load()
{
InitFileConfig();
ReadJson();
Save();
}
private void InitFileConfig()
{
slim.Wait();
try
{
fs.Seek(0, SeekOrigin.Begin);
string text = reader.ReadToEnd();
if (string.IsNullOrWhiteSpace(text))
{
return;
}
JsonDic = text.DeJson<Dictionary<string, Dictionary<string, object>>>();
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
finally
{
slim.Release();
}
}
private void ReadJson()
{
if (JsonDic.TryGetValue("Client", out Dictionary<string, object> elClient))
{
Client = elClient.ToJson().DeJson<ConfigClientInfo>();
}
if (JsonDic.TryGetValue("Server", out Dictionary<string, object> elServer))
{
Server = elServer.ToJson().DeJson<ConfigServerInfo>();
}
if (JsonDic.TryGetValue("Common", out Dictionary<string, object> elCommon))
{
Common = elCommon.ToJson().DeJson<ConfigCommonInfo>();
}
}
public void Save()
{
slim.Wait();
try
{
JsonDic["Client"] = Client.ToJson().DeJson<Dictionary<string, object>>();
JsonDic["Server"] = Server.ToJson().DeJson<Dictionary<string, object>>();
JsonDic["Common"] = Common.ToJson().DeJson<Dictionary<string, object>>();
fs.Seek(0, SeekOrigin.Begin);
fs.SetLength(0);
writer.Write(JsonDic.ToJsonFormat());
writer.Flush();
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
finally
{
slim.Release();
}
}
}
public sealed partial class ConfigCommonInfo
{
public string[] Modes { get; set; } = new string[] { "client", "server" };
public bool BlueProtect { get; set; }
}
public sealed partial class ConfigClientInfo
{
private string server = new IPEndPoint(IPAddress.Loopback, 1802).ToString();
public string Server
{
get => server; set
{
server = value;
if (string.IsNullOrWhiteSpace(server) == false)
{
string[] arr = server.Split(':');
int port = arr.Length == 2 ? int.Parse(arr[1]) : 1802;
IPAddress ip = NetworkHelper.GetDomainIp(arr[0]);
ServerEP = new IPEndPoint(ip, port);
}
}
}
[JsonIgnore]
public IPEndPoint ServerEP { get; set; } = new IPEndPoint(IPAddress.Loopback, 1802);
private string name = Dns.GetHostName().SubStr(0, 12);
public string Name
{
get => name; set
{
name = value.SubStr(0, 12);
}
}
public string ShareMemoryKey { get; set; } = "cmonitor/share";
public int ShareMemoryCount { get; set; } = 100;
public int ShareMemorySize { get; set; } = 1024;
}
public sealed partial class ConfigServerInfo
{
public int WebPort { get; set; } = 1800;
public string WebRoot { get; set; } = "./web/";
public int ApiPort { get; set; } = 1801;
public int ServicePort { get; set; } = 1802;
}
}
namespace cmonitor.install.win
{
public sealed class ViewerConfigInfo
{
}
public sealed partial class ConfigClientInfo
{
public ViewerConfigInfo Viewer { get; set; } = new ViewerConfigInfo();
}
public sealed partial class ConfigServerInfo
{
public ViewerConfigInfo Viewer { get; set; } = new ViewerConfigInfo();
}
}

View File

@@ -1,248 +0,0 @@
namespace cmonitor.install.win
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
serverIP = new TextBox();
label1 = new Label();
label2 = new Label();
serverPort = new TextBox();
label3 = new Label();
webPort = new TextBox();
label4 = new Label();
apiPort = new TextBox();
modeClient = new CheckBox();
modeServer = new CheckBox();
label5 = new Label();
shareLen = new TextBox();
label6 = new Label();
shareKey = new TextBox();
label11 = new Label();
machineName = new TextBox();
installBtn = new Button();
runBtn = new Button();
checkStateBtn = new Button();
label16 = new Label();
shareItemLen = new TextBox();
gbClient = new GroupBox();
gbServer = new GroupBox();
gbClient.SuspendLayout();
gbServer.SuspendLayout();
SuspendLayout();
//
// serverIP
//
resources.ApplyResources(serverIP, "serverIP");
serverIP.Name = "serverIP";
//
// label1
//
resources.ApplyResources(label1, "label1");
label1.Name = "label1";
//
// label2
//
resources.ApplyResources(label2, "label2");
label2.Name = "label2";
//
// serverPort
//
resources.ApplyResources(serverPort, "serverPort");
serverPort.Name = "serverPort";
//
// label3
//
resources.ApplyResources(label3, "label3");
label3.Name = "label3";
//
// webPort
//
resources.ApplyResources(webPort, "webPort");
webPort.Name = "webPort";
//
// label4
//
resources.ApplyResources(label4, "label4");
label4.Name = "label4";
//
// apiPort
//
resources.ApplyResources(apiPort, "apiPort");
apiPort.Name = "apiPort";
//
// modeClient
//
resources.ApplyResources(modeClient, "modeClient");
modeClient.Name = "modeClient";
modeClient.UseVisualStyleBackColor = true;
//
// modeServer
//
resources.ApplyResources(modeServer, "modeServer");
modeServer.Name = "modeServer";
modeServer.UseVisualStyleBackColor = true;
//
// label5
//
resources.ApplyResources(label5, "label5");
label5.Name = "label5";
//
// shareLen
//
resources.ApplyResources(shareLen, "shareLen");
shareLen.Name = "shareLen";
//
// label6
//
resources.ApplyResources(label6, "label6");
label6.Name = "label6";
//
// shareKey
//
resources.ApplyResources(shareKey, "shareKey");
shareKey.Name = "shareKey";
//
// label11
//
resources.ApplyResources(label11, "label11");
label11.Name = "label11";
//
// machineName
//
resources.ApplyResources(machineName, "machineName");
machineName.Name = "machineName";
//
// installBtn
//
resources.ApplyResources(installBtn, "installBtn");
installBtn.Name = "installBtn";
installBtn.UseVisualStyleBackColor = true;
installBtn.Click += OnInstallClick;
//
// runBtn
//
resources.ApplyResources(runBtn, "runBtn");
runBtn.Name = "runBtn";
runBtn.UseVisualStyleBackColor = true;
runBtn.Click += RunClick;
//
// checkStateBtn
//
resources.ApplyResources(checkStateBtn, "checkStateBtn");
checkStateBtn.Name = "checkStateBtn";
checkStateBtn.UseVisualStyleBackColor = true;
checkStateBtn.Click += checkStateBtn_Click;
//
// label16
//
resources.ApplyResources(label16, "label16");
label16.Name = "label16";
//
// shareItemLen
//
resources.ApplyResources(shareItemLen, "shareItemLen");
shareItemLen.Name = "shareItemLen";
//
// gbClient
//
resources.ApplyResources(gbClient, "gbClient");
gbClient.Controls.Add(machineName);
gbClient.Controls.Add(label16);
gbClient.Controls.Add(serverIP);
gbClient.Controls.Add(shareItemLen);
gbClient.Controls.Add(label1);
gbClient.Controls.Add(label11);
gbClient.Controls.Add(shareLen);
gbClient.Controls.Add(shareKey);
gbClient.Controls.Add(label5);
gbClient.Controls.Add(label6);
gbClient.Name = "gbClient";
gbClient.TabStop = false;
//
// gbServer
//
resources.ApplyResources(gbServer, "gbServer");
gbServer.Controls.Add(apiPort);
gbServer.Controls.Add(serverPort);
gbServer.Controls.Add(label2);
gbServer.Controls.Add(label4);
gbServer.Controls.Add(webPort);
gbServer.Controls.Add(label3);
gbServer.Name = "gbServer";
gbServer.TabStop = false;
//
// MainForm
//
resources.ApplyResources(this, "$this");
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(gbServer);
Controls.Add(gbClient);
Controls.Add(checkStateBtn);
Controls.Add(runBtn);
Controls.Add(installBtn);
Controls.Add(modeServer);
Controls.Add(modeClient);
Name = "MainForm";
Load += OnLoad;
gbClient.ResumeLayout(false);
gbClient.PerformLayout();
gbServer.ResumeLayout(false);
gbServer.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
private System.Windows.Forms.TextBox serverIP;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox serverPort;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox webPort;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox apiPort;
private System.Windows.Forms.CheckBox modeClient;
private System.Windows.Forms.CheckBox modeServer;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.TextBox shareLen;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox shareKey;
private System.Windows.Forms.Label label11;
private System.Windows.Forms.TextBox machineName;
private System.Windows.Forms.Button installBtn;
private System.Windows.Forms.Button runBtn;
private System.Windows.Forms.Button checkStateBtn;
#endregion
private Label label16;
private TextBox shareItemLen;
private GroupBox gbClient;
private GroupBox gbServer;
}
}

View File

@@ -1,304 +0,0 @@
using common.libs;
using System.Diagnostics;
namespace cmonitor.install.win
{
public partial class MainForm : Form
{
Config config = new Config();
public MainForm()
{
InitializeComponent();
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
}
private void OnLoad(object sender, EventArgs e)
{
LoadConfig();
SaveConfig();
CheckInstall();
CheckRunning();
}
private void SaveConfig()
{
config.Save();
}
private void LoadConfig()
{
modeClient.Checked = config.Common.Modes.Contains("client");
modeServer.Checked = config.Common.Modes.Contains("server");
machineName.Text = config.Client.Name;
serverIP.Text = config.Client.Server;
shareKey.Text = config.Client.ShareMemoryKey;
shareLen.Text = config.Client.ShareMemoryCount.ToString();
shareItemLen.Text = config.Client.ShareMemorySize.ToString();
serverPort.Text = config.Server.ServicePort.ToString();
apiPort.Text = config.Server.ApiPort.ToString();
webPort.Text = config.Server.WebPort.ToString();
}
private bool loading = false;
private bool installed = false;
private bool running = false;
private string serviceName = "cmonitor.sas.service";
private string exeName = "cmonitor.sas.service.exe";
private void OnInstallClick(object sender, EventArgs e)
{
if (loading)
{
return;
}
bool result = CheckMode();
if (result == false) return;
result = CheckIPAndPort();
if (result == false) return;
result = CheckShare();
if (result == false) return;
CheckLoading(true);
SaveConfig();
string filename = Process.GetCurrentProcess().MainModule.FileName;
string dir = Path.GetDirectoryName(filename);
string sasPath = Path.Combine(dir, exeName);
string sasIndexStr = "4";
string shareKeyStr = shareKey.Text;
string shareLenStr = shareLen.Text;
string shareItemLenStr = shareItemLen.Text;
Task.Run(async () =>
{
if (installed == false)
{
string taskStr = $"sc create \"{serviceName}\" binpath= \"{sasPath} {shareKeyStr} {shareLenStr} {shareItemLenStr} {sasIndexStr} \" start= AUTO";
CommandHelper.Windows(string.Empty, new string[] {
taskStr,
$"net start {serviceName}",
});
}
else
{
while (running)
{
Stop();
await Task.Delay(1000);
CheckRunning();
}
string resultStr = CommandHelper.Windows(string.Empty, new string[] {
"schtasks /delete /TN \"cmonitorService\" /f",
$"net stop {serviceName}",
$"sc delete {serviceName}",
});
}
CheckLoading(false);
CheckInstall();
CheckRunning();
});
}
private bool CheckMode()
{
if (modeClient.Checked == false && modeServer.Checked == false)
{
MessageBox.Show("客户端和服务端必须选择一样!");
return false;
}
if (string.IsNullOrWhiteSpace(machineName.Text))
{
MessageBox.Show("机器名必填!");
return false;
}
config.Client.Name = machineName.Text;
List<string> modeStr = new List<string>();
if (modeClient.Checked)
{
modeStr.Add("client");
}
if (modeServer.Checked)
{
modeStr.Add("server");
}
config.Common.Modes = modeStr.ToArray();
return true;
}
private bool CheckIPAndPort()
{
if (string.IsNullOrWhiteSpace(serverIP.Text))
{
MessageBox.Show("服务器ip必填");
return false;
}
if (string.IsNullOrWhiteSpace(serverPort.Text))
{
MessageBox.Show("服务器端口必填");
return false;
}
if (string.IsNullOrWhiteSpace(apiPort.Text))
{
MessageBox.Show("管理端口必填");
return false;
}
if (string.IsNullOrWhiteSpace(webPort.Text))
{
MessageBox.Show("web端口必填");
return false;
}
config.Client.Server = serverIP.Text;
config.Server.WebPort = int.Parse(webPort.Text);
config.Server.ApiPort = int.Parse(apiPort.Text);
config.Server.ServicePort = int.Parse(serverPort.Text);
return true;
}
private bool CheckShare()
{
if (string.IsNullOrWhiteSpace(shareKey.Text))
{
MessageBox.Show("共享数据键必填");
return false;
}
if (string.IsNullOrWhiteSpace(shareLen.Text))
{
MessageBox.Show("共享数量必填");
return false;
}
if (string.IsNullOrWhiteSpace(shareItemLen.Text))
{
MessageBox.Show("共享每项数据长度必填");
return false;
}
config.Client.ShareMemoryKey = shareKey.Text;
config.Client.ShareMemoryCount = int.Parse(shareLen.Text);
config.Client.ShareMemorySize = int.Parse(shareItemLen.Text);
return true;
}
private void CheckLoading(bool state)
{
loading = state;
this.Invoke(new EventHandler(delegate
{
if (loading)
{
installBtn.Text = "操作中..";
runBtn.Text = "操作中..";
checkStateBtn.Text = "操作中..";
}
else
{
checkStateBtn.Text = "检查状态";
if (installed)
{
installBtn.ForeColor = Color.Red;
installBtn.Text = "解除自启动";
runBtn.Enabled = true;
}
else
{
installBtn.ForeColor = Color.Black;
installBtn.Text = "安装自启动";
runBtn.Enabled = false;
}
if (running)
{
runBtn.ForeColor = Color.Red;
runBtn.Text = "停止运行";
}
else
{
runBtn.ForeColor = Color.Black;
runBtn.Text = "启动";
}
}
}));
}
private void CheckInstall()
{
Task.Run(() =>
{
string result = CommandHelper.Windows(string.Empty, new string[] { $"sc query {serviceName}" });
installed = result.Contains($"SERVICE_NAME: {serviceName}");
CheckLoading(loading);
});
}
private void RunClick(object sender, EventArgs e)
{
if (loading) return;
CheckLoading(true);
Task.Run(async () =>
{
if (running)
{
Stop();
while (running)
{
CheckRunning();
await Task.Delay(1000);
}
}
else
{
Run();
for (int i = 0; i < 15 && running == false; i++)
{
CheckRunning();
await Task.Delay(1000);
}
}
CheckLoading(false);
});
}
private void Run()
{
CommandHelper.Windows(string.Empty, new string[] {
"schtasks /run /I /TN \"cmonitorService\"",
$"net stop {serviceName}",
$"net start {serviceName}",
});
}
private void Stop()
{
CommandHelper.Windows(string.Empty, new string[] { $"net stop \"{serviceName}\"", });
}
private void CheckRunning()
{
Task.Run(() =>
{
string result = CommandHelper.Windows(string.Empty, new string[] { $"sc query {serviceName}" });
running = result.Contains(": 4 RUNNING");
CheckLoading(loading);
});
}
private void checkStateBtn_Click(object sender, EventArgs e)
{
if (loading) return;
CheckLoading(loading);
CheckInstall();
CheckRunning();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,638 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="serverIP.Location" type="System.Drawing.Point, System.Drawing">
<value>186, 95</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="serverIP.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="serverIP.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="label1.Location" type="System.Drawing.Point, System.Drawing">
<value>34, 100</value>
</data>
<data name="label1.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label1.Size" type="System.Drawing.Size, System.Drawing">
<value>134, 31</value>
</data>
<data name="label1.Text" xml:space="preserve">
<value>服务端地址</value>
</data>
<data name="label2.Location" type="System.Drawing.Point, System.Drawing">
<value>34, 146</value>
</data>
<data name="label2.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label2.Size" type="System.Drawing.Size, System.Drawing">
<value>110, 31</value>
</data>
<data name="label2.Text" xml:space="preserve">
<value>服务端口</value>
</data>
<data name="serverPort.Location" type="System.Drawing.Point, System.Drawing">
<value>158, 140</value>
</data>
<data name="serverPort.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="serverPort.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="label3.Location" type="System.Drawing.Point, System.Drawing">
<value>34, 51</value>
</data>
<data name="label3.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label3.Size" type="System.Drawing.Size, System.Drawing">
<value>110, 31</value>
</data>
<data name="webPort.Location" type="System.Drawing.Point, System.Drawing">
<value>158, 44</value>
</data>
<data name="webPort.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="webPort.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="label4.Location" type="System.Drawing.Point, System.Drawing">
<value>34, 98</value>
</data>
<data name="label4.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label4.Size" type="System.Drawing.Size, System.Drawing">
<value>110, 31</value>
</data>
<data name="label4.Text" xml:space="preserve">
<value>管理端口</value>
</data>
<data name="apiPort.Location" type="System.Drawing.Point, System.Drawing">
<value>158, 93</value>
</data>
<data name="apiPort.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="apiPort.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="modeClient.Location" type="System.Drawing.Point, System.Drawing">
<value>210, 39</value>
</data>
<data name="modeClient.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="modeClient.Size" type="System.Drawing.Size, System.Drawing">
<value>118, 35</value>
</data>
<data name="modeServer.Location" type="System.Drawing.Point, System.Drawing">
<value>596, 39</value>
</data>
<data name="modeServer.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="modeServer.Size" type="System.Drawing.Size, System.Drawing">
<value>118, 35</value>
</data>
<data name="label5.Location" type="System.Drawing.Point, System.Drawing">
<value>38, 274</value>
</data>
<data name="label5.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label5.Size" type="System.Drawing.Size, System.Drawing">
<value>110, 31</value>
</data>
<data name="shareLen.Location" type="System.Drawing.Point, System.Drawing">
<value>186, 268</value>
</data>
<data name="shareLen.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="shareLen.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="label6.Location" type="System.Drawing.Point, System.Drawing">
<value>28, 226</value>
</data>
<data name="label6.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label6.Size" type="System.Drawing.Size, System.Drawing">
<value>134, 31</value>
</data>
<data name="shareKey.Location" type="System.Drawing.Point, System.Drawing">
<value>186, 219</value>
</data>
<data name="shareKey.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="shareKey.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="label11.Location" type="System.Drawing.Point, System.Drawing">
<value>52, 53</value>
</data>
<data name="label11.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label11.Size" type="System.Drawing.Size, System.Drawing">
<value>86, 31</value>
</data>
<data name="machineName.Location" type="System.Drawing.Point, System.Drawing">
<value>186, 46</value>
</data>
<data name="machineName.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="machineName.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="installBtn.Location" type="System.Drawing.Point, System.Drawing">
<value>350, 502</value>
</data>
<data name="installBtn.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="installBtn.Size" type="System.Drawing.Size, System.Drawing">
<value>162, 64</value>
</data>
<data name="runBtn.Location" type="System.Drawing.Point, System.Drawing">
<value>176, 502</value>
</data>
<data name="runBtn.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="runBtn.Size" type="System.Drawing.Size, System.Drawing">
<value>162, 64</value>
</data>
<data name="checkStateBtn.Location" type="System.Drawing.Point, System.Drawing">
<value>610, 513</value>
</data>
<data name="checkStateBtn.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="checkStateBtn.Size" type="System.Drawing.Size, System.Drawing">
<value>150, 42</value>
</data>
<data name="label16.Location" type="System.Drawing.Point, System.Drawing">
<value>14, 326</value>
</data>
<data name="label16.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 0, 6, 0</value>
</data>
<data name="label16.Size" type="System.Drawing.Size, System.Drawing">
<value>158, 31</value>
</data>
<data name="shareItemLen.Location" type="System.Drawing.Point, System.Drawing">
<value>186, 321</value>
</data>
<data name="shareItemLen.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="shareItemLen.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 38</value>
</data>
<data name="gbClient.Location" type="System.Drawing.Point, System.Drawing">
<value>24, 88</value>
</data>
<data name="gbClient.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="gbClient.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="gbClient.Size" type="System.Drawing.Size, System.Drawing">
<value>400, 387</value>
</data>
<data name="gbClient.Text" xml:space="preserve">
<value>客户端参数</value>
</data>
<data name="gbServer.Location" type="System.Drawing.Point, System.Drawing">
<value>438, 90</value>
</data>
<data name="gbServer.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="gbServer.Padding" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
<data name="gbServer.Size" type="System.Drawing.Size, System.Drawing">
<value>374, 385</value>
</data>
<data name="gbServer.Text" xml:space="preserve">
<value>服务端参数</value>
</data>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>14, 31</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>836, 601</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
</value>
</data>
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
</root>

View File

@@ -1,27 +0,0 @@
namespace cmonitor.install.win
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Mutex mutex = new Mutex(true, System.Diagnostics.Process.GetCurrentProcess().ProcessName, out bool isAppRunning);
if (isAppRunning == false)
{
Environment.Exit(1);
}
AppDomain.CurrentDomain.UnhandledException += (a, b) =>
{
};
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new MainForm());
}
}
}

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net7.0-windows\publish\win-x64\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net7.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>True|2024-01-15T07:11:18.1268938Z;True|2024-01-15T15:08:01.2098368+08:00;True|2024-01-15T15:06:39.4979669+08:00;True|2024-01-15T15:00:07.0902803+08:00;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View File

@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
元素。
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素,
Windows 将自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
</application>
</compatibility>
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI无需
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<!--
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
-->
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>

View File

@@ -1,41 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net7.0-windows;net8.0-windows</TargetFrameworks>
<Nullable>disable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<Configurations>Debug;Release</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net7.0-windows|AnyCPU'">
<DebugType>embedded</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0-windows|AnyCPU'">
<DebugType>embedded</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net7.0-windows|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0-windows|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<Content Include="favicon.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\common.libs\common.libs.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>D:\desktop\cmonitor\cmonitor.install.win\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
<ItemGroup>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,25 @@
{
"Client":{
"ApiPassword":"snltty",
"ApiPort":1803,
"GroupId":"snltty",
"Name":"DESKTOP-1111",
"Server":"127.0.0.1:1802",
"ShareMemoryCount":100,
"ShareMemoryKey":"cmonitor/share",
"ShareMemorySize":1024,
"WebPort":1804
},
"Common":{
"Modes":[
"client",
"server"
]
},
"Server":{
"ApiPassword":"snltty",
"ApiPort":1801,
"ServicePort":1802,
"WebPort":1800
}
}

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="cmonitor.install.win" libEmbed="true" icon="..\cmonitor\favicon.ico" ui="win" output="cmonitor.install.win.exe" CompanyName="单位名称" FileDescription="cmonitor.install.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="cmonitor.install.win" InternalName="cmonitor.install.win" FileVersion="0.0.0.03" ProductVersion="0.0.0.03" 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"/>
<file name="favicon1.ico" path="res\favicon1.ico" comment="res\favicon1.ico"/>
</folder>
<folder name="窗体文件" path="dlg" comment="目录" embed="true" local="false" ignored="false"/>
</project>

Binary file not shown.

View File

@@ -0,0 +1,17 @@
//config 配置文件
import fsys.config;
config = fsys.config("/config/");
//config = fsys.config( io.appData("/软件作者/应用程序名/") );
//不需要序列化的配置名字前请添加下划线
namespace config {
__appName = "应用程序名";
__website = "http://www.aardio.com/";
}
/**intellisense(config)
__appName = 应用程序名
__website = 官方网站
saveAll() = 写入所有配置到文件
? = 获取值时指定不以下划线开始的配置表名称,\n返回一个可自动序列化到同名配置文件的表对象。\n如果此对象名以下划线开始则可以正常读写值不会序列化为配置文件。\n否则不能对此对象直接赋值只能对配置表对象的成员赋值。\n\n配置表可自动自文件加载,退出线程前自动序列化并存入文件。\n仅序列化以字符串、数值为键的元素\n仅序列化值为字符串、数值、buffer 以及定义了 _serialize 元方法的成员。\n循环引用的值转换为 null序列化时忽略成员函数\n!fsys_table.
end intellisense**/

View File

@@ -0,0 +1,333 @@
import win.ui;
/*DSG{{*/
mainForm = win.form(text="cmonitor.install.win";right=403;bottom=395;max=false)
mainForm.add(
btnCheck={cls="button";text="检查安装";left=324;top=351;right=393;bottom=374;z=4};
btnHidePassword={cls="button";text="隐藏密码";left=321;top=201;right=382;bottom=224;z=34};
btnInstall={cls="button";text="安装";left=129;top=349;right=189;bottom=379;z=6};
btnRun={cls="button";text="运行";left=205;top=349;right=265;bottom=379;z=14};
btnSaveConfig={cls="button";text="保存";left=210;top=202;right=248;bottom=225;z=35};
btnShowPassword={cls="button";text="显示密码";left=255;top=202;right=316;bottom=225;z=33};
cbClient={cls="checkbox";text="客户端";left=72;top=17;right=133;bottom=36;tabstop=1;z=19};
cbService={cls="checkbox";text="服务端";left=262;top=17;right=327;bottom=35;tabstop=1;z=20};
editApiClientPassword={cls="edit";left=74;top=199;right=174;bottom=221;edge=1;password=1;tabstop=1;z=25};
editApiClientPort={cls="edit";left=74;top=168;right=174;bottom=190;edge=1;tabstop=1;z=24};
editApiPassword={cls="edit";left=273;top=135;right=373;bottom=157;edge=1;password=1;tabstop=1;z=28};
editApiPort={cls="edit";left=273;top=105;right=373;bottom=127;edge=1;tabstop=1;z=27};
editMachineName={cls="edit";left=74;top=75;right=174;bottom=97;edge=1;tabstop=1;z=21};
editServer={cls="edit";left=74;top=105;right=174;bottom=127;edge=1;tabstop=1;z=22};
editServicePort={cls="edit";left=273;top=168;right=373;bottom=190;edge=1;tabstop=1;z=29};
editShareKey={cls="edit";left=72;top=271;right=172;bottom=290;edge=1;tabstop=1;z=30};
editShareLength={cls="edit";left=72;top=297;right=172;bottom=319;edge=1;tabstop=1;z=31};
editShareSize={cls="edit";left=273;top=295;right=373;bottom=317;edge=1;tabstop=1;z=32};
editWebClientPort={cls="edit";left=74;top=136;right=174;bottom=158;edge=1;tabstop=1;z=23};
editWebPort={cls="edit";left=273;top=75;right=373;bottom=97;edge=1;tabstop=1;z=26};
groupbox={cls="groupbox";text="客户端参数";left=13;top=44;right=196;bottom=236;edge=1;z=9};
groupbox2={cls="groupbox";text="服务端参数";left=200;top=46;right=393;bottom=236;edge=1;z=8};
groupbox3={cls="groupbox";text="共享数据";left=13;top=241;right=393;bottom=332;edge=1;z=2};
static={cls="static";text="机器名";left=24;top=79;right=69;bottom=101;transparent=1;z=13};
static10={cls="static";text="web端口";left=20;top=139;right=70;bottom=164;transparent=1;z=11};
static11={cls="static";text="管理端口";left=17;top=172;right=71;bottom=194;transparent=1;z=3};
static12={cls="static";text="管理密码";left=17;top=203;right=71;bottom=225;transparent=1;z=18};
static13={cls="static";text="管理密码";left=210;top=139;right=264;bottom=161;transparent=1;z=17};
static2={cls="static";text="服务器";left=23;top=108;right=69;bottom=133;transparent=1;z=15};
static3={cls="static";text="web端口";left=213;top=79;right=267;bottom=101;transparent=1;z=7};
static4={cls="static";text="管理端口";left=210;top=109;right=264;bottom=131;transparent=1;z=5};
static5={cls="static";text="服务端口";left=210;top=172;right=266;bottom=194;transparent=1;z=1};
static7={cls="static";text="键名";left=30;top=271;right=61;bottom=293;transparent=1;z=16};
static8={cls="static";text="个数";left=28;top=301;right=58;bottom=323;transparent=1;z=10};
static9={cls="static";text="每项长度";left=208;top=299;right=266;bottom=321;transparent=1;z=12}
)
/*}}*/
import process.mutex;
mainForm.mutex = process.mutex(mainForm.text)
if( mainForm.mutex.conflict ){
import win.ui.atom;
var atom,hwndConflict = win.ui.atom.find(mainForm.text)
if( hwndConflict ) win.setForeground(hwndConflict);
return;
}
mainForm.serviceName = "cmonitor.sas.service";
mainForm.exeName = "cmonitor.sas.service.exe";
import dotNet;
dotNet.import("System");
var defaultConfig = {
"Client": {
"Server": "127.0.0.1:1802",
"Name":string.slice(System.Net.Dns.GetHostName(),1,12),
"GroupId": "snltty",
"ShareMemoryKey": "cmonitor/share",
"ShareMemoryCount": 100,
"ShareMemorySize": 1024,
"ApiPort": 1803,
"ApiPassword": "snltty",
"WebPort": 1804
},
"Common": {
"Modes": {"client","server"}
},
"Server": {
"WebPort": 1800,
"ApiPort": 1801,
"ServicePort": 1802,
"ApiPassword": "snltty"
}
};
import win.image;
hIcon = win.image.loadIconFromFile("/res/favicon.ico",true);
hIcon1 = win.image.loadIconFromFile("/res/favicon1.ico",true);
mainForm.myTray = null;
mainForm.wndproc = function(hwnd,message,wParam,lParam){
//托盘菜单
if(message === 0xACCF ){
//右键
if( lParam === 0x205){
var pt = ::POINT();
::User32.GetCursorPos(pt);
win.setForeground(mainForm.hwnd)
mainForm.popmenu.popup(pt.x,pt.y,true );
}
//左键
if(lParam === 0x0202){
mainForm.show();
}
}
//关闭
if(message === 0x10){
mainForm.show(false);
return 0;
}
}
mainForm.showPopmenu = function(){
import win.util.tray;
import win.ui.menu;
import service;
if(mainForm.myTray != null){
mainForm.myTray.delete();
mainForm.myTray = null;
}
tray = win.util.tray(mainForm);
mainForm.myTray = tray;
if(service.isRunning(mainForm.serviceName))
{
tray.icon = hIcon;
}else
{
tray.icon = hIcon1;
}
tray.tip = mainForm.text;
tray.message = 0xACCF;
mainForm.popmenu=win.ui.popmenu(mainForm);
mainForm.popmenu.add(service.isRunning(mainForm.serviceName) ? '停止服务':'运行服务',function(id){mainForm.installCommand()});
mainForm.popmenu.add(service.isExist(mainForm.serviceName) ? '卸载服务':'安装服务',function(id){mainForm.installCommand()});
mainForm.popmenu.add('退出托盘',function(id){
win.quitMessage();
mainForm.close();
});
}
mainForm.loadConfig = function(){
import web.json;
var configJson = defaultConfig;
try{
jsonText = string.load(io.fullpath("configs/config.json"));
if(jsonText == null || string.len(jsonText) == 0)
{
return;
}
configJson = web.json.parse(jsonText);
}
return configJson;
}
mainForm.saveConfig = function(){
import web.json;
import win.ui;
var result = false;
try{
mainForm.readConfigFromControll();
if(string.len(mainForm.editMachineName.text)>12)
{
win.msgbox("机器名最多12字符");
return;
}
if(string.len(mainForm.editApiClientPassword.text)>16)
{
win.msgbox("管理密码最多16字符");
return;
}
if(string.len(mainForm.editApiPassword.text)>16)
{
win.msgbox("管理密码最多16字符");
return;
}
path = io.fullpath("./configs/config.json");
string.save(path,web.json.stringify(mainForm.configJson,true));
result = true;
}catch(e){
result = false;
}
return result;
}
mainForm.bindConfig2Controll = function(){
mainForm.cbClient.checked = table.indexOf( mainForm.configJson["Common"]["Modes"],"client") >= 1;
mainForm.cbService.checked = table.indexOf( mainForm.configJson["Common"]["Modes"],"server") >= 1;
mainForm.editMachineName.text = mainForm.configJson["Client"]["Name"] || defaultConfig["Client"]["Name"];
mainForm.editServer.text = mainForm.configJson["Client"]["Server"] || defaultConfig["Client"]["Server"];
mainForm.editWebClientPort.text = mainForm.configJson["Client"]["WebPort"] || defaultConfig["Client"]["WebPort"];
mainForm.editApiClientPort.text = mainForm.configJson["Client"]["ApiPort"] || defaultConfig["Client"]["ApiPort"];
mainForm.editApiClientPassword.text = mainForm.configJson["Client"]["ApiPassword"] || defaultConfig["Client"]["ApiPassword"];
mainForm.editShareKey.text = mainForm.configJson["Client"]["ShareMemoryKey"] || defaultConfig["Client"]["ShareMemoryKey"];
mainForm.editShareLength.text = mainForm.configJson["Client"]["ShareMemoryCount"] || defaultConfig["Client"]["ShareMemoryCount"];
mainForm.editShareSize.text = mainForm.configJson["Client"]["ShareMemorySize"] || defaultConfig["Client"]["ShareMemorySize"];
mainForm.editWebPort.text = mainForm.configJson["Server"]["WebPort"] || defaultConfig["Server"]["WebPort"];
mainForm.editApiPort.text = mainForm.configJson["Server"]["ApiPort"] || defaultConfig["Server"]["ApiPort"];
mainForm.editServicePort.text = mainForm.configJson["Server"]["ServicePort"] || defaultConfig["Server"]["ServicePort"];
mainForm.editApiPassword.text = mainForm.configJson["Server"]["ApiPassword"] || defaultConfig["Server"]["ApiPassword"];
}
mainForm.readConfigFromControll = function(){
modes = {};
if(mainForm.cbClient.checked) table.push(modes,"client");
if(mainForm.cbService.checked) table.push(modes,"server");
mainForm.configJson["Common"]["Modes"] = modes;
mainForm.configJson["Client"]["Name"] = mainForm.editMachineName.text;
mainForm.configJson["Client"]["Server"] = mainForm.editServer.text;
mainForm.configJson["Client"]["WebPort"] = tonumber(mainForm.editWebClientPort.text);
mainForm.configJson["Client"]["ApiPort"] = tonumber(mainForm.editApiClientPort.text);
mainForm.configJson["Client"]["ApiPassword"] = mainForm.editApiClientPassword.text;
mainForm.configJson["Client"]["ShareMemoryKey"] = mainForm.editShareKey.text;
mainForm.configJson["Client"]["ShareMemoryCount"] = tonumber(mainForm.editShareLength.text);
mainForm.configJson["Client"]["ShareMemorySize"] = tonumber(mainForm.editShareSize.text);
mainForm.configJson["Server"]["WebPort"] = tonumber(mainForm.editWebPort.text);
mainForm.configJson["Server"]["ApiPort"] = tonumber(mainForm.editApiPort.text);
mainForm.configJson["Server"]["ServicePort"] = tonumber(mainForm.editServicePort.text);
mainForm.configJson["Server"]["ApiPassword"] = mainForm.editApiPassword.text;
}
mainForm.showPassword = function(){
::SendMessageInt(mainForm.editApiClientPassword.hwnd, 0xCC/*_EM_SETPASSWORDCHAR*/, 0, 0);
::SendMessageInt(mainForm.editApiPassword.hwnd, 0xCC/*_EM_SETPASSWORDCHAR*/, 0, 0);
mainForm.editApiClientPassword.setFocus()
mainForm.editApiPassword.setFocus()
}
mainForm.hidePassword = function(){
::SendMessageInt(mainForm.editApiClientPassword.hwnd, 0xCC/*_EM_SETPASSWORDCHAR*/, '*'#, 0);
::SendMessageInt(mainForm.editApiPassword.hwnd, 0xCC/*_EM_SETPASSWORDCHAR*/, '*'#, 0);
mainForm.editApiClientPassword.setFocus()
mainForm.editApiPassword.setFocus()
}
mainForm.btnHidePassword.oncommand = function(){
mainForm.hidePassword();
}
mainForm.btnShowPassword.oncommand = function(){
mainForm.showPassword();
}
mainForm.checkService = function(){
import service;
mainForm.btnInstall.text = service.isExist(mainForm.serviceName) ? "卸载" : "安装";
mainForm.btnRun.text = service.isRunning(mainForm.serviceName) ? "停止" : "运行";
mainForm.showPopmenu();
}
mainForm.btnCheck.oncommand = function(id,event){
mainForm.checkService();
win.msgbox('已检查');
}
mainForm.runCommand = function(id,event){
import thread;
thread.invoke(
function(mainForm){
import service;
import win.ui;
try{
mainForm.saveConfig();
mainForm.btnRun.text = '....';
if(service.isRunning(mainForm.serviceName)){
if(service.stop(mainForm.serviceName,true)){
}else{
win.msgbox("停止失败");
}
}else{
if(service.start(mainForm.serviceName)){
}else{
win.msgbox("运行失败");
}
}
mainForm.checkService();
}catch(e){
}
},mainForm
);
}
mainForm.btnRun.oncommand = function(){
mainForm.runCommand();
}
mainForm.installCommand = function(id,event){
import thread;
thread.invoke(
function(mainForm){
import service;
import win.ui;
try{
mainForm.saveConfig();
mainForm.btnInstall.text = '....';
if(service.isExist(mainForm.serviceName)){
if(service.delete(mainForm.serviceName)){
}else{
win.msgbox("卸载失败");
}
}else{
if(service.create(io.fullpath(mainForm.exeName),mainForm.serviceName,mainForm.serviceName,mainForm.serviceName)){
}else{
win.msgbox("安装失败");
}
}
mainForm.checkService();
}catch(e){
}
},mainForm
);
}
mainForm.btnInstall.oncommand = function(){
mainForm.installCommand();
}
mainForm.btnSaveConfig.oncommand = function(id,event){
if(mainForm.saveConfig()){
win.msgbox('已保存');
}else{
win.msgbox("保存失败~请先停止服务后重新尝试保存");
}
}
mainForm.configJson = mainForm.loadConfig();
mainForm.bindConfig2Controll();
mainForm.checkService();
mainForm.saveConfig();
mainForm.showPopmenu();
mainForm.show();
return win.loopMessage();

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -17,6 +17,5 @@ namespace cmonitor.libs
public void ReadArray(int position, byte[] bytes, int offset, int length);
public void WriteArray(int position, byte[] data, int offset, int length);
public void WritSpan(int position, Span<byte> span);
}
}

View File

@@ -347,14 +347,8 @@ namespace cmonitor.libs
return Update(index, Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(value), addAttri, removeAttri);
}
}
public bool Update(int index, byte[] key, byte[] value,
ShareMemoryAttribute addAttri = ShareMemoryAttribute.None,
ShareMemoryAttribute removeAttri = ShareMemoryAttribute.None)
{
return Update(index, key, value.AsSpan(), addAttri, removeAttri);
}
public bool Update(int index, byte[] key, Span<byte> value,
public bool Update(int index, byte[] key, byte[] value,
ShareMemoryAttribute addAttri = ShareMemoryAttribute.None,
ShareMemoryAttribute removeAttri = ShareMemoryAttribute.None)
{
@@ -401,12 +395,12 @@ namespace cmonitor.libs
if (accessorLocal != null)
{
accessorLocal.WriteInt(valIndex, vallen);
accessorLocal.WritSpan(valIndex + 4, value);
accessorLocal.WriteArray(valIndex + 4, value,0,value.Length);
}
if (accessorGlobal != null)
{
accessorGlobal.WriteInt(valIndex, vallen);
accessorGlobal.WritSpan(valIndex + 4, value);
accessorGlobal.WriteArray(valIndex + 4, value,0,value.Length);
}
IncrementVersion(index);
if (removeAttri > 0)

View File

@@ -60,13 +60,6 @@ namespace cmonitor.libs
Marshal.Copy(bytes, offset, shmPtr + position, length);
}
}
public unsafe void WritSpan(int position, Span<byte> span)
{
if (shmPtr != IntPtr.Zero)
{
span.CopyTo(new Span<byte>((void*)(shmPtr + position), span.Length));
}
}
public byte ReadByte(int position)
{

View File

@@ -60,13 +60,6 @@ namespace cmonitor.libs
Marshal.Copy(bytes, offset, shmPtr + position, length);
}
}
public unsafe void WritSpan(int position, Span<byte> span)
{
if (shmPtr != IntPtr.Zero)
{
span.CopyTo(new Span<byte>((void*)(shmPtr + position), span.Length));
}
}
public byte ReadByte(int position)
{

View File

@@ -57,13 +57,6 @@ namespace cmonitor.libs
accessorLocal.WriteArray(position, data, offset, length);
}
}
public void WritSpan(int position, Span<byte> span)
{
if (accessorLocal != null)
{
accessorLocal.SafeMemoryMappedViewHandle.WriteSpan<byte>((ulong)position, span);
}
}
public byte ReadByte(int position)
{

View File

@@ -0,0 +1,79 @@
using System;
using System.Runtime.InteropServices;
namespace cmonitor.share.lib
{
public sealed class Hook
{
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
private static int hHook = 0;
private const int WH_KEYBOARD_LL = 13;
HookProc KeyBoardHookProcedure;
[StructLayout(LayoutKind.Sequential)]
private class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll")]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string name);
private Func<int, bool> hookAction;
public void Start(Func<int, bool> hookAction = null)
{
this.hookAction = hookAction;
// 安装键盘钩子
if (hHook != 0)
{
return;
}
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(null), 0);
//如果设置钩子失败.
if (hHook == 0)
{
Close();
return;
}
}
public void Close()
{
if (hHook != 0)
{
UnhookWindowsHookEx(hHook);
hHook = 0;
}
}
public int CurrentKeys { get; set; }
public DateTime LastDateTime { get; private set; } = DateTime.Now;
private int KeyBoardHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode >= 0)
{
KeyBoardHookStruct kbh = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));
CurrentKeys = kbh.vkCode;
LastDateTime = DateTime.Now;
if (hookAction != null && hookAction.Invoke(nCode))
{
return 1;
}
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
}

View File

@@ -0,0 +1,19 @@
namespace cmonitor.share.lib
{
//1 attr + 8 version + 4 klen + key + 4 vlen + val
public interface IShareMemory
{
bool Init();
byte ReadByte(int position);
void WriteByte(int position, byte value);
int ReadInt(int position);
void WriteInt(int position, int value);
long ReadInt64(int position);
void WriteInt64(int position, long value);
void ReadArray(int position, byte[] bytes, int offset, int length);
void WriteArray(int position, byte[] data, int offset, int length);
}
}

View File

@@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("cmonitor.share.lib")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("cmonitor.share.lib")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("9a3d0eb7-b775-4be8-a5af-c2bac9e5cfd0")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -0,0 +1,615 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace cmonitor.share.lib
{
/// <summary>
/// InitLocal 和 InitGlobal 都可以初始化,都初始化时,需要启动 StartLoop将InitGlobal同步数据到Local
/// AddAttributeAction 设置状态变化回调,需要启动 Loop监听数据变化
/// </summary>
public sealed class ShareMemory
{
private const int shareMemoryAttributeIndex = 0;
private const int shareMemoryAttributeSize = 1;
private const int shareMemoryVersionSize = 8;
private const int shareMemoryVersionIndex = 1;
private const int shareMemoryHeadSize = shareMemoryAttributeSize + shareMemoryVersionSize;
private string key;
private int length;
private int itemSize;
private byte[] bytes;
private object lockObj = new object();
private long mainVersion = 0;
IShareMemory accessorLocal = null;
IShareMemory accessorGlobal = null;
private readonly ShareMemoryAttribute[] itemAttributes = Array.Empty<ShareMemoryAttribute>();
private readonly long[] itemVersions = Array.Empty<long>();
ConcurrentDictionary<int, List<Action<ShareMemoryAttribute>>> attributeActions = new ConcurrentDictionary<int, List<Action<ShareMemoryAttribute>>>();
private CancellationTokenSource cancellationTokenSource;
private ConcurrentQueue<ShareItemAttributeChanged> attributeChangeds = new ConcurrentQueue<ShareItemAttributeChanged>();
private readonly Dictionary<string, ShareItemInfo> dic = new Dictionary<string, ShareItemInfo>();
public ShareMemory(string key, int length, int itemSize)
{
this.key = key;
this.length = length;
this.itemSize = itemSize;
bytes = new byte[length * itemSize];
itemAttributes = new ShareMemoryAttribute[length];
itemVersions = new long[length];
}
public void InitLocal()
{
try
{
if (accessorLocal == null)
{
accessorLocal = ShareMemoryFactory.Create(key, length, itemSize);
if (accessorLocal.Init() == false)
{
accessorLocal = null;
}
}
}
catch (Exception)
{
}
}
private byte[] gloablBytes;
public void InitGlobal()
{
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && accessorGlobal == null)
{
gloablBytes = new byte[bytes.Length];
accessorGlobal = ShareMemoryFactory.Create($"Global\\{key}", length, itemSize);
if (accessorGlobal.Init() == false)
{
accessorGlobal = null;
}
}
}
catch (Exception)
{
}
}
public void AddAttributeAction(int index, Action<ShareMemoryAttribute> action)
{
if (attributeActions.TryGetValue(index, out List<Action<ShareMemoryAttribute>> actions) == false)
{
actions = new List<Action<ShareMemoryAttribute>>();
attributeActions.TryAdd(index, actions);
}
if (actions.Any(c => c == action) == false)
{
actions.Add(action);
}
}
public void RemoveAttributeAction(int index, Action<ShareMemoryAttribute> action)
{
if (attributeActions.TryGetValue(index, out List<Action<ShareMemoryAttribute>> actions) == false)
{
return;
}
actions.Remove(action);
}
public void StartLoop()
{
cancellationTokenSource?.Cancel();
cancellationTokenSource = new CancellationTokenSource();
Task.Factory.StartNew(async () =>
{
while (cancellationTokenSource.IsCancellationRequested == false)
{
try
{
SyncMemory();
AttributeCallback();
ReadItems();
}
catch (Exception)
{
}
await Task.Delay(10);
}
}, TaskCreationOptions.LongRunning);
Task.Factory.StartNew(async () =>
{
while (cancellationTokenSource.IsCancellationRequested == false)
{
try
{
while (attributeChangeds.TryDequeue(out ShareItemAttributeChanged result))
{
result.Action(result.Attribute);
}
}
catch (Exception)
{
}
await Task.Delay(30);
}
}, TaskCreationOptions.LongRunning);
}
private void AttributeCallback()
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return;
bool allUpdated = false;
for (int index = 0; index < length; index++)
{
ShareMemoryAttribute attribute = ReadAttribute(accessorLocal, index);
bool updated = ReadVersionUpdated(accessorLocal, index);
allUpdated |= updated;
if (updated)
{
itemAttributes[index] &= (~ShareMemoryAttribute.Updated);
attribute |= ShareMemoryAttribute.Updated;
}
if (attribute != itemAttributes[index])
{
itemAttributes[index] = attribute;
if (attributeActions.TryGetValue(index, out List<Action<ShareMemoryAttribute>> actions) && actions.Count > 0)
{
foreach (var action in actions)
{
attributeChangeds.Enqueue(new ShareItemAttributeChanged { Action = action, Attribute = attribute });
}
}
}
}
if (allUpdated)
{
mainVersion++;
}
}
private void SyncMemory()
{
if (accessorGlobal != null && accessorLocal != null)
{
lock (lockObj)
{
accessorGlobal.ReadArray(0, gloablBytes, 0, gloablBytes.Length);
accessorLocal.WriteArray(0, gloablBytes, 0, itemSize);
for (int index = 0; index < length; index++)
{
//检查更新状态
if (ReadVersionUpdated(accessorGlobal, index) == false)
{
continue;
}
int _index = index * itemSize;
int keyLen = BitConverter.ToInt32(gloablBytes, _index + shareMemoryHeadSize);
if (keyLen > 0)
{
accessorLocal.WriteArray(_index, gloablBytes, _index, itemSize);
}
}
}
}
}
private void ReadItems()
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return;
try
{
lock (lockObj)
{
accessor.ReadArray(0, bytes, 0, bytes.Length);
for (int index = 0; index < length; index++)
{
ShareMemoryAttribute attribute = ReadAttribute(accessor, index);
long itemVersion = ReadVersion(accessor, index);
bool skip = (itemVersion <= itemVersions[index] || (attribute & ShareMemoryAttribute.HiddenForList) == ShareMemoryAttribute.HiddenForList);
itemVersions[index] = itemVersion;
if (skip)
{
continue;
}
//key length
int _index = index * itemSize + shareMemoryHeadSize;
int keyLen = BitConverter.ToInt32(bytes, _index);
_index += 4;
if (keyLen > 0 && keyLen + 8 + shareMemoryHeadSize < itemSize)
{
//key
string key = Encoding.UTF8.GetString(bytes, _index, keyLen);
_index += keyLen;
//val length
string val = string.Empty;
int valLen = BitConverter.ToInt32(bytes, _index);
_index += 4;
//value
if (keyLen + 8 + shareMemoryHeadSize + valLen <= itemSize)
{
val = Encoding.UTF8.GetString(bytes, _index, valLen);
}
dic[key] = new ShareItemInfo
{
Index = index,
Value = val
};
}
}
}
}
catch (Exception)
{
}
}
public Dictionary<string, ShareItemInfo> ReadItems(out long version)
{
version = mainVersion;
return dic;
}
public string ReadValueString(int index)
{
byte[] bytes = ReadValueArray(index);
if (bytes.Length == 0) return string.Empty;
return Encoding.UTF8.GetString(bytes);
}
public long ReadValueInt64(int index)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null || index >= length) return 0;
index = index * itemSize + shareMemoryHeadSize;
int keylen = accessor.ReadInt(index);
index += 4 + keylen;
if (keylen == 0) return 0;
int vallen = accessor.ReadInt(index);
index += 4;
if (vallen == 0 || keylen + 8 + shareMemoryHeadSize + vallen > itemSize) return 0;
return accessor.ReadInt64(index);
}
public byte[] ReadValueArray(int index)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null || index >= length) return Array.Empty<byte>();
index = index * itemSize + shareMemoryHeadSize;
int keylen = accessor.ReadInt(index);
index += 4 + keylen;
int vallen = accessor.ReadInt(index);
index += 4;
if (vallen == 0 || keylen + 8 + shareMemoryHeadSize + vallen > itemSize) return Array.Empty<byte>();
byte[] bytes = new byte[vallen];
accessor.ReadArray(index, bytes, 0, bytes.Length);
return bytes;
}
public int ReadValueArray(int index, byte[] bytes)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null || index >= length) return 0;
index = index * itemSize + shareMemoryHeadSize;
int keylen = accessor.ReadInt(index);
index += 4 + keylen;
int vallen = accessor.ReadInt(index);
index += 4;
if (vallen == 0 || keylen + 8 + shareMemoryHeadSize + vallen > itemSize) return 0;
accessor.ReadArray(index, bytes, 0, bytes.Length);
return vallen;
}
public bool Update(int index, string key, string value,
ShareMemoryAttribute addAttri = ShareMemoryAttribute.None,
ShareMemoryAttribute removeAttri = ShareMemoryAttribute.None)
{
if (string.IsNullOrWhiteSpace(key))
{
return Update(index, Array.Empty<byte>(), Encoding.UTF8.GetBytes(value), addAttri, removeAttri);
}
else
{
return Update(index, Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(value), addAttri, removeAttri);
}
}
public bool Update(int index, byte[] key, byte[] value,
ShareMemoryAttribute addAttri = ShareMemoryAttribute.None,
ShareMemoryAttribute removeAttri = ShareMemoryAttribute.None)
{
try
{
if (accessorLocal == null && accessorGlobal == null) return false;
if (index > length) return false;
if (key.Length + 8 + shareMemoryHeadSize + value.Length > itemSize) return false;
lock (lockObj)
{
int valIndex = index * itemSize + shareMemoryHeadSize;
int startIndex = valIndex;
int keylen = key.Length;
int vallen = value.Length;
if (key.Length > 0)
{
if (accessorLocal != null)
{
accessorLocal.WriteInt(valIndex, keylen);
accessorLocal.WriteArray(valIndex + 4, key, 0, key.Length);
}
if (accessorGlobal != null)
{
accessorGlobal.WriteInt(valIndex, keylen);
accessorGlobal.WriteArray(valIndex + 4, key, 0, key.Length);
}
valIndex += 4 + key.Length;
}
else
{
int keyLen = 0;
if (accessorLocal != null)
{
keyLen = accessorLocal.ReadInt(valIndex);
}
if (keyLen == 0 && accessorGlobal != null)
{
keyLen = accessorGlobal.ReadInt(valIndex);
}
valIndex += 4 + keyLen;
}
if (accessorLocal != null)
{
accessorLocal.WriteInt(valIndex, vallen);
accessorLocal.WriteArray(valIndex + 4, value, 0, value.Length);
}
if (accessorGlobal != null)
{
accessorGlobal.WriteInt(valIndex, vallen);
accessorGlobal.WriteArray(valIndex + 4, value, 0, value.Length);
}
IncrementVersion(index);
if (removeAttri > 0)
{
RemoveAttribute(index, removeAttri);
}
if (addAttri > 0)
{
AddAttribute(index, addAttri);
}
}
return true;
}
catch (Exception)
{
}
return false;
}
private ShareMemoryAttribute ReadAttribute(IShareMemory accessor, int index)
{
if (accessor == null || index >= length) return ShareMemoryAttribute.None;
ShareMemoryAttribute stateByte = (ShareMemoryAttribute)accessor.ReadByte(index * itemSize + shareMemoryAttributeIndex);
return stateByte;
}
private bool ReadAttributeEqual(IShareMemory accessor, int index, ShareMemoryAttribute attribute)
{
if (accessor == null || index >= length) return false;
ShareMemoryAttribute attributeByte = (ShareMemoryAttribute)accessor.ReadByte(index * itemSize + shareMemoryAttributeIndex);
return (attributeByte & attribute) == attribute;
}
private void AddAttribute(IShareMemory accessor, int index, ShareMemoryAttribute attribute)
{
if (accessor == null || index >= length) return;
byte attributeValue = accessor.ReadByte(index * itemSize + shareMemoryAttributeIndex);
byte attributeByte = (byte)attribute;
attributeValue |= attributeByte;
accessor.WriteByte(index * itemSize + shareMemoryAttributeIndex, attributeValue);
IncrementVersion(accessor, index);
}
private void RemoveAttribute(IShareMemory accessor, int index, ShareMemoryAttribute attribute)
{
if (accessor == null || index >= length) return;
byte attributeValue = accessor.ReadByte(index * itemSize + shareMemoryAttributeIndex);
byte attributeByte = (byte)attribute;
attributeValue &= (byte)(~attributeByte);
accessor.WriteByte(index * itemSize + shareMemoryAttributeIndex, attributeValue);
IncrementVersion(accessor, index);
}
private DateTime startTime = new DateTime(1970, 1, 1);
private void IncrementVersion(IShareMemory accessor, int index)
{
if (accessor == null || index >= length) return;
long version = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds;
accessor.WriteInt64(index * itemSize + shareMemoryVersionIndex, version);
}
private long ReadVersion(IShareMemory accessor, int index)
{
if (accessor == null || index >= length) return 0;
long version = accessor.ReadInt64(index * itemSize + shareMemoryVersionIndex);
return version;
}
private bool ReadVersionUpdated(IShareMemory accessor, int index)
{
long version = ReadVersion(accessor, index);
return version > itemVersions[index];
}
private bool ReadVersionUpdated(IShareMemory accessor, int index, ref long version)
{
long _version = ReadVersion(accessor, index);
bool res = _version > version;
version = _version;
return res;
}
public ShareMemoryAttribute ReadAttribute(int index)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return ShareMemoryAttribute.None;
return ReadAttribute(accessor, index);
}
public bool ReadAttributeEqual(int index, ShareMemoryAttribute attribute)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return false;
return ReadAttributeEqual(accessor, index, attribute);
}
public void AddAttribute(int index, ShareMemoryAttribute attribute)
{
AddAttribute(accessorLocal, index, attribute);
AddAttribute(accessorGlobal, index, attribute);
}
public void RemoveAttribute(int index, ShareMemoryAttribute attribute)
{
RemoveAttribute(accessorLocal, index, attribute);
RemoveAttribute(accessorGlobal, index, attribute);
}
public void IncrementVersion(int index)
{
IncrementVersion(accessorLocal, index);
IncrementVersion(accessorGlobal, index);
}
public long ReadVersion(int index)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return 0;
return ReadVersion(accessor, index);
}
public bool ReadVersionUpdated(int index)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return false;
return ReadVersionUpdated(accessor, index);
}
public bool ReadVersionUpdated(int index, ref long version)
{
IShareMemory accessor = accessorLocal ?? accessorGlobal;
if (accessor == null) return false;
return ReadVersionUpdated(accessor, index, ref version);
}
public void ListenClose(int shareIndex)
{
Task.Run(async () =>
{
while (true)
{
if (ReadAttributeEqual(shareIndex, ShareMemoryAttribute.Closed))
{
RemoveAttribute(shareIndex, ShareMemoryAttribute.Running);
RemoveAttribute(shareIndex, ShareMemoryAttribute.Running);
Environment.Exit(0);
Process.GetCurrentProcess().Kill();
}
await Task.Delay(30);
}
});
}
}
public enum ShareMemoryAttribute : byte
{
None = 0,
Updated = 0b0000_0001,
Closed = 0b0000_0010,
Running = 0b0000_0100,
HiddenForList = 0b0000_1000,
Error = 0b0001_0000,
All = 0b1111_1111
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ShareItem
{
public byte Attr;
public ulong Version;
public ulong Time;
public byte KeyLength;
/// <summary>
/// 255长度
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte[] Key;
public byte ValLength;
/// <summary>
/// 9966长度
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9966)]
public byte[] Value;
}
public sealed class ShareItemAttributeChanged
{
public Action<ShareMemoryAttribute> Action { get; set; }
public ShareMemoryAttribute Attribute { get; set; }
}
public sealed partial class ShareItemInfo
{
/// <summary>
/// 内存下标
/// </summary>
public int Index { get; set; }
/// <summary>
/// 内存值
/// </summary>
public string Value { get; set; }
}
}

View File

@@ -0,0 +1,17 @@
using System.Runtime.InteropServices;
namespace cmonitor.share.lib
{
public static class ShareMemoryFactory
{
public static IShareMemory Create(string key, int length, int itemSize)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return new ShareMemoryWindows(key, length, itemSize);
}
return new ShareMemoryWindows(key, length, itemSize);
}
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
namespace cmonitor.share.lib
{
public sealed class ShareMemoryWindows : IShareMemory
{
private string key;
private int length;
private int itemSize;
MemoryMappedFile mmfLocal = null;
MemoryMappedViewAccessor accessorLocal = null;
public ShareMemoryWindows(string key, int length, int itemSize)
{
this.key = key;
this.length = length;
this.itemSize = itemSize;
}
public bool Init()
{
try
{
if (accessorLocal == null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
mmfLocal = MemoryMappedFile.CreateOrOpen($"{key}", length * itemSize, MemoryMappedFileAccess.ReadWriteExecute, MemoryMappedFileOptions.None, HandleInheritability.None);
SetSecurityInfoByHandle(mmfLocal.SafeMemoryMappedFileHandle, 1, 4, null, null, null, null);
accessorLocal = mmfLocal.CreateViewAccessor();
return true;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return false;
}
[DllImport("advapi32.dll", EntryPoint = "SetSecurityInfo", CallingConvention = CallingConvention.Winapi, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
static extern uint SetSecurityInfoByHandle(SafeHandle handle, uint objectType, uint securityInformation, byte[] owner, byte[] group, byte[] dacl, byte[] sacl);
public void ReadArray(int position, byte[] bytes, int offset, int length)
{
if (accessorLocal != null)
{
accessorLocal.ReadArray(position, bytes, offset, bytes.Length);
}
}
public void WriteArray(int position, byte[] data, int offset, int length)
{
if (accessorLocal != null)
{
accessorLocal.WriteArray(position, data, offset, length);
}
}
public byte ReadByte(int position)
{
if (accessorLocal != null)
{
return accessorLocal.ReadByte(position);
}
return 0;
}
public void WriteByte(int position, byte value)
{
if (accessorLocal != null)
{
accessorLocal.Write(position, value);
}
}
public int ReadInt(int position)
{
if (accessorLocal != null)
{
return accessorLocal.ReadInt32(position);
}
return 0;
}
public void WriteInt(int position, int value)
{
if (accessorLocal != null)
{
accessorLocal.Write(position, value);
}
}
public long ReadInt64(int position)
{
if (accessorLocal != null)
{
return accessorLocal.ReadInt64(position);
}
return 0;
}
public void WriteInt64(int position, long value)
{
if (accessorLocal != null)
{
accessorLocal.Write(position, value);
}
}
}
}

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>cmonitor.share.lib</RootNamespace>
<AssemblyName>cmonitor.share.lib</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Hook.cs" />
<Compile Include="IShareMemory.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ShareMemory.cs" />
<Compile Include="ShareMemoryFactory.cs" />
<Compile Include="ShareMemoryWindows.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@@ -11,7 +11,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.sas.service", "cmo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.libs", "cmonitor.libs\cmonitor.libs.csproj", "{9080618D-367F-474E-AACA-A3C2F294448F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.install.win", "cmonitor.install.win\cmonitor.install.win.csproj", "{4EB9FFB0-B05C-4C4E-BD44-796715E47585}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.install.win1", "cmonitor.install.win1\cmonitor.install.win1.csproj", "{4EB9FFB0-B05C-4C4E-BD44-796715E47585}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.llock.win", "cmonitor.llock.win\cmonitor.llock.win.csproj", "{6F2602B3-221D-475D-B643-D54987605644}"
EndProject
@@ -29,6 +29,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmonitor.killer", "cmonitor
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.tests", "cmonitor.tests\cmonitor.tests.csproj", "{04AA3054-5350-4D8B-97F6-31495AE0609D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cmonitor.share.lib", "cmonitor.share.lib\cmonitor.share.lib.csproj", "{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -195,6 +197,18 @@ Global
{04AA3054-5350-4D8B-97F6-31495AE0609D}.Release|x64.Build.0 = Release|Any CPU
{04AA3054-5350-4D8B-97F6-31495AE0609D}.Release|x86.ActiveCfg = Release|Any CPU
{04AA3054-5350-4D8B-97F6-31495AE0609D}.Release|x86.Build.0 = Release|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Debug|x64.ActiveCfg = Debug|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Debug|x64.Build.0 = Debug|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Debug|x86.ActiveCfg = Debug|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Debug|x86.Build.0 = Debug|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Release|Any CPU.Build.0 = Release|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Release|x64.ActiveCfg = Release|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Release|x64.Build.0 = Release|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Release|x86.ActiveCfg = Release|Any CPU
{9A3D0EB7-B775-4BE8-A5AF-C2BAC9E5CFD0}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="cmonitor.viewer.client.win" libEmbed="true" icon="C:\Users\snltty\Desktop\cmonitor\cmonitor\favicon.ico" ui="win" output="cmonitor.viewer.client.win.exe" CompanyName="snltty" FileDescription="cmonitor.viewer.client.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="cmonitor.viewer.client.win" InternalName="cmonitor.viewer.client.win" FileVersion="0.0.0.43" ProductVersion="0.0.0.43" publishDir="/dist/" dstrip="false">
<project ver="10" name="cmonitor.viewer.client.win" libEmbed="true" icon="..\cmonitor\favicon.ico" ui="win" output="cmonitor.viewer.client.win.exe" CompanyName="snltty" FileDescription="cmonitor.viewer.client.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="cmonitor.viewer.client.win" InternalName="cmonitor.viewer.client.win" FileVersion="0.0.0.44" ProductVersion="0.0.0.44" publishDir="/dist/" dstrip="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true"/>
<folder name="资源文件" path="res" embed="true" local="false" ignored="false"/>
<folder name="窗体文件" path="dlg" comment="目录" embed="true"/>
</project>

View File

@@ -46,7 +46,7 @@ namespace cmonitor.viewer.server.win
this.ShowInTaskbar = false;
this.WindowState = FormWindowState.Minimized;
this.Visible = false;
FireWallHelper.Write(Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName));
FireWallHelper.Write(Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName),"./plugins/viewer/");
#endif
CheckRunning();

View File

@@ -36,7 +36,7 @@
<script>
import { computed, onMounted, reactive, watch } from 'vue';
import { initWebsocket, subWebsocketState } from '../apis/request'
import { initWebsocket, subWebsocketState,closeWebsocket } from '../apis/request'
import { getConfig,getSignInfo } from '../apis/signin'
import { useRoute, useRouter } from 'vue-router';
import { injectGlobalData } from '../provide';
@@ -47,11 +47,11 @@ export default {
const route = useRoute();
const router = useRouter();
const queryCache = JSON.parse(localStorage.getItem('api-cache') || JSON.stringify({api:`${window.location.hostname}:1805`,psd:'snltty',groupid:'snltty'}));
const queryCache = JSON.parse(localStorage.getItem('api-cache') || JSON.stringify({api:`${window.location.hostname}:1804`,psd:'snltty',groupid:'snltty'}));
const state = reactive({
api:queryCache.api,
psd:queryCache.psd,
groupid: queryCache.groupid,
groupid:globalData.value.groupid || queryCache.groupid,
showPort: false
});
const showPort = computed(() => globalData.value.connected == false && state.showPort);
@@ -62,6 +62,7 @@ export default {
queryCache.psd = state.psd;
queryCache.groupid = state.groupid;
localStorage.setItem('api-cache',JSON.stringify(queryCache));
closeWebsocket();
initWebsocket(`ws://${state.api}`,state.psd);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -19,7 +19,7 @@
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
</div>
<div style="padding-top:1rem ;">
秘钥 : <el-input type="password" v-model="state.apipsd" style="width:70%"></el-input>
秘钥 : <el-input type="password" v-model="state.psd" style="width:70%"></el-input>
</div>
<div style="padding-top:1rem ;">
分组 : <el-input v-model="state.groupid" style="width:70%"></el-input>
@@ -37,27 +37,24 @@ import { computed, onMounted, reactive, watch } from 'vue';
import { initWebsocket, subWebsocketState,closeWebsocket } from '../apis/request'
import { getRules, addName } from '../apis/rule'
import { getConfig } from '../apis/signin'
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { injectGlobalData } from './provide';
export default {
setup() {
const globalData = injectGlobalData();
const route = useRoute();
const router = useRouter();
const queryCache = JSON.parse(localStorage.getItem('api-cache') || JSON.stringify({username:'',api:`${window.location.hostname}:1801`,psd:'snltty',groupid:'snltty'}));
const state = reactive({
api: route.query.api ? `${window.location.hostname}:${route.query.api}` : (localStorage.getItem('api') || `${window.location.hostname}:1801`),
apipsd: route.query.apipsd ? `${route.query.apipsd}` : (localStorage.getItem('apipsd') || `snltty`),
groupid: route.query.groupid ? `${route.query.groupid}` : (localStorage.getItem('groupid') || `snltty`),
api:queryCache.api,
psd:queryCache.psd,
groupid: globalData.value.groupid || queryCache.groupid,
usernames: [],
username: globalData.value.username || localStorage.getItem('username') || '',
username: globalData.value.username || queryCache.username,
showPort: false
});
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
localStorage.setItem('groupid', state.groupid);
globalData.value.username = state.username;
globalData.value.groupid = state.groupid;
const showSelectUsername = computed(() => !!!globalData.value.username && globalData.value.connected);
const showPort = computed(() => globalData.value.connected == false && state.showPort);
@@ -89,20 +86,22 @@ export default {
state.usernames = Object.keys(res.Data);
}).catch(() => { });
}
const saveCache = ()=>{
globalData.value.username = state.username;
globalData.value.groupid = state.groupid;
queryCache.api = state.api;
queryCache.psd = state.psd;
queryCache.groupid = state.groupid;
}
const handleConnect = () => {
saveCache();
closeWebsocket();
//initWebsocket(`ws://hk.cmonitor.snltty.com:1801`,state.apipsd);
initWebsocket(`ws://${state.api}`,state.apipsd);
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
localStorage.setItem('groupid', state.groupid);
//initWebsocket(`ws://hk.cmonitor.snltty.com:1801`,state.psd);
initWebsocket(`ws://${state.api}`,state.psd);
}
const handleUsername = () => {
globalData.value.username = state.username || '';
globalData.value.groupid = state.groupid || '';
localStorage.setItem('username', globalData.value.username);
//localStorage.setItem('groupid', globalData.value.groupid);
//localStorage.setItem('apipsd', globalData.value.apipsd);
saveCache();
document.title = `班长-${globalData.value.username}`
}
const handleChange = (value) => {
@@ -114,8 +113,7 @@ export default {
}
onMounted(() => {
handleUsername();
handleConnect();
_getRules();
_getConfig();
@@ -123,6 +121,15 @@ export default {
setTimeout(() => { state.showPort = true; }, 100);
subWebsocketState((state) => { if (state) globalData.value.updateRuleFlag = Date.now(); });
router.isReady().then(()=>{
state.api = route.query.api ?`${window.location.hostname}:${route.query.api}` : state.api;
state.psd = route.query.psd || state.psd;
state.groupid = route.query.groupid || state.groupid;
state.username = route.query.username || state.username;
handleUsername();
handleConnect();
});
});
return {

View File

@@ -57,10 +57,10 @@ namespace cmonitor.config
public int ShareMemoryCount { get; set; } = 100;
public int ShareMemorySize { get; set; } = 1024;
public int ApiPort { get; set; } = 1805;
public int ApiPort { get; set; } = 1803;
public string ApiPassword { get; set; } = "snltty";
public int WebPort { get; set; } = 1806;
public int WebPort { get; set; } = 1804;
public string WebRoot { get; set; } = "./web-client/";

View File

@@ -27,6 +27,9 @@
<ItemGroup>
<Content Include="favicon.ico" />
<Content Include="plugins\wallpaper\bg.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="favicon.ico" />
@@ -60,6 +63,9 @@
<EmbeddedResource Remove="Properties\**" />
<None Remove="Properties\**" />
</ItemGroup>
<ItemGroup>
<None Remove="plugins\wallpaper\bg.jpg" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ManagedNativeWifi" Version="2.5.0" />

View File

@@ -1,5 +1,4 @@
using cmonitor.plugins.tunnel.messenger;
using cmonitor.plugins.tunnel.server;
using cmonitor.server;
using common.libs.extends;
using MemoryPack;
@@ -42,21 +41,28 @@ namespace cmonitor.plugins.tunnel.compact
public async Task<TunnelCompactIPEndPoint> GetUdpExternalIPAsync(IPEndPoint server)
{
return null;
/*
using UdpClient udpClient = new UdpClient();
udpClient.Client.Reuse(true);
for (int i = 0; i < 10; i++)
{
try
{
await udpClient.SendAsync(new byte[1] { 0 }, server);
var result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromSeconds(5));
UdpReceiveResult result = await udpClient.ReceiveAsync().WaitAsync(TimeSpan.FromSeconds(500));
if (result.Buffer.Length == 0)
{
return null;
}
IPEndPoint remoteEP = IPEndPoint.Parse(result.Buffer.AsSpan().GetString());
TunnelExternalIPInfo tunnelExternalIPInfo = MemoryPackSerializer.Deserialize<TunnelExternalIPInfo>(result.Buffer);
return new TunnelCompactIPEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = tunnelExternalIPInfo.ExternalIP };
*/
return new TunnelCompactIPEndPoint { Local = udpClient.Client.LocalEndPoint as IPEndPoint, Remote = remoteEP };
}
catch (Exception)
{
}
}
return null;
}
}
}

View File

@@ -13,7 +13,7 @@ namespace cmonitor.plugins.tunnel.server
public Action<object, Socket> OnTcpConnected { get; set; } = (state, socket) => { };
public Action<object, UdpClient> OnUdpConnected { get; set; } = (state, udpClient) => { };
private ConcurrentDictionary<int, SocketAsyncEventArgs> acceptBinds = new ConcurrentDictionary<int, SocketAsyncEventArgs>();
private ConcurrentDictionary<int, AsyncUserToken> acceptBinds = new ConcurrentDictionary<int, AsyncUserToken>();
public void Bind(IPEndPoint local, object state)
{
@@ -36,7 +36,7 @@ namespace cmonitor.plugins.tunnel.server
SocketFlags = SocketFlags.None,
};
token.Saea = acceptEventArg;
acceptBinds.AddOrUpdate(local.Port, acceptEventArg, (a, b) => acceptEventArg);
acceptBinds.AddOrUpdate(local.Port, token, (a, b) => token);
acceptEventArg.Completed += IO_Completed;
StartAccept(acceptEventArg);
@@ -44,7 +44,7 @@ namespace cmonitor.plugins.tunnel.server
socketUdp = new UdpClient();
socketUdp.Client.ReuseBind(new IPEndPoint(IPAddress.Any, local.Port));
socketUdp.Client.EnableBroadcast = true;
//socketUdp.Client.EnableBroadcast = true;
socketUdp.Client.WindowsUdpBug();
IAsyncResult result = socketUdp.BeginReceive(ReceiveCallbackUdp, state);
}
@@ -55,7 +55,7 @@ namespace cmonitor.plugins.tunnel.server
}
public void RemoveBind(int localPort)
{
if (acceptBinds.TryRemove(localPort, out SocketAsyncEventArgs saea))
if (acceptBinds.TryRemove(localPort, out AsyncUserToken saea))
{
CloseClientSocket(saea);
}
@@ -115,26 +115,21 @@ namespace cmonitor.plugins.tunnel.server
}
}
private void CloseClientSocket(SocketAsyncEventArgs e)
private void CloseClientSocket(AsyncUserToken token)
{
if (e == null || e.UserToken == null) return;
if (token == null) return;
AsyncUserToken token = e.UserToken as AsyncUserToken;
Socket socket = token.SourceSocket;
if (socket != null)
{
token.Clear();
e.Dispose();
if (acceptBinds.TryRemove(token.LocalPort, out SocketAsyncEventArgs saea1))
if (acceptBinds.TryRemove(token.LocalPort, out AsyncUserToken tk))
{
CloseClientSocket(saea1);
CloseClientSocket(tk);
}
}
}
public delegate Task OnTunnelData(AsyncUserToken token, Memory<byte> data);
public delegate Task OnTunnelUdpData(AsyncUserUdpToken token, IPEndPoint remote, Memory<byte> data);
public sealed class AsyncUserToken
{
public Socket SourceSocket { get; set; }
@@ -147,20 +142,7 @@ namespace cmonitor.plugins.tunnel.server
SourceSocket?.SafeClose();
SourceSocket = null;
GC.Collect();
}
}
public sealed class AsyncUserUdpToken
{
public UdpClient SourceSocket { get; set; }
public object State { get; set; }
public OnTunnelUdpData OnData { get; set; }
public void Clear()
{
SourceSocket?.Close();
SourceSocket = null;
Saea?.Dispose();
GC.Collect();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 KiB

View File

@@ -14,6 +14,13 @@ namespace cmonitor.plugins.wallpaper.report
{
if (info.Open)
{
/*
string filename = Process.GetCurrentProcess().MainModule.FileName;
string dir = Path.GetDirectoryName(filename);
string file = Path.Combine(dir, "./plugins/wallpaper/bg.jpg");
User32.SystemParametersInfo(User32.SPI_SETDESKWALLPAPER, 0, file, User32.SPIF_UPDATEINIFILE | User32.SPIF_SENDCHANGE);
*/
CommandHelper.Windows(string.Empty, new string[] {
$"start ./plugins/wallpaper/cmonitor.wallpaper.win.exe \"{info.ImgUrl}\" {config.Data.Client.ShareMemoryKey} {config.Data.Client.ShareMemoryCount} {config.Data.Client.ShareMemorySize} {(int)ShareMemoryIndexs.Keyboard} {(int)ShareMemoryIndexs.Wallpaper}"
},false);

View File

@@ -70,21 +70,7 @@ namespace cmonitor.server
byte[] bytes = socketUdp.EndReceive(result, ref endPoint);
try
{
IPHostEntry entry = Dns.GetHostEntry(Dns.GetHostName());
List<IPAddress> ips = entry.AddressList.Where(c => c.AddressFamily == AddressFamily.InterNetwork).Distinct().ToList();
Dictionary<IPAddress, BroadcastEndpointInfo> dic = new Dictionary<IPAddress, BroadcastEndpointInfo>();
foreach (var item in ips)
{
dic.Add(item, new BroadcastEndpointInfo
{
Web = config.Data.Server.WebPort,
Api = config.Data.Server.ApiPort,
Service = config.Data.Server.ServicePort
});
}
await socketUdp.SendAsync(dic.ToJson().ToBytes(), endPoint);
await socketUdp.SendAsync(endPoint.ToString().ToBytes(), endPoint);
}
catch (Exception)
{

View File

@@ -30,7 +30,7 @@ namespace common.libs
});
}
private static void Windows(string fileName,string distPatth)
private static void Windows(string fileName,string distPath)
{
try
{
@@ -52,11 +52,11 @@ cmd /c netsh advfirewall firewall add rule name=""{fileName}"" dir=in action=all
cmd /c netsh advfirewall firewall add rule name=""{fileName}"" dir=in action=allow program=""%CD%\{fileName}.exe"" protocol=tcp enable=yes profile=private
cmd /c netsh advfirewall firewall add rule name=""{fileName}"" dir=in action=allow program=""%CD%\{fileName}.exe"" protocol=udp enable=yes profile=private
:end";
if(Directory.Exists(distPatth) == false)
if(Directory.Exists(distPath) == false)
{
Directory.CreateDirectory(distPatth);
Directory.CreateDirectory(distPath);
}
string firewall = Path.Join(distPatth, "firewall.bat");
string firewall = Path.Join(distPath, "firewall.bat");
System.IO.File.WriteAllText(firewall, content);
CommandHelper.Execute(firewall, string.Empty, new string[0]);

View File

@@ -13,7 +13,6 @@ call npm run build
cd ../
dotnet publish ./cmonitor.sas.service -c release -f net8.0 -o public/extends/ -r win-x64 -p:PublishTrimmed=true -p:TrimMode=partial --self-contained true -p:TieredPGO=true -p:DebugType=none -p:DebugSymbols=false -p:PublishSingleFile=true -p:EnableCompressionInSingleFile=true -p:DebuggerSupport=false -p:EnableUnsafeBinaryFormatterSerialization=false -p:EnableUnsafeUTF7Encoding=false -p:HttpActivityPropagationSupport=false -p:InvariantGlobalization=true -p:MetadataUpdaterSupport=false -p:UseSystemResourceKeys=true
dotnet publish ./cmonitor.install.win -c release -f net8.0-windows -r win-x64 -o public/extends/ -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.snatch.win -c release -f net8.0-windows -r win-x64 -o public/extends/plugins/snatch -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.llock.win -c release -f net8.0-windows -r win-x64 -o public/extends/plugins/llock -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.message.win -c release -f net8.0-windows -r win-x64 -o public/extends/plugins/message -p:PublishSingleFile=true --self-contained false

View File

@@ -16,6 +16,7 @@ dotnet publish ./cmonitor -c release -f net8.0 -r linux-x64 -o ./public/publish/
for %%r in (win-x64,win-x64-any) do (
echo F|xcopy "public\\extends\\*" "public\\publish\\%%r\\*" /s /f /h /y
echo F|xcopy "cmonitor.viewer.client.win\\dist\\*" "public\\publish\\%%r\\plugins\\viewer\\*" /s /f /h /y
echo F|xcopy "cmonitor.install.win\\dist\\*" "public\\publish\\%%r\\*" /s /f /h /y
)
for %%r in (linux-x64,linux-x64-any) do (