From 82d025960f61b2d9337123952150f1f006dcb88a Mon Sep 17 00:00:00 2001 From: xieguigang Date: Fri, 5 Oct 2018 02:56:00 +0800 Subject: [PATCH 1/6] add code comments --- .../Network/Tcp/TcpSynchronizationServicesSocket.vb | 2 +- Language/Value/DefaultValue/DefaultString.vb | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb b/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb index 09b1fa94..c056ff0b 100644 --- a/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb +++ b/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb @@ -105,7 +105,7 @@ Namespace Net ''' 监听的本地端口号,假若需要进行端口映射的话,则可以在方法之中设置映射的端口号 ''' Sub New(Optional LocalPort As Integer = 11000, - Optional exHandler As Abstract.ExceptionHandler = Nothing) + Optional exHandler As ExceptionHandler = Nothing) Me._LocalPort = LocalPort Me.__exceptionHandle = If(exHandler Is Nothing, AddressOf PrintException, exHandler) diff --git a/Language/Value/DefaultValue/DefaultString.vb b/Language/Value/DefaultValue/DefaultString.vb index 46a05c87..156c964d 100644 --- a/Language/Value/DefaultValue/DefaultString.vb +++ b/Language/Value/DefaultValue/DefaultString.vb @@ -153,7 +153,8 @@ Namespace Language.Default End Operator ''' - ''' If is empty then returns , else returns itself. + ''' If is empty then returns , + ''' else returns itself. ''' ''' ''' @@ -166,6 +167,12 @@ Namespace Language.Default End If End Operator + ''' + ''' Get a value or using default value. + ''' + ''' + ''' + ''' Public Shared Operator Or(value As DefaultString, x%) As Integer Return CInt(value Or CDbl(x)) End Operator From d48cf079c761a9e0426bd30ccfea21d18ad93f22 Mon Sep 17 00:00:00 2001 From: xieguigang Date: Fri, 5 Oct 2018 03:03:43 +0800 Subject: [PATCH 2/6] obsolete code removes --- .../Tools/Network/SSL/Certificate.vb | 278 ------------------ .../Tools/Network/SSL/Extensions.vb | 85 ------ .../Tools/Network/SSL/Protocol.vb | 271 ----------------- .../Tools/Network/SSL/SSL.pptx | Bin 65296 -> 0 bytes .../SSL/SSLSynchronizationServicesSocket.vb | 258 ---------------- 5 files changed, 892 deletions(-) delete mode 100644 ApplicationServices/Tools/Network/SSL/Certificate.vb delete mode 100644 ApplicationServices/Tools/Network/SSL/Extensions.vb delete mode 100644 ApplicationServices/Tools/Network/SSL/Protocol.vb delete mode 100644 ApplicationServices/Tools/Network/SSL/SSL.pptx delete mode 100644 ApplicationServices/Tools/Network/SSL/SSLSynchronizationServicesSocket.vb diff --git a/ApplicationServices/Tools/Network/SSL/Certificate.vb b/ApplicationServices/Tools/Network/SSL/Certificate.vb deleted file mode 100644 index 4d6bc865..00000000 --- a/ApplicationServices/Tools/Network/SSL/Certificate.vb +++ /dev/null @@ -1,278 +0,0 @@ -#Region "Microsoft.VisualBasic::dfc585cd43fad999d3346ae63aaaa225, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\SSL\Certificate.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class Certificate - ' - ' Properties: AppDomain, hash, IsPublicToken, PrivateKey, uid - ' - ' Constructor: (+4 Overloads) Sub New - ' Function: __decrypt, __load, (+2 Overloads) CopyFrom, (+2 Overloads) Decrypt, DecryptString - ' (+2 Overloads) Encrypt, EncryptData, (+2 Overloads) Install, InstallPublicToken, PublicEncrypt - ' ToString - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports Microsoft.VisualBasic.Emit.CodeDOM_VBC -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.SecurityString - -Namespace Net.SSL - - ''' - ''' 应用程序的完整性验证和用户身份的验证 - ''' - Public Class Certificate : Implements SecurityString.SecurityStringModel.ISecurityStringModel - - Protected _SHA256 As SecurityString.SHA256 - - ''' - ''' 私有密匙 - ''' - ''' - Public Overridable ReadOnly Property PrivateKey As String - Get - Return _SHA256.strPassphrase - End Get - End Property - - ''' - ''' 计算出来的哈希值只能为负数,现在约定,当这个属性为0的时候就认为这个证书是公共密匙, - ''' 这个一般是使用用户的账号所计算出来的哈希值 - ''' - ''' - Public ReadOnly Property uid As Long - Get - Return _uid - End Get - End Property - - ''' - ''' 初始化继承类所需要的 - ''' - Protected _uid As Long - - Public ReadOnly Property IsPublicToken As Boolean - Get - Return uid = 0L - End Get - End Property - - ''' - ''' 与属性所不同的是,这个属性是的哈希值, - ''' 通常这个哈希值在请求resultful WebAPI的时候用来作为用户的唯一标识 - ''' - ''' - Public ReadOnly Property hash As Long - - Public Overrides Function ToString() As String - Return $"[{NameOf(Certificate)}] {uid} {_SHA256.Passphrase}" - End Function - - ''' - ''' 请注意这个构造方法会计算一遍密码的哈希值,假若需要直接进行初始化,请使用方法 - ''' - ''' 用户的私有密匙 - ''' 大小写无关的 - Sub New(hash As String, uid As String) - hash = SecurityString.MD5Hash.GetMd5Hash(hash) - _SHA256 = New SecurityString.SHA256(hash, SALT) - Me._uid = SecurityString.MD5Hash.ToLong(SecurityString.MD5Hash.GetMd5Hash(uid.ToLower)) - Me.hash = SecurityString.MD5Hash.ToLong(hash) - End Sub - - ''' - ''' - ''' - ''' 原始的密码,会在这个构造函数之中计算为哈希值产生新的密码。 - ''' 客户端所发送过来的使用哈希值计算出来的唯一标识符 - Sub New(hash As String, uid As Long) - hash = SecurityString.MD5Hash.GetMd5Hash(hash) - _SHA256 = New SecurityString.SHA256(hash, SALT) - Me._uid = uid - Me.hash = SecurityString.MD5Hash.ToLong(hash) - End Sub - - ''' - ''' 从服务器上面所返回来的握手数据 - ''' - ''' - Sub New(handshakeData As RequestStream) - Dim hash As String = SecurityString.MD5Hash.GetMd5Hash(handshakeData.GetUTF8String) - _SHA256 = New SHA256(hash, SALT) - Me._uid = handshakeData.uid - Me.hash = SecurityString.MD5Hash.ToLong(hash) - End Sub - - ''' - ''' 这个构造函数不再计算哈希值而是直接初始化 - ''' - ''' 必须是md5哈希值 - Protected Sub New(hash As String) - _SHA256 = New SHA256(hash, SALT) - Me.hash = SecurityString.MD5Hash.ToLong(hash) - End Sub - - Const SALT As String = "88888888" - - Public Shared Function CopyFrom(CA As SSL.Certificate, uid As String) As SSL.Certificate - Dim hashCode As String = SecurityString.MD5Hash.ToLong(SecurityString.MD5Hash.GetMd5Hash(uid.ToLower)) - Return New SSL.Certificate(CA._SHA256.Passphrase) With {._uid = hashCode} - End Function - - Public Shared Function CopyFrom(CA As SSL.Certificate, uid As Long) As SSL.Certificate - Return New SSL.Certificate(CA._SHA256.Passphrase) With {._uid = uid} - End Function - - ''' - ''' 不计算密匙哈希值而是直接安装 - ''' - ''' - ''' - ''' - Public Shared Function Install(privateKey As String, uid As Long) As SSL.Certificate - Return New SSL.Certificate(privateKey) With {._uid = uid} - End Function - - Public Shared Function InstallPublicToken(publicKey As String) As SSL.Certificate - Call $"Install public token ssl certificate.".__DEBUG_ECHO - Return New SSL.Certificate(publicKey) - End Function - - ''' - ''' 函数会根据uid的值来设定协议为私有密匙还是公共密匙 - ''' - ''' - ''' - Public Overridable Function Encrypt(request As RequestStream) As RequestStream - Dim byteData As Byte() = request.Serialize - Dim Protocol = If(IsPublicToken, RequestStream.Protocols.SSL_PublicToken, RequestStream.Protocols.SSL) - byteData = _SHA256.Encrypt(byteData) - request = New RequestStream(RequestStream.SYS_PROTOCOL, Protocol, byteData) With {.uid = uid} - - Return request - End Function - - ''' - ''' 强制将协议设定为公共密匙加密 - ''' - ''' - ''' - Public Overridable Function PublicEncrypt(request As RequestStream) As RequestStream - Dim byteData As Byte() = request.Serialize - byteData = _SHA256.Encrypt(byteData) - request = New RequestStream(RequestStream.SYS_PROTOCOL, RequestStream.Protocols.SSL_PublicToken, byteData) With {.uid = uid} - - Return request - End Function - - ''' - ''' - ''' - ''' - ''' - Public Overridable Function Decrypt(request As RequestStream) As RequestStream - Return __decrypt(request, _SHA256) - End Function - - Protected Shared Function __decrypt(request As RequestStream, sha256 As SecurityString.SHA256) As RequestStream - Dim byteData As Byte() = request.ChunkBuffer - byteData = sha256.Decrypt(byteData) - request = New RequestStream(byteData) - Return request - End Function - - ''' - ''' 检查应用程序的完整性 - ''' - ''' - Public Shared ReadOnly Property AppDomain As Certificate = Install(App.ExecutablePath, publicToken:=True) - - ''' - ''' - ''' - ''' 可执行程序的文件路径 - ''' - Public Shared Function Install(App As String, Optional publicToken As Boolean = False) As Certificate - Call Console.WriteLine() - Call Console.WriteLine() - Call $"**************************************************[ INSTALL {NameOf(Certificate)}: {App.ToFileURL}]****************************************************************".__DEBUG_ECHO - - Dim Modules = (From [module] As String - In __load(App).AsParallel - Select [module], hash = SecurityString.MD5Hash.GetFileHashString([module]) - Order By hash Ascending).ToArray '????已经排过序了,为什么顺序还是不一样 - For Each [module] In Modules - Call $" Installed Module ==> {[module].ToString}".__DEBUG_ECHO - Next - Dim caHashString As String = String.Join("+", (From [mod] In Modules Select [mod].hash).ToArray) - Dim CA As Certificate = If(publicToken, Certificate.InstallPublicToken(SecurityString.GetMd5Hash(caHashString)), New Certificate(caHashString, NameOf(App))) - - Call Console.WriteLine() - Call Console.WriteLine() - Call $"**************************************************[ END OF INSTALL {NameOf(Certificate)} ==> {CA.ToString}]****************************************************************".__DEBUG_ECHO - - Return CA - End Function - - Private Shared Function __load(path As String) As String() - Dim assembly As System.Reflection.Assembly - Try - assembly = System.Reflection.Assembly.LoadFile(FileIO.FileSystem.GetFileInfo(path).FullName) - Catch ex As Exception - Throw New Exception(path.ToFileURL, ex) - End Try - Dim refListBuffer = GetReferences(assembly:=assembly, removeSystem:=True) - - Return refListBuffer - End Function - - Public Overridable Function Decrypt(input() As Byte) As Byte() Implements SecurityStringModel.ISecurityStringModel.Decrypt - Return _SHA256.Decrypt(input) - End Function - - Public Overridable Function DecryptString(text As String) As String Implements SecurityStringModel.ISecurityStringModel.DecryptString - Return _SHA256.DecryptString(text) - End Function - - Public Overridable Function Encrypt(input() As Byte) As Byte() Implements SecurityStringModel.ISecurityStringModel.Encrypt - Return _SHA256.Encrypt(input) - End Function - - Public Overridable Function EncryptData(text As String) As String Implements SecurityStringModel.ISecurityStringModel.EncryptData - Return _SHA256.EncryptData(text) - End Function - End Class -End Namespace diff --git a/ApplicationServices/Tools/Network/SSL/Extensions.vb b/ApplicationServices/Tools/Network/SSL/Extensions.vb deleted file mode 100644 index da54d5b6..00000000 --- a/ApplicationServices/Tools/Network/SSL/Extensions.vb +++ /dev/null @@ -1,85 +0,0 @@ -#Region "Microsoft.VisualBasic::684b0b62a717929ca1123ca139351092, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\SSL\Extensions.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Module CAExtensions - ' - ' Function: InstallCommon - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Reflection -Imports Microsoft.VisualBasic.Win32 - -Namespace Net.SSL - - Module CAExtensions - - Public Function InstallCommon(ByRef privateKeys As Dictionary(Of Long, Net.SSL.Certificate), - CA As Certificate, - [overrides] As Boolean, - trace As String, - invoke As MethodInfo) As Boolean - - If privateKeys.ContainsKey(CA.uid) Then - If WindowsServices.Initialized Then - Call ServicesLogs.WriteEntry({$"{invoke.DeclaringType.Name} private key dictionary contains a certificate which its uid: {CA.uid} is conflict with the new install certificate.", - If([overrides], "And the old conflicting certificates was overrides by the new one.", "The certificates operation was skipped!"), - $"Current: {privateKeys(CA.uid).ToString}", - $"Certificates_going_to_install: {CA.ToString}", - $"install_trace: {trace}"}, - invoke.FullName, - EventLogEntryType.SuccessAudit) - End If - - If [overrides] Then - Call privateKeys.Remove(CA.uid) - Else - Return False - End If - End If - - Call privateKeys.Add(CA.uid, CA) - - If WindowsServices.Initialized Then - Call ServicesLogs.WriteEntry({$"New certificates was installed on server!", CA.ToString}, - $"{trace} ==> {invoke.FullName}", - EventLogEntryType.SuccessAudit) - End If - - Return True - End Function - End Module -End Namespace diff --git a/ApplicationServices/Tools/Network/SSL/Protocol.vb b/ApplicationServices/Tools/Network/SSL/Protocol.vb deleted file mode 100644 index 0419ad73..00000000 --- a/ApplicationServices/Tools/Network/SSL/Protocol.vb +++ /dev/null @@ -1,271 +0,0 @@ -#Region "Microsoft.VisualBasic::c143a9b4ec352912719cad03404449ab, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\SSL\Protocol.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Module SSLProtocols - ' - ' Function: (+3 Overloads) Handshaking - ' Interface ISSLServices - ' - ' Properties: CA, DeclaringModule, InstallCertificates, PrivateKeys, RaiseHandshakingEvent - ' RefuseHandshake, ResponseHandler - ' - ' Function: Install - ' - ' Delegate Sub - ' - ' - ' Delegate Function - ' - ' Function: __sslHandshake, SSLServicesResponseHandler - ' - ' - ' - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Reflection -Imports Microsoft.VisualBasic.Net.Http -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Win32 - -Namespace Net.SSL - - Public Module SSLProtocols - - ''' - ''' 客户端与服务器之间初始化加密连接 - ''' - ''' 客户端的证书,这个是服务器来进行客户端程序的完整性验证的 - ''' - Public Function Handshaking(CA As SSL.Certificate, services As System.Net.IPEndPoint) As SSL.Certificate - Dim request As RequestStream = - New RequestStream(RequestStream.SYS_PROTOCOL, - RequestStream.Protocols.SSLHandshake, - New Byte() {}) With { - .uid = CA.uid - } - request = New Net.AsynInvoke(services).SendMessage(request, CA, isPublicToken:=True) '这个函数会把用户的账号和当前的客户端的数字证书发送给服务器 -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(CA)} hash:={CA.uid}".__DEBUG_ECHO -#End If - '服务器验证数字证书通过之后就会返回动态的客户端的私有密匙,一般是对随机数做MD5得到私有密匙 - Dim PrivateKey As New SSL.Certificate(request) -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(PrivateKey)} hash:={PrivateKey.uid}".__DEBUG_ECHO -#End If - Return PrivateKey - End Function - - Public Function Handshaking(PublicToken As SSL.Certificate, uid As String, services As System.Net.IPEndPoint) As SSL.Certificate - Dim CA = SSL.Certificate.CopyFrom(PublicToken, uid) -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(CA)} hash:={CA.uid}".__DEBUG_ECHO -#End If - Dim privateKey As SSL.Certificate = Handshaking(CA, services) -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(privateKey)} hash:={privateKey.uid}".__DEBUG_ECHO -#End If - Return privateKey - End Function - - Public Function Handshaking(CA As SSL.Certificate, services As System.Net.IPEndPoint, Install As InstallCertificates) As SSL.Certificate - Dim request As RequestStream = - New RequestStream(RequestStream.SYS_PROTOCOL, - RequestStream.Protocols.SSLHandshake, - New Byte() {}) With { - .uid = CA.uid - } - request = New Net.AsynInvoke(services).SendMessage(request, CA, isPublicToken:=True) '这个函数会把用户的账号和当前的客户端的数字证书发送给服务器 -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(CA)} hash:={CA.uid}".__DEBUG_ECHO -#End If - '服务器验证数字证书通过之后就会返回动态的客户端的私有密匙,一般是对随机数做MD5得到私有密匙 - Dim PrivateKey As SSL.Certificate = Install(request.GetUTF8String, CA.uid) -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking {NameOf(PrivateKey)} hash:={PrivateKey.uid}".__DEBUG_ECHO -#End If - Return PrivateKey - End Function - - ''' - ''' 抽象SSL服务器 - ''' - Public Interface ISSLServices - - ''' - ''' 告诉SSL层如何安装数字证书 - ''' - ''' - Property InstallCertificates As InstallCertificates - ''' - ''' 有新的客户端请求进行连接 - ''' - ''' - Property RaiseHandshakingEvent As HandshakingEvent - ''' - ''' 对于某些应用出于安全性的考虑,会将这里设置为False,则服务器就会全部拒绝后面的所有的握手请求,只接受来自于从外部导入的用户证书的数据请求 - ''' - ''' - Property RefuseHandshake As Boolean - - ''' - ''' 公共密匙 - ''' - ''' - ReadOnly Property CA As SSL.Certificate - ''' - ''' 客户端的私有密匙 - ''' - ''' - ReadOnly Property PrivateKeys As Dictionary(Of Long, SSL.Certificate) - ''' - ''' 处理私有密匙的数据请求 - ''' - ''' - ReadOnly Property ResponseHandler As Net.Abstract.DataRequestHandler - ReadOnly Property DeclaringModule As Object - - ''' - ''' - ''' - ''' - ''' 当证书的哈希值有冲突的时候,新安装的证书可不可以将旧的证书覆盖掉 - Function Install(CA As Certificate, [overrides] As Boolean, Optional trace As String = "") As Boolean - - End Interface - - Public Delegate Sub HandshakingEvent(uid As Long, CA As SSL.Certificate, remoteDev As System.Net.IPEndPoint) - Public Delegate Function InstallCertificates(privateKey As String, uid As Long) As Certificate - - ''' - ''' - ''' - ''' - ''' 解密使用的证书凭据,这个用来鉴别客户端身份是否被伪造 - ''' - ''' - ''' - ''' - Public Function SSLServicesResponseHandler(ssl As ISSLServices, CA As Long, - request As RequestStream, - remoteDev As System.Net.IPEndPoint, - InstallCertificates As InstallCertificates) As RequestStream - Dim uid As Long - - If request.IsSSL_PublicToken Then - uid = request.uid - request = ssl.CA.Decrypt(request) - End If - - If request.IsSSLHandshaking Then '客户端与服务器之间进行连接的初始化,服务器会在这里为客户端动态的生成一个密匙 - request = __sslHandshake(uid, ssl, request, remoteDev, InstallCertificates) - Return request - ElseIf request.IsSSLProtocol Then - uid = request.uid - - If Not ssl.PrivateKeys.ContainsKey(uid) Then ' 不存在的数字证书 - ' 记录进系统日志 - If WindowsServices.Initialized Then - Call ServicesLogs.WriteEntry({$"Remote socket {remoteDev.ToString} try send request with an not authorised certificates, and ssl server refused this request!", - $"{NameOf(CA)} (not_authorised) {CA}", - $"{NameOf(remoteDev)}: {remoteDev.ToString}"}, - $"{ssl.DeclaringModule.GetType.FullName} [{Scripting.ToString(ssl.DeclaringModule)}] ==> {MethodBase.GetCurrentMethod}", - EventLogEntryType.Warning) - End If - - Return New RequestStream(RequestStream.SYS_PROTOCOL, - RequestStream.Protocols.InvalidCertificates, - NameOf(RequestStream.Protocols.InvalidCertificates)) - End If - - Dim PrivateCertificate As SSL.Certificate = ssl.PrivateKeys(uid) - request = PrivateCertificate.Decrypt(request) '使用用户的私有密匙进行加密 - request = ssl.ResponseHandler(CA, request, remoteDev) ' CA应该是用户客户端的数字证书编号 - request = PrivateCertificate.Encrypt(request) - Return request - End If - - Return NetResponse.RFC_NO_CERT - End Function - - ''' - ''' 客户端与服务器之间进行连接的初始化,服务器会在这里为客户端动态的生成一个密匙 - ''' - ''' - Private Function __sslHandshake(uid As Long, ssl As ISSLServices, - request As RequestStream, - remoteDev As System.Net.IPEndPoint, - InstallCertificates As InstallCertificates) As RequestStream - If ssl.RefuseHandshake Then - Return New RequestStream(RequestStream.SYS_PROTOCOL, - RequestStream.Protocols.InvalidCertificates, - "Services Refused!") - End If - - Dim key As String = Guid.NewGuid.ToString - key = SecurityString.MD5Hash.GetMd5Hash(key) - - If uid <> request.uid Then - Return New RequestStream(RequestStream.SYS_PROTOCOL, - RequestStream.Protocols.InvalidCertificates, - NameOf(RequestStream.Protocols.InvalidCertificates)) - Else - request = New RequestStream(RequestStream.SYS_PROTOCOL, - RequestStream.Protocols.SSLHandshake, key) With { - .uid = uid - } - End If - - If ssl.PrivateKeys.ContainsKey(uid) Then ' 哈希函数设计不正确,有重复的哈希值,则当前的握手用户不能够使用这个哈希值,需要重新握手 - Call $"{NameOf(SSLServicesResponseHandler)} ==> {uid} was duplicated!".__DEBUG_ECHO - Return New RequestStream(RequestStream.SYS_PROTOCOL, RequestStream.Protocols.InvalidCertificates, "Duplicated hash value!") - End If - -#If DEBUG Then - Call $"[{MethodBase.GetCurrentMethod.GetFullName}] Handshaking hash:={uid}".__DEBUG_ECHO -#End If - - Dim PrivateKey As SSL.Certificate = InstallCertificates(key, uid) - Call ssl.PrivateKeys.Add(uid, PrivateKey) - Call ssl.RaiseHandshakingEvent()(uid, PrivateKey, remoteDev) - - request = Net.SSL.Certificate.CopyFrom(ssl.CA, uid).Encrypt(request) - - Return request - End Function - - End Module -End Namespace diff --git a/ApplicationServices/Tools/Network/SSL/SSL.pptx b/ApplicationServices/Tools/Network/SSL/SSL.pptx deleted file mode 100644 index e1561c140554c9a983d4b581b6eb4d375377ed36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65296 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

