桌面共享使用打洞或者服务器中继进行代理

This commit is contained in:
少年郎秃头呀
2024-05-07 18:37:23 +08:00
parent fe61072d0a
commit b997c970eb
55 changed files with 2366 additions and 2618 deletions

View File

@@ -1,60 +0,0 @@
namespace cmonitor.clipboard.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));
textBox1 = new TextBox();
SuspendLayout();
//
// textBox1
//
textBox1.Location = new Point(12, 12);
textBox1.Multiline = true;
textBox1.Name = "textBox1";
textBox1.Size = new Size(261, 287);
textBox1.TabIndex = 0;
//
// MainForm
//
AutoScaleDimensions = new SizeF(7F, 17F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(285, 450);
Controls.Add(textBox1);
Icon = (Icon)resources.GetObject("$this.Icon");
Name = "MainForm";
Text = "剪贴板";
ResumeLayout(false);
PerformLayout();
}
#endregion
private TextBox textBox1;
}
}

View File

@@ -1,138 +0,0 @@
using System.Runtime.InteropServices;
namespace cmonitor.clipboard.win
{
public partial class MainForm : Form
{
protected override CreateParams CreateParams
{
get
{
const int WS_EX_APPWINDOW = 0x40000;
const int WS_EX_TOOLWINDOW = 0x80;
CreateParams cp = base.CreateParams;
cp.ExStyle &= (~WS_EX_APPWINDOW);
cp.ExStyle |= WS_EX_TOOLWINDOW;
return cp;
}
}
private IntPtr nextClipboardViewer;
const int WM_DRAWCLIPBOARD = 0x0308;
const uint CF_TEXT = 1;
const uint CF_HDROP = 15;
public MainForm()
{
StartPosition = FormStartPosition.CenterScreen;
MaximizeBox = false;
MinimizeBox = false;
InitializeComponent();
nextClipboardViewer = SetClipboardViewer(this.Handle);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DRAWCLIPBOARD)
{
OnClipboardChanged();
}
}
private void OnClipboardChanged()
{
if (OpenClipboard(IntPtr.Zero))
{
uint format = 0;
while ((format = EnumClipboardFormats(format)) != 0)
{
switch (format)
{
case CF_TEXT:
HandleTextData();
break;
case CF_HDROP:
HandleFileListData();
break;
}
}
CloseClipboard();
}
}
private void HandleTextData()
{
IntPtr clipboardData = GetClipboardData(CF_TEXT);
if (clipboardData != IntPtr.Zero)
{
string text = Marshal.PtrToStringAnsi(clipboardData);
this.Invoke(() =>
{
textBox1.Text = text;
});
}
}
private void HandleFileListData()
{
IntPtr clipboardData = GetClipboardData(CF_HDROP);
if (clipboardData != IntPtr.Zero)
{
IntPtr fileDropHandle = Marshal.ReadIntPtr(clipboardData);
uint fileCount = DragQueryFile(fileDropHandle, 0xFFFFFFFF, null, 0);
List<string> fileList = new List<string>();
for (uint i = 0; i < fileCount; i++)
{
uint bufferSize = DragQueryFile(fileDropHandle, i, null, 0) + 1;
char[] fileName = new char[bufferSize];
DragQueryFile(fileDropHandle, i, fileName, bufferSize);
string filePath = new string(fileName);
fileList.Add(filePath);
}
DragFinish(fileDropHandle);
this.Invoke(() =>
{
textBox1.Text = string.Join("\r\n", fileList);
});
}
}
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", SetLastError = true)]
static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("user32.dll", SetLastError = true)]
static extern bool IsClipboardFormatAvailable(uint format);
[DllImport("user32.dll", SetLastError = true)]
static extern uint EnumClipboardFormats(uint format);
[DllImport("shell32.dll")]
static extern uint DragQueryFile(IntPtr hDrop, uint iFile, char[] lpszFile, uint cch);
[DllImport("shell32.dll")]
static extern void DragFinish(IntPtr hDrop);
[DllImport("user32.dll", SetLastError = true)]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError = true)]
static extern bool CloseClipboard();
[DllImport("kernel32.dll")]
static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
static extern bool GlobalUnlock(IntPtr hMem);
}
}

View File

@@ -1,400 +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="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAAAAAAAEAIABdQAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKoZgAAQCRJ
REFUeNrtnXd8XMW5sJ/ZIq16lyzZsi1Z7sYFY9xxwwUINU7hkpBCQsKFG0joBGKZllySmwspBEJyk5BQ
EhIwfDHYuGKMK+7dlmXZkmVZVu9b5/tjJFuWzqrualfSPP6dn9Y7Z8+Zc3bnPe+88xbQaDQajUbT/xCB
7oDGx2RffCUu/pXN3hOAvNjatI+8+J5s/P+lVnlxn8uPr+kDaAEQzGQ3/hWEAjYkNiAMsDVuUQgSkEQD
4Y1bWIvXoUBI42YBrI1/QxpfAzgBB+BqfO1q/L8DsAP1QF3j1vx1FYJSJNVAQ2NbA9CAiQbM2JHAk4G+
kRpvaAEQKLIvvjIhMWPGCsTiIRlIBlIa/yYDiUA8ENtsi0MNcAGYGo8lmm3+QDbbADyNr+uBcqCi2VYG
lADFwHkExUiKMVGMoAInTkJwk4yHSuDhQH0R/RstAHqKZwCw4iYeSAASEAxCMgIYDmRxaVA3bTbAHOiu
dxM3l7SDpq0MyUkEJ4DjSAqAEkyUYqIccPJUoLvdP9ACwNc8i7qrLqxIwoAkYDQwBhgFDAEGAmlAJPo7
kEANUAicBU4DR4FDwBEkFxA0oKYm2gbhY/r7j883ZAPqSZ2KepKPAsYBVwAZQDQQgZp7a9rHBdQCVcAp
4ACCA0iOATnAOcCthUH30QKgKzwNgBkPscBQYCowBfWkz0LN1/W99S0SKEUJgKPADgTbgdMIKgA3Pwl0
F3sf+kfaUX4CCEwIBgETUIN+NupJH4myqmt6Dgdq6nAQ2ARsR7APOIvEo7WDjqEFQFtkA4JwYBCSq5HM
RzARyARiAt09zWVUAieBvcB6BDuBAiR1Whh4RwuA5mQDM4HPMeFkIB5mA/OBeUA6l9bNNcGNE8gHNgDr
EHyKpBC1bKkNic3QAqCJxwAbSQgmI7kBuAb1pI8MdNc03aIGyAU+Af4N7AEuaCGg6L8CIPviKwtqae4G
4EZgGnrQ91VqgC0oQbASwRkcuAgHfhzorgWG/icAnkctLoURjeRK4GbgOpQ1PzTQ3dP0CHYgD/gQwfvA
HuqpIhp4ItBd61n6jwDIRtnpncQjmQ/cAcxCudlq+i8XgM3Am8A6lEtzv7ET9A8BsAwwkYhkIXAnavku
ItDd0gQVNShB8BcEa/BQyvJAd8n/9G0BkA2oJ/x1qIE/HT3wNW1TA2wFXkewijWU8G3g24Huln/omwJg
OSAIw8Ni4PvAXPT8XtM5GoCNwKtIViOo74vTgr4lAJTKFgpchYd7EFyHcsvVaLpKKZIPMfEKgl1I7CwL
dJd8R98QAE+hIs9TyEQ98e9ARdtpNL7iLPAGglc4xikyUZGfvZzeLwCyAYhCchOCB4BJ9P4Yek1w4gZ2
A/+L4N9AdW/XBnqvAHgasGDCyXgk9wNL0Q48mp6hGvgnghexcRAHnt6awKT3CYDsi69igTuQ3I9gGJfS
Ymk0PYEHOAH8CngDFYzU6/wHepeq/DRgwgSMRPn03Y9gAL1RkGl6OwK1xDwP5Up+BChjLmrtoJfQewSA
SrVlxcMtSF4CFqFj8DWBxwqMB2agvApPMhdPbxECvUMALAMkKXh4CKVkDUM/9TXBg0CtOs1DJXI9wlxq
e4MQCO5BlH3x1ShUXt1b0Hn1NMGNC/gnsAzBcTwQzC7FwasBPIOy8nuYBfwWuDao+6vRKEyoDNCTgWPY
KGAuKjVJEBKcA2o5ILHiZinwEmqOFdzaikZzCQEMBmbipgg4wbzgtAsEnwDIBtR6/g9QekB6oLuk0XSR
RGAO4EZwgHk4gk0IBJcAeBoQRCN5AngEVSlHo+nNRKJWCKyY2Mk8HME0HQgeAbAMEMQjWQ7ciypuqdH0
BUKAKUiigB3MoyFYNIHgEADZgCAJ+CnwXXTorqbvYUUZBuOQbGcudXwS6C4FgwDIBlQF3F+gknbo1Nua
vooZmIggFcGWYPAVCKwAUIk74oHngG+g1/g1fR8zqmZkLIItzKM+kEIgcAIgG4AolBj4LvrJr+k/mFBC
IALYzNzArQ4ERgBkA8o6+gRwH3rOr+l/mFE1Jk2BXB3oeQGQDShV/wfAw2hrv6b/YgUmIanBxM5ABBH1
rABoSuLh4UsoJx+9zq/p74QCE5CcwspR5iJ7UhPoOQGgIvrAzTUIXgIG9dxlajRBTSQwEcke3JxhAT0W
O9BzWXRMgIkxwH+jwnk1Gs0lhiP5GWZGIXvupD2jAWQDMAD4HwQL0IE9Go0Rg4BUYBNzqekJe4D/BUA2
oFwhHwG+g87dp9F4Q6ByXzhRy4NufwsB/w7Gp1HV2FUij+/5/XwaTe/HBHwPwc3sxO+1B/w7ID3AJMYC
jwMJ/r0UjabPkIDkcaYwGpd/T+S/KcAlN9+fAQv9exkaTZ8jFUkMJjb6M3rQPwJgOWDGhIe7UZ5+2sdf
o+ksgiygGCs7mYNf0o37Zwqg1vsnouL6bf66PxpNHycc+C+cTPTX0qDvNYBsAGJQnn5z/XRjNJr+QgIQ
hmA987D7WgvwrQaQffHVrY2bRqPpPrchuRUHPk8x7lsBIADBSOB+VKijRqPpPpHA/YQw3NcH9t0UQFn9
Q5A8gnr6a28/jcZ3pAANmNjkSwch32kAHkAyBbgdPfg1Gl9jAv4DyWTcvj1o93kWsBCO5B5UjTSNRuN7
BiH5PibCfFWGvPsCIBtVDc3NIuC6wN0bjaZfcAOqMja+EAK+mgIkAt8H4gNzTzSafkMCaqz5xLXeVwLg
BlQJJI1G43/m4iNtu3sCQFn+k4CvoT3+NJqewgZ8HUFCd/0Cui4AslEuv5JrgemBviMaTT9jBpJFuFFh
912ku1OAOFQ1H+30o9H0LJHA1zETh6frB+muAFgAzA70ndBo+inXIFnQnQN0TQBkAxAN3IF++vdOZLNN
01uJAG5HENVVW0DnPfZ+CtQDZuYh+QdqCVATbDQf3AKsZisWswWBwGwyYxZmROPX75ZuJBK3dOP2uHG6
nXjcHvV50WzTBCMlwJdoyhaQ3bkPdz5Rhx0wYUFyG3rwBwfNn+ICYm2xDIweSIItgYHRA0mKTGJw9GBS
IlKwmCxEhUQRbYvGJJQCWOOoweF2UOuopdpRzdmqs5yqOEVJXQll9WUU1RRRWF2Iw+W47DyaoCARlXNz
M3Q+gVhXM/UMA5YE+sr7PRIswkJkWCRpUWmMTRrLrMGzmDRgEokRicTaYkkISyDEHNLpQ7s8LuqcdVTa
KympK+HIhSNsL9jOoQuHOFJyhPL6cuqd9WpnLQwCzXUIfguc6OwHO/fVZV989RBqMqBTffUkTWq9gFBL
KKOTRnPTiJu4euDVTE6bTFxYHFaT9eKT3de4PC7qnfXklOew+9xutuZvZd2pdZyuOI2UjWqIFgaBwAk8
BvwS6NQ0oHNf1zIAUhG8DVwT6KvuV0iIDIkkMz6TGekzWDp6KZlxmQyJHeK3Ad8e9a56jpYcZdPpTXx0
4iP2nd9HcU0xnu6sS2m6yicIbgfONY7TDtFxAfA04AYENwD/RHv+9QxSGfCmpU/ja1d8jRtH3EhKZErA
Br03ah217Di7gzcPvsnKEyspqi5SWoHWCHqKOuCLSFZhBn7SsQ91PCHIHEBgAh5Ae/75Hwnh1nBmDJnB
8nnLeWLWE8weMpuo0CiECL5RFWIOISMugwUZC5g2aBoWs4XiumJq7DWB7lp/wQpUIFiNRHY0YUjH5/Dq
gZOOR6v+fkWCWZgZkTSCe6++l/8Y9x/EhXWvirpbqqU9p8eJx+NRy35SUu+qJ9QcisVkQQiByWTCLMwX
3+sKESERzBs6j6kDp7K9YDt/O/A3/nn4n1Q1VGltwP/MxcRAIL+jH+jYV5J98dU3gJdR6Yo1vkZCSmQK
Xxv/Ne6efDdZ8VldUvWr7dUU1hSSX5nP6crT5JbnUlBVwNmqs1TaK6myV2F32XFLNyZhIiokihBzCJGh
kcSExjAqcRRDY4cyOHowiRGJpMekkxKegtVs7XRf6px1rD65mhc+e4HPCz/H5XZpQeA/alGhwn8DOmQM
7NhXobyMIpC8gor80/gYq7AyL3MeP5r+I+YNndeppTuH20FRTRHHS4/z2ZnP2HZ2G2erzpJflU9FfUWX
+iMQhFpDiQ+LJz0mnbFJY5k6cCpjksYwJmkMcba4Tk1Fjpce55+H/8lru14jrzxPV4n0H3/GxL1I6jpi
DOy4BiAYheRjID3QV9inkBAXFsddV97Fj6b/iNTI1A5/tMZRw/aC7fz7+L9Zn7ee3LJc6l31uN3uS99s
d5+2jUuPQgisFisR1giuTLuSO8ffyaTUSYxOHN3h6YJbutlwagMPr3mYvUV7A3G3+wN5CJYgOeY7DUAd
6JvA71HGBo0PEFIwMmkk2XOzuXnkzdgs7S+suDwu8iryeOPAG6zNXcuJkhOcrznfs+66EsJCwkiPTmfO
0Dl8ecyXmTZoGpEhkR36+P7z+/nltl/y9v63sXvsPdTpfoMTwV14+GtH4gPaXwX4H8CCGScPAhMDfXV9
BgnXDruWX1//axYNW4TV1LZcdUs3R0uO8qsdv+KJdU+w4sgKTpefptZZq9TpnpxXCyWISmtL2XNuD6tz
V3Oi7AQWk4WB0QPbnb6kRKYwY/AMbFYbB84fUB6F2i7gK8xANSY+YF77qwHtC4CZgIsMVLGPlEBfXV/A
bDLzxTFf5JeLfsn4lPEXg3KMkEgKqwv59fZf89i6x1h5fCUldSVIIQMfpNN4/lpHLfuK9rEmdw05ZTkk
RySTEJ7QptEwwhrBzMEzSYtK4+CFg5TVlWkh4EsEHwEV3RMAfwZKAZiP4NtA553KNZdodOq5a9JdPL/g
eTLiMtrcvdZRy/pT63nw4wd5fd/rlNaW4hEe38zrQR2nRdRgd6hz1LG3aC8f5nzI2aqzjEseR4wtxuv+
ZmFmbPJYMuMyOVp6lKLqIi0EfEMEsA04ymJgnfcd2xYAE1GRf4JvoZN+dpswaxj3T7ufZ+Y9Q1JEktf9
pJQcLTnKY+se42ef/YyjF44q91ofDHyzycyoxFEszFrInCFzGJs8lmhbNPXOemodtd07R6NGUOOoYde5
Xew6t4tIayRZ8VleDYVmYWZY/DBGJY7iaMlRzlad1UKg+4QCpzGzEReetrSAtgXAXEClH34UGBToq+rN
2Cw27p96P09d8xRRoVFe93N5XGw6vYl7P7qXVTmrfDo/TolM4dFZj7JszjLunnw3N4y4gS+M+AJfHP1F
JqdNptJeSV5FHh7ZfV9+ieR0xWnWnlpLjbOGUYmjiA6NNtzXJExkxGUwJnkMe8/v5Vz1OS0Euo9AsgKo
654AUMU+fwiEBfqKeitmYeb2K27nZ9f+jKgQ74O/2lHNr7b/ikfXPMqxkmO+m+NLSItO43df+B3fmfQd
kiOSL67hm4QJm8XG8IThXD3was5Wn+XIhSO+uXABDa4GtuZvJa8ij+HxwxkQOcCr/0BaVBrD4oaxo3AH
pXWlWgh0jwjgfaCouxrALcDN7e6rMUbCDSNu4KcLfsqAyAFedyupK+G5Tc/xiy2/oLy+3Kc/fovZwiMz
H+E7k77TpmdhfFg8wxOG8+mZT7lQe8FnfZBIjlw4wtazWxmTPIYhMUMMhYBJmBgcO5iEsAR2FO6guqFa
C4GuYwb2Abu6JgCyAXX77wGuCvTV9EokLM5azK+v/zXD4od53e1s9VkeW/sYf977Z98viXlgxuAZPDv/
Wa8qeHMGRA7A5XGx6uQq394LAedrzrOzcCcJEQkMTxhuaBcwCzOjk0YTExrDxryNONwOLQS6hhkoBv4f
c8GbEPAuAOYBgjTgP9Hef51HwqikUby45EXGp4z3utuZyjP8cNUPeevAW7ikf/zkbxtzG18a86UO7y+E
4MMTH1Jt9/ETWMCFugt8fvZzYkJjGJs81qsQGJs8lip7FbvO7cItfVgOt3/RgOBDBDXeBIB3fVAtD2UB
WYG+il6HhPCQcB6e8TDTBk3zutu56nPcs/Ie/nX4X357ytmsNkYljOrUZ5IjkhkYNdBvt+d05Wme2/wc
7xx+x6vB0Wax8eD0B7ku6zqdubjrDEMyrK37ZywAltN000cByYG+it6GEIJ7rrqHr477qtd9SutL+enm
n7ImZ41fVVynx0mFvaJTn/FIj9+fuqcrTvPspmf5+OTHXvdJjUrlidlPkBWfpYVA10gBRiHBm1uwsQBQ
eedC0K6/nUfCNUOu4b6r7yPcahw1Xeus5eef/Zw/7P4DTun0a3fcLjfHSo6puXQHKasvo7C60O+36njJ
cR5d+yifnvnU6z5T0qbw+OzHiQmL0UKga0xEEOLt3rUVlGkDxqPpFEkRSTw661GGxg41bHd5XLy0/SVe
2v7Spay6fuZIyREVMNRBdpzdcSnAyJ8I2F+0nwdXP8iJMuOEtkIIlo5Zym2jbuuRe9UHGU8b6fuMBYBa
f04Chga6972NpWOWMnfoXK/tG/I28Jvtv6HB2dAz1m0T7CzcyR/2/AGXp/208UdLjvKH3X+4lOXX3wj4
vPBzntv0HBUNFYa7RIdGc9eku8hK0FOBLjAUQaK335rxKsBcQIUBfRWd/LNjNFr9X1j4glcDWm55Lo+s
eYQDRQd6NCGG9EjOVJ4hKSKJ4fHDvQbpnK06y4OrH2Rj3sYeX3o7WXaSOFsc09KnGQZHDYoeRIOrgY2n
N/rEU7EfIYFNwAmjlYC2BMCtwHXo3C0dwmK28MTsJ7hp5E2G7bXOWrI3ZvPu4XdVJF9PIqCioYJNpzfh
8DjIjMvELMxYzVY8eKhsqOST05/w8JqH+fjkx8gAPGYdbgdHy44yJW0Kg2MGt74EIRgUPYjN+ZsprCrU
vgEdxwIcALYYCYDWtzEbUILhNeBbge59r0DC9PTp/P1Lfyc92thl4u1Db/OtFd+iwdUQ0H6GWEIYnjCc
cUnjyIjLUAOv5ChbC7ZSXudbD8TOYhImlmQt4U83/4nkCOPFp7/s+wv3rLynx+wnfYT/A74LeFpmCWrt
haF+AAlIhgS6170CqTLhfmfyd7wO/lPlp/jfrf/bc/N+bwj1pD10/hCHig5d9n7Acwuglh/X5K7hvaPv
8b3J3zPcZ1HmImYMmsG6k+u0btpxBiNIAC60bGh9C5UDUAKQFuhe9xbGpYxTDisGuD1u3jz4JnvO7Qn4
ALuIQH3zTVuw9Atwupy8tus1jpceN2xPjUrl5pE3E2oNDXRXexNpSBKMZnaXC4BLWUQTAP+5gvUhQiwh
fGPCN7wm8zxRdoK/7P0LTrd/1/vbRXZiCyQC9hfv5/e7fu91unTLqFsYlTQq8H3tPaQhiTe6X5dPAcw0
lf8aCHQsw2N/xgNjB4xlUeYir7u8eeBNTpadDNxT1qMMlJG2SOJscUSFRpESkUJyRDLJEcnYXXYKqgso
qyujvKGckroSapw11Nnr1FJgANRsp8vJimMruH3c7UxOm9yqfVDMIO644g72Fe0L0E3tdcRgIg038Czw
5KWGywWABEIROBhOUCmGQYqA2UNme430O1h8kH8c/odaturBjL1NfUuOSGZy2mRmDJrBnKFzVASesGA1
W7Ga1ObBg9PlxCmduDwuqu3V7Cnaw6qcVewq3MXhksPYnfaLx+yp+5pXkcf7x95nUuqkViHMAsGizEW8
EvcKuWW5+pfaPgJJFiYErsv1gNYCwIEFGB7oHvcGYmwx3DjiRsM2j/Tw7pF3OV5yvGfTdVvCmDJoCl8d
91UmDZjEqMRRxNpi2/xYqPnSfDopPInMuExuGnET+VX57D63m5UnVrLy+Eou1FzoMY3A7Xaz4ugKvjLu
K4xNGtuqPSs+iwkpE8gt1QKggwxH6fiXeYMZJWqzAMM6csR+jYSMuAwmDJhg2FxQVcB7R9/rmQq5jYU7
pg6aytcmfI2vjP0KCeEJbWYbbg+r2UpmXCaZcZksyVrCraNu5U97/8S63HW+DxM2QiivxPW56w0FQERI
BF8Y8QU+yvkosEurvYcs1Ni+TABcLs/NgIloIDHQvQ12hEnw1XFfJTHc+Faty113Ka2XP5HKS+7Ja57k
raVvce+Ue0kMT+zW4G9JZEgkN428iT/f/Gf+ettfWZy1GFMPqAJOt5N3j76r0oMZMHPwTFIiUrQxsGMk
YmDXu/xb9ACSFHT+v7aRMDRmKAsyFhgOtDpnHevy1vnfWcWj3I9/f9PvWTZ3mdcAJF8RY4vh5pE38+qN
r3LXlXepqYOfB9++on3sOrfLsG1IzBAWDVvUySP2WyIwqOvRWgB4GICu/ts2jer/qETjRBs5ZTlsyd/i
1y6YhZn5w+bz2o2vsWTYEsyi/ZSNHumhyl5FQVUBx0uPs/vcbvad38ep8lOU1JWoKkMdYEjMEF5Y+AL3
T7tfeez5SwgIKG8oZ23uWsPgJJvFxuS0yZhM2iOoA4QDrZJSXm4DUA+zFLQAaBsTjEse57UW3vaC7Zwq
P+U39d8kTHxl3Ff42bU/8+p92ITT46SsroytBVtZm7uWM5VnKKsvo8peRVlDGVaTlYSwBBLCE4i1xTI5
bTILMhYwKmEU4dZwrxl8Y22xLJuzjCuSr+CJdU+QX5nvn+v1wNaCrRTWFBoGWU0cMJFB0YM4U3FGGwPb
pgMCQJGKFgBtYrPYmDPEuE6K0+1kw+kNTUlV/MINI25oM+oQ1NN++9nt/P3g31mTu4aCygKqGqpUY4t+
5ZXnXXyKv3vkXV6KeImJAybyrYnfYvGwxV7rGIRbw7l93O3Y3XYe+vghVYrc19dsUsVE8yryDK83IzZD
CYByLQDaIYw2BcDTqDJgcbr+X3tEWCMYnTjasK3eVe+7vPotkXBFyhVkz8luc/AfLz3Oyztf5v2j75NX
kafebHL/9Ubj4HF5XBRWFVJYVci2gm0szFzINyd+k/kZ8w2LfppNZr405kvklOXw4tYXaXD73iJfba8m
pyyHmekzW7UlhCcwJmkMW874d8rVBzABKVQDzwE/vvSmwgPEEQ4kdf7Y/QgJ4weM91raa9e5Xf5JpyWV
B9wvFv2CK1Ov9LKLZPXJ1dzx7h38etuv1eDvSpBP42fK6sv4+8G/c8e7d/D8p8+rsl0GRIdG8+jMR7ll
9C1+sQdIKdlWsM0woYlZmJk5eCYhFl22sgMkE4Ot+UJgy2eCDYgLdC+DGqmMYN7y/e0r2ueXqjbh1nAe
mv4Q8zPmG7Y3uBp4++Db3P3B3Xxe8LlvioiCEgR1Zfx8y895fP3jnKo4Zbhbk01gevp0vwiBwxcOU+8y
XlVJi0zzWntQcxlxeAhr/v20FAChQExnjtgfSY9O9yoACqoKcLt8nFFXquIeX5/wdcMfusvj4g97/sB9
K+/jTOUZ33vrCbW0+bd9f+ORNY+ocxgwMnEkd0++myhblM+FQF5FHrnluYZtKZEpWgB0jBjUGL+IkQYQ
G+heBjUmvDr/VNur1eDw8dM/MjSSH0z9AfFh8Ybt/zryL5755BnK6sv8agiTSFYcWcHj6x6nuLa4VbtA
cP3w61mYudDn565x1FBQVWDYFh8WT2pUqnYIap9YWqT4MxIAWgPwhlSqrjeHmxpnDedrfZxN1wNLspZ4
TTS6p2gPyzYso7i6uEes4C7pYsXRFby882VDF9zkiGS+c+V3iAuL892AFFBlr+Jk+UnD5jBLmF8LmfQh
YmhHAISiNYA2iQqJ8pquqspepdbDfYWE+PB47rnqHsOqwmX1ZTy1/imOlR7r0bDdOkcdv9n5G1afXG3Y
PjN9JouzFvv0nC6PSy0zGhAdGq2csrQG0B6xeJ0CqHXrKHQW4DYJtYR6dQCqddRyoc53VXUBJqZOZMrA
KYZtq3JWsSFvQ8/fBAGltaX8bufvDFN5R4dGc/3w6wkP8aE7iUfVUbS77a2aTMJkuESpaUU4LeIBLgkA
AUji0ZnWvCNV6Kw3AVDvqu9UBZ6OsDBzoeH5zlSe4eWdL1PnqAvMvRCw+cxmr1rANYOvUV6KPnwqOzwO
3J7WBlaLyeL1O9FchoDLMwNdrgFANNqfqk1CzCFEWCMM26oaqnxXUEPCgKgBzBo8yzDgaG/RXnYW7gzo
t1Vrr+WN/W9Q2VDZqi0lMoVp6dO6cFTv1DvrvRY38eayrLkMAUQ1/81c7ggkiOj0IfsZZpPZ65JTlaPK
dzn1JYxIGMGIhBGtmpweJx/lfITD5Vtto9MI5fh0rPRYqyabxcb4ZN9Wlqt11HrVsGxmPXPtAAKIoFld
lUsCwAxIItEaQJsIITCbjCPvfFpOywRXpV1laHAsry9n0+lNgb4VIOBczTl2nN1h2Dw+ZTwJEQm+mQYI
NcXypgGEWXUEewcQQGTzSX7L+X4EWgC0iQmT19BbX6qhFpOFAZEDDNu2FmxV1XGCAOmRrM9bb7gkODR2
qO/sAFJpFd60rx6rZdi7EbQI9DO1aNQaQDu4pdurGhodEu2zTDxmk9mr48/hC4epdFQGzTeVV5GH09M6
7Xl0aDTRodE+O0+ENcKrtb/GURPo29AbaDXGjTQATRs43U6vPulmk9lng9JqsjIoapBhW0VDBdIdPE+8
sroySmpLWr1vs9iwWXw3N08ITyDM0lrVd3vcVNmrAn0beguXjXEjDUDTBm7p9lrkI8Qc4jMNwGKyGEYc
Ot1OQzfcQOJwOyitb523L8wS5lMNINQcamh/sbvtlNSXdOGI/ZLLpvktNQBtSWmLxtp6dU7jtfe4sDgi
QnyjRJmEyXDw2N12ah0dS93VU9jddsPEnVazyjbkE5kolaGvZY0AUPN/t8cdNFOiIOeyMd5SA2g/sVw/
p9peTXGd8RM40hrJgIgBPjF6SSkNDWsWkyXovN6sJqvXJ73dZffZKoA3/wtvGojGEGvz/7QUpzqmsh2q
HdVeVfDI0EgVleYDnB4n52rOtXo/xByitIzgMQFgs9hIjmy9XNngalCqeXf7KiHSFklWfJZhs8Pt8Bon
oGmFmTamAFoAtIVQP2ojzzeAOFscGbEZPhmcbo+bC7WtqjljEibibfFBpe5aTBbDYKXyhnLK68t90tfE
8EQmDpho2FbjqFGJSoLongQxl43xlgJATwHaweV2cbTkqKFDitVsJSHcN3Nel3R5VWsz4jKwhQSP59uA
yAGG6nmDs8HrikmnkBATGsPgmMGGzbnluXoVoOO0KQC0BtAB8irzDA2BAsHVA68mxhbTbS3A6XZ6TYAx
I32GSkoSJNOAOUPmYLO2FkiV9koq7T7wVxCQlZDl1fZx6MIhnwdh9VkkFmNXYG0E7DAnSk9Q7ag2bBub
NFYlw+guHnUeu6t1+GtmXCaTBkwK9G0AIDwknNlDZht6Rx6+cFglSPWBAJg+aLpXAbD73G5cLlcnD9pv
0VOAbiFUKK63/HQDowZ6NVZ19jy7z+3mQPGBVk1h1jBmpM8I/JzXowqkGKVIb3A1sCpnFfWO7k8BLCaL
YYFQgMqGSs5UnenkEfsxAgsm70bAIFEqg5tqRzVb87catkWGRKrB2V0EFNYUGkbaCQQ3jrxRDYoAfmNW
i5WlY5YyJHZIq7Z6Vz17ivZ0/yQSxiSNYVi8ccHqguoCztf4OA1bP6K5AJCAj9PZ9k3cbjeHLhzCIz2t
2oQQTE6dTExY91MrOl1OVuesNvQHGJs0lqVjlwauLp6EyamTueOKOwybDxYfNFzG7Mp5pqRNUasrBhwv
OU5+lZ/KkvVNXDR7bJgMGjXtIdUP3Ft67KvSrmJCygTwdPK4Bmwp2HKpuk8LvjH+GwHTAkItodw54U7S
otJatTndTt49/K5P6iNEhEawIHOBYRSgw+1g7am11NqDyzMyqJG4vBkBQQuAjiHgVMUpw/k5QGpUKgsy
FmC2dNOkIuBU+Sn+uv+vhsuOQ2KH8PCMh0mJSOlZIeCBxVmL+eKYLxo27z63m/ePve8TB6CB0QOZPXi2
YXNJXUlw5EXoTQhcbeUD0FOAjiCgvK6cNSfXGC4/CQQLMhcQZ+t+amyPx8NbB97iYPHBVm0mYeKr477K
PVffg8XcQyu4HpiaPpXnFzxvmKzE6Xby6q5XfVMdWcLcIXO9lmHbfGazX6sw91Eue5JcnhJMagHQGTac
2uDVLXh8ynimD5re/ZM0ahuv7nrVMCOu1Wzlvqvv4+sTvo7VZO3CCTqBhMFxg3lqzlNerfKf5X/GRzkf
+eR0kbZIrh9+PaHm0FZtHunhk9OfBF1gVC/AiwCQrRs1bSCUB9onpz8xbI4KieLOCXeqIBkfqMIrj69k
8+nNhs0JYQk8P/957pxwp+Fg8cnlSsGk1En85vrfcMPwGwz3qbRX8tru1yiqLur+U9kD84bOY0HmAsPm
3PJctuTrisCdRuLGbWQENCMRWgB0hjpnHety1xk+mQEWZCxgztA53T+RgPyqfJZ/stxwWRCUO+4vF/+S
Fxa+oEJwfWUTkGqqsTBrIa/f+jpfGP4Fw91cHhev7HyFfx3+l09U8ojQCO6efLfXdN97ivaoe6HV/85y
2Ri/ZKWaiwBuACYGuoe9ieK6YmYPma1y37UgzBqGw+3g49yPDVNmdZbC6kKq7FXMGjzLsDhpqCWUiQMm
kh6dTrm9nAs1F3C6nF0bJBIswsLg2ME8MO0Bls1ZxvCE4V7zHq48vpIn1j+hAqV88PS/YcQNPDDtAUIt
rTWaOmcdz3/6PPuK9mkB0FkEOzHxARvVI6K5AABYCEzpynH7JULlB4gPj2f+0PmGySqSIpI4WHyQE6Un
uv1j9UgPh4oPYTaZmTV4lmF2HIvJwviU8SzOWszg2MGU28s5V3NO+Sy01Aqa+tPifbPZzPCE4Xxtwtd4
8boXuXnkzW26N2/N38o9H97jm8KoEqLDosmem82EARMMd9mQt4H/2fo/Kh5DC4DOshn4iI3qPy01gLmA
D9zY+hfna85zbea1hlbx6NBoYmwxrM1dqwxW3RUCHg+HLhwiMjSSMUljDOf8QgiiQqK4KvUqlmQtYX7G
fDLiMvA0/rNarJhMJqSUhFhCiA6NJio0itSoVJYMX8IDUx/goZkP8eWxXyYlIsVQsDWxrWAbD615iH3n
fPc0vm30bfxw+g+xmlsbNasd1Tz/6fNsL9iuB3/X2AisaxIAzdeOJFBDU5VATccQcLriNP849A9GJo40
tMQvyFjA0rFLeXnnyz45X1ldGY98/Agny06ybM4yr9mDhRAMjB7IwOiBLM5aTJW9itzyXM7XnqesrozS
+lIiQyJJjkwm0hpJWlQaQ2OHdijjkNOjvBSfWPcEB84f8Fnar6GxQ/mvqf9lOMUBJXBW5azywcn6Jc3H
ONBcADQAYdQ1lrbRAqATuDwu3jzwJreNvs0waYXNYuN7k7/HtoJt7C7c7ZPoOLvbzu8+/x0Xai/w+KzH
uSLlijY/YhImYm2xXJl6Zbevt8HVwOv7XufpTU9ztvKsz34tYdYwfjTjR0wdONWwvd5Vz1/2/sUnHob9
FAlcFsd+aQowDzAxEbgefXs7h1DZb0LMISwatshQZU6JTMFmsbHu1DpV0ssHd9gjPRwtOcreor2kR6cz
KHqQ18IZvsAjPZyqOMWL21/kmU3PUFrrw4Eo4Qsjv8CT1zzp9em/MW8jP9/yc1UQVf9Cu4IHWAHsam0D
mA/AGOAmdIXgziNVZNrktMleA1dGJIyguK6YXed2+ayGoEd6KKgqYMOpDZyuPE2MLYbUyFSv5cu6Sl5F
Hq/vf52HP36Yfx/7N/XOep8O/mHxw3hpyUteQ6kr7ZU8/cnT7CjYoQd/15HAO0j20+i+culXMgcQDAOW
ogVA5xHKQFXRUMH8jPmG6cGtZitjk8eyv3g/p8p868JaZa/i88LPWXdqHWerz5IckUxUSBQWk6VLJcsk
kgZnA2cqz/DPI//kx+t/zP/t/j+Ka4tx48MU3FKlU392/rMsyVri1eD48s6Xefnzl3FJ7arSDTwI/obk
WGsBMBcwkQx8DZ0YpMvkVuQSY4th+qDphj/mWFssWfFZ7D63m6IaH3jMNdF4nMr6SnYU7GBlzko2nd5E
QVUB9c56wq3hRIVGtXsYu8vOoQuH+PDEh/xmx294YcsLvH3gbU5XnFbn8PHTN9QSygPTH+Deq+81tPqD
KoX+yNpHKK4p1k//7uFC8AqSM00C4NLtXAbAJASfAO3/UjTGNKqzf7r5T8weMtvLLpKPTnzEQx8/xJEL
R/zzo242w0gITyArPov0mHTSo9OJD4snPiye1KhUquxVVDZUUlxbTH5VPkU1RZwqP8WZyjOX0pH5adBZ
zVbum3Ify+YuIybUOH9CWX0Z3/7g27x/9H3/dKJ/UYl61O8lW71xyWKkvuSGxp20AOgqAk6WneS/P/tv
shKySI1MNdhFsGjYIh6Z+QgPffyQf6zazY5XWl9KaX4p2/O3g0mtCJiFGbPJjEd68EgPbulGeuSlRWA/
PO2bYxZmbh55M09e86TXwQ/wzuF3+OiEb4KLNFSgxvhFWnoCRgO3AskdPqSmNY0RfG7p5poh1xj6BpiE
idFJo4kKjWLH2R2+Nap56VPT8SUSj/Tg8rhwS/elzEY9MPCbWDhsIb9Y9AsGRQ/yus+GUxt4dO2jqvCo
Vv19wRngDaDCyBMQVN2wG4HBnTuupiUej4fDFw6TEJ7A5NTJhoY4i8nCpAGTiA2LZU/RHq+ZhvsMUl3z
nRPv5OcLf95m8tTc8lzuX3W/9vf3LceAt4Ga1gJgHiCwAtcBIwLd016PUAa1nLIcRiaOJDMu01AImE1m
xqeMJys+i2Mlx/p0gstQSyj3Xn0vz89/vs0SavmV+dy/6n7W5q7ts/ciQOwD/gk0GPsBmBBIrgUmdP7Y
mlYIKK0rZX/xfsanjPda2cZisjA8YTijE0dzsOSgiqfvS/6YEmJsMfxg6g946pqniLXFet21rL6MH6//
MW8feLvvXH/wsA0TKwBXawGwENiOkzRmAT5IZaMBQKhgoSYh4G3OaxImhsQOYWHmQirtleSU5ah0Y719
EEjIjM/k+fnP859T/tNrfD+oMN8XPnuB3+/6vV7v9w9rcPERJmgtANYB/wGofAALA93TPoWAc1Xn2Hd+
H9MGTSMlMsV4NyGIC4tjRvoMbFYbR0qOUGOv6Z1CQKpKxreMvoWXlrzE9cOvbzPIqN5Zz693/JoXPnvB
N/UENS2RwApMbGlaAoSWDj9zARgGLKZFHXFNNxFQWFXIrnO7uCLlijat3xEhEcxMn8mk1EnkV+WTX5mP
lLJ3CIJG/4Nh8cN4bPZjPHnNk2TFZ7XpjVjRUMELW17ghc9e8EnItMaQOpQBcH/T0x+MBcAA1EpAeMeO
q+kwjUJgb9FexiWPY2D0QK8DwyRMZMZmsiBzAcPjh1NYU8iF2gvBLQgkRNuiWZK1hJ8v+jlfGvMlQ5fo
5hRWF/Lkhid55fNXdIIP/1KJ4HUEud4FgFoJiAS+BHS/tI2mNQLOVZ/j83OfkxSRxIiEEYaFNUFNCWJC
Y5icNpm5Q+YSbg2nqLaIivoKFdcVLINFqiKhS7KW8JM5P+HhmQ+3+9QHFWB030f38daBt3C6u5i6TNNR
SoHfA8VtCwD1NdwBJAa6x30WAedrz/PpmU8JtYQyKnEUNoutjd0FieGJzB48m3kZ84ixxVDrqqW8rhy3
x4eBOZ3Fo6z712ZeyzPznuGBaQ8wOW1yhzIT7y3ayw9X/5APT3yoIiP14Pc35zDxG0zUsuHSm5ff9mxA
OQOtRacG8z8SQiwhfGXsV3hwxoOqnFiHPibJr8hnxbEVrDu1ji35WyirL8Pj9vjPk0+qTQiBLcTG0Nih
3DTiJqanT2fe0Hkq/XkHqHXU8u7Rd3lx24u+SY6i6SibUcb9huZGQCMBYAX+CHw90D3uT0wbNI2nrnmK
+Rnz29QGmiORVNmrOFZyjLW5a9l8ZjMnSk9QUF1Ag7NFQdHODLSWSUJNZqJDo8mIy+DK1Cv58pgvMyZ5
DEnhSR1KH9ZETlkOv9z6S/66/6+9d3Wj9/IX4LuAsz0BIIAngacD3eN+hVRRe9+d/F3unXJvl5J6VNur
yS3P5VjpMfYW7WXf+X3kV+ZzvvY8Da4GHG7HxeAfj/QogyLK4GgxWzAJEyZhItQcSnxYPENjh3JV6lWM
Sx5HUkQSIxNHkh6d3maSUCMcbgfvH3ufn23+GXvO7QluQ2bf5cfY+Cl2ZGPkL9Dya1hOk3Hpq8Cb6K+p
Z5EqRHZc8ji+OfGb3D7udq918drD5XFR76yn3lVPaX0pBZUFnK48Tb2rnjpnHQ2uBmqdqqxWVEgUKREp
hFvDsVlsDIkdwpCYIYRaQomwRnQ5zZjb4+Z42XFe2/Uar+97XaUQ06lmAoEEvoLkHczATy41XD7A/wAU
ADALWImKDtT0NI22gWszr+X+qfd7LQQSrLg9bo6XHuftQ2/zzqF3OFZyDI8vaqVrukoFkhuALSy/vOFy
HfMDmnwBIlDJQfVKQCAQ4JZuTpSeYO2pteSW52ISJhLDEwmzhgW6d15xSzXwf7vztzy54UlWHFmhfBdE
T9Yu1xiQi+DPCEqbLwHC5XUBmlMKnAVGBbrn/RoBRTVF/HH3H3nv6HuMSRrDtyd+m3lD5zEweqBfMwB3
htK6UnLKc1iVs4q3D75NTmkOLo+rx3ILaNrlLGpMt6ItAXA60L3WKCSS0tpSPq35lO0F2xmdOJprM69l
SdYSZg6eSZglMFpBg6uBNw68wTuH3mHb2W1U2atUViE98ION04RThkEN29Zm5o3AXCTq6a+ChDWBp3FQ
uaWb8zXn2Za/jfV56xmXPI7hCcMD0qWSuhKWb1zO2pNrL1VI1gM/2HABb+NkS3PrfxNt6ZAHgWogNtBX
oGmBACklaVFphpWIQD2ddxTuwGa2kRmXidVkxWwyYxZmTCYTAoFJmC6mB5NSXkwPVu+sp6KhgryKPMob
yhmRMIJJAya1OkdSRBIzBs9g/an1gb4jGu/UAIe8NRoLACXFjyC1AAhaJCzKXMSAyAGGzRvzNvL9f3+f
WmctcbY4om3RJEckExMaQ2RIJCGmECJCInC4HWpZ0N1Alb2KKnsV+ZX51DpqaXA1YHfbuXvy3UxImdBq
/d8szCzJWsKf9/6ZgsoC/fQPTiqBo94ajQWAMtqWAqeAdDTBhYTkyGTmZ8z36pSz7tQ6TperXP4ltSXd
Ot3qnNXcNekuxiWPa9U2Pnk8YxLHUFChBUCQkosXAyC0Pb+vB/YHuvcaY2YNmcW0QdMM23LKclhzcs3l
WX67sR0tOcrqk6sNzxUVGsXSMUsJsXbcJVjTo+zHRIM34WwsAAQgcaKSCGqCjBBLCDeNuMmrT8CGvA0c
LD7osyeylJI1J9dc9BxsyeKsxYxMGImPyh1qfIcE9uLC6e1Rb/z2Mpp+PEeB84G+Ck0zJGTEZjAvY55h
s91t572j76kwYR+y69wutuRvMWwbEDmAuUPnagEQfBQhOY4AnjLewfsUQKl/J4GcQF+FphkClo5dysDo
gYbNuwt3s/fcXp+fs7SulE/yPrlURKQZIeYQlmQtITEyUQuB4OIkgpNtaYLeBYCK/y6iDQuipoeRkBaZ
xuLMxYZZhFweFyuOrfBt0dGmU0vJu0feJbc817B95uCZTB04NdB3SHM5R8jmPG1kZfMuALIBJQZ2Ao5A
X4kGkDB+wHimDJxi2Hym8gwrj6+8GObrUwScKDvBp6c/NWyOCY3hxpE3djqEWeM37MAOsoGHve/UES+/
HShnAk2AsVgs3DLqFq8JQ7YVbONYyTG/Lce53C5Wn1yt8vcZMG3QNAZGDdTTgOCgBsGO9nbqiADIR9UU
0wQSCVckX8GizEWGzTWOGt45/I4KwvEjWwu2suvcLsO2EfEjuGHEDdofIDg4gqSwvZ3aFgACMFOByiem
CTALMhcwNHaoYduOszvYmr/Vvx0Qqm7fB8c+MBQ0YdYwrsu6joSwBK0FBJ7PgPL2dmpbAFgBNy5gG3oa
EDik8rtfPGyxYaptj/SwLnddjxQWlVKy+uRqLtReMGyfMXgGIxJ0bdkAU41kG5J214LbFgBP0LQcuAc4
Geir6s/MSJ/h1fPvXPU5Vp1c1TMdEXC89DifF35u2JwQlsCto2/V04DAkouJPZigeQJQIzoa6nsa7RUY
MIRJcNvo27wW1tyQt4FDxYd6bNDV2Gt479h7qnipAdMGTSMlIkVPAwLHXhI4Q0b7O7YvAJYBEg+qfKiz
3f01HUd2YPPAmMQxTB1kvMZe76zng2MfYHfaO3Y8H22b8jZxoPiAYZ+uSruKxVmLO3Ysja9xIljDBSR3
tr9zZ3JK7QAKgSGBvsJej1QGs+TIZBLDEtssoeXyuLhxxI0Mixtm2F7WUEZ6dDpLxy3tdLru7iCEoKKh
wrAtzBLGzSNvJqcsB7vbjvCimtQ4aiisLqTGXqOThvqOAiQ7O6oNdmy35YAgHA8vA98I9BX2ZoQQjEka
w2MzH2N+xvx28/pJJOGWcKJCowzb3dJNg6vBP84/7WA1WQm1GJcBc7gdVNor2+yX2+PmWOkxXt31Ku8d
ee9SViFNd/g/TNyHpN4oA1BLOqYBKHWtDlUybCkQ0aHPaS5HQlZCFq/c8AozB8/0+mTsDGZhJsIafF9H
iDmEpPD2axqkRqUyacAkYkJjeG33a4axBpoOUwOsxUN9Rz/QMZ0xm6bVgE2oJCGaLmAymbjv6vuYNXiW
TwZ/XyHGFsMPp/9QJRzRdoHukIvgUwTtWv+b6PikUWkBBcAngb7K3kpkSCTXDL4m0N0ISjJjM7ky9cpA
d6O3sxFJYWeEaGetRh5UxaC6QF9pr0PCoOhBXufy/R2r2UpaVJr2H+g6dcCHSDydGdUd3zX74qu9qAhB
TWcQUFxbTHl9u96Z/RK3dHPkwhE9Beg624F9CC6r/dcendMArICdc8D/Q/sEdJqSuhL+fujv2tBlwN6i
vewp2hPobvRWnMAHSIo6q0F1Lnh7PbAQEJSiagcmBPrKexUScityGRo7lFGJo3p03T6YyS3PZfkny9ly
ZoueAnSNHGAZgvKOGv+a6HxxOaWi5QIfAYEpSdNbEVBUXcSDqx9ka8FWZgyawcjEkYbZffoD1Y5qdhbu
5K2Db6lIRj34u8qHdLGUX+dv+XJodNqai+AddAXhziPBJEyEhYQRZgnrt0uCbummxlGDw+XQg7/rXED5
5mwCOrz810TXbrs6SRTwF+DWQN+BXk1/N3rpgd9d/oXgW0B1Rzz/WtK1SWg2oOoGvgXUdukYGoWPinf0
2k3THWqAt5BdG/zQ3cq/grXAp906hkaj6SqfoEzzXabrAsAEuCkHXkdrARpNT1MD/JUOpP1qi64LgJ9c
/PRaYEuXj6PRaLrCZ6ix12nDX3O6NwVQJ76A0gIaAn1HNJp+QgOCvwKl3Rn80F0BAE1BQqvQQUIaTU+x
vnHMdZvuCwBlzS0BXgXKAntfNJo+TynwKi5KsXb/YN0XANkXX61GeSRpNBp/IVmJ5GMswI+7fzjfOKNn
ozIGCV6B9quRaDSaLlGA4BUEDd2d+zfhu2gUAUh2Am+CzvCo0fgYCbyNiV2+dKDynQDIBgQOBH8A9vfw
zdFo+jp7gdfw4Oiq158Rvo1HVSsCx4CX0M5BGo2vqAFeBI77+sC+jUPdCMwFVOLQTGC8f++LRtMveAv4
X8Duq7l/E74PRN8IzMUO5AHz0UlDNJrucAx4CDjt68EPvp4CXM5e1FRAJxDVaLpGHfAitsZcf37AP6lo
NgLzAMEJJEMRTPDTDdJo+jJvAL/A5btlv5b4LxfVRmAuDQiOAtOBVL+dS6Ppe3wO/Ag466/BD/6dAjRx
BHgOFTSk0Wjapxg1Zo75+0T+zUa5kaZVgRwgHJhFzwgdjaa34gJ+AfwR8Pjz6Q/+FgDQJAQ8wGFUafEx
6GRQGo0RHuAdBM8gqPH34IeeEADQZBSsRbAfmAwM7pHzajS9i80IfgTk+9Lbry16Vh33cBx4HDjRo+fV
aIIfNTZcvvf2a4ueq0ixEbU0CAVAETAHCL7C9hpNz3Me5ezzMSa6leKrs/RsSZqNwDwkgmOo+c4MIKRH
+6DRBBfVwHOY+Qs9YPRrSc/XpNpIk1FwPxAKTKErJco0mt5PPfC/mPgV0NBT8/7mBKYo3UZgLg5gBxAN
XBmwvmg0gcEOvAw8i6QmEIMfAjnoNgLzcCDYgaovOBHtI6DpH7iAPyLJBqpYHriOBPapuxGYSz1KE0gB
xga8TxqNf3GiCno8iaA0kIMfgmGwbQTmUItaA40CJqBtApq+iR34PSZ+jKAkUGp/cwIvAEBVFJhPHYIt
KMPgRPBF0mONJmioA36LYDlQHgyDH4JFAIDSBObTgGArEoEyDIYGulsajQ+oBn6JiecRVAXL4IdgEgAA
G4A5OICdqJs2EYgMdLc0mm5wHngW+BWS2mAa/BBsAgCaVgecCHYBuSghoNOKaXojx4GHEPzVl7n8fUnw
CQBQQmABHqwcwc1eYDSQho4i1PQOPMBW4L8IZTUSNz8JdJeMCU4BAGo6MBuAM6hSyKnACLSvgCa4cQHv
Afcj2IMTgk3tb07veKJmAzAAuBf4HpAU6C5pNAZcAF5BefgVBaPK35Lg1QCasxG4lhpMbEaSAwxHCYTe
IcA0fR0J7EXwKBZew0RVsKr8LekdAgBgPSqIyMQxlOdALJCF9hfQBJY64O/AD3GxGQ/uYFb5W9J7BAA0
LRNKoKTxf+eRDEcQh9YGND2LB0kOgmeBF4ACTMhAu/Z2lt47aJ4GrJhwMAHJA8AX0QlGND1DLfAvBC8S
wj6ceHqLyt+S3isAmsgGVEjxrcADqHqEeqVA4w88wD5Uxav3gKreYOhri941BTBiI021CPdjYj0SCWSg
PQg1vuU88EdMPIZkA34o1BkIer8G0Bw1/7IhuRr4PrAYiA90tzS9mjJgFYJXUWHrAcnc4y/6lgBoYjkg
CMfDYuBuVHkSW6C7pelVNKD0y1cxsRpJfV8a+E30TQEAzTOrJgJLgDtRNQr11EDTFjUoN97XgY8QlPbF
gd9E3xUAzVkGmEhAshD4BqpEmRYEmiYkyrL/KYLXgTV4Ap+tpyfoHwIAmmsEccAC4D9Q0QaJge6aJqCU
AJuANxCsx0oFDno0N38g6T8CoInngSogjGgkk4FbgOtQdQt1jYL+gQM4DXyEWs7bhco/0W8GfhP9TwA0
8SzwTeCPWJBkADcBXwCuRlUy1vQ96lCW/H8DHwCnUNF7/W7gN9F/BUBL/geoYgCCq1CCYBYwFO1d2Nup
BfKAzcBKJDuJpogHA92t4EALgOZkAzFALWbcpCOZA8xHLSOmobMV9xZcwFnUMt561Bw/H3AD/fZpb4QW
AG2RDQgigHRgKpIFKFfjTCAq0N3TXEY1cArJXgTrgB0I8pHU6gHvHS0AOsovAImJOoYgmQBMRzIbwSjU
NEEbEHsWB0q9PwJ8CmwD9iI5A3j6wxKeL9ACoLNkX3xlQRKHIANV4PQqYCQwDLW0qAOSfIsHlXEnFzgG
fI5gB5JTCCoAFxKt3ncSLQB8QTagAqsGoKYHw4ErUFWOMlGWhUi0DaGjuFAeeZVITiLYj2B/Y/z9SSRF
BKCUdl9ECwBfk43yKzNjxYMNldJ8FDAOldR0MDAIGIgSDP39O5BAJVDQuOWjnvCHgKNIShHUE44LF/BE
oLvbt+jvP76e4zkAzLiIQZKImiYMRE0bRqLSm8UDYc02G70/ZNuNCqypb7aVASeA4wiOIylAeeSVoISB
Wz/dewYtAAJJNqC+AwtmrEhi8ZCMIBlJMqpicjJKWMSj8iA2bXEoISG4ZG8QzTZ/IJttoOblEjWoy4GK
ZlsZakAXA+cRFCMpxkQxUIEbJwIXNBbJ1gQELQCCmWdR35Cb0MbphI1LmoENtRSZgMqIFN64hbV4HYZK
nGpF2SCsLTZQJasdqLm3s/Gvo3GzowZ4XePW/HUVglIk1ainfNOTvgETDZixI4EnA30jNd7QAqCvkX3x
lbj4VzZ7T6Ce2eKyfeTF92Tj/y+1yov7XH58jUaj0Wg0Gk2v5P8D5M/bzdE8cNIAAAAASUVORK5CYII=
</value>
</data>
</root>