>uRrCa}`5Fv2}p^MkLs?p=x5WsOHpE(!!$ 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 V?ji<44na%7&k-323K?U+`!BMJUW)(# diff --git a/ApplicationServices/Tools/Network/SSL/SSLSynchronizationServicesSocket.vb b/ApplicationServices/Tools/Network/SSL/SSLSynchronizationServicesSocket.vb deleted file mode 100644 index 3cb56abb..00000000 --- a/ApplicationServices/Tools/Network/SSL/SSLSynchronizationServicesSocket.vb +++ /dev/null @@ -1,258 +0,0 @@ -#Region "Microsoft.VisualBasic::5196cbf0510b65ca84c69fedf87bbb1a, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\SSL\SSLSynchronizationServicesSocket.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class SSLSynchronizationServicesSocket - ' - ' Properties: CA, DeclaringModule, IsRunning, IsShutdown, ISSLServices_InstallCertificates - ' LocalPort, PrivateKeys, RaiseHandshakingEvent, RefuseHandshake, Responsehandler - ' - ' Constructor: (+1 Overloads) Sub New - ' - ' Function: __responsehandler, Install, InstallCertificates, (+2 Overloads) Run, ToString - ' - ' Sub: (+2 Overloads) Dispose, HandShakingEventDoNothing, WaitForStart - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Reflection -Imports System.Runtime.CompilerServices -Imports Microsoft.VisualBasic.ComponentModel -Imports Microsoft.VisualBasic.Net.Abstract -Imports Microsoft.VisualBasic.Net.Protocols - -Namespace Net.SSL - - Public Class SSLSynchronizationServicesSocket - Implements IDisposable - Implements ITaskDriver - Implements IServicesSocket - Implements SSL.SSLProtocols.ISSLServices - - Dim _ServicesSocket As Net.TcpSynchronizationServicesSocket - - '''

- ''' 这个数字证书是当前版本下的服务器的客户端的数字签名,服务器会使用这个证书来验证客户端的文件是否被恶意破解,相当于公有密匙 - ''' - Public ReadOnly Property CA As Certificate Implements ISSLServices.CA - ''' - ''' A table stores the certificates of the current connected clients on this server. - ''' (连接上来的客户端的私有证书列表) - ''' - ''' - Public ReadOnly Property PrivateKeys As Dictionary(Of Long, Certificate) Implements ISSLServices.PrivateKeys - - ''' - ''' - ''' - ''' - ''' 服务器在部署的时候向对应版本您的客户端的数字签名 - ''' Public Delegate Sub (ex As ) - Sub New(LocalPort As Integer, - CA As SSL.Certificate, - container As Object, - Optional exHandler As Abstract.ExceptionHandler = Nothing) - - _DeclaringModule = container - _ServicesSocket = New TcpSynchronizationServicesSocket(LocalPort, exHandler) - _CA = CA - _PrivateKeys = New Dictionary(Of Long, Certificate) - End Sub - - Public ReadOnly Property IsShutdown As Boolean Implements IServicesSocket.IsShutdown - Get - If _ServicesSocket Is Nothing Then - Return True - End If - - Return _ServicesSocket.IsShutdown - End Get - End Property - - Public ReadOnly Property IsRunning As Boolean Implements IServicesSocket.IsRunning - Get - If _ServicesSocket Is Nothing Then - Return False - End If - - Return _ServicesSocket.Running - End Get - End Property - - ''' - ''' 底层工作socket所监听的端口号 - ''' - ''' - Public ReadOnly Property LocalPort As Integer Implements IServicesSocket.LocalPort - Get - Return _ServicesSocket.LocalPort - End Get - End Property - - Public Overrides Function ToString() As String - Return Me._ServicesSocket.ToString - End Function - -#Region "Responsehandler" - - ''' - ''' : - ''' Public Delegate Function (CA As , request As , - ''' RemoteAddress As ) As - ''' - ''' - Public Property Responsehandler As DataRequestHandler Implements IServicesSocket.Responsehandler, ISSLServices.ResponseHandler - Get - Return _responsehandler - End Get - Set(value As DataRequestHandler) - _ServicesSocket.Responsehandler = New DataRequestHandler(AddressOf __responsehandler) - _responsehandler = value - End Set - End Property - - ''' - ''' 生成证书的方法 - ''' - ''' - Public Property ISSLServices_InstallCertificates As InstallCertificates = - AddressOf InstallCertificates Implements ISSLServices.InstallCertificates - - ''' - ''' 客户端和服务器握手之后触发这个动作 - ''' - ''' - Public Property RaiseHandshakingEvent As HandshakingEvent = - AddressOf SSLSynchronizationServicesSocket.HandShakingEventDoNothing Implements ISSLServices.RaiseHandshakingEvent - - ''' - ''' Does this ssl server accepts the handshaking from the user client or just allow the client connect to this server from manual imports their certificates by using method - ''' - ''' - Public Property RefuseHandshake As Boolean Implements ISSLServices.RefuseHandshake - - Public ReadOnly Property DeclaringModule As Object Implements ISSLServices.DeclaringModule - - Dim _responsehandler As DataRequestHandler - - Private Function __responsehandler(CA As Long, request As RequestStream, remoteDev As System.Net.IPEndPoint) As RequestStream - Return SSL.SSLProtocols.SSLServicesResponseHandler(Me, CA, request, remoteDev, ISSLServices_InstallCertificates) - End Function -#End Region - - ''' - ''' 等待底层socket成功进入监听模式 - ''' - Public Sub WaitForStart() - Call _ServicesSocket.WaitForStart() - End Sub - - ''' - ''' This server waits for a connection and then uses asychronous operations to - ''' accept the connection, get data from the connected client, - ''' echo that data back to the connected client. - ''' It then disconnects from the client and waits for another client.(请注意,当服务器的代码运行到这里之后,代码将被阻塞在这里) - ''' - ''' - Public Function Run(localEndPoint As System.Net.IPEndPoint) As Integer Implements IServicesSocket.Run - Return _ServicesSocket.Run(localEndPoint) - End Function - - ''' - ''' This server waits for a connection and then uses asychronous operations to - ''' accept the connection, get data from the connected client, - ''' echo that data back to the connected client. - ''' It then disconnects from the client and waits for another client.(请注意,当服务器的代码运行到这里之后,代码将被阻塞在这里) - ''' - ''' - Public Function Run() As Integer Implements IServicesSocket.Run, ITaskDriver.Run - Return _ServicesSocket.Run - End Function - -#Region "IDisposable Support" - Private disposedValue As Boolean ' To detect redundant calls - - ' IDisposable - Protected Overridable Sub Dispose(disposing As Boolean) - If Not disposedValue Then - If disposing Then - ' TODO: dispose managed state (managed objects). - Call Me._ServicesSocket.Free - End If - - ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. - ' TODO: set large fields to null. - End If - disposedValue = True - End Sub - - ' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources. - 'Protected Overrides Sub Finalize() - ' ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. - ' Dispose(False) - ' MyBase.Finalize() - 'End Sub - - ' This code added by Visual Basic to correctly implement the disposable pattern. - Public Sub Dispose() Implements IDisposable.Dispose - ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. - Dispose(True) - ' TODO: uncomment the following line if Finalize() is overridden above. - ' GC.SuppressFinalize(Me) - End Sub -#End Region - - Public Shared Function InstallCertificates(privateKey As String, uid As Long) As SSL.Certificate - Return New SSL.Certificate(privateKey, uid) - End Function - - Public Shared Sub HandShakingEventDoNothing(uid As Long, CA As SSL.Certificate, remote As System.Net.IPEndPoint) - ' DO NOTHING - End Sub - - ''' - ''' If the property of is set to TRUE, then no more new client can be connect to this server object. - ''' The only way to add new client on this server is using this function to imports the client's certificates direct manually. - ''' (假若ssl层关闭了握手协议,则不可能会再有新的客户端可以连接到这个服务器上面了,则这个时候就可以使用这个方法来手工的为新的客户端导入数字证书,从而可以只接受指定的客户端的连接操作 - ''' 假若是证书同步操作的话,则可以将app授权证书通过这个方法导入到服务器模块接收主节点的证书同步操作) - ''' - ''' - ''' - ''' - Public Function Install(CA As Certificate, [overrides] As Boolean, Optional trace As String = "") As Boolean Implements ISSLServices.Install - Return CAExtensions.InstallCommon(PrivateKeys, CA, [overrides], trace, MethodBase.GetCurrentMethod) - End Function - End Class -End Namespace From d6f0c510df872ad8254c37b49be54f3a6c3be8ea Mon Sep 17 00:00:00 2001 From: xieguigang Date: Fri, 5 Oct 2018 03:10:15 +0800 Subject: [PATCH 3/6] obsolete code removes --- 47-dotnet_Microsoft.VisualBasic.vbproj | 11 - .../Parallel/Threads/ServicesFolk.vb | 165 ------- ApplicationServices/Tools/Network/Abstract.vb | 3 +- .../Tools/Network/Tcp/AsynInvoke.vb | 147 ++----- .../MessagePushServices/Abstract.vb | 59 --- .../MessagePushServices/MessagePushServer.vb | 412 ------------------ .../MessagePushServices/SSLClient.vb | 116 ----- .../MessagePushServices/SSLPushServices.vb | 217 --------- .../Persistent/MessagePushServices/User.vb | 305 ------------- .../Tcp/Persistent/Protocols/UserId.vb | 56 --- .../Tools/Network/Tcp/TCPExtensions.vb | 30 -- 11 files changed, 43 insertions(+), 1478 deletions(-) delete mode 100644 ApplicationServices/Parallel/Threads/ServicesFolk.vb delete mode 100644 ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/Abstract.vb delete mode 100644 ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/MessagePushServer.vb delete mode 100644 ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLClient.vb delete mode 100644 ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLPushServices.vb delete mode 100644 ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/User.vb delete mode 100644 ApplicationServices/Tools/Network/Tcp/Persistent/Protocols/UserId.vb diff --git a/47-dotnet_Microsoft.VisualBasic.vbproj b/47-dotnet_Microsoft.VisualBasic.vbproj index 04c7ae97..3d5772f2 100644 --- a/47-dotnet_Microsoft.VisualBasic.vbproj +++ b/47-dotnet_Microsoft.VisualBasic.vbproj @@ -1342,7 +1342,6 @@ - @@ -1371,30 +1370,20 @@ - - - - - - - - - - diff --git a/ApplicationServices/Parallel/Threads/ServicesFolk.vb b/ApplicationServices/Parallel/Threads/ServicesFolk.vb deleted file mode 100644 index eef93009..00000000 --- a/ApplicationServices/Parallel/Threads/ServicesFolk.vb +++ /dev/null @@ -1,165 +0,0 @@ -#Region "Microsoft.VisualBasic::e1ba5a0dba6fb894a52bf987d07b8a33, Microsoft.VisualBasic.Core\ApplicationServices\Parallel\Threads\ServicesFolk.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Module ServicesFolk - ' - ' Function: Folk, ReturnPortal - ' Class __getChildPortal - ' - ' Function: HandleRequest, WaitForPortal - ' - ' - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Reflection -Imports Microsoft.VisualBasic.Net.Http -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Win32 -Imports SetValueAction = Microsoft.VisualBasic.Linq.SetValue(Of Microsoft.VisualBasic.Net.TcpSynchronizationServicesSocket) - -Namespace Parallel - - ''' - ''' 主服务和子服务之间的相互作用的特点是子服务不会知道主服务节点的数据接口,所有的交互都是通过子服务上面的一个模块来监听主服务来实现的 - ''' 当主服务有数据需要向子服务更新的时候,会主动发送数据请求至子服务节点 - ''' - ''' 当前的用户规模还比较小这里仅仅是实现了本地的调用,后面考虑到业务吞吐量的问题,会将服务的调用分开到两台物理主机之上 - Public Module ServicesFolk - - ''' - ''' 函数返回子进程的交互数据通信的端口号 - ''' - ''' - ''' 命令行参数字符串,可以在这里加入一些其他的自定义数据 - ''' 函数返回子服务的交互端口 - Public Function Folk(assm As String, ByRef CLI As String, Optional ByRef folked As Process = Nothing) As Integer - Dim Portal As Integer - - '开通一个临时的端口用来和子服务交互 - Using TempListen As New Net.TcpSynchronizationServicesSocket( - Net.TCPExtensions.GetFirstAvailablePort, - Sub(ex) App.LogException(ex, MethodBase.GetCurrentMethod.GetFullName)) - - Dim __getChildPortal As New __getChildPortal - - Call SetValueAction.InvokeSet(Of Net.Abstract.DataRequestHandler)( - TempListen, - NameOf(TempListen.Responsehandler), - AddressOf __getChildPortal.HandleRequest) - - Call RunTask(AddressOf TempListen.Run) - Call TempListen.WaitForStart() - - Dim path As String = - If(assm.FileExists, FileIO.FileSystem.GetFileInfo(assm).FullName, $"{App.HOME}/{assm}") -#If DEBUG Then - Call $"Invoke start {path.ToFileURL} @{MethodBase.GetCurrentMethod.GetFullName}".__DEBUG_ECHO -#End If - Dim FolkSvr As Process = - Process.Start(path, $"{CLI} {ParentPortal} {TempListen.LocalPort}") - - __getChildPortal.PID = FolkSvr.Id - Portal = __getChildPortal.WaitForPortal - folked = FolkSvr - CLI = __getChildPortal.addArgs - End Using - - Dim msg As String = $"Get folked child services {assm} local_services:={Portal}" - - Call msg.__DEBUG_ECHO - - If WindowsServices.Initialized Then - Call ServicesLogs.WriteEntry(msg, EventLogEntryType.SuccessAudit) - End If - - Return Portal - End Function - - Private Class __getChildPortal - - Public PID As Integer - Public Portal As Integer = -100 - ''' - ''' 所返回来的额外的参数信息 - ''' - Public addArgs As String - - Public Function HandleRequest(uid As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - If uid <> PID Then - Return NetResponse.RFC_TOKEN_INVALID - End If - - Dim result As String = request.GetUTF8String - - Portal = Scripting.CTypeDynamic(Of Integer)(result) - addArgs = CommandLine.GetTokens(result).ElementAtOrDefault(1) - - Return NetResponse.RFC_OK - End Function - - Public Function WaitForPortal() As Integer - Do While Portal < 0 - Call Threading.Thread.Sleep(1) - Loop - - Return Portal - End Function - End Class - - Const ParentPortal As String = "--portal" - - ''' - ''' 子服务向服务主节点返回端口号数据,这个方法需要要在子服务上面的服务程序启动之后再调用 - ''' - ''' - ''' - ''' 额外返回的参数信息 - ''' - Public Function ReturnPortal(CLI As CommandLine.CommandLine, Port As Integer, Optional addArgs As String = "") As Boolean - Dim parentPortal As Integer = CLI.GetInt32(ServicesFolk.ParentPortal) - Dim Client As New Net.AsynInvoke("127.0.0.1", parentPortal) -#If DEBUG Then - Call $"{MethodBase.GetCurrentMethod.GetFullName} ==> ""{CLI}"" returns {Port}".__DEBUG_ECHO -#End If - Dim request As New RequestStream(Process.GetCurrentProcess.Id, 0, $"{CStr(Port)} ""{addArgs}""") With { - .uid = Process.GetCurrentProcess.Id - } - Dim response As RequestStream = Client.SendMessage(request) - Return response.Protocol = HTTP_RFC.RFC_OK - End Function - End Module -End Namespace diff --git a/ApplicationServices/Tools/Network/Abstract.vb b/ApplicationServices/Tools/Network/Abstract.vb index 88825071..4bd3d52f 100644 --- a/ApplicationServices/Tools/Network/Abstract.vb +++ b/ApplicationServices/Tools/Network/Abstract.vb @@ -86,11 +86,10 @@ Namespace Net.Abstract ''' ''' ''' - ''' ''' ''' ''' - Public Delegate Function DataRequestHandler(CA As Long, request As RequestStream, RemoteAddress As System.Net.IPEndPoint) As RequestStream + Public Delegate Function DataRequestHandler(request As RequestStream, RemoteAddress As System.Net.IPEndPoint) As RequestStream ''' ''' 处理错误的工作逻辑的抽象接口 diff --git a/ApplicationServices/Tools/Network/Tcp/AsynInvoke.vb b/ApplicationServices/Tools/Network/Tcp/AsynInvoke.vb index 8c6ee79d..3a590abc 100644 --- a/ApplicationServices/Tools/Network/Tcp/AsynInvoke.vb +++ b/ApplicationServices/Tools/Network/Tcp/AsynInvoke.vb @@ -1,62 +1,58 @@ #Region "Microsoft.VisualBasic::43478869161388f889b5f12a85a8f75e, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\AsynInvoke.vb" - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . +' Author: +' +' asuka (amethyst.asuka@gcmodeller.org) +' xie (genetics@smrucc.org) +' xieguigang (xie.guigang@live.com) +' +' Copyright (c) 2018 GPL3 Licensed +' +' +' GNU GENERAL PUBLIC LICENSE (GPL3) +' +' +' This program is free software: you can redistribute it and/or modify +' it under the terms of the GNU General Public License as published by +' the Free Software Foundation, either version 3 of the License, or +' (at your option) any later version. +' +' This program is distributed in the hope that it will be useful, +' but WITHOUT ANY WARRANTY; without even the implied warranty of +' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +' GNU General Public License for more details. +' +' You should have received a copy of the GNU General Public License +' along with this program. If not, see . - ' /********************************************************************************/ +' /********************************************************************************/ - ' Summaries: +' Summaries: - ' Class AsynInvoke - ' - ' Properties: LocalIPAddress - ' - ' Constructor: (+4 Overloads) Sub New - ' Function: LocalConnection, OperationTimeOut, SafelySendMessage, (+2 Overloads) SendMessage, ToString - ' Delegate Function - ' - ' Function: __decryptMessageCommon, (+6 Overloads) SendMessage - ' - ' Sub: __send, ConnectCallback, (+2 Overloads) Dispose, Receive, ReceiveCallback - ' SendCallback - ' - ' - ' - ' /********************************************************************************/ +' Class AsynInvoke +' +' Properties: LocalIPAddress +' +' Constructor: (+4 Overloads) Sub New +' Function: LocalConnection, OperationTimeOut, SafelySendMessage, (+2 Overloads) SendMessage, ToString +' Delegate Function +' +' Function: __decryptMessageCommon, (+6 Overloads) SendMessage +' +' Sub: __send, ConnectCallback, (+2 Overloads) Dispose, Receive, ReceiveCallback +' SendCallback +' +' +' +' /********************************************************************************/ #End Region -Imports System Imports System.Net Imports System.Net.Sockets -Imports System.Reflection -Imports System.Text Imports System.Threading -Imports Microsoft.VisualBasic.Net.Abstract Imports Microsoft.VisualBasic.Net.Http Imports Microsoft.VisualBasic.Net.Protocols @@ -233,27 +229,6 @@ Namespace Net End If End Function - Public Function SafelySendMessage(Message As RequestStream, - CA As SSL.Certificate, - Optional OperationTimeOut As Integer = 30 * 1000, - Optional OperationTimeoutHandler As Action = Nothing) As RequestStream - - Message = CA.Encrypt(Message) - Message = SendMessage(Message, OperationTimeOut, OperationTimeoutHandler) - - If Message.IsSSLProtocol OrElse Message.IsSSL_PublicToken Then - Message = CA.Decrypt(Message) - Else - Try - Message.ChunkBuffer = CA.Decrypt(Message.ChunkBuffer) - Catch ex As Exception - Return Message - End Try - End If - - Return Message - End Function - Public Delegate Function SendMessageInvoke(Message As String) As String Public Function SendMessage(Message As String, Callback As Action(Of String)) As IAsyncResult @@ -274,13 +249,6 @@ Namespace Net Return response End Function 'Main - Public Function SendMessage(Message As String, CA As SSL.Certificate) As String - Dim request = New RequestStream(0, 0, Message) - Dim byteData = CA.Encrypt(request).Serialize - byteData = SendMessage(byteData) - Return __decryptMessageCommon(byteData, CA).GetUTF8String - End Function - ''' ''' Send a request message to the remote server. ''' @@ -296,37 +264,6 @@ Namespace Net End If End Function - Private Function __decryptMessageCommon(retData As Byte(), CA As SSL.Certificate) As RequestStream - If Not RequestStream.IsAvaliableStream(retData) Then Return New RequestStream(0, 0, retData) - - Dim Message = New RequestStream(retData) - - If Message.IsSSLProtocol OrElse Message.IsSSL_PublicToken Then - Message = CA.Decrypt(Message) - Else - Try - Message.ChunkBuffer = CA.Decrypt(Message.ChunkBuffer) - Catch ex As Exception - Call App.LogException(ex, MethodBase.GetCurrentMethod.GetFullName) - End Try - End If - - Return Message - End Function - - ''' - ''' 发送一段使用证书对象进行数据加密操作的消息请求 - ''' - ''' - ''' - ''' - ''' - Public Function SendMessage(Message As RequestStream, CA As SSL.Certificate, Optional isPublicToken As Boolean = False) As RequestStream - Dim byteData = If(isPublicToken, CA.PublicEncrypt(Message), CA.Encrypt(Message)).Serialize - byteData = SendMessage(byteData) - Return __decryptMessageCommon(byteData, CA) - End Function - ''' ''' 最底层的消息发送函数 ''' diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/Abstract.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/Abstract.vb deleted file mode 100644 index ddb751ec..00000000 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/Abstract.vb +++ /dev/null @@ -1,59 +0,0 @@ -#Region "Microsoft.VisualBasic::9df9f6c84fab11bf4cb9193eb5fa65be, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\Persistent\MessagePushServices\Abstract.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Delegate Sub - ' - ' - ' Delegate Function - ' - ' - ' - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports Microsoft.VisualBasic.Net.Protocols - -Namespace Net.Persistent - - ''' - ''' 离线数据请求 - ''' - ''' - ''' - ''' - Public Delegate Sub OffLineMessageSendHandler(FromUSER_ID As Long, USER_ID As Long, Message As RequestStream) - Public Delegate Function PushMessage(USER_ID As Long, Message As RequestStream) As RequestStream -End Namespace diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/MessagePushServer.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/MessagePushServer.vb deleted file mode 100644 index bc8361cb..00000000 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/MessagePushServer.vb +++ /dev/null @@ -1,412 +0,0 @@ -#Region "Microsoft.VisualBasic::4503a5e2e9f2543ee1661b0f2816f869, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\Persistent\MessagePushServices\MessagePushServer.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class MessagePushServer - ' - ' Properties: LocalPort, ProtocolHandler, Responsehandler, SSLMode, UidMappings - ' UidMappingsBack - ' - ' Constructor: (+1 Overloads) Sub New - ' - ' Function: __broadcastMessage, __getMyIPAddress, __isGetSocketPortal, __isUserOnlineQuery, __Logon - ' __nonUidMappings, __requestHandlerInterface, (+2 Overloads) __sendMessage, __usrInvokeSend, GetEnumerator - ' IEnumerable_GetEnumerator, Run - ' - ' Sub: __socketCleanup, AcceptClient, DisconnectUser, Dispose, Install - ' RemoveFreeConnections, Run, SendMessage - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Reflection -Imports System.Threading -Imports Microsoft.VisualBasic.ComponentModel -Imports Microsoft.VisualBasic.Linq.Extensions -Imports Microsoft.VisualBasic.Net.Abstract -Imports Microsoft.VisualBasic.Net.Http -Imports Microsoft.VisualBasic.Net.Persistent.Application.Protocols -Imports Microsoft.VisualBasic.Net.Persistent.Socket -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Net.Protocols.Reflection - -Namespace Net.Persistent.Application - - ''' - ''' 长连接模式的消息推送服务器 - ''' - - Public Class MessagePushServer : Inherits ServicesSocket - Implements IEnumerable(Of KeyValuePair(Of Long, WorkSocket)) - Implements ITaskDriver, IDataRequestHandler - - Public ReadOnly Property ProtocolHandler As ProtocolHandler - - Dim _socketList As New Dictionary(Of Long, WorkSocket) - ''' - ''' 客户端对这个服务器的端口号是自动配置的,只需要向客户端返回端口就可以了 - ''' - Dim _workSocket As TcpSynchronizationServicesSocket - Dim _offlineMessageSendHandler As OffLineMessageSendHandler - ''' - ''' 使用证书来加密发出去的消息 - ''' - Dim _sslLayer As SSL.ISSLServices - - Public ReadOnly Property SSLMode As Boolean - - Public Sub Install(ssl As SSL.ISSLServices) - _sslLayer = ssl - _SSLMode = Not ssl Is Nothing - End Sub - - ''' - ''' 从这个端口号进行登录(协同长连接的socket正常工作的socket的端口号,可以看作为UserAPI) - ''' - ''' - Public Overrides ReadOnly Property LocalPort As Integer - Get - Return Me._workSocket.LocalPort - End Get - End Property - - Dim _responsehandler As DataRequestHandler - - Friend Property Responsehandler As DataRequestHandler Implements IDataRequestHandler.Responsehandler - Get - Return _responsehandler - End Get - Set(value As DataRequestHandler) - _responsehandler = value - Me._workSocket.Responsehandler = AddressOf __requestHandlerInterface - End Set - End Property - - ''' - ''' 只要是为ssl服务设置的 - ''' - ''' - ''' - Private Function __requestHandlerInterface(CA As Long, - requestData As RequestStream, - remote As System.Net.IPEndPoint) As RequestStream - requestData = _responsehandler(CA, requestData, remote) - Return requestData - End Function - - ''' - ''' - ''' - ''' - ''' Public Delegate Sub (FromUSER_ID As , USER_ID As , Message As ) - ''' - Sub New(Optional LocalPort As Integer = 11000, - Optional OffLineMessageSendHandler As OffLineMessageSendHandler = Nothing, - Optional exHandler As Abstract.ExceptionHandler = Nothing) - - Call MyBase.New(GetFirstAvailablePort(5000), exHandler) - - Me._ProtocolHandler = New ProtocolHandler(Me) - Me.AcceptCallbackHandleInvoke = AddressOf AcceptClient - Me._workSocket = New TcpSynchronizationServicesSocket(AddressOf _ProtocolHandler.HandleRequest, LocalPort, Me.__exceptionHandle) - Me._offlineMessageSendHandler = If(OffLineMessageSendHandler Is Nothing, - Sub([from], USER_ID, MESSAGE) Call Console.WriteLine($" >>> [DEBUG {Now.ToString}, {from} => {USER_ID}] {MESSAGE}"), - OffLineMessageSendHandler) - End Sub - - Public Overrides Sub Run(localEndPoint As System.Net.IPEndPoint) - Call New Thread(AddressOf Me._workSocket.Run).Start() - Call Thread.Sleep(1000) - Call $"please logon server {Me.GetType.Name} at api_port={Me._workSocket.LocalPort}".__DEBUG_ECHO - Call MyBase.Run(localEndPoint) - End Sub - - Public Overrides Function Run() As Integer Implements ITaskDriver.Run - Return MyBase.Run() - End Function - - ''' - ''' Disconnect user persistent connection who have the specific from this server. - ''' (断开服务器与用户客户端的长连接) - ''' - ''' This user will be deleted from the server registry. - ''' 是否在删除socket句柄的时候还会删除相对应的ssl证书 - Public Sub DisconnectUser(USER_ID As Long, removeCA As Boolean) - If Me._socketList.ContainsKey(USER_ID) Then - Dim socket As WorkSocket = _socketList(USER_ID) - Call _socketList.Remove(USER_ID) - Call $"Clean up connection for user {USER_ID} previous connection.".__DEBUG_ECHO - Call socket.Free - End If - If removeCA AndAlso SSLMode Then - If _sslLayer.PrivateKeys.ContainsKey(USER_ID) Then - Call _sslLayer.PrivateKeys.Remove(USER_ID) - End If - End If - End Sub - - Protected Overrides Sub __socketCleanup(hash As Integer) - Dim LQuery = (From usr In _socketList Where hash = usr.Value.GetHashCode Select usr.Key).FirstOrDefault - Call DisconnectUser(LQuery, True) - End Sub - - ''' - ''' - ''' - ''' - ''' - ''' - Public Sub SendMessage(From As Long, USER_ID As Long, Message As RequestStream) - Dim request = ServicesProtocol.SendMessageRequest(From, USER_ID, Message) - Call __sendMessage(From, USER_ID, request) - End Sub - - ''' - ''' 发送出去的数据需要进行加密,假若是ssl模式的话 - ''' - ''' - ''' - ''' - ''' - Private Function __sendMessage(From As Long, USER_ID As Long, Message As RequestStream) As RequestStream -#If DEBUG Then - Call Console.Write($"{MethodBase.GetCurrentMethod.GetFullName} {NameOf(USER_ID)}:{USER_ID} mappings to ") -#End If - USER_ID = _UidMappings(USER_ID) -#If DEBUG Then - Call Console.WriteLine(USER_ID) '衔接着上一个输出语句 -#End If - If Me._socketList.ContainsKey(USER_ID) Then - Dim Socket As WorkSocket = Me._socketList(USER_ID) - Return __sendMessage(Socket, From, USER_ID, Message) - End If - -#If DEBUG Then - Call $"Unable to found user '{USER_ID}' on server...".__DEBUG_ECHO - Call $"Current users: {String.Join("; ", _socketList.Keys.Select(Function(id) CStr(id)).ToArray)}".__DEBUG_ECHO -#End If - Call Me._offlineMessageSendHandler(From, USER_ID, Message) - Return NetResponse.RFC_TEMP_REDIRECT - End Function - - ''' - ''' 将外部编号映射为内部的客户端句柄 - ''' 假若找不到,请返回-1 - ''' - ''' - Public Property UidMappings As Func(Of Long, Long) = AddressOf __nonUidMappings - Public Property UidMappingsBack As Func(Of Long, Long) = AddressOf __nonUidMappings - - Private Shared Function __nonUidMappings(USER_ID As Long) As Long - Return USER_ID - End Function - - ''' - ''' - ''' - ''' - ''' 这个是这一条消息的源头,可能需要进行映射 - ''' - ''' - ''' - Private Function __sendMessage(socket As WorkSocket, - From As Long, - USER_ID As Long, - Message As RequestStream) As RequestStream - - From = Me._UidMappingsBack(From) - - If socket Is Nothing OrElse socket.workSocket Is Nothing Then - Call _socketList.Remove(USER_ID) - Call Me._offlineMessageSendHandler(From, USER_ID, Message) - Return NetResponse.RFC_TEMP_REDIRECT - End If - -#If DEBUG Then - Call Console.WriteLine($"*Call {NameOf(__sendMessage)} ===> {Message}") -#End If - If SSLMode Then - Dim CA As SSL.Certificate = _sslLayer.PrivateKeys(USER_ID) - Dim post As New SendMessagePost(Message.ChunkBuffer) - post.Message = CA.Encrypt(post.Message) - post.FROM = From - Message = New RequestStream(ServicesProtocol.ProtocolEntry, - ServicesProtocol.Protocols.SendMessage, - post.Serialize) -#If DEBUG Then - Call $"Request encrypts from {CA.uid} job done!".__DEBUG_ECHO -#End If - End If - - Call socket.SendMessage(Message) '原封不动的进行数据转发 - Return NetResponse.RFC_OK - End Function - - ''' - ''' 用户客户端请求发送消息至指定编号的用户的终端之上 - ''' - ''' - ''' - ''' - ''' - - Private Function __usrInvokeSend(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Dim [From] As Long, USER_ID As Long -#If DEBUG Then - Call $"{NameOf(From)}:{From} invoke send to {NameOf(USER_ID)}:{USER_ID}".__DEBUG_ECHO -#End If - If ServicesProtocol.GetSendMessage(request, From, USER_ID) Then - Return Me.__sendMessage(From, USER_ID, request) - Else - Return NetResponse.RFC_TOKEN_INVALID - End If - End Function - - - Private Function __Logon(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Dim USER_ID As Long, remoteEp As String = "" - - If Not ServicesProtocol.GetLogOnUSER(request.GetUTF8String, USER_ID, remoteEp) Then - Return NetResponse.RFC_TOKEN_INVALID - End If - - Dim hash As Integer = CInt(Val(remoteEp)) - - If Not Me._Connections.ContainsKey(hash) Then - Call Console.WriteLine($"No connection could be made! {hash} for socket hash is not exists in the hash table!") - Return NetResponse.RFC_CONFLICT - End If - - Dim SocketClient As WorkSocket = Nothing - Call Me._Connections.TryGetValue(hash, SocketClient) - - If SocketClient Is Nothing Then - Call Console.WriteLine("No connection could be made!") - Return NetResponse.RFC_BAD_GATEWAY - Else - Call Console.WriteLine(" >> " & SocketClient.workSocket.RemoteEndPoint.ToString) - End If - - Call DisconnectUser(USER_ID, False) - Call _socketList.Add(USER_ID, SocketClient) - - Return NetResponse.RFC_OK - End Function - - - Private Function __broadcastMessage(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - For Each cnn In Me.Connections - Call cnn.SendMessage(request) - Next - Return NetResponse.RFC_OK - End Function - - - Private Function __getMyIPAddress(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Return New RequestStream(0, HTTP_RFC.RFC_OK, remote.ToString.Split(":"c)(Scan0)) - End Function - - - Private Function __isGetSocketPortal(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Return New RequestStream(0, HTTP_RFC.RFC_OK, CStr(_LocalPort)) - End Function - - - Private Function __isUserOnlineQuery(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Dim USER_ID As Long = Scripting.CTypeDynamic(Of Long)(request.GetUTF8String) - Dim result As String = CStr(Me._socketList.ContainsKey(USER_ID)) - Return New RequestStream(0, HTTP_RFC.RFC_OK, result) - End Function - - Dim _freeCnnInfo As New List(Of String) - - ''' - ''' 哈希值不存在于现有的登录用户列表之中就是空闲连接 - ''' - Public Sub RemoveFreeConnections() - Dim LQuery = (From Guid As String In _freeCnnInfo.AsParallel '上一次刷新的时候的空闲连接 - Let LowCnn = (From cnn In Me.Connections.AsParallel - Where Guid.Equals(CStr(cnn.GetHashCode)) - Select cnn).FirstOrDefault - Where Not LowCnn Is Nothing AndAlso - (From cnn In Me._socketList - Where Guid.Equals(CStr(cnn.Value.GetHashCode)) - Select cnn).ToArray.IsNullOrEmpty '哈希值不存在的 - Select LowCnn).ToArray '对于上一次刷新的列表之中的连接而言,假若在这么长的一段时间间隔之中还是处于空闲状态,则服务器会将这些连接断开连接 - For Each cnn In LQuery - Call Me.ForceCloseHandle(cnn) - Call cnn.Free - Next - - Call $"Clean up {LQuery.Length } free connections.....".__DEBUG_ECHO - '获取新产生的空闲连接 - _freeCnnInfo = (From cnn In Me._Connections.AsParallel - Where (From item In Me._socketList Where item.Value.GetHashCode = cnn.GetHashCode Select 1).ToArray.IsNullOrEmpty - Select Guid = CStr(cnn.GetHashCode)).AsList - Call $"{_freeCnnInfo.Count} free connections pending for clean up....".__DEBUG_ECHO - - For Each usr In Me._socketList.ToArray - Call usr.Value.SendMessage(NetResponse.RFC_OK) - Next - End Sub - - ''' - ''' 建立一个新的连接 - ''' - ''' - Private Sub AcceptClient(Client As WorkSocket) - 'Do Nothing - Call $"{Client.workSocket.RemoteEndPoint.ToString} connection request accept!".__DEBUG_ECHO - End Sub - - Public Iterator Function GetEnumerator() As IEnumerator(Of KeyValuePair(Of Long, WorkSocket)) Implements IEnumerable(Of KeyValuePair(Of Long, WorkSocket)).GetEnumerator - For Each entry In Me._socketList.ToArray - Yield entry - Next - End Function - - Private Iterator Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator - Yield GetEnumerator() - End Function - - Protected Overrides Sub Dispose(disposing As Boolean) - If disposing Then - For Each cnn In Me._socketList.ToArray - Call DisconnectUser(cnn.Key, True) - Next - End If - Call MyBase.Dispose(disposing) - End Sub - End Class -End Namespace diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLClient.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLClient.vb deleted file mode 100644 index 82f23bea..00000000 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLClient.vb +++ /dev/null @@ -1,116 +0,0 @@ -#Region "Microsoft.VisualBasic::c3fcc9a39fc606f3958191507f70b593, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\Persistent\MessagePushServices\SSLClient.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class SSLClient - ' - ' Properties: PrivateKey, PushUser - ' - ' Constructor: (+1 Overloads) Sub New - ' - ' Function: __sslRedirect, SendMessage - ' - ' Sub: Handshaking, Logon, SetDisconnectHandle - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Net -Imports System.Net.Sockets -Imports System.Threading -Imports Microsoft.VisualBasic.Net.Abstract -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Net.Protocols.Reflection - -Namespace Net.Persistent.Application - - Public Class SSLClient - - Public ReadOnly Property PrivateKey As Net.SSL.Certificate - Public ReadOnly Property PushUser As Net.Persistent.Application.USER - - ReadOnly _DataRequestHandle As PushMessage - - ''' - ''' - ''' - ''' - ''' - ''' Public Delegate Function PushMessage(USER_ID As , Message As ) As - ''' - Sub New(services As System.Net.IPEndPoint, ID As Long, DataRequestHandle As PushMessage, Optional ExceptionHandler As Abstract.ExceptionHandler = Nothing) - _DataRequestHandle = DataRequestHandle - PushUser = New USER(services, ID, AddressOf __sslRedirect, ExceptionHandler) - End Sub - - Private Function __sslRedirect(USER_ID As Long, request As RequestStream) As RequestStream - request = PrivateKey.Decrypt(request) ' 解密之后在讲数据传递到实际的业务逻辑之上 - request = _DataRequestHandle(USER_ID, request) - Return request - End Function - - Public Sub Handshaking(PublicToken As Net.SSL.Certificate) - Dim Services = New System.Net.IPEndPoint(System.Net.IPAddress.Parse(PushUser.remoteHost), PushUser.remotePort) - _PrivateKey = Net.SSL.Certificate.CopyFrom(PublicToken, PushUser.USER_ID) - _PrivateKey = Net.SSL.SSLProtocols.Handshaking(PrivateKey, Services) - Call PushUser.BeginConnect(PrivateKey, _disconnectHandler) - End Sub - - ''' - ''' 使用已经拥有的用户证书登录服务器,这一步省略了握手步骤 - ''' - ''' - Public Sub Logon(UserToken As Net.SSL.Certificate) - _PrivateKey = UserToken - _PushUser.BeginConnect(UserToken, _disconnectHandler) - End Sub - - Dim _disconnectHandler As MethodInvoker - - Public Sub SetDisconnectHandle([handle] As MethodInvoker) - _disconnectHandler = handle - _PushUser.SetDisconnectHandle(handle) - End Sub - - ''' - ''' 消息在这个函数之中自动被加密处理 - ''' - ''' - ''' - ''' - Public Function SendMessage(USER_ID As Long, request As RequestStream) As Boolean - Return PushUser.SendMessage(USER_ID, request, PrivateKey) - End Function - End Class -End Namespace diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLPushServices.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLPushServices.vb deleted file mode 100644 index a762553d..00000000 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/SSLPushServices.vb +++ /dev/null @@ -1,217 +0,0 @@ -#Region "Microsoft.VisualBasic::207dc029de94e511c91be0be3ac1991a, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\Persistent\MessagePushServices\SSLPushServices.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class SSLPushServices - ' - ' Properties: CA, Connections, DeclaringModule, InstallCertificates, IsRunning - ' IsShutdown, LocalPort, PrivateKeys, PushServices, RaiseHandshakingEvent - ' RefuseHandshake, Responsehandler - ' - ' Constructor: (+1 Overloads) Sub New - ' - ' Function: __redirect, __responsehandler, Install, (+2 Overloads) Run - ' - ' Sub: (+2 Overloads) Dispose, Install, WaitForRunning - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Reflection -Imports System.Runtime.CompilerServices -Imports Microsoft.VisualBasic.ComponentModel -Imports Microsoft.VisualBasic.Net.Abstract -Imports Microsoft.VisualBasic.Net.Persistent.Socket -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Net.SSL - -Namespace Net.Persistent.Application - - ''' - ''' 消息都是经过加密操作了的 - ''' - Public Class SSLPushServices : Implements Net.Abstract.IServicesSocket - Implements ISSLServices - - Public ReadOnly Property PushServices As Net.Persistent.Application.MessagePushServer - - ''' - ''' 共有密匙 - ''' - ''' - Public ReadOnly Property CA As Certificate Implements ISSLServices.CA - ''' - ''' 连接到当前的这个服务器上面的客户端的私有密匙列表 - ''' - ''' - Public ReadOnly Property PrivateKeys As Dictionary(Of Long, Certificate) Implements ISSLServices.PrivateKeys - - Public ReadOnly Property IsShutdown As Boolean Implements IServicesSocket.IsShutdown - Get - Return _PushServices.IsShutdown - End Get - End Property - - Public ReadOnly Property LocalPort As Integer Implements IServicesSocket.LocalPort - Get - Return _PushServices.LocalPort - End Get - End Property - - Dim _responsehandler As DataRequestHandler - - Private Property Responsehandler As DataRequestHandler Implements IDataRequestHandler.Responsehandler, ISSLServices.ResponseHandler - Get - Return _responsehandler - End Get - Set(value As DataRequestHandler) - _PushServices.Responsehandler = AddressOf __responsehandler - _responsehandler = value - End Set - End Property - - Private Function __responsehandler(CA As Long, request As RequestStream, remoteDev As System.Net.IPEndPoint) As RequestStream - Return SSL.SSLProtocols.SSLServicesResponseHandler(Me, CA, request, remoteDev, InstallCertificates) - End Function - - Public ReadOnly Property Connections As WorkSocket() - Get - Return _PushServices.Connections - End Get - End Property - - Public Property InstallCertificates As InstallCertificates = - AddressOf Net.SSL.SSLSynchronizationServicesSocket.InstallCertificates Implements ISSLServices.InstallCertificates - - Public Property RaiseHandshakingEvent As HandshakingEvent = - AddressOf SSL.SSLSynchronizationServicesSocket.HandShakingEventDoNothing Implements ISSLServices.RaiseHandshakingEvent - - Public Property RefuseHandshake As Boolean Implements ISSLServices.RefuseHandshake - - Public ReadOnly Property IsRunning As Boolean Implements IServicesSocket.IsRunning - Get - Return Me._PushServices.Running - End Get - End Property - - Public ReadOnly Property DeclaringModule As Object Implements ISSLServices.DeclaringModule - - ''' - ''' - ''' - ''' - ''' - ''' Public Delegate Sub (FromUSER_ID As , USER_ID As , Message As ) - ''' - ''' - Sub New(LocalPort As Integer, - container As Object, - Optional OffLineMessageSendHandler As OffLineMessageSendHandler = Nothing, - Optional exHandler As Abstract.ExceptionHandler = Nothing) - _PushServices = New MessagePushServer(LocalPort, OffLineMessageSendHandler, exHandler) - _DeclaringModule = container - Responsehandler = AddressOf __redirect - PrivateKeys = New Dictionary(Of Long, Certificate) - Call _PushServices.Install(Me) - End Sub - - Private Function __redirect(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - request = _PushServices.ProtocolHandler.HandleRequest(CA, request, remote) - Return request - End Function - - ''' - ''' 安装新的公有密匙 - ''' - ''' - Public Sub Install(CA As SSL.Certificate) - _CA = CA - End Sub - - ''' - ''' 安装新的用户私有密匙 - ''' - ''' - ''' - ''' - Public Function Install(CA As Certificate, [overrides] As Boolean, Optional trace As String = "") As Boolean Implements ISSLServices.Install - Return CAExtensions.InstallCommon(PrivateKeys, CA, [overrides], trace, MethodBase.GetCurrentMethod) - End Function - - Public Sub WaitForRunning() - Call _PushServices.WaitForRunning() - End Sub - - Public Function Run() As Integer Implements IServicesSocket.Run, ITaskDriver.Run - Return _PushServices.Run - End Function - - Public Function Run(localEndPoint As System.Net.IPEndPoint) As Integer Implements IServicesSocket.Run - Call _PushServices.Run(localEndPoint) - Return 0 - End Function - -#Region "IDisposable Support" - Private disposedValue As Boolean ' To detect redundant calls - - ' IDisposable - Protected Overridable Sub Dispose(disposing As Boolean) - If Not disposedValue Then - If disposing Then - ' TODO: dispose managed state (managed objects). - End If - - ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. - ' TODO: set large fields to null. - End If - disposedValue = True - End Sub - - ' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources. - 'Protected Overrides Sub Finalize() - ' ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. - ' Dispose(False) - ' MyBase.Finalize() - 'End Sub - - ' This code added by Visual Basic to correctly implement the disposable pattern. - Public Sub Dispose() Implements IDisposable.Dispose - ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. - Dispose(True) - ' TODO: uncomment the following line if Finalize() is overridden above. - ' GC.SuppressFinalize(Me) - End Sub -#End Region - End Class -End Namespace diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/User.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/User.vb deleted file mode 100644 index 2894d549..00000000 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/MessagePushServices/User.vb +++ /dev/null @@ -1,305 +0,0 @@ -#Region "Microsoft.VisualBasic::b3e9fc10f1f2408c56e6cb5242725b75, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\Persistent\MessagePushServices\User.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class USER - ' - ' Properties: USER_ID - ' - ' Constructor: (+4 Overloads) Sub New - ' - ' Function: __receiveBroadcastMessage, (+3 Overloads) __sendMessage, __sendMessageToMe, IsUserOnLine, (+4 Overloads) SendMessage - ' ToString - ' - ' Sub: (+2 Overloads) BeginConnect, (+2 Overloads) BroadCastMessage, (+2 Overloads) Dispose, SetDisconnectHandle - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports System.Text -Imports System.Threading -Imports Microsoft.VisualBasic.Net.Http -Imports Microsoft.VisualBasic.Net.Persistent.Application.Protocols -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Net.Protocols.Reflection -Imports Microsoft.VisualBasic.Parallel - -Namespace Net.Persistent.Application - - ''' - ''' 服务器也相当于一个USER,只不过服务器的UID为0,即最高级的用户 - ''' - ''' - - Public Class USER : Implements System.IDisposable - - Public ReadOnly Property USER_ID As Long - - Friend remotePort As Integer, remoteHost As String - Dim __exceptionHandler As Abstract.ExceptionHandler - Dim _requestHandler As ProtocolHandler - - ''' - ''' - ''' - ''' - ''' - ''' - ''' 使用这个函数来获取外部发送过来的用户消息 - ''' - Sub New(HostName As String, - RemotePort As Integer, - ID As Long, - DataRequestHandle As PushMessage, - Optional ExceptionHandler As Abstract.ExceptionHandler = Nothing) - - Me.remoteHost = HostName - Me.USER_ID = ID - Me.remotePort = RemotePort - Me.__dataRequestHandle = DataRequestHandle - Me._requestHandler = New ProtocolHandler(Me) - End Sub - - Sub New(services As System.Net.IPEndPoint, ID As Long, DataRequestHandle As PushMessage, Optional ExceptionHandler As Abstract.ExceptionHandler = Nothing) - Call Me.New(New IPEndPoint(services), ID, DataRequestHandle, ExceptionHandler) - End Sub - - Sub New(services As IPEndPoint, ID As Long, DataRequestHandle As PushMessage, Optional ExceptionHandler As Abstract.ExceptionHandler = Nothing) - Call Me.New(services.IPAddress, services.Port, ID, DataRequestHandle, ExceptionHandler) - End Sub - - Sub New(post As UserId, DataRequestHandle As PushMessage, Optional ExceptionHandler As Abstract.ExceptionHandler = Nothing) - Call Me.New(post.Remote.IPAddress, post.Remote.Port, post.uid, DataRequestHandle, ExceptionHandler) - End Sub - - Dim __dataRequestHandle As PushMessage - Dim _pcnnSocket As Socket.PersistentClient - - Public Sub SetDisconnectHandle(handle As MethodInvoker) - Try - _pcnnSocket.RemoteServerShutdown = handle - Catch ex As Exception - ' 可能是在socket还没有启动的时候就设置句柄了,导致空引用,不过这个没有太多的影响,忽略这个错误 - End Try - End Sub - - ''' - ''' 请注意,线程会在这里阻塞 - ''' - ''' 远程主机强制关闭连接之后触发这个动作 - Public Sub BeginConnect(Optional ForceCloseConnection As MethodInvoker = Nothing, Optional CA As Net.SSL.Certificate = Nothing) - Dim remoteEp As System.Net.IPEndPoint = New System.Net.IPEndPoint(System.Net.IPAddress.Parse(Me.remoteHost), Me.remotePort) - Dim request As RequestStream = ServicesProtocol.GetServicesConnection - - Call $"Begin connect to {remoteEp.ToString}".__DEBUG_ECHO - If CA Is Nothing Then - request = New Net.AsynInvoke(remoteEp).SendMessage(request) - Else - request = New Net.AsynInvoke(remoteEp).SendMessage(request, CA) - End If - - Dim port As Integer = CInt(Val(request.GetUTF8String)) - - Me._pcnnSocket = New Socket.PersistentClient(Me.remoteHost, port, Me.__exceptionHandler) - Me._pcnnSocket.RemoteServerShutdown = ForceCloseConnection - Me._pcnnSocket.Responsehandler = AddressOf Me._requestHandler.HandleRequest - - Call RunTask(AddressOf Me._pcnnSocket.BeginConnect) - Call Me._pcnnSocket.WaitForConnected() - Call Thread.Sleep(1000) - Call Me._pcnnSocket.WaitForHash() - - request = ServicesProtocol.LogOnRequest(Me.USER_ID, Me._pcnnSocket.OnServerHashCode) - If CA Is Nothing Then - request = __sendMessage(request) - Else - request = CA.Encrypt(request) - request = __sendMessage(request) - request = CA.Decrypt(request) - End If - - If Not request.Protocol = HTTP_RFC.RFC_OK Then - '连接不成功 - Throw New Exception(NetResponse.RFC_BAD_REQUEST.GetUTF8String) - End If - - Do While Not Me.disposedValue - Call Thread.Sleep(1000) - Loop - End Sub - - ''' - ''' 不会发生阻塞 - ''' - ''' 远程主机强制关闭连接之后触发这个动作 - Public Sub BeginConnect(CA As Net.SSL.Certificate, Optional ForceCloseConnection As MethodInvoker = Nothing) - Call RunTask(Sub() Call BeginConnect(ForceCloseConnection, CA)) - End Sub - - ''' - ''' - ''' - ''' - ''' - ''' 由于数据都是通过中心服务器转发的,所以这个已经没有存在的意义了,但是为了和短连接的socket的数据处理接口保持兼容,所以还保留这个参数 - ''' - - Private Function __sendMessageToMe(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Dim post As New SendMessagePost(request.ChunkBuffer) - Return Me.__dataRequestHandle(post.FROM, post.Message) - End Function - - - Private Function __receiveBroadcastMessage(CA As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Return Me.__dataRequestHandle(CA, request) - End Function - - Private Function __sendMessage(Message As String) As String -#If DEBUG Then - Call Console.WriteLine($" * >> {NameOf(__sendMessage)} {Message}") -#End If - Dim reply As String = New Net.AsynInvoke(Me.remoteHost, Me.remotePort, Me.__exceptionHandler).SendMessage(Message) - Return reply - End Function - - Private Function __sendMessage(Message As Byte()) As Byte() - Dim reply = New Net.AsynInvoke(Me.remoteHost, Me.remotePort, Me.__exceptionHandler).SendMessage(Message) - Return reply - End Function - - Private Function __sendMessage(request As RequestStream) As RequestStream - Return New RequestStream(__sendMessage(request.Serialize)) - End Function - - ''' - ''' True标识发送成功,False标识用户离线 - ''' - ''' - ''' 在发送之前请对消息进行加密处理 - ''' - Public Function SendMessage(USER_ID As Long, Message As RequestStream) As Boolean - Dim request = ServicesProtocol.SendMessageRequest(Me.USER_ID, USER_ID, Message) - Return SendMessage(request) - End Function - - Public Function SendMessage(USER_ID As Long, Message As RequestStream, CA As SSL.Certificate) As Boolean - Dim request = ServicesProtocol.SendMessageRequest(Me.USER_ID, USER_ID, Message) - request = CA.Encrypt(request) - Return SendMessage(request) - End Function - - Public Function SendMessage(Message As RequestStream) As Boolean - Dim bytesData = Message.Serialize - bytesData = __sendMessage(bytesData) - If RequestStream.IsAvaliableStream(bytesData) Then - Message = New RequestStream(bytesData) - Return Message.Protocol = HTTP_RFC.RFC_OK - Else - Return System.Text.Encoding.UTF8.GetString(bytesData).ParseBoolean - End If - End Function - - Public Function SendMessage(Message As RequestStream, CA As SSL.Certificate, Optional isPublicToken As Boolean = False) As Boolean - Dim byteData = If(isPublicToken, CA.PublicEncrypt(Message), CA.Encrypt(Message)).Serialize - byteData = __sendMessage(byteData) - If RequestStream.IsAvaliableStream(byteData) Then - Message = New RequestStream(byteData) - - If Message.IsSSLProtocol Then - Message = CA.Decrypt(Message) - Else - Return CA.DecryptString(Message.GetUTF8String).ParseBoolean - End If - - Return Message.GetUTF8String.ParseBoolean - Else - Return Encoding.UTF8.GetString(byteData).ParseBoolean - End If - End Function - - Public Sub BroadCastMessage(Message As RequestStream) - Dim request As RequestStream = ServicesProtocol.BroadcastMessage(Me.USER_ID, Message) - request = __sendMessage(request) - End Sub - - Public Sub BroadCastMessage(Message As RequestStream, CA As SSL.Certificate) - Dim request As RequestStream = ServicesProtocol.BroadcastMessage(Me.USER_ID, Message) - request = CA.Encrypt(request) - Call SendMessage(request) - End Sub - - Public Function IsUserOnLine(USER_ID As Long) As Boolean - Dim request As RequestStream = ServicesProtocol.IsUserOnlineRequest(USER_ID) - request = __sendMessage(request) - Return request.Protocol = HTTP_RFC.RFC_OK - End Function - - Public Overrides Function ToString() As String - Return USER_ID - End Function - -#Region "IDisposable Support" - Private disposedValue As Boolean ' To detect redundant calls - - ' IDisposable - Protected Overridable Sub Dispose(disposing As Boolean) - If Not disposedValue Then - If disposing Then - - ' TODO: dispose managed state (managed objects). - End If - - ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below. - ' TODO: set large fields to null. - End If - disposedValue = True - End Sub - - ' TODO: override Finalize() only if Dispose(disposing As Boolean) above has code to free unmanaged resources. - 'Protected Overrides Sub Finalize() - ' ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. - ' Dispose(False) - ' MyBase.Finalize() - 'End Sub - - ' This code added by Visual Basic to correctly implement the disposable pattern. - Public Sub Dispose() Implements IDisposable.Dispose - ' Do not change this code. Put cleanup code in Dispose(disposing As Boolean) above. - Dispose(True) - ' TODO: uncomment the following line if Finalize() is overridden above. - ' GC.SuppressFinalize(Me) - End Sub -#End Region - End Class -End Namespace diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/Protocols/UserId.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/Protocols/UserId.vb deleted file mode 100644 index 6326cfe9..00000000 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/Protocols/UserId.vb +++ /dev/null @@ -1,56 +0,0 @@ -#Region "Microsoft.VisualBasic::ecd0ffd91b41c2edf66248fea5772d55, Microsoft.VisualBasic.Core\ApplicationServices\Tools\Network\Tcp\Persistent\Protocols\UserId.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Class UserId - ' - ' Properties: Remote, uid - ' - ' Function: CreateApp - ' - ' - ' /********************************************************************************/ - -#End Region - -Namespace Net.Persistent.Application.Protocols - - Public Class UserId - - Public Property Remote As IPEndPoint - Public Property uid As Long - - Public Function CreateApp(protocols As PushMessage) As USER - Return New USER(Remote.IPAddress, Remote.Port, uid, protocols) - End Function - End Class -End Namespace diff --git a/ApplicationServices/Tools/Network/Tcp/TCPExtensions.vb b/ApplicationServices/Tools/Network/Tcp/TCPExtensions.vb index 9d1c1e8e..3c67432a 100644 --- a/ApplicationServices/Tools/Network/Tcp/TCPExtensions.vb +++ b/ApplicationServices/Tools/Network/Tcp/TCPExtensions.vb @@ -44,12 +44,10 @@ Imports System.Net Imports System.Net.NetworkInformation Imports System.Net.Sockets -Imports System.Reflection Imports System.Runtime.CompilerServices Imports Microsoft.VisualBasic.Linq.Extensions Imports Microsoft.VisualBasic.Net.Http Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Serialization.JSON Namespace Net @@ -182,33 +180,5 @@ Namespace Net Return True End Function - -#Region "OAuth Arguments" - - Const hash As String = "hash" - Const uid As String = "uid" - - Public Function BuildOAuth(ca As Net.SSL.Certificate) As String - Dim array As KeyValuePair(Of String, String)() = { - New KeyValuePair(Of String, String)(hash, ca.PrivateKey), - New KeyValuePair(Of String, String)(uid, ca.uid) - } - Dim oauth As String = WebServiceUtils.BuildUrlData(array) - Return oauth - End Function - - Public Function GetCA(args As String) As Net.SSL.Certificate -#If DEBUG Then - Call $"{MethodBase.GetCurrentMethod.GetFullName} ==> {args}".__DEBUG_ECHO -#End If - Dim data = WebServiceUtils.QueryStringParameters(args, False) -#If DEBUG Then - Call data.AllKeys.Select(Function(k) data(k)).ToArray.GetJson.__DEBUG_ECHO -#End If - Dim privateKey As String = data(hash) - Dim uid As Long = Scripting.CTypeDynamic(Of Long)(data(TCPExtensions.uid)) - Return Net.SSL.Certificate.Install(privateKey, uid) - End Function -#End Region End Module End Namespace From 91bcb5cc888ff26e985a5e0467acbf8ad887ebe1 Mon Sep 17 00:00:00 2001 From: xieguigang Date: Fri, 5 Oct 2018 03:16:38 +0800 Subject: [PATCH 4/6] obsolete code removes --- 47-dotnet_Microsoft.VisualBasic.vbproj | 1 - .../Parallel/Threads/ParallelLoading.vb | 323 ------------------ ApplicationServices/Tools/Network/Abstract.vb | 2 +- .../Network/Protocol/Reflection/AppMgr.vb | 4 +- .../Protocol/Reflection/ProtocolHandler.vb | 9 +- .../Protocol/Reflection/ProtocolInvoker.vb | 15 +- .../Tcp/Persistent/Socket/TcpClient.vb | 2 +- .../Tcp/TcpSynchronizationServicesSocket.vb | 2 +- 8 files changed, 16 insertions(+), 342 deletions(-) delete mode 100644 ApplicationServices/Parallel/Threads/ParallelLoading.vb diff --git a/47-dotnet_Microsoft.VisualBasic.vbproj b/47-dotnet_Microsoft.VisualBasic.vbproj index 3d5772f2..a9ad452c 100644 --- a/47-dotnet_Microsoft.VisualBasic.vbproj +++ b/47-dotnet_Microsoft.VisualBasic.vbproj @@ -1343,7 +1343,6 @@ - diff --git a/ApplicationServices/Parallel/Threads/ParallelLoading.vb b/ApplicationServices/Parallel/Threads/ParallelLoading.vb deleted file mode 100644 index d4a9c1a2..00000000 --- a/ApplicationServices/Parallel/Threads/ParallelLoading.vb +++ /dev/null @@ -1,323 +0,0 @@ -#Region "Microsoft.VisualBasic::1fe2c3e9c08f62f177338a7aa8385ad6, Microsoft.VisualBasic.Core\ApplicationServices\Parallel\Threads\ParallelLoading.vb" - - ' Author: - ' - ' asuka (amethyst.asuka@gcmodeller.org) - ' xie (genetics@smrucc.org) - ' xieguigang (xie.guigang@live.com) - ' - ' Copyright (c) 2018 GPL3 Licensed - ' - ' - ' GNU GENERAL PUBLIC LICENSE (GPL3) - ' - ' - ' This program is free software: you can redistribute it and/or modify - ' it under the terms of the GNU General Public License as published by - ' the Free Software Foundation, either version 3 of the License, or - ' (at your option) any later version. - ' - ' This program is distributed in the hope that it will be useful, - ' but WITHOUT ANY WARRANTY; without even the implied warranty of - ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - ' GNU General Public License for more details. - ' - ' You should have received a copy of the GNU General Public License - ' along with this program. If not, see . - - - - ' /********************************************************************************/ - - ' Summaries: - - ' Module ParallelLoading - ' - ' Function: __loadEntry, __loadTask, __parallelLoading, __subMain, DynamicsVBCTask - ' (+2 Overloads) Load, SendMessageAPI - ' Class LoadEntry - ' - ' Properties: LoadType, MethodEntryPoint - ' - ' Function: ToString - ' - ' Class LoadTaskInvoker - ' - ' Constructor: (+1 Overloads) Sub New - ' - ' Function: DataProcessor, Load - ' - ' Sub: FillData, GetSendData, StartProcess, WaitForTaskComplete - ' - ' Delegate Function - ' - ' - ' - ' - ' - ' /********************************************************************************/ - -#End Region - -Imports Microsoft.VisualBasic.ApplicationServices -Imports Microsoft.VisualBasic.Emit.CodeDOM_VBC -Imports Microsoft.VisualBasic.Language -Imports Microsoft.VisualBasic.Linq -Imports Microsoft.VisualBasic.Net.Http -Imports Microsoft.VisualBasic.Net.Protocols -Imports Microsoft.VisualBasic.Parallel.Tasks -Imports Microsoft.VisualBasic.Serialization.BinaryDumping - -Namespace Parallel - - ''' - ''' - ''' - Public Module ParallelLoading - - - Public Class LoadEntry : Inherits Attribute - - ''' - ''' 必须满足接口类型: Function(path As String) As T - ''' - ''' - Public Property MethodEntryPoint As System.Reflection.MethodInfo - - Public ReadOnly Property LoadType As Type - Get - Return MethodEntryPoint.DeclaringType - End Get - End Property - - Public Overrides Function ToString() As String - Return MethodEntryPoint.ToString - End Function - End Class - - ''' - ''' 当目标数据集非常的大的时候,在单个应用程序里面进行加载已经回非常缓慢了, - ''' 则这个时候可以使用这个函数将数据的加载任务分配到多个子进程之中以提高加载的时候的CPU的利用效率 - ''' - ''' - ''' - ''' - ''' 函数会自动从泛型类型之中解析出加载的函数 - Public Function Load(Of T)(sourceURL As Generic.IEnumerable(Of String), Optional TrimNull As Boolean = False) As KeyValuePair(Of String, T())() - Dim TypeEntry As Type = GetType(T) - Dim EntryPoint = Parallel.ParallelLoading.__loadEntry(TypeEntry) - - If EntryPoint Is Nothing Then - Throw New Exception($"Could not found any entry point for type:={TypeEntry.ToString}!") - End If - - Dim Process As String = DynamicsVBCTask(EntryPoint) '开始进行任务进程的动态编译 - Dim LQuery = (From source As String '进行并行化任务调度 - In sourceURL'这里不再使用并行化,因为启动Socket任务的需要为了避免端口占用的情况出现,任务不可以同时启动 - Select source, Task = Load(Of T)(url:=source, Process:=Process)).ToArray - Dim WaitTasks = (From mmfTask In LQuery.AsParallel '等待任务的结束然后返回数据集 - Let value As T() = mmfTask.Task.GetValue - Select New KeyValuePair(Of String, T())(mmfTask.source, value)).ToArray - - If TrimNull Then - WaitTasks = (From obj In WaitTasks.AsParallel Where Not obj.Value.IsNullOrEmpty Select obj).ToArray - End If - Return WaitTasks - End Function - - ''' - ''' 通过与并行进程进行内存共享来传输加载完毕的数据 - ''' - ''' - ''' - ''' - ''' - Private Function Load(Of T)(url As String, Process As String) As Task(Of String, T()) - Dim Task As New Task(Of String, T())(url, ParallelLoading.__loadTask(Of T)(Process)) - Return Task - End Function - - Private Function __loadTask(Of T)(process As String) As Func(Of String, T()) - Call Threading.Thread.Sleep(1000) - Return AddressOf New LoadTaskInvoker(Of T)(process).Load - End Function - - Private Class LoadTaskInvoker(Of T) - - ReadOnly Process As String - - Sub New(Process As String) - Me.Process = Process - End Sub - - Public Function Load(url As String) As T() - Dim Socket As New Microsoft.VisualBasic.Net.TcpSynchronizationServicesSocket(AddressOf DataProcessor, Net.GetFirstAvailablePort) - Call New Threading.Thread(AddressOf Socket.Run).Start() - Call StartProcess($"{url.CLIPath} { Socket.LocalPort}") - Call WaitForTaskComplete() - Return resultBuffer - End Function - - Private Sub StartProcess(argvs As String) - Dim ProcStart = New ProcessStartInfo(Process, arguments:=argvs) - Dim ProcInvoke As New Process With {.StartInfo = ProcStart} - - ProcStart.CreateNoWindow = True - ProcInvoke.Start() - End Sub - - Private Function DataProcessor(uid As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream - Dim requestData As String = request.GetUTF8String - - If String.IsNullOrEmpty(requestData) Then - Return NetResponse.RFC_NO_CONTENT - End If - - If requestData.StartsWith(MMFProtocol.MMFSocket.MMF_PROTOCOL) Then - '进程开始向父进程返回数据了 - Dim host As String = Mid(requestData, Len(MMFProtocol.MMFSocket.MMF_PROTOCOL) + 1) - Call GetSendData(host) - End If - - Return NetResponse.RFC_OK - End Function - - Dim TaskComplete As Boolean = False - - Private Sub WaitForTaskComplete() - Do While Not TaskComplete - Call Threading.Thread.Sleep(100) - Loop - End Sub - - Dim resultBuffer As T() - Dim _client As MMFProtocol.MMFSocket - - Private Sub GetSendData(host As String) - _client = New MMFProtocol.MMFSocket(host, AddressOf FillData) - End Sub - - Private Sub FillData(byteBuffer As Byte()) - ' resultBuffer = byteBuffer.DeSerialize(Of T()) - TaskComplete = True - End Sub - End Class - - ''' - ''' 动态编译的加载进程的调用API来向主进程返回消息 - ''' - ''' - ''' - Public Function SendMessageAPI(Port As Integer) As String - Dim host As String = "Parallel-" & Process.GetCurrentProcess.Id - Dim Client As New Microsoft.VisualBasic.Net.AsynInvoke("127.0.0.1", Port) - Call Client.SendMessage($"{MMFProtocol.MMFSocket.MMF_PROTOCOL}{host}") - Return host - End Function - - - - ''' - ''' 动态编译 - ''' - ''' - ''' - Public Function DynamicsVBCTask(LoadEntry As LoadEntry) As String - Dim refList As String() = GetReferences(LoadEntry.LoadType) - Dim ns As New CodeDom.CodeNamespace(NameOf(Parallel.ParallelLoading)) - - Call ns.Types.Add(__subMain(LoadEntry)) - Call ns.GenerateCode.__DEBUG_ECHO - - Dim assembly As System.Reflection.Assembly = ns.Compile(refList, RunTimeDirectory, CodeDOMExtension.ExecutableProfile) - Dim Dir As String = FileIO.FileSystem.GetParentPath(assembly.Location) - For Each File As String In refList - Dim buffer = IO.File.ReadAllBytes(File) - Dim Saved As String = $"{Dir}/{FileIO.FileSystem.GetFileInfo(File).Name}" - Try - Call IO.File.WriteAllBytes(Saved, buffer) - Catch ex As Exception - Call ex.PrintException - End Try - Next - Return assembly.Location - End Function - - Private Function __subMain(loadEntry As LoadEntry) As CodeDom.CodeTypeDeclaration - Dim ProgramEntry As New CodeDom.CodeTypeDeclaration("Program") - Dim SubMain As New CodeDom.CodeMemberMethod() - - Call ProgramEntry.Members.Add(SubMain) - SubMain.Name = "Main" - SubMain.ReturnType = New CodeDom.CodeTypeReference(GetType(System.Void)) - SubMain.Parameters.Add(New CodeDom.CodeParameterDeclarationExpression(GetType(String()), SubMainArgv)) - SubMain.Attributes = CodeDom.MemberAttributes.Public Or CodeDom.MemberAttributes.Static - SubMain = __parallelLoading(invoke:=SubMain, loadEntry:=loadEntry) - - Return ProgramEntry - End Function - - Const SubMainArgv As String = "Argv" - Const LoadFile As String = "File" - Const LoadResult As String = "LoadResult" - Const Port As String = "Port" - Const Host As String = "host" - Const Socket As String = "Socket" - Const Buffer As String = "buffer" - - Private Function __parallelLoading(invoke As CodeDom.CodeMemberMethod, loadEntry As LoadEntry) As CodeDom.CodeMemberMethod - - ' Dim File As String = argv(Scan0) - Call invoke.Statements.Add(LocalsInit(LoadFile, GetType(String), CodeDOMExpressions.GetValue(New CodeDom.CodeArgumentReferenceExpression(SubMainArgv), Scan0))) - - Dim PortValue As CodeDom.CodeExpression = CodeDOMExpressions.GetValue(New CodeDom.CodeArgumentReferenceExpression(SubMainArgv), 1) - PortValue = [Call](GetType(Conversion), NameOf(Conversion.Val), {PortValue}) - PortValue = [CType](PortValue, GetType(Integer)) - - ' Dim Port As Integer = CInt(Val(argv(1))) - Call invoke.Statements.Add(LocalsInit(Port, GetType(Integer), PortValue)) - Call invoke.Statements.Add([Call](GetType(Extensions), NameOf(__DEBUG_ECHO), - { - [Call](GetType(String), NameOf(String.Format), {CodeDOMExpressions.Value("Load stream from url:={0}, port:={1}..."), LocalVariable(LoadFile), LocalVariable(Port)}) - })) - Call invoke.Statements.Add([Call](GetType(Extensions), NameOf(__DEBUG_ECHO), {"Start to loading data..."})) - ' Dim LoadResult = ParallelLoadingTest.Load(File) '数据加载 - Call invoke.Statements.Add(LocalsInit(LoadResult, loadEntry.LoadType.MakeArrayType, initExpression:=[Call](loadEntry.MethodEntryPoint, {LocalVariable(LoadFile)}))) - Call invoke.Statements.Add([Call](GetType(Extensions), NameOf(__DEBUG_ECHO), {"Data loading Job Done!"})) - - '得到结果之后进行序列化通过内存映射共享返回给主程序 - ' Dim host As String = Microsoft.VisualBasic.Parallel.ParallelLoading.SendMessageAPI(Port) '返回消息 - Call invoke.Statements.Add(LocalsInit(Host, GetType(String), [Call](GetType(ParallelLoading), NameOf(SendMessageAPI), {LocalVariable(Port)}))) - ' Dim Socket As New Microsoft.VisualBasic.MMFProtocol.MMFSocket(hostName:=host) '打开映射的端口 - Call invoke.Statements.Add(LocalsInit(Socket, GetType(MMFProtocol.MMFSocket), [New](GetType(MMFProtocol.MMFSocket), {LocalVariable(Host)}))) - Call invoke.Statements.Add([Call](GetType(Extensions), NameOf(__DEBUG_ECHO), {"Init transfer device job done, start to transferred data!"})) - ' Call Socket.SendMessage(LoadResult.GetSerializeBuffer) '返回内存数据 - Call invoke.Statements.Add(LocalsInit(Buffer, GetType(Byte()), [Call](GetType(StructSerializer), NameOf(StructureToByte), {LocalVariable(LoadResult)}))) - Call invoke.Statements.Add([Call](LocalVariable(Socket), NameOf(MMFProtocol.MMFSocket.SendMessage), {LocalVariable(Buffer)})) - Call invoke.Statements.Add([Call](GetType(Extensions), NameOf(__DEBUG_ECHO), {"Data transportation Job Done!"})) - - Return invoke - End Function - - Private Function __loadEntry(Type As Type) As LoadEntry - Dim Entries = Type.GetMethods(System.Reflection.BindingFlags.Public Or System.Reflection.BindingFlags.Static) - If Entries.IsNullOrEmpty Then - Return Nothing - End If - - Dim setValue = New SetValue(Of ParallelLoading.LoadEntry)() _ - .GetSet(NameOf(ParallelLoading.LoadEntry.MethodEntryPoint)) - Dim LQuery As LoadEntry = - LinqAPI.DefaultFirst(Of LoadEntry) <= From EntryPoint As System.Reflection.MethodInfo - In Entries.AsParallel - Let attrs As Object() = EntryPoint.GetCustomAttributes(attributeType:=GetType(LoadEntry), inherit:=True) - Where Not attrs.IsNullOrEmpty - Let LoadEntry = DirectCast(attrs.First, LoadEntry) - Select setValue(LoadEntry, EntryPoint) - Return LQuery - End Function - - Delegate Function ParallelLoad(Of T)(sourceUrl As String) As T() - - End Module -End Namespace diff --git a/ApplicationServices/Tools/Network/Abstract.vb b/ApplicationServices/Tools/Network/Abstract.vb index 4bd3d52f..71256687 100644 --- a/ApplicationServices/Tools/Network/Abstract.vb +++ b/ApplicationServices/Tools/Network/Abstract.vb @@ -76,7 +76,7 @@ Namespace Net.Abstract Public MustInherit Class IProtocolHandler MustOverride ReadOnly Property ProtocolEntry As Long - MustOverride Function HandleRequest(CA As Long, request As RequestStream, remoteDevcie As System.Net.IPEndPoint) As RequestStream + MustOverride Function HandleRequest(request As RequestStream, remoteDevcie As System.Net.IPEndPoint) As RequestStream End Class #Region "Delegate Abstract Interface" diff --git a/ApplicationServices/Tools/Network/Protocol/Reflection/AppMgr.vb b/ApplicationServices/Tools/Network/Protocol/Reflection/AppMgr.vb index b3dc366f..a4871c07 100644 --- a/ApplicationServices/Tools/Network/Protocol/Reflection/AppMgr.vb +++ b/ApplicationServices/Tools/Network/Protocol/Reflection/AppMgr.vb @@ -97,13 +97,13 @@ Namespace Net.Protocols.Reflection Return Register(DirectCast(App, Object), [overrides]) End Function - Public Overrides Function HandleRequest(CA As Long, request As RequestStream, remoteDevcie As System.Net.IPEndPoint) As RequestStream + Public Overrides Function HandleRequest(request As RequestStream, remoteDevcie As System.Net.IPEndPoint) As RequestStream If Not ProtocolApps.ContainsKey(request.ProtocolCategory) Then Return NetResponse.RFC_NOT_FOUND End If Dim Protocol As ProtocolHandler = ProtocolApps(request.ProtocolCategory) - Return Protocol.HandleRequest(CA, request, remoteDevcie) + Return Protocol.HandleRequest(request, remoteDevcie) End Function End Class End Namespace diff --git a/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb b/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb index 00400f22..3b3d8d1d 100644 --- a/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb +++ b/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb @@ -116,17 +116,16 @@ Namespace Net.Protocols.Reflection End Function Public Function HandlePush(uid As Long, request As RequestStream) As RequestStream - Return HandleRequest(uid, request, Nothing) + Return HandleRequest(request, Nothing) End Function ''' - ''' Handle the data request from the client for socket events: or + ''' Handle the data request from the client for socket events: . ''' - ''' ''' The request stream object which contains the commands from the client ''' The IPAddress of the target incoming client data request. ''' - Public Overrides Function HandleRequest(CA As Long, request As RequestStream, remoteDevcie As System.Net.IPEndPoint) As RequestStream + Public Overrides Function HandleRequest(request As RequestStream, remoteDevcie As System.Net.IPEndPoint) As RequestStream If request.ProtocolCategory <> Me.ProtocolEntry Then #If DEBUG Then Call $"Protocol_entry:={request.ProtocolCategory} was not found!".__DEBUG_ECHO @@ -142,7 +141,7 @@ Namespace Net.Protocols.Reflection End If Dim EntryPoint As DataRequestHandler = Me.Protocols(request.Protocol) - Dim value As RequestStream = EntryPoint(CA, request, remoteDevcie) + Dim value As RequestStream = EntryPoint(request, remoteDevcie) Return value End Function diff --git a/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolInvoker.vb b/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolInvoker.vb index ea6e240b..8eb7f9a7 100644 --- a/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolInvoker.vb +++ b/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolInvoker.vb @@ -56,20 +56,20 @@ Namespace Net.Protocols.Reflection Me.Method = Method End Sub - Public Function InvokeProtocol0(CA As Long, request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream + Public Function InvokeProtocol0(request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream Dim value = Method.Invoke(obj, Nothing) Dim data = DirectCast(value, RequestStream) Return data End Function - Public Function InvokeProtocol1(CA As Long, request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream - Dim value = Method.Invoke(obj, {CA}) + Public Function InvokeProtocol1(request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream + Dim value = Method.Invoke(obj, {}) Dim data = DirectCast(value, RequestStream) Return data End Function - Public Function InvokeProtocol2(CA As Long, request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream - Dim value = Method.Invoke(obj, {CA, request}) + Public Function InvokeProtocol2(request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream + Dim value = Method.Invoke(obj, {request}) Dim data = DirectCast(value, RequestStream) Return data End Function @@ -77,13 +77,12 @@ Namespace Net.Protocols.Reflection ''' ''' ''' - ''' ''' ''' ''' - Public Function InvokeProtocol3(CA As Long, request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream + Public Function InvokeProtocol3(request As RequestStream, remoteDevice As System.Net.IPEndPoint) As RequestStream Try - Dim value = Method.Invoke(obj, {CA, request, remoteDevice}) + Dim value = Method.Invoke(obj, {request, remoteDevice}) Dim data = DirectCast(value, RequestStream) Return data Catch ex As Exception diff --git a/ApplicationServices/Tools/Network/Tcp/Persistent/Socket/TcpClient.vb b/ApplicationServices/Tools/Network/Tcp/Persistent/Socket/TcpClient.vb index 98839d79..e33970b4 100644 --- a/ApplicationServices/Tools/Network/Tcp/Persistent/Socket/TcpClient.vb +++ b/ApplicationServices/Tools/Network/Tcp/Persistent/Socket/TcpClient.vb @@ -385,7 +385,7 @@ Namespace Net.Persistent.Socket If ServicesProtocol.Protocols.ServerHash = request.Protocol Then Me._OnServerHashCode = Scripting.CTypeDynamic(Of Integer)(request.GetUTF8String) Else - Call RunTask(Sub() Me.Responsehandler()(request.uid, request, Nothing)) + Call RunTask(Sub() Me.Responsehandler()(request, Nothing)) End If End Sub diff --git a/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb b/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb index c056ff0b..b8ca3b98 100644 --- a/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb +++ b/ApplicationServices/Tools/Network/Tcp/TcpSynchronizationServicesSocket.vb @@ -332,7 +332,7 @@ Namespace Net If requestData.IsPing Then requestData = NetResponse.RFC_OK Else - requestData = Me.Responsehandler()(requestData.uid, requestData, remoteEP) + requestData = Me.Responsehandler()(requestData, remoteEP) End If Call Send(handler, requestData) Catch ex As Exception From 2fb4ee31b1dc0d22b44bac44f7422107fd52d651 Mon Sep 17 00:00:00 2001 From: xieguigang Date: Fri, 5 Oct 2018 03:27:47 +0800 Subject: [PATCH 5/6] add type casting handler --- .../Tools/Network/Protocol/Reflection/ProtocolHandler.vb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb b/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb index 3b3d8d1d..0ccf69af 100644 --- a/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb +++ b/ApplicationServices/Tools/Network/Protocol/Reflection/ProtocolHandler.vb @@ -189,5 +189,9 @@ Namespace Net.Protocols.Reflection Return Nothing End Function + + Public Shared Narrowing Operator CType(handler As ProtocolHandler) As DataRequestHandler + Return AddressOf handler.HandleRequest + End Operator End Class End Namespace From 21c844350a21f5f20c7fe1d0695d03a14b78e140 Mon Sep 17 00:00:00 2001 From: xieguigang Date: Fri, 5 Oct 2018 03:49:52 +0800 Subject: [PATCH 6/6] code comment style improvbememnts --- .../Network/Protocol/Reflection/Protocol.vb | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ApplicationServices/Tools/Network/Protocol/Reflection/Protocol.vb b/ApplicationServices/Tools/Network/Protocol/Reflection/Protocol.vb index e2e3b113..0770e71a 100644 --- a/ApplicationServices/Tools/Network/Protocol/Reflection/Protocol.vb +++ b/ApplicationServices/Tools/Network/Protocol/Reflection/Protocol.vb @@ -46,7 +46,8 @@ Namespace Net.Protocols.Reflection ''' - ''' This attribute indicates the entry point of the protocol processor definition location and the details of the protocol processor. + ''' This attribute indicates the entry point of the protocol processor definition location + ''' and the details of the protocol processor. ''' Public Class Protocol : Inherits Attribute @@ -66,18 +67,20 @@ Namespace Net.Protocols.Reflection ''' ''' Generates the protocol method entrypoint.(应用于服务器上面的协议处理方法) ''' - ''' - Sub New(EntryPoint As Long) - Me.EntryPoint = EntryPoint + ''' + Sub New(entryPoint As Long) + Me.EntryPoint = entryPoint End Sub ''' - ''' Generates the on the server side, this is using for initialize a protocol API entry point.(客户端上面的类型) + ''' Generates the on the server side, + ''' this is using for initialize a protocol API entry point. + ''' (客户端上面的类型) ''' - ''' 客户端上面的类型 - Sub New(Type As Type) - EntryPoint = SecurityString.MD5Hash.ToLong(Type.GUID.ToByteArray) - DeclaringType = Type + ''' 客户端上面的类型 + Sub New(type As Type) + EntryPoint = SecurityString.MD5Hash.ToLong(type.GUID.ToByteArray) + DeclaringType = type End Sub Public Overrides Function ToString() As String @@ -105,7 +108,8 @@ Namespace Net.Protocols.Reflection End Function ''' - ''' This method is usually using for generates a details protocol processor, example is calling the method interface: + ''' This method is usually using for generates a details protocol processor, example + ''' is calling the method interface: ''' Correspondent to the protocol entry property ''' '''