View File

@@ -1,17 +0,0 @@
namespace cmonitor.clipboard.win
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// 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,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,17 +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>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Content Include="favicon.ico" />
</ItemGroup>
</Project>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -180,10 +180,6 @@ namespace cmonitor.install.win
{
public sealed class ViewerConfigInfo
{
[JsonIgnore]
public const string userNameKey = "viewer-username";
public int ProxyPort { get; set; } = 1803;
}
public sealed partial class ConfigClientInfo

View File

@@ -52,11 +52,6 @@
shareItemLen = new TextBox();
gbClient = new GroupBox();
gbServer = new GroupBox();
cbBlueProtect = new CheckBox();
tbViewerPortClient = new TextBox();
label7 = new Label();
tbViewerPortServer = new TextBox();
label8 = new Label();
gbClient.SuspendLayout();
gbServer.SuspendLayout();
SuspendLayout();
@@ -177,8 +172,6 @@
// gbClient
//
resources.ApplyResources(gbClient, "gbClient");
gbClient.Controls.Add(tbViewerPortClient);
gbClient.Controls.Add(label7);
gbClient.Controls.Add(machineName);
gbClient.Controls.Add(label16);
gbClient.Controls.Add(serverIP);
@@ -195,8 +188,6 @@
// gbServer
//
resources.ApplyResources(gbServer, "gbServer");
gbServer.Controls.Add(tbViewerPortServer);
gbServer.Controls.Add(label8);
gbServer.Controls.Add(apiPort);
gbServer.Controls.Add(serverPort);
gbServer.Controls.Add(label2);
@@ -206,37 +197,10 @@
gbServer.Name = "gbServer";
gbServer.TabStop = false;
//
// cbBlueProtect
//
resources.ApplyResources(cbBlueProtect, "cbBlueProtect");
cbBlueProtect.Name = "cbBlueProtect";
cbBlueProtect.UseVisualStyleBackColor = true;
//
// tbViewerPortClient
//
resources.ApplyResources(tbViewerPortClient, "tbViewerPortClient");
tbViewerPortClient.Name = "tbViewerPortClient";
//
// label7
//
resources.ApplyResources(label7, "label7");
label7.Name = "label7";
//
// tbViewerPortServer
//
resources.ApplyResources(tbViewerPortServer, "tbViewerPortServer");
tbViewerPortServer.Name = "tbViewerPortServer";
//
// label8
//
resources.ApplyResources(label8, "label8");
label8.Name = "label8";
//
// MainForm
//
resources.ApplyResources(this, "$this");
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(cbBlueProtect);
Controls.Add(gbServer);
Controls.Add(gbClient);
Controls.Add(checkStateBtn);
@@ -280,17 +244,5 @@
private TextBox shareItemLen;
private GroupBox gbClient;
private GroupBox gbServer;
private CheckBox cbBlueProtect;
/* 项目“cmonitor.install.win (net8.0-windows)”的未合并的更改
在此之前:
private TextBox textBox1;
在此之后:
private TextBox tbViewerPortCLient;
*/
private TextBox tbViewerPortClient;
private Label label7;
private TextBox tbViewerPortServer;
private Label label8;
}
}

View File

@@ -31,14 +31,11 @@ namespace cmonitor.install.win
}
private void LoadConfig()
{
cbBlueProtect.Checked = config.Common.BlueProtect;
modeClient.Checked = config.Common.Modes.Contains("client");
modeServer.Checked = config.Common.Modes.Contains("server");
machineName.Text = config.Client.Name;
serverIP.Text = config.Client.Server;
tbViewerPortClient.Text = config.Client.Viewer.ProxyPort.ToString();
shareKey.Text = config.Client.ShareMemoryKey;
shareLen.Text = config.Client.ShareMemoryCount.ToString();
@@ -47,7 +44,6 @@ namespace cmonitor.install.win
serverPort.Text = config.Server.ServicePort.ToString();
apiPort.Text = config.Server.ApiPort.ToString();
webPort.Text = config.Server.WebPort.ToString();
tbViewerPortServer.Text = config.Server.Viewer.ProxyPort.ToString();
}
private bool loading = false;
@@ -115,8 +111,6 @@ namespace cmonitor.install.win
private bool CheckMode()
{
config.Common.BlueProtect = cbBlueProtect.Checked;
if (modeClient.Checked == false && modeServer.Checked == false)
{
MessageBox.Show("客户端和服务端必须选择一样!");
@@ -164,20 +158,11 @@ namespace cmonitor.install.win
MessageBox.Show("web端口必填");
return false;
}
if (string.IsNullOrWhiteSpace(tbViewerPortClient.Text) || string.IsNullOrWhiteSpace(tbViewerPortServer.Text))
{
MessageBox.Show("共享桌面代理端口必填");
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);
config.Client.Viewer.ProxyPort = int.Parse(tbViewerPortClient.Text);
config.Server.Viewer.ProxyPort = int.Parse(tbViewerPortServer.Text);
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -119,165 +119,239 @@
</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>93, 52</value>
<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>17, 55</value>
<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>68, 17</value>
<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>17, 80</value>
<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>56, 17</value>
<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>79, 77</value>
<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>17, 28</value>
<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>79, 24</value>
<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>17, 54</value>
<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>56, 17</value>
<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>79, 51</value>
<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>105, 45</value>
<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>298, 45</value>
<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>19, 150</value>
<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>93, 147</value>
<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>14, 124</value>
<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>93, 120</value>
<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>26, 29</value>
<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>93, 25</value>
<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>175, 299</value>
<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>88, 299</value>
<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>305, 305</value>
<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>7, 179</value>
<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>93, 176</value>
<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>12, 72</value>
<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>200, 212</value>
<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>219, 73</value>
<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>187, 211</value>
<value>374, 385</value>
</data>
<data name="gbServer.Text" xml:space="preserve">
<value>服务端参数</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="cbBlueProtect.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="cbBlueProtect.Size" type="System.Drawing.Size, System.Drawing">
<value>111, 21</value>
</data>
<data name="cbBlueProtect.Text" xml:space="preserve">
<value>异常关闭则蓝屏</value>
</data>
<data name="tbViewerPortClient.Location" type="System.Drawing.Point, System.Drawing">
<value>93, 80</value>
</data>
<data name="tbViewerPortClient.Size" type="System.Drawing.Size, System.Drawing">
<value>100, 23</value>
</data>
<data name="tbViewerPortClient.TabIndex" type="System.Int32, mscorlib">
<value>37</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="label7.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="label7.Location" type="System.Drawing.Point, System.Drawing">
<value>11, 83</value>
</data>
<data name="label7.Size" type="System.Drawing.Size, System.Drawing">
<value>80, 17</value>
</data>
<data name="label7.TabIndex" type="System.Int32, mscorlib">
<value>38</value>
</data>
<data name="label7.Text" xml:space="preserve">
<value>共享桌面端口</value>
</data>
<data name="tbViewerPortServer.Location" type="System.Drawing.Point, System.Drawing">
<value>79, 104</value>
</data>
<data name="tbViewerPortServer.Size" type="System.Drawing.Size, System.Drawing">
<value>100, 23</value>
</data>
<data name="tbViewerPortServer.TabIndex" type="System.Int32, mscorlib">
<value>39</value>
</data>
<data name="label8.ImeMode" type="System.Windows.Forms.ImeMode, System.Windows.Forms">
<value>NoControl</value>
</data>
<data name="label8.Location" type="System.Drawing.Point, System.Drawing">
<value>-3, 107</value>
</data>
<data name="label8.Size" type="System.Drawing.Size, System.Drawing">
<value>80, 17</value>
</data>
<data name="label8.TabIndex" type="System.Int32, mscorlib">
<value>40</value>
</data>
<data name="label8.Text" xml:space="preserve">
<value>共享桌面端口</value>
<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>418, 346</value>
<value>836, 601</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
@@ -558,4 +632,7 @@
lbj4VzZ7T6Ce2eKyfeTF92Tj/y+1yov7XH58jUaj0Wg0Gk2v5P8D5M/bzdE8cNIAAAAASUVORK5CYII=
</value>
</data>
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>6, 5, 6, 5</value>
</data>
</root>

View File

@@ -27,9 +27,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.viewer.server.win"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmonitor.killer", "cmonitor.killer\cmonitor.killer.vcxproj", "{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.clipboard.win", "cmonitor.clipboard.win\cmonitor.clipboard.win.csproj", "{2A23EA37-3EAC-4B60-8576-84607ADB0256}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cmonitor.tests", "cmonitor.tests\cmonitor.tests.csproj", "{04AA3054-5350-4D8B-97F6-31495AE0609D}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.tests", "cmonitor.tests\cmonitor.tests.csproj", "{04AA3054-5350-4D8B-97F6-31495AE0609D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -185,18 +183,6 @@ Global
{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}.Release|x64.Build.0 = Release|x64
{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}.Release|x86.ActiveCfg = Release|Win32
{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}.Release|x86.Build.0 = Release|Win32
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x64.ActiveCfg = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x64.Build.0 = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x86.ActiveCfg = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x86.Build.0 = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|Any CPU.Build.0 = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x64.ActiveCfg = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x64.Build.0 = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x86.ActiveCfg = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x86.Build.0 = Release|Any CPU
{04AA3054-5350-4D8B-97F6-31495AE0609D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{04AA3054-5350-4D8B-97F6-31495AE0609D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{04AA3054-5350-4D8B-97F6-31495AE0609D}.Debug|x64.ActiveCfg = Debug|Any CPU

View File

@@ -1,5 +1,5 @@
<?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.42" ProductVersion="0.0.0.42" publishDir="/dist/" dstrip="false">
<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">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true"/>
<folder name="窗体文件" path="dlg" comment="目录" embed="true"/>

View File

@@ -51,9 +51,9 @@ mainForm.connect = function(){
mainForm.show();
if(!_STUDIO_INVOKED)
{
//mainForm.fullscreen();
//mainForm.modifyStyleEx(0x40000/*_WS_EX_APPWINDOW*/,0x80/*_WS_EX_TOOLWINDOW*/);
//::SetWindowPos(mainForm.hwnd,-1/*_HWND_TOPMOST*/,0,0,0,0,0x2/*_SWP_NOMOVE*/ + 0x1/*_SWP_NOSIZE*/);
mainForm.fullscreen();
mainForm.modifyStyleEx(0x40000/*_WS_EX_APPWINDOW*/,0x80/*_WS_EX_TOOLWINDOW*/);
::SetWindowPos(mainForm.hwnd,-1/*_HWND_TOPMOST*/,0,0,0,0,0x2/*_SWP_NOMOVE*/ + 0x1/*_SWP_NOSIZE*/);
}
mainForm.setInterval(

View File

@@ -0,0 +1,17 @@
import { sendWebsocketMsg } from './request'
export const getLogger = (data) => {
return sendWebsocketMsg('loggerclient/get', data);
}
export const clearLogger = () => {
return sendWebsocketMsg('loggerclient/clear');
}
export const getLoggerConfig = () => {
return sendWebsocketMsg('loggerclient/getconfig');
}
export const updateLoggerConfig = (data) => {
return sendWebsocketMsg('loggerclient/setconfig', data);
}

View File

@@ -87,6 +87,10 @@ a {
margin-right: 1rem;
}
.m-l-1 {
margin-left: 1rem;
}
table {
border-spacing: 0;
border-collapse: collapse;

View File

@@ -6,11 +6,14 @@
<img src="../assets/logo.png" alt="">
</router-link>
</div>
<div class="menu">
<ul class="flex-1">
<div class="menu flex-1">
<ul class="flex">
<li>
<router-link :to="{name:'Index'}">首页</router-link>
</li>
<li>
<router-link :to="{name:'Logger'}">日志</router-link>
</li>
</ul>
</div>
</div>
@@ -21,7 +24,7 @@
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
</div>
<div class="pdt-10">
秘钥 : <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>
<template #footer>
@@ -35,44 +38,41 @@
import { computed, onMounted, reactive, watch } from 'vue';
import { initWebsocket, subWebsocketState } from '../apis/request'
import { getConfig,getSignInfo } 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({api:`${window.location.hostname}:1805`,psd:'snltty',groupid:'snltty'}));
const state = reactive({
api: route.query.api ? `${window.location.hostname}:${route.query.api}` : (localStorage.getItem('api') || `${window.location.hostname}:1805`),
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: queryCache.groupid,
showPort: false
});
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
localStorage.setItem('groupid', state.groupid);
globalData.value.groupid = state.groupid;
const showPort = computed(() => globalData.value.connected == false && state.showPort);
const handleConnect = () => {
initWebsocket(`ws://${state.api}`,state.apipsd);
localStorage.setItem('api', state.api);
localStorage.setItem('apipsd', state.apipsd);
localStorage.setItem('groupid', state.groupid);
globalData.value.groupid = state.groupid;
queryCache.api = state.api;
queryCache.psd = state.psd;
queryCache.groupid = state.groupid;
localStorage.setItem('api-cache',JSON.stringify(queryCache));
initWebsocket(`ws://${state.api}`,state.psd);
}
const _getConfig = ()=>{
getConfig().then((res)=>{
console.log(res);
globalData.value.config.Common = res.Data.Common;
globalData.value.config.Client = res.Data.Client;
setTimeout(()=>{
_getConfig();
},1000);
}).catch((err)=>{
console.log(err);
setTimeout(()=>{
_getConfig();
},1000);
@@ -93,11 +93,17 @@ export default {
}
onMounted(() => {
_getConfig();
_getSignInfoInfo();
handleConnect();
setTimeout(() => { state.showPort = true; }, 100);
subWebsocketState((state) => { if (state) globalData.value.updateFlag = Date.now(); });
subWebsocketState((state) => { if (state) {
_getConfig();
_getSignInfoInfo();
}});
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;
handleConnect();
});
});
return {
@@ -120,7 +126,7 @@ export default {
}
.menu{
padding-left:1rem;font-size:1.4rem;
li{box-sizing:border-box;padding:.5rem 0;margin-right:.5rem}
li{box-sizing:border-box;padding:.5rem 0;margin-right:.5rem;}
a{
display:block;
color:#333;

View File

@@ -3,7 +3,12 @@ const routes = [
{
path: '/',
name: 'Index',
component: () => import('../views/Index.vue')
component: () => import('../views/devices/Index.vue')
},
{
path: '/logger.html',
name: 'Logger',
component: () => import('../views/logger/Index.vue')
}
]

View File

@@ -18,14 +18,14 @@
<el-table-column prop="LastSignIn" label="最后登入" width="140" />
<el-table-column label="操作">
<template #default="scope">
<el-dropdown>
<el-dropdown class="m-r-1">
<el-button size="small">
测试<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="handleTestTunnel(scope.row.MachineName)">打洞</el-dropdown-item>
<el-dropdown-item @click="handleTestRelay(scope.row.MachineName)">中继</el-dropdown-item>
<el-dropdown-item @click="handleTestTunnel(scope.row.MachineName)">打洞</el-dropdown-item>
<el-dropdown-item @click="handleTestRelay(scope.row.MachineName)">中继</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -39,7 +39,7 @@
</el-table>
<div class="page t-c">
<div class="page-wrap">
<el-pagination small background layout="prev, pager, next"
<el-pagination small background layout="total,prev, pager, next"
:total="state.page.Count" :page-size="state.page.Request.Size" :current-page="state.page.Request.Page"
@current-change="handlePageChange"/>
</div>
@@ -51,7 +51,7 @@ import {getSignList,updateSignInDel} from '@/apis/signin.js'
import {updateTunnelConnect} from '@/apis/tunnel.js'
import {updateRelayConnect} from '@/apis/relay.js'
import {subWebsocketState} from '@/apis/request.js'
import {injectGlobalData} from '../provide.js'
import {injectGlobalData} from '@/provide.js'
import {reactive,onMounted, ref, nextTick, onUnmounted} from 'vue'
export default {
setup(props) {
@@ -68,6 +68,7 @@ export default {
});
const _getSignList = ()=>{
state.page.Request.GroupId = globalData.value.groupid;
getSignList(state.page.Request).then((res)=>{
state.page.Request = res.Request;
state.page.Count = res.Count;
@@ -98,6 +99,7 @@ export default {
subWebsocketState((state)=>{ if(state)_getSignList();});
resizeTable();
window.addEventListener('resize',resizeTable);
_getSignList();
});
onUnmounted(()=>{
window.removeEventListener('resize',resizeTable);

View File

@@ -0,0 +1,178 @@
<template>
<div class="logger-setting-wrap flex flex-column h-100" ref="wrap">
<el-tabs type="border-card">
<el-tab-pane label="主页">
<div class="inner">
<div class="head flex">
<div>
<el-select v-model="state.type" @change="loadData" size="small" class="m-r-1" style="width: 6rem;">
<el-option :value="-1" label="all"></el-option>
<el-option :value="0" label="debug"></el-option>
<el-option :value="1" label="info"></el-option>
<el-option :value="2" label="warning"></el-option>
<el-option :value="3" label="error"></el-option>
<el-option :value="4" label="fatal"></el-option>
</el-select>
</div>
<el-button type="warning" size="small" :loading="state.loading" @click="clearData">清空</el-button>
<el-button size="small" :loading="state.loading" @click="loadData">刷新列表</el-button>
<span class="flex-1"></span>
</div>
<div class="body flex-1 relative">
<div v-if="state.page.List.length > 0">
<el-table border :data="state.page.List" size="small" :height="`${state.height}px`" @row-click="handleRowClick" :row-class-name="tableRowClassName">
<el-table-column type="index" width="50" />
<el-table-column prop="Type" label="类别" width="80">
<template #default="scope">
<span>{{state.types[scope.row.Type]}} </span>
</template>
</el-table-column>
<el-table-column prop="Time" label="时间" width="160"></el-table-column>
<el-table-column prop="content" label="内容"></el-table-column>
</el-table>
</div>
<el-empty v-else />
</div>
<div class="pages t-c">
<div class="page-wrap">
<el-pagination small :total="state.page.Count" v-model:currentPage="state.page.Page" :page-size="state.page.Size" @current-change="loadData" background layout="total,prev, pager, next">
</el-pagination>
</div>
</div>
</div>
</el-tab-pane>
<el-tab-pane label="配置">
<Setting></Setting>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import { reactive } from '@vue/reactivity'
import { getLogger, clearLogger } from '@/apis/logger'
import { onMounted,onUnmounted } from '@vue/runtime-core'
import Setting from './Setting.vue'
import { ElMessageBox } from 'element-plus'
import {subWebsocketState} from '@/apis/request.js'
import { nextTick, ref } from 'vue'
export default {
components: { Setting },
setup() {
const wrap = ref(null);
const state = reactive({
loading: true,
type:-1,
page: { Page: 1, Size: 20, Count: 0, List: [] },
types: ['debug', 'info', 'warning', 'error', 'fatal'],
height:0,
})
const loadData = () => {
state.loading = true;
getLogger({
Page : state.page.Page,
Size : state.page.Size,
Type : state.type
}).then((res) => {
state.loading = false;
res.List.map(c => {
c.content = c.Content.substring(0, 50);
});
state.page = res;
}).catch((err) => {
console.log(err);
state.loading = false;
});
}
const clearData = () => {
state.loading = true;
clearLogger().then(() => {
state.loading = false;
loadData();
}).catch(() => {
state.loading = false;
});
}
const tableRowClassName = ({ row, rowIndex }) => {
return `type-${row.Type}`;
}
const handleRowClick = (row, column, event) => {
let css = `padding:1rem;border:1px solid #ddd; resize:none;width:39rem;box-sizing: border-box;white-space: nowrap; height:30rem;`;
ElMessageBox.alert(`<textarea class="scrollbar-4" style="${css}">${row.Content}</textarea>`, '内容', {
dangerouslyUseHTMLString: true,
});
}
const resizeTable = ()=>{
nextTick(()=>{
state.height = wrap.value.offsetHeight - 200;
});
}
onMounted(()=>{
subWebsocketState((state)=>{ if(state)loadData();});
resizeTable();
window.addEventListener('resize',resizeTable);
loadData();
});
onUnmounted(()=>{
window.removeEventListener('resize',resizeTable);
});
return {
wrap,state, loadData, clearData, tableRowClassName, handleRowClick
}
}
}
</script>
<style lang="stylus" scoped>
.pages {
padding: 1rem 0 0 1rem;
}
.page-wrap{
display:inline-block;
}
.logger-setting-wrap {
padding: 2rem;
box-sizing: border-box;
.inner {
padding: 1rem;
}
.head {
margin-bottom: 1rem;
}
}
</style>
<style lang="stylus">
.logger-setting-wrap {
.el-table {
.type-0 {
color: blue;
}
.type-1 {
color: #333;
}
.type-2 {
color: #cd9906;
}
.type-3 {
color: red;
}
.type-4 {
color: red;
font-weight: bold;
}
}
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<el-form label-width="8rem" ref="formDom" :model="state.form" :rules="state.rules">
<el-form-item label="" label-width="0">
<el-row>
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="显示数量" prop="Size">
<el-input size="default" v-model="state.form.Size"></el-input>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="8" :md="8" :lg="8" :xl="8">
<el-form-item label="日志等级" prop="LoggerType">
<el-select v-model="state.form.LoggerType">
<el-option :value="-1" label="all"></el-option>
<el-option :value="0" label="debug"></el-option>
<el-option :value="1" label="info"></el-option>
<el-option :value="2" label="warning"></el-option>
<el-option :value="3" label="error"></el-option>
<el-option :value="4" label="fatal"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form-item>
<el-form-item label-width="0">
<div class="t-c w-100">
<el-button type="primary" :loading="state.loading" @click="submit"> </el-button>
</div>
</el-form-item>
</el-form>
</template>
<script>
import { ref, reactive } from "@vue/reactivity";
import { getLoggerConfig, updateLoggerConfig } from "@/apis/logger";
import { onMounted } from "@vue/runtime-core";
import { ElMessage } from 'element-plus';
import {subWebsocketState} from '@/apis/request.js'
export default {
setup() {
const formDom = ref(null);
const state = reactive({
loading: false,
configInfo: {},
form: {
Size: 0,
LoggerType: -1,
},
rules: {
Size: [
{ required: true, message: "必填", trigger: "blur" },
{
type: "number",
min: 1,
max: 10000,
message: "数字 1-10000",
trigger: "blur",
transform(value) {
return Number(value);
},
},
],
},
});
const loadConfig = () => {
getLoggerConfig()
.then((json) => {
console.log(json);
state.configInfo = json;
state.form.Size = json.Size;
state.form.LoggerType = json.LoggerType;
})
.catch((msg) => { });
};
const getJson = () => {
let _json = JSON.parse(JSON.stringify(state.configInfo));
_json.Size = +state.form.Size;
_json.LoggerType = +state.form.LoggerType;
return _json;
};
const submit = () => {
return new Promise((resolve, reject) => {
formDom.value.validate((valid) => {
if (valid == false) {
reject();
return false;
}
state.loading = true;
const _json = getJson();
updateLoggerConfig(_json).then((res) => {
state.loading = false;
resolve();
if (res) {
ElMessage.success('操作成功!');
} else {
ElMessage.error('操作失败!');
}
}).catch(() => {
state.loading = false;
resolve();
})
});
});
};
onMounted(() => {
subWebsocketState((state)=>{ if(state)loadConfig();});
loadConfig();
});
return {
state,
formDom,
submit,
};
},
};
</script>
<style lang="stylus" scoped>
.el-row {
width: 100%;
}
.el-form-item {
width: 100%;
}
.el-form-item:last-child {
margin-bottom: 0;
}
@media screen and (max-width: 768px) {
.el-col {
margin-top: 0.6rem;
}
}
</style>

View File

@@ -60,7 +60,7 @@ namespace cmonitor
private static void LoggerConsole()
{
Logger.Instance.LoggerLevel = LoggerTypes.DEBUG;
//Logger.Instance.LoggerLevel = LoggerTypes.DEBUG;
if (Directory.Exists("logs") == false)
{
Directory.CreateDirectory("logs");

View File

@@ -53,7 +53,7 @@ namespace cmonitor.client.api
}
Logger.Instance.Warning($"load client api:{item.Name}");
string path = item.Name.Replace("ApiController", "");
string path = item.Name.Replace("ApiController", "").Replace("ApiController", "");
foreach (MethodInfo method in item.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
string key = $"{path}/{method.Name}".ToLower();

View File

@@ -67,7 +67,7 @@ namespace cmonitor.client.tunnel
public void BeginReceive(TunnelReceivceCallback receiveCallback, TunnelCloseCallback closeCallback, object userToken)
{
if (receiveCallback != null) return;
if (this.receiveCallback != null) return;
this.receiveCallback = receiveCallback;
this.closeCallback = closeCallback;
@@ -162,4 +162,6 @@ namespace cmonitor.client.tunnel
Socket?.SafeClose();
}
}
}

View File

@@ -0,0 +1,610 @@
using common.libs;
using common.libs.extends;
using System.Buffers;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
namespace cmonitor.client.tunnel
{
public class TunnelProxy
{
private AsyncUserToken userToken;
private Socket socket;
private UdpClient udpClient;
private readonly NumberSpace ns = new NumberSpace();
private readonly ConcurrentDictionary<ConnectId, Socket> dic = new ConcurrentDictionary<ConnectId, Socket>();
public IPEndPoint LocalEndpoint => socket?.LocalEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
public TunnelProxy()
{
}
public void Start(int port)
{
try
{
Stop();
IPEndPoint localEndPoint = new IPEndPoint(NetworkHelper.IPv6Support ? IPAddress.IPv6Any : IPAddress.Any, port);
socket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.IPv6Only(localEndPoint.AddressFamily, false);
socket.ReuseBind(localEndPoint);
socket.Listen(int.MaxValue);
userToken = new AsyncUserToken
{
Socket = socket
};
SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
userToken.Saea = acceptEventArg;
acceptEventArg.Completed += IO_Completed;
StartAccept(acceptEventArg);
udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, localEndPoint.Port));
udpClient.Client.EnableBroadcast = true;
udpClient.Client.WindowsUdpBug();
IAsyncResult result = udpClient.BeginReceive(ReceiveCallbackUdp, null);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
}
private readonly AsyncUserUdpToken asyncUserUdpToken = new AsyncUserUdpToken
{
Proxy = new ProxyInfo { Step = ProxyStep.Forward, ConnectId = 0 }
};
private async void ReceiveCallbackUdp(IAsyncResult result)
{
try
{
//System.Net.Quic.QuicListener.IsSupported
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
byte[] bytes = udpClient.EndReceive(result, ref endPoint);
asyncUserUdpToken.Proxy.Data = bytes;
await ConnectUdp(asyncUserUdpToken);
result = udpClient.BeginReceive(ReceiveCallbackUdp, null);
}
catch (Exception)
{
}
}
protected virtual async Task ConnectUdp(AsyncUserUdpToken token)
{
await Task.CompletedTask;
}
private void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
acceptEventArg.AcceptSocket = null;
AsyncUserToken token = (AsyncUserToken)acceptEventArg.UserToken;
try
{
if (token.Socket.AcceptAsync(acceptEventArg) == false)
{
ProcessAccept(acceptEventArg);
}
}
catch (Exception)
{
token.Clear();
}
}
private void IO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
ProcessAccept(e);
break;
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
default:
break;
}
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
if (e.AcceptSocket != null)
{
BindReceive(e);
StartAccept(e);
}
}
private void BindReceive(SocketAsyncEventArgs e)
{
try
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
var socket = e.AcceptSocket;
if (socket == null || socket.RemoteEndPoint == null)
{
return;
}
socket.KeepAlive();
AsyncUserToken userToken = new AsyncUserToken
{
Socket = socket,
Proxy = new ProxyInfo { Data = Helper.EmptyArray, Step = ProxyStep.Request, ConnectId = ns.Increment() }
};
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
userToken.Saea = readEventArgs;
readEventArgs.SetBuffer(new byte[8 * 1024], 0, 8 * 1024);
readEventArgs.Completed += IO_Completed;
if (socket.ReceiveAsync(readEventArgs) == false)
{
ProcessReceive(readEventArgs);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
}
}
private async void ProcessReceive(SocketAsyncEventArgs e)
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
try
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
int offset = e.Offset;
int length = e.BytesTransferred;
await ReadPacket(token, e.Buffer.AsMemory(offset, length));
if (token.Socket.Available > 0)
{
while (token.Socket.Available > 0)
{
length = token.Socket.Receive(e.Buffer);
if (length > 0)
{
await ReadPacket(token, e.Buffer.AsMemory(0, length));
}
else
{
CloseClientSocket(token);
return;
}
}
}
if (token.Socket.Connected == false)
{
CloseClientSocket(token);
return;
}
if (token.Socket.ReceiveAsync(e) == false)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(token);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
CloseClientSocket(token);
}
}
private async Task ReadPacket(AsyncUserToken token, Memory<byte> data)
{
if (token.Proxy.Step == ProxyStep.Request)
{
await Connect(token);
if (token.Connection != null)
{
//发送连接请求包
await SendToConnection(token).ConfigureAwait(false);
token.Proxy.Step = ProxyStep.Forward;
token.Proxy.TargetEP = null;
//发送后续数据包
token.Proxy.Data = data;
await SendToConnection(token).ConfigureAwait(false);
//绑定
dic.TryAdd(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode()), token.Socket);
}
else
{
CloseClientSocket(token);
}
}
else
{
token.Proxy.Data = data;
await SendToConnection(token).ConfigureAwait(false);
}
}
protected virtual async Task Connect(AsyncUserToken token)
{
await Task.CompletedTask;
}
private async Task SendToConnection(AsyncUserToken token)
{
byte[] connectData = token.Proxy.ToBytes(out int length);
try
{
await token.Connection.SendAsync(connectData.AsMemory(0, length)).ConfigureAwait(false);
}
catch (Exception)
{
CloseClientSocket(token);
}
finally
{
token.Proxy.Return(connectData);
}
}
protected void BindConnectionReceive(ITunnelConnection connection)
{
connection.BeginReceive(InputConnectionData, CloseConnection, new AsyncUserToken
{
Connection = connection,
Buffer = new ReceiveDataBuffer(),
Proxy = new ProxyInfo { }
});
}
protected async Task InputConnectionData(ITunnelConnection connection, Memory<byte> memory, object userToken)
{
AsyncUserToken token = userToken as AsyncUserToken;
//是一个完整的包
if (token.Buffer.Size == 0 && memory.Length > 4)
{
int packageLen = memory.ToInt32();
if (packageLen == memory.Length - 4)
{
token.Proxy.DeBytes(memory.Slice(0, packageLen + 4));
await ReadConnectionPack(token).ConfigureAwait(false);
return;
}
}
//不是完整包
token.Buffer.AddRange(memory);
do
{
int packageLen = token.Buffer.Data.ToInt32();
if (packageLen > token.Buffer.Size - 4)
{
break;
}
token.Proxy.DeBytes(token.Buffer.Data.Slice(0, packageLen + 4));
await ReadConnectionPack(token).ConfigureAwait(false);
token.Buffer.RemoveRange(0, packageLen + 4);
} while (token.Buffer.Size > 4);
}
protected async Task CloseConnection(ITunnelConnection connection, object userToken)
{
CloseClientSocket(userToken as AsyncUserToken);
await Task.CompletedTask;
}
private async Task ReadConnectionPack(AsyncUserToken token)
{
if (token.Proxy.Step == ProxyStep.Request)
{
await ConnectBind(token).ConfigureAwait(false);
}
else
{
await SendToSocket(token).ConfigureAwait(false);
}
}
private async Task ConnectBind(AsyncUserToken token)
{
Socket socket = new Socket(token.Proxy.TargetEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(token.Proxy.TargetEP);
dic.TryAdd(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode()), socket);
BindReceiveTarget(new AsyncUserToken
{
Connection = token.Connection,
Socket = socket,
Proxy = new ProxyInfo
{
ConnectId = token.Proxy.ConnectId,
Step = ProxyStep.Forward
}
});
}
private async Task SendToSocket(AsyncUserToken token)
{
ConnectId connectId = new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode());
if (dic.TryGetValue(connectId, out Socket source))
{
try
{
await source.SendAsync(token.Proxy.Data);
}
catch (Exception)
{
CloseClientSocket(token);
}
}
}
private void IO_CompletedTarget(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceiveTarget(e);
break;
default:
break;
}
}
private void BindReceiveTarget(AsyncUserToken userToken)
{
try
{
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
readEventArgs.SetBuffer(new byte[8 * 1024], 0, 8 * 1024);
readEventArgs.Completed += IO_CompletedTarget;
if (userToken.Socket.ReceiveAsync(readEventArgs) == false)
{
ProcessReceiveTarget(readEventArgs);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
}
}
private async void ProcessReceiveTarget(SocketAsyncEventArgs e)
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
try
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
int offset = e.Offset;
int length = e.BytesTransferred;
token.Proxy.Data = e.Buffer.AsMemory(offset, length);
await SendToConnection(token).ConfigureAwait(false);
if (token.Socket.Available > 0)
{
while (token.Socket.Available > 0)
{
length = token.Socket.Receive(e.Buffer);
if (length > 0)
{
token.Proxy.Data = e.Buffer.AsMemory(0, length);
await SendToConnection(token).ConfigureAwait(false);
}
else
{
CloseClientSocket(token);
return;
}
}
}
if (token.Connection.Connected == false)
{
CloseClientSocket(token);
return;
}
if (token.Socket.ReceiveAsync(e) == false)
{
ProcessReceiveTarget(e);
}
}
else
{
CloseClientSocket(token);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
CloseClientSocket(token);
}
}
private void CloseClientSocket(AsyncUserToken token)
{
if (token == null) return;
if (token.Connection != null)
{
int code = token.Connection.GetHashCode();
if (token.Connection.Connected == false)
{
foreach (ConnectId item in dic.Keys.Where(c => c.hashCode == code).ToList())
{
dic.TryRemove(item, out _);
}
}
else
{
dic.TryRemove(new ConnectId(token.Proxy.ConnectId, code), out _);
}
}
token.Clear();
}
public void Stop()
{
CloseClientSocket(userToken);
udpClient?.Close();
}
}
public enum ProxyStep : byte
{
Request = 1,
Forward = 2
}
public record struct ConnectId
{
public ulong connectId;
public int hashCode;
public ConnectId(ulong connectId, int hashCode)
{
this.connectId = connectId;
this.hashCode = hashCode;
}
}
public sealed class ProxyInfo
{
public ulong ConnectId { get; set; }
public ProxyStep Step { get; set; } = ProxyStep.Request;
public IPEndPoint TargetEP { get; set; }
public Memory<byte> Data { get; set; }
public byte[] ToBytes(out int length)
{
int ipLength = TargetEP == null ? 0 : (TargetEP.AddressFamily == AddressFamily.InterNetwork ? 4 : 16) + 2;
length = 4 + 8 + 1
+ 1 + ipLength
+ Data.Length;
byte[] bytes = ArrayPool<byte>.Shared.Rent(length);
Memory<byte> memory = bytes.AsMemory();
int index = 0;
(length - 4).ToBytes(memory);
index += 4;
ConnectId.ToBytes(memory.Slice(index));
index += 8;
bytes[index] = (byte)Step;
index += 1;
bytes[index] = (byte)ipLength;
index += 1;
if (ipLength > 0)
{
TargetEP.Address.TryWriteBytes(memory.Slice(index).Span, out int writeLength);
index += writeLength;
((ushort)TargetEP.Port).ToBytes(memory.Slice(index));
index += 2;
}
Data.CopyTo(memory.Slice(index));
return bytes;
}
public void Return(byte[] bytes)
{
ArrayPool<byte>.Shared.Return(bytes);
}
public void DeBytes(Memory<byte> memory)
{
int index = 4;
Span<byte> span = memory.Span;
ConnectId = memory.Slice(index).ToUInt64();
index += 8;
Step = (ProxyStep)span[index];
index += 1;
byte ipLength = span[index];
index += 1;
if (ipLength > 0)
{
IPAddress ip = new IPAddress(span.Slice(index, ipLength - 2));
index += ipLength;
ushort port = span.Slice(index - 2).ToUInt16();
TargetEP = new IPEndPoint(ip, port);
}
Data = memory.Slice(index);
}
}
public sealed class AsyncUserUdpToken
{
public UdpClient SourceSocket { get; set; }
public Socket TargetSocket { get; set; }
public ProxyInfo Proxy { get; set; }
public void Clear()
{
SourceSocket?.Close();
SourceSocket = null;
GC.Collect();
}
}
public sealed class AsyncUserToken
{
public Socket Socket { get; set; }
public ITunnelConnection Connection { get; set; }
public ProxyInfo Proxy { get; set; }
public ReceiveDataBuffer Buffer { get; set; }
public SocketAsyncEventArgs Saea { get; set; }
public void Clear()
{
Socket?.SafeClose();
Socket = null;
Buffer?.Clear();
Saea?.Dispose();
GC.Collect();
}
}
}

View File

@@ -90,6 +90,21 @@ namespace cmonitor.config
{
public string[] Modes { get; set; } = new string[] { "client", "server" };
#if DEBUG
private LoggerTypes loggerType { get; set; } = LoggerTypes.DEBUG;
#else
private LoggerTypes loggerType { get; set; } = LoggerTypes.WARNING;
#endif
public LoggerTypes LoggerType
{
get => loggerType; set
{
loggerType = value;
Logger.Instance.LoggerLevel = value;
}
}
public int LoggerSize { get; set; } = 100;
private string[] includePlugins = Array.Empty<string>();
public string[] IncludePlugins
{
@@ -102,7 +117,7 @@ namespace cmonitor.config
{
"cmonitor.client.","cmonitor.server.","cmonitor.serializes.",
"cmonitor.plugins.signin.", "cmonitor.plugins.watch.","cmonitor.plugins.devices.","cmonitor.plugins.report.",
"cmonitor.plugins.share.","cmonitor.plugins.rule.","cmonitor.plugins.modes.","cmonitor.plugins.tunnel.","cmonitor.plugins.relay",
"cmonitor.plugins.share.","cmonitor.plugins.rule.","cmonitor.plugins.modes.","cmonitor.plugins.tunnel.","cmonitor.plugins.relay.","cmonitor.plugins.logger.",
}).Distinct().ToArray();
}
}
@@ -115,7 +130,7 @@ namespace cmonitor.config
{
types = types.Where(c => IncludePlugins.Any(d => c.FullName.Contains(d)));
}
if(ExcludePlugins.Length > 0)
if (ExcludePlugins.Length > 0)
{
types = types.Where(c => ExcludePlugins.Any(d => c.FullName.Contains(d) == false));
}

View File

@@ -11,9 +11,8 @@ namespace cmonitor.plugins.firewall
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
#if RELEASE
common.libs.FireWallHelper.Write(Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName));
common.libs.FireWallHelper.Write(Path.GetFileNameWithoutExtension(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName), "./plugins/firewall");
#endif
}

View File

@@ -17,7 +17,7 @@ namespace cmonitor.plugins.llock.report
if (value)
{
CommandHelper.Windows(string.Empty, new string[] {
$"start cmonitor.llock.win.exe {config.Data.Client.ShareMemoryKey} {config.Data.Client.ShareMemoryCount} {config.Data.Client.ShareMemorySize} {(int)ShareMemoryIndexs.LLock}"
$"start ./plugins/llock/cmonitor.llock.win.exe {config.Data.Client.ShareMemoryKey} {config.Data.Client.ShareMemoryCount} {config.Data.Client.ShareMemorySize} {(int)ShareMemoryIndexs.LLock}"
},false);
}
}

View File

@@ -0,0 +1,95 @@
using common.libs.extends;
using common.libs.api;
using cmonitor.client.api;
using common.libs;
using cmonitor.config;
namespace cmonitor.plugins.logger
{
public sealed class LoggerClientApiController : IApiClientController
{
private readonly List<LoggerModel> loggers = new List<LoggerModel>();
private readonly Config config;
public LoggerClientApiController(Config config)
{
this.config = config;
Logger.Instance.OnLogger += (LoggerModel logger) =>
{
loggers.Add(logger);
if (loggers.Count > config.Data.Common.LoggerSize)
{
loggers.RemoveAt(0);
}
};
}
public LoggerPageInfo Get(ApiControllerParamsInfo param)
{
LoggerPageParamInfo info = param.Content.DeJson<LoggerPageParamInfo>();
IEnumerable<LoggerModel> result = loggers;
if (info.Type >= 0)
{
result = result.Where(c => c.Type == (LoggerTypes)info.Type);
}
result = result.OrderByDescending(c => c.Time);
return new LoggerPageInfo
{
Page = info.Page,
Size = info.Size,
Type = info.Type,
Count = result.Count(),
List = result.Skip((info.Page - 1) * info.Size).Take(info.Size).ToList(),
};
}
public bool Clear(ApiControllerParamsInfo param)
{
loggers.Clear();
return true;
}
public LoggerSetParamInfo GetConfig(ApiControllerParamsInfo param)
{
return new LoggerSetParamInfo
{
LoggerType = config.Data.Common.LoggerType,
Size = config.Data.Common.LoggerSize
};
}
public bool SetConfig(ApiControllerParamsInfo param)
{
LoggerSetParamInfo info = param.Content.DeJson<LoggerSetParamInfo>();
config.Data.Common.LoggerSize = info.Size;
config.Data.Common.LoggerType = info.LoggerType;
config.Save();
return true;
}
}
public sealed class LoggerPageInfo
{
public int Page { get; set; }
public int Size { get; set; }
public int Type { get; set; }
public int Count { get; set; }
public List<LoggerModel> List { get; set; }
}
public sealed class LoggerPageParamInfo
{
public int Page { get; set; }
public int Size { get; set; }
public int Type { get; set; }
}
public sealed class LoggerSetParamInfo
{
public LoggerTypes LoggerType { get; set; }
public int Size { get; set; }
}
}

View File

@@ -0,0 +1,31 @@
using cmonitor.config;
using cmonitor.startup;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace cmonitor.plugins.logger
{
public sealed class LoggerStartup : IStartup
{
public StartupLevel Level => StartupLevel.Top;
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<LoggerClientApiController>();
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
LoggerClientApiController logger = serviceProvider.GetService<LoggerClientApiController>();
}
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
}
}

View File

@@ -8,11 +8,11 @@ namespace cmonitor.plugins.notify.report
{
AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
{
CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /im \"notify.win.exe\"" }, true);
CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /im \"cmonitor.notify.win.exe\"" }, true);
};
Console.CancelKeyPress += (sender, e) =>
{
CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /im \"notify.win.exe\"" }, true);
CommandHelper.Windows(string.Empty, new string[] { "taskkill /f /im \"cmonitor.notify.win.exe\"" }, true);
};
}
public void Update(NotifyInfo notify)
@@ -20,7 +20,7 @@ namespace cmonitor.plugins.notify.report
Task.Run(() =>
{
CommandHelper.Windows(string.Empty, new string[] {
$"start cmonitor.notify.win.exe {notify.Speed} \"{notify.Msg}\" {notify.Star1} {notify.Star2} {notify.Star3}"
$"start ./plugins/notify/cmonitor.notify.win.exe {notify.Speed} \"{notify.Msg}\" {notify.Star1} {notify.Star2} {notify.Star3}"
}, false);
});
}

View File

@@ -2,6 +2,7 @@
using cmonitor.config;
using cmonitor.plugins.relay.transport;
using common.libs;
using common.libs.extends;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Reflection;
@@ -67,11 +68,16 @@ namespace cmonitor.plugins.relay
TransactionId = transactionId,
TransportName = transport.Name
};
Logger.Instance.Debug($"relay to {relayInfo.RemoteMachineName} {relayInfo.ToJson()}");
ITunnelConnection connection = await transport.RelayAsync(relayInfo);
if (connection != null)
{
return connection;
}
else
{
Logger.Instance.Error($"relay to {relayInfo.RemoteMachineName} fail,{relayInfo.ToJson()}");
}
}
catch (Exception ex)
{

View File

@@ -18,6 +18,10 @@ namespace cmonitor.plugins.signin.messenger
{
this.configDataProvider = configDataProvider;
config = configDataProvider.Load().Result ?? new SignCacheFileInfo();
foreach (var item in config.Clients.Values)
{
item.Connected = false;
}
SaveConfig();
}

View File

@@ -1,7 +1,6 @@
using cmonitor.config;
using cmonitor.server;
using common.libs;
using common.libs.extends;
using MemoryPack;
namespace cmonitor.plugins.signin.messenger
@@ -37,13 +36,16 @@ namespace cmonitor.plugins.signin.messenger
{
SignInListRequestInfo request = MemoryPackSerializer.Deserialize<SignInListRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
List<SignCacheInfo> list = signCaching.Get(request.GroupId);
int count = list.Count;
list = list.Skip((request.Page - 1) * request.Size).Take(request.Size).ToList();
if (signCaching.Get(connection.Name, out SignCacheInfo cache))
{
List<SignCacheInfo> list = signCaching.Get(cache.GroupId);
int count = list.Count;
list = list.Skip((request.Page - 1) * request.Size).Take(request.Size).ToList();
SignInListResponseInfo response = new SignInListResponseInfo { Request = request, Count = count, List = list };
SignInListResponseInfo response = new SignInListResponseInfo { Request = request, Count = count, List = list };
connection.Write(MemoryPackSerializer.Serialize(response));
connection.Write(MemoryPackSerializer.Serialize(response));
}
}
[MessengerId((ushort)SignInMessengerIds.Delete)]

View File

@@ -15,7 +15,7 @@ namespace cmonitor.plugins.snatch.report
public void StartUp(SnatchQuestionInfo snatchQuestionInfo)
{
CommandHelper.Windows(string.Empty, new string[] {
$"start cmonitor.snatch.win.exe {config.Data.Client.ShareMemoryKey} {config.Data.Client.ShareMemoryCount} {config.Data.Client.ShareMemorySize} {(int)ShareMemoryIndexs.SnatchQuestion} {(int)ShareMemoryIndexs.SnatchAnswer}"
$"start ./plugins/snatch/cmonitor.snatch.win.exe {config.Data.Client.ShareMemoryKey} {config.Data.Client.ShareMemoryCount} {config.Data.Client.ShareMemorySize} {(int)ShareMemoryIndexs.SnatchQuestion} {(int)ShareMemoryIndexs.SnatchAnswer}"
},false);
}
}

View File

@@ -29,10 +29,6 @@ namespace cmonitor.plugins.tunnel
TunnelTest();
}
public Dictionary<string, TunnelConnectInfo> Connections(ApiControllerParamsInfo param)
{
return tunnelTransfer.Connections;
}
public void Connect(ApiControllerParamsInfo param)
{
Task.Run(async () =>
@@ -50,6 +46,10 @@ namespace cmonitor.plugins.tunnel
}
connection.Close();
}
else
{
Logger.Instance.Error($"tunnel {param.Content} fail");
}
}
catch (Exception ex)
{

View File

@@ -1,7 +1,6 @@
using cmonitor.config;
using cmonitor.plugins.tunnel.compact;
using cmonitor.plugins.tunnel.messenger;
using cmonitor.plugins.tunnel.report;
using cmonitor.plugins.tunnel.server;
using cmonitor.plugins.tunnel.transport;
using cmonitor.startup;
@@ -19,8 +18,6 @@ namespace cmonitor.plugins.tunnel
{
serviceCollection.AddSingleton<TunnelApiController>();
serviceCollection.AddSingleton<TunnelReport>();
serviceCollection.AddSingleton<TunnelClientMessenger>();
serviceCollection.AddSingleton<CompactTransfer>();

View File

@@ -10,7 +10,6 @@ using common.libs.extends;
using MemoryPack;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using System.Transactions;
namespace cmonitor.plugins.tunnel
{
@@ -47,7 +46,6 @@ namespace cmonitor.plugins.tunnel
item.OnConnectBegin = OnConnectBegin;
item.OnConnecting = OnConnecting;
item.OnConnected = _OnConnected;
item.OnDisConnected = OnDisConnected;
item.OnConnectFail = OnConnectFail;
}
@@ -181,82 +179,29 @@ namespace cmonitor.plugins.tunnel
}
public Dictionary<string, TunnelConnectInfo> Connections { get; } = new Dictionary<string, TunnelConnectInfo>();
private int connectionsChangeFlag = 1;
public bool ConnectionChanged => Interlocked.CompareExchange(ref connectionsChangeFlag, 0, 1) == 1;
private void OnConnecting(TunnelTransportInfo tunnelTransportInfo)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Debug($"tunnel connect [{tunnelTransportInfo.TransactionId}]->{tunnelTransportInfo.Remote.MachineName}");
}
CheckDic(tunnelTransportInfo.Remote.MachineName, out TunnelConnectInfo info);
info.Status = TunnelConnectStatus.Connecting;
Interlocked.Exchange(ref connectionsChangeFlag, 1);
Logger.Instance.Debug($"tunnel connecting {tunnelTransportInfo.Remote.MachineName},{tunnelTransportInfo.ToJson()}");
}
private void OnConnectBegin(TunnelTransportInfo tunnelTransportInfo)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Debug($"tunnel connect from {tunnelTransportInfo.Remote.MachineName}->{tunnelTransportInfo.ToJson()}");
}
CheckDic(tunnelTransportInfo.Remote.MachineName, out TunnelConnectInfo info);
info.Status = TunnelConnectStatus.Connecting;
Interlocked.Exchange(ref connectionsChangeFlag, 1);
Logger.Instance.Debug($"tunnel connecting from {tunnelTransportInfo.Remote.MachineName},{tunnelTransportInfo.ToJson()}");
}
private void _OnConnected(ITunnelConnection connection)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Debug($"tunnel connect [{connection.TransactionId}]->{connection.RemoteMachineName} success");
}
CheckDic(connection.RemoteMachineName, out TunnelConnectInfo info);
info.Status = TunnelConnectStatus.Connected;
info.Connection = connection;
Interlocked.Exchange(ref connectionsChangeFlag, 1);
if (OnConnected.TryGetValue(connection.TransactionId, out Action<ITunnelConnection> _callback) == false)
Logger.Instance.Debug($"tunnel connect {connection.RemoteMachineName} success");
if (OnConnected.TryGetValue(connection.TransactionId, out Action<ITunnelConnection> _callback))
{
_callback(connection);
}
}
private void OnDisConnected(ITunnelConnection connection)
public void OnDisConnected(ITunnelConnection connection)
{
CheckDic(connection.RemoteMachineName, out TunnelConnectInfo info);
info.Status = TunnelConnectStatus.None;
info.Connection = null;
Interlocked.Exchange(ref connectionsChangeFlag, 1);
}
private void OnConnectFail(string machineName)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
{
Logger.Instance.Error($"tunnel connect {machineName} fail");
}
CheckDic(machineName, out TunnelConnectInfo info);
info.Status = TunnelConnectStatus.None;
info.Connection = null;
Interlocked.Exchange(ref connectionsChangeFlag, 1);
}
private void CheckDic(string name, out TunnelConnectInfo info)
{
if (Connections.TryGetValue(name, out info) == false)
{
info = new TunnelConnectInfo();
Connections[name] = info;
}
}
public sealed class TunnelConnectInfo
{
public TunnelConnectStatus Status { get; set; }
public ITunnelConnection Connection { get; set; }
}
public enum TunnelConnectStatus
{
None = 0,
Connecting = 1,
Connected = 2,
Logger.Instance.Error($"tunnel connect {machineName} fail");
}
}
}

View File

@@ -1,31 +0,0 @@
using cmonitor.client.report;
using static cmonitor.plugins.tunnel.TunnelTransfer;
namespace cmonitor.plugins.tunnel.report
{
public sealed class TunnelReport : IClientReport
{
public string Name => "Tunnel";
private readonly TunnelTransfer tunnelTransfer;
private readonly TunnelReportInfo tunnelReportInfo = new TunnelReportInfo();
public TunnelReport(TunnelTransfer tunnelTransfer)
{
this.tunnelTransfer = tunnelTransfer;
}
public object GetReports(ReportType reportType)
{
if (tunnelTransfer.ConnectionChanged)
{
tunnelReportInfo.Connections = tunnelTransfer.Connections;
return tunnelReportInfo;
}
return null;
}
public sealed class TunnelReportInfo
{
public Dictionary<string, TunnelConnectInfo> Connections { get; set; } = new Dictionary<string, TunnelConnectInfo>();
}
}
}

View File

@@ -26,10 +26,6 @@ namespace cmonitor.plugins.tunnel.transport
/// 收到连接
/// </summary>
public Action<ITunnelConnection> OnConnected { get; set; }
/// <summary>
/// 断开连接
/// </summary>
public Action<ITunnelConnection> OnDisConnected { get; set; }
public Action<string> OnConnectFail { get; set; }

View File

@@ -18,7 +18,6 @@ namespace cmonitor.plugins.tunnel.transport
public Action<TunnelTransportInfo> OnConnectBegin { get; set; } = (info) => { };
public Action<TunnelTransportInfo> OnConnecting { get; set; }
public Action<ITunnelConnection> OnConnected { get; set; } = (state) => { };
public Action<ITunnelConnection> OnDisConnected { get; set; } = (state) => { };
public Action<string> OnConnectFail { get; set; } = (machineName) => { };

View File

@@ -0,0 +1,29 @@
using cmonitor.config;
using cmonitor.startup;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace cmonitor.plugins.viewer
{
public sealed class TuntapStartup : IStartup
{
public StartupLevel Level => StartupLevel.Normal;
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
}
}

View File

@@ -24,7 +24,7 @@ namespace cmonitor.plugins.viewer
serviceCollection.AddSingleton<ViewerClientMessenger>();
serviceCollection.AddSingleton<ViewerProxyClient>();
serviceCollection.AddSingleton<ViewerProxy>();
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
@@ -37,7 +37,7 @@ namespace cmonitor.plugins.viewer
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
Logger.Instance.Info($"use viewer proxy server in client mode.");
ViewerProxyClient viewerProxyServer = serviceProvider.GetService<ViewerProxyClient>();
ViewerProxy viewerProxyServer = serviceProvider.GetService<ViewerProxy>();
viewerProxyServer.Start(0);
}

View File

@@ -1,612 +1,52 @@
using cmonitor.client.tunnel;
using cmonitor.client.running;
using cmonitor.client.tunnel;
using cmonitor.config;
using cmonitor.plugins.relay;
using cmonitor.plugins.tunnel;
using common.libs;
using common.libs.extends;
using System.Buffers;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
namespace cmonitor.plugins.viewer.proxy
{
public class ViewerProxy
public sealed class ViewerProxy : TunnelProxy
{
private AsyncUserToken userToken;
private Socket socket;
private UdpClient udpClient;
private readonly NumberSpace ns = new NumberSpace();
private readonly ConcurrentDictionary<ConnectId, Socket> dic = new ConcurrentDictionary<ConnectId, Socket>();
private readonly RunningConfig runningConfig;
private readonly TunnelTransfer tunnelTransfer;
private readonly RelayTransfer relayTransfer;
private readonly Config config;
public IPEndPoint LocalEndpoint => socket?.LocalEndPoint as IPEndPoint ?? new IPEndPoint(IPAddress.Any, 0);
private ITunnelConnection connection;
public ViewerProxy()
public ViewerProxy(RunningConfig runningConfig, TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, Config config)
{
this.runningConfig = runningConfig;
this.tunnelTransfer = tunnelTransfer;
this.relayTransfer = relayTransfer;
this.config = config;
Start(0);
Logger.Instance.Info($"start viewer proxy, port : {LocalEndpoint.Port}");
tunnelTransfer.SetConnectCallback("viewer", BindConnectionReceive);
relayTransfer.SetConnectCallback("viewer", BindConnectionReceive);
}
public void Start(int port)
protected override async Task Connect(AsyncUserToken token)
{
try
token.Proxy.TargetEP = runningConfig.Data.Viewer.ConnectEP;
token.Connection = connection;
if (connection == null || connection.Connected == false)
{
Stop();
IPEndPoint localEndPoint = new IPEndPoint(NetworkHelper.IPv6Support ? IPAddress.IPv6Any : IPAddress.Any, port);
socket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.IPv6Only(localEndPoint.AddressFamily, false);
socket.ReuseBind(localEndPoint);
socket.Listen(int.MaxValue);
userToken = new AsyncUserToken
connection = await tunnelTransfer.ConnectAsync(runningConfig.Data.Viewer.ServerMachine, "viewer");
if (connection == null)
{
Socket = socket
};
SocketAsyncEventArgs acceptEventArg = new SocketAsyncEventArgs
connection = await relayTransfer.ConnectAsync(runningConfig.Data.Viewer.ServerMachine, "viewer", config.Data.Client.Relay.SecretKey);
}
if (connection != null)
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
userToken.Saea = acceptEventArg;
acceptEventArg.Completed += IO_Completed;
StartAccept(acceptEventArg);
udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, localEndPoint.Port));
udpClient.Client.EnableBroadcast = true;
udpClient.Client.WindowsUdpBug();
IAsyncResult result = udpClient.BeginReceive(ReceiveCallbackUdp, null);
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
}
}
private readonly AsyncUserUdpToken asyncUserUdpToken = new AsyncUserUdpToken
{
Proxy = new ProxyInfo { Step = ProxyStep.Forward, ConnectId = 0 }
};
private async void ReceiveCallbackUdp(IAsyncResult result)
{
try
{
//System.Net.Quic.QuicListener.IsSupported
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, IPEndPoint.MinPort);
byte[] bytes = udpClient.EndReceive(result, ref endPoint);
asyncUserUdpToken.Proxy.Data = bytes;
await ConnectUdp(asyncUserUdpToken);
result = udpClient.BeginReceive(ReceiveCallbackUdp, null);
}
catch (Exception)
{
}
}
protected virtual async Task ConnectUdp(AsyncUserUdpToken token)
{
await Task.CompletedTask;
}
private void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
acceptEventArg.AcceptSocket = null;
AsyncUserToken token = (AsyncUserToken)acceptEventArg.UserToken;
try
{
if (token.Socket.AcceptAsync(acceptEventArg) == false)
{
ProcessAccept(acceptEventArg);
BindConnectionReceive(connection);
token.Connection = connection;
}
}
catch (Exception)
{
token.Clear();
}
}
private void IO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Accept:
ProcessAccept(e);
break;
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
default:
break;
}
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
if (e.AcceptSocket != null)
{
BindReceive(e);
StartAccept(e);
}
}
private void BindReceive(SocketAsyncEventArgs e)
{
try
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
var socket = e.AcceptSocket;
if (socket == null || socket.RemoteEndPoint == null)
{
return;
}
socket.KeepAlive();
AsyncUserToken userToken = new AsyncUserToken
{
Socket = socket,
Proxy = new ProxyInfo { Data = Helper.EmptyArray, Step = ProxyStep.Request, ConnectId = ns.Increment() }
};
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
userToken.Saea = readEventArgs;
readEventArgs.SetBuffer(new byte[8 * 1024], 0, 8 * 1024);
readEventArgs.Completed += IO_Completed;
if (socket.ReceiveAsync(readEventArgs) == false)
{
ProcessReceive(readEventArgs);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
}
}
private async void ProcessReceive(SocketAsyncEventArgs e)
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
try
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
int offset = e.Offset;
int length = e.BytesTransferred;
await ReadPacket(token, e.Buffer.AsMemory(offset, length));
if (token.Socket.Available > 0)
{
while (token.Socket.Available > 0)
{
length = token.Socket.Receive(e.Buffer);
if (length > 0)
{
await ReadPacket(token, e.Buffer.AsMemory(0, length));
}
else
{
CloseClientSocket(token);
return;
}
}
}
if (token.Socket.Connected == false)
{
CloseClientSocket(token);
return;
}
if (token.Socket.ReceiveAsync(e) == false)
{
ProcessReceive(e);
}
}
else
{
CloseClientSocket(token);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
CloseClientSocket(token);
}
}
private async Task ReadPacket(AsyncUserToken token, Memory<byte> data)
{
if (token.Proxy.Step == ProxyStep.Request)
{
await Connect(token);
if (token.Connection != null)
{
//发送连接请求包
await SendToConnection(token).ConfigureAwait(false);
token.Proxy.Step = ProxyStep.Forward;
token.Proxy.TargetEP = null;
//发送后续数据包
token.Proxy.Data = data;
await SendToConnection(token).ConfigureAwait(false);
//绑定
dic.TryAdd(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode()), token.Socket);
}
else
{
CloseClientSocket(token);
}
}
else
{
token.Proxy.Data = data;
await SendToConnection(token).ConfigureAwait(false);
}
}
protected virtual async Task Connect(AsyncUserToken token)
{
await Task.CompletedTask;
}
private async Task SendToConnection(AsyncUserToken token)
{
byte[] connectData = token.Proxy.ToBytes(out int length);
try
{
await token.Connection.SendAsync(connectData.AsMemory(0, length)).ConfigureAwait(false);
}
catch (Exception)
{
CloseClientSocket(token);
}
finally
{
token.Proxy.Return(connectData);
}
}
protected void BindConnectionReceive(ITunnelConnection connection)
{
connection.BeginReceive(InputConnectionData, CloseConnection, new AsyncUserToken
{
Connection = connection,
Buffer = new ReceiveDataBuffer(),
Proxy = new ProxyInfo { }
});
}
protected async Task InputConnectionData(ITunnelConnection connection, Memory<byte> memory, object userToken)
{
AsyncUserToken token = userToken as AsyncUserToken;
//是一个完整的包
if (token.Buffer.Size == 0 && memory.Length > 4)
{
int packageLen = memory.ToInt32();
if (packageLen == memory.Length - 4)
{
token.Proxy.DeBytes(memory.Slice(0, packageLen + 4));
await ReadConnectionPack(token).ConfigureAwait(false);
return;
}
}
//不是完整包
token.Buffer.AddRange(memory);
do
{
int packageLen = token.Buffer.Data.ToInt32();
if (packageLen > token.Buffer.Size - 4)
{
break;
}
token.Proxy.DeBytes(token.Buffer.Data.Slice(0, packageLen + 4));
await ReadConnectionPack(token).ConfigureAwait(false);
token.Buffer.RemoveRange(0, packageLen + 4);
} while (token.Buffer.Size > 4);
}
protected async Task CloseConnection(ITunnelConnection connection, object userToken)
{
CloseClientSocket(userToken as AsyncUserToken);
await Task.CompletedTask;
}
private async Task ReadConnectionPack(AsyncUserToken token)
{
if (token.Proxy.Step == ProxyStep.Request)
{
await ConnectBind(token).ConfigureAwait(false);
}
else
{
await SendToSocket(token).ConfigureAwait(false);
}
}
private async Task ConnectBind(AsyncUserToken token)
{
Socket socket = new Socket(token.Proxy.TargetEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.KeepAlive();
await socket.ConnectAsync(token.Proxy.TargetEP);
dic.TryAdd(new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode()), socket);
BindReceiveTarget(new AsyncUserToken
{
Connection = token.Connection,
Socket = socket,
Proxy = new ProxyInfo
{
ConnectId = token.Proxy.ConnectId,
Step = ProxyStep.Forward
}
});
}
private async Task SendToSocket(AsyncUserToken token)
{
ConnectId connectId = new ConnectId(token.Proxy.ConnectId, token.Connection.GetHashCode());
if (dic.TryGetValue(connectId, out Socket source))
{
try
{
await source.SendAsync(token.Proxy.Data);
}
catch (Exception)
{
CloseClientSocket(token);
}
}
}
private void IO_CompletedTarget(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceiveTarget(e);
break;
default:
break;
}
}
private void BindReceiveTarget(AsyncUserToken userToken)
{
try
{
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs
{
UserToken = userToken,
SocketFlags = SocketFlags.None,
};
readEventArgs.SetBuffer(new byte[8 * 1024], 0, 8 * 1024);
readEventArgs.Completed += IO_CompletedTarget;
if (userToken.Socket.ReceiveAsync(readEventArgs) == false)
{
ProcessReceiveTarget(readEventArgs);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
}
}
private async void ProcessReceiveTarget(SocketAsyncEventArgs e)
{
AsyncUserToken token = (AsyncUserToken)e.UserToken;
try
{
if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
{
int offset = e.Offset;
int length = e.BytesTransferred;
token.Proxy.Data = e.Buffer.AsMemory(offset, length);
await SendToConnection(token).ConfigureAwait(false);
if (token.Socket.Available > 0)
{
while (token.Socket.Available > 0)
{
length = token.Socket.Receive(e.Buffer);
if (length > 0)
{
token.Proxy.Data = e.Buffer.AsMemory(0, length);
await SendToConnection(token).ConfigureAwait(false);
}
else
{
CloseClientSocket(token);
return;
}
}
}
if (token.Connection.Connected == false)
{
CloseClientSocket(token);
return;
}
if (token.Socket.ReceiveAsync(e) == false)
{
ProcessReceiveTarget(e);
}
}
else
{
CloseClientSocket(token);
}
}
catch (Exception ex)
{
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
CloseClientSocket(token);
}
}
private void CloseClientSocket(AsyncUserToken token)
{
if (token.Connection != null)
{
int code = token.Connection.GetHashCode();
if (token.Connection.Connected == false)
{
foreach (ConnectId item in dic.Keys.Where(c => c.hashCode == code).ToList())
{
dic.TryRemove(item, out _);
}
}
else
{
dic.TryRemove(new ConnectId(token.Proxy.ConnectId, code), out _);
}
}
token.Clear();
}
public void Stop()
{
CloseClientSocket(userToken);
udpClient?.Close();
}
}
public enum ProxyStep : byte
{
Request = 1,
Forward = 2
}
public record struct ConnectId
{
public ulong connectId;
public int hashCode;
public ConnectId(ulong connectId, int hashCode)
{
this.connectId = connectId;
this.hashCode = hashCode;
}
}
public sealed class ProxyInfo
{
public ulong ConnectId { get; set; }
public ProxyStep Step { get; set; } = ProxyStep.Request;
public IPEndPoint TargetEP { get; set; }
public Memory<byte> Data { get; set; }
public byte[] ToBytes(out int length)
{
int ipLength = TargetEP == null ? 0 : (TargetEP.AddressFamily == AddressFamily.InterNetwork ? 4 : 16) + 2;
length = 4 + 8 + 1
+ 1 + ipLength
+ Data.Length;
byte[] bytes = ArrayPool<byte>.Shared.Rent(length);
Memory<byte> memory = bytes.AsMemory();
int index = 0;
(length - 4).ToBytes(memory);
index += 4;
ConnectId.ToBytes(memory.Slice(index));
index += 8;
bytes[index] = (byte)Step;
index += 1;
bytes[index] = (byte)ipLength;
index += 1;
if (ipLength > 0)
{
TargetEP.Address.TryWriteBytes(memory.Slice(index).Span, out int writeLength);
index += writeLength;
((ushort)TargetEP.Port).ToBytes(memory.Slice(index));
index += 2;
}
Data.CopyTo(memory.Slice(index));
return bytes;
}
public void Return(byte[] bytes)
{
ArrayPool<byte>.Shared.Return(bytes);
}
public void DeBytes(Memory<byte> memory)
{
int index = 4;
Span<byte> span = memory.Span;
ConnectId = memory.Slice(index).ToUInt64();
index += 8;
Step = (ProxyStep)span[index];
index += 1;
byte ipLength = span[index];
index += 1;
if (ipLength > 0)
{
IPAddress ip = new IPAddress(span.Slice(index, ipLength - 2));
index += ipLength;
ushort port = span.Slice(index - 2).ToUInt16();
TargetEP = new IPEndPoint(ip, port);
}
Data = memory.Slice(index);
}
}
public sealed class AsyncUserUdpToken
{
public UdpClient SourceSocket { get; set; }
public Socket TargetSocket { get; set; }
public ProxyInfo Proxy { get; set; }
public void Clear()
{
SourceSocket?.Close();
SourceSocket = null;
GC.Collect();
}
}
public sealed class AsyncUserToken
{
public Socket Socket { get; set; }
public ITunnelConnection Connection { get; set; }
public ProxyInfo Proxy { get; set; }
public ReceiveDataBuffer Buffer { get; set; }
public SocketAsyncEventArgs Saea { get; set; }
public void Clear()
{
Socket?.SafeClose();
Socket = null;
Buffer?.Clear();
Saea?.Dispose();
GC.Collect();
}
}
}

View File

@@ -1,52 +0,0 @@
using cmonitor.client.running;
using cmonitor.client.tunnel;
using cmonitor.config;
using cmonitor.plugins.relay;
using cmonitor.plugins.tunnel;
using common.libs;
namespace cmonitor.plugins.viewer.proxy
{
public sealed class ViewerProxyClient : ViewerProxy
{
private readonly RunningConfig runningConfig;
private readonly TunnelTransfer tunnelTransfer;
private readonly RelayTransfer relayTransfer;
private readonly Config config;
private ITunnelConnection connection;
public ViewerProxyClient(RunningConfig runningConfig, TunnelTransfer tunnelTransfer, RelayTransfer relayTransfer, Config config)
{
this.runningConfig = runningConfig;
this.tunnelTransfer = tunnelTransfer;
this.relayTransfer = relayTransfer;
this.config = config;
Start(0);
Logger.Instance.Info($"start viewer proxy, port : {LocalEndpoint.Port}");
tunnelTransfer.SetConnectCallback("viewer", BindConnectionReceive);
relayTransfer.SetConnectCallback("viewer", BindConnectionReceive);
}
protected override async Task Connect(AsyncUserToken token)
{
token.Proxy.TargetEP = runningConfig.Data.Viewer.ConnectEP;
token.Connection = connection;
if (connection == null || connection.Connected == false)
{
connection = await tunnelTransfer.ConnectAsync(runningConfig.Data.Viewer.ServerMachine, "viewer");
if (connection == null)
{
connection = await relayTransfer.ConnectAsync(runningConfig.Data.Viewer.ServerMachine, "viewer", config.Data.Client.Relay.SecretKey);
}
if (connection != null)
{
BindConnectionReceive(connection);
token.Connection = connection;
}
}
}
}
}

View File

@@ -29,9 +29,9 @@ namespace cmonitor.plugins.viewer.report
private readonly MessengerSender messengerSender;
private readonly ClientSignInState clientSignInState;
private readonly Config config;
private readonly ViewerProxyClient viewerProxyClient;
private readonly ViewerProxy viewerProxyClient;
public ViewerReport(Config config, RunningConfig runningConfig, IViewer viewer, ShareMemory shareMemory, ClientSignInState clientSignInState, MessengerSender messengerSender, ViewerProxyClient viewerProxyClient)
public ViewerReport(Config config, RunningConfig runningConfig, IViewer viewer, ShareMemory shareMemory, ClientSignInState clientSignInState, MessengerSender messengerSender, ViewerProxy viewerProxyClient)
{
this.config = config;
this.runningConfig = runningConfig;

View File

@@ -15,7 +15,7 @@ namespace cmonitor.plugins.wallpaper.report
if (info.Open)
{
CommandHelper.Windows(string.Empty, new string[] {
$"start cmonitor.wallpaper.win.exe \"{info.ImgUrl}\" {config.Data.Client.ShareMemoryKey} {config.Data.Client.ShareMemoryCount} {config.Data.Client.ShareMemorySize} {(int)ShareMemoryIndexs.Keyboard} {(int)ShareMemoryIndexs.Wallpaper}"
$"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

@@ -1,5 +1,6 @@
using cmonitor.client.report;
using cmonitor.config;
using common.libs;
namespace cmonitor.plugins.watch.report
{
@@ -12,6 +13,7 @@ namespace cmonitor.plugins.watch.report
#if RELEASE
OpenFiles();
#endif
OpenFiles();
}
public object GetReports(ReportType reportType)
@@ -27,11 +29,32 @@ namespace cmonitor.plugins.watch.report
try
{
fss.Add(new FileStream(item, FileMode.Open, FileAccess.Read, FileShare.Read));
Logger.Instance.Warning($"watch file {item}");
}
catch (Exception)
{
}
}
OpenFiles("./plugins");
}
private void OpenFiles(string path)
{
foreach (var item in Directory.GetFiles(path))
{
try
{
fss.Add(new FileStream(item, FileMode.Open, FileAccess.Read, FileShare.Read));
Logger.Instance.Warning($"watch file {item}");
}
catch (Exception)
{
}
}
foreach (var item in Directory.GetDirectories(path))
{
OpenFiles(item);
}
}
}
}

View File

@@ -1,14 +1,15 @@
using System;
using System.IO;
namespace common.libs
{
public static class FireWallHelper
{
public static void Write(string fileName)
public static void Write(string fileName, string distPatt)
{
if (OperatingSystem.IsWindows())
{
Windows(fileName);
Windows(fileName, distPatt);
}
else if (OperatingSystem.IsLinux())
{
@@ -29,7 +30,7 @@ namespace common.libs
});
}
private static void Windows(string fileName)
private static void Windows(string fileName,string distPatth)
{
try
{
@@ -51,9 +52,15 @@ 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";
System.IO.File.WriteAllText("firewall.bat", content);
CommandHelper.Execute("firewall.bat", string.Empty, new string[0]);
System.IO.File.Delete("firewall.bat");
if(Directory.Exists(distPatth) == false)
{
Directory.CreateDirectory(distPatth);
}
string firewall = Path.Join(distPatth, "firewall.bat");
System.IO.File.WriteAllText(firewall, content);
CommandHelper.Execute(firewall, string.Empty, new string[0]);
System.IO.File.Delete(firewall);
}
catch (Exception)
{

View File

@@ -14,10 +14,10 @@ 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/ -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.llock.win -c release -f net8.0-windows -r win-x64 -o public/extends/ -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.message.win -c release -f net8.0-windows -r win-x64 -o public/extends/ -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.notify.win -c release -f net8.0-windows -r win-x64 -o public/extends/ -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.wallpaper.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
dotnet publish ./cmonitor.notify.win -c release -f net8.0-windows -r win-x64 -o public/extends/plugins/notify -p:PublishSingleFile=true --self-contained false
dotnet publish ./cmonitor.wallpaper.win -c release -f net8.0-windows -r win-x64 -o public/extends/plugins/wallpaper -p:PublishSingleFile=true --self-contained false
dotnet restore ./cmonitor.viewer.server.win
MSBuild.exe ./cmonitor.viewer.server.win /t:Publish /p:Configuration=Release /p:TargetFramework=net8.0-windows /p:PublishSingleFile=true /p:RuntimeIdentifier=win-x64 /p:PublishDir=../public/extends/
MSBuild.exe ./cmonitor.viewer.server.win /t:Publish /p:Configuration=Release /p:TargetFramework=net8.0-windows /p:PublishSingleFile=true /p:RuntimeIdentifier=win-x64 /p:PublishDir=../public/extends/plugins/viewer

View File

@@ -15,7 +15,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\\*" /s /f /h /y
echo F|xcopy "cmonitor.viewer.client.win\\dist\\*" "public\\publish\\%%r\\plugins\\viewer\\*" /s /f /h /y
)
for %%r in (linux-x64,linux-x64-any) do (