1 #Region "Microsoft.VisualBasic::9a83f1918829b5783719a1b23169aea4, Microsoft.VisualBasic.Core\ApplicationServices\Tools\MMFProtocol\mmfsocket.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Delegate Sub
35     
36     
37     '     Delegate Sub
38     
39     
40     '     Class MMFSocket
41     
42     '         Properties: NewMessageCallBack, URI
43     
44     '         Constructor: (+2 OverloadsSub New
45     
46     '         Function: CreateObject, getMessage, Ping, ReadData, ReadString
47     '                   SendMessage, ToString, WriteMessage
48     
49     '         Sub: __dataArrival, (+2 Overloads) Dispose, (+3 Overloads) SendMessage
50     
51     
52     
53     
54     
55     ' /********************************************************************************/
56
57 #End Region
58
59 Imports System.IO
60 Imports System.Runtime.Serialization.Formatters.Binary
61 Imports Microsoft.VisualBasic.CommandLine.Reflection
62 Imports Microsoft.VisualBasic.MMFProtocol.MapStream
63 Imports Microsoft.VisualBasic.Net.Protocols
64 Imports Microsoft.VisualBasic.Text
65
66 Namespace MMFProtocol
67
68     ''' <summary>
69     ''' 客户端接受到的数据需要经过反序列化解码方能读取
70     ''' </summary>
71     ''' <param name="data"></param>
72     ''' <remarks></remarks>
73     Public Delegate Sub DataArrival(data As Byte())
74     ''' <summary>
75     ''' 
76     ''' </summary>
77     ''' <param name="message">UTF8 string</param>
78     Public Delegate Sub ReadNewMessage(message As String)
79
80     ''' <summary>
81     ''' MMFProtocol socket object for the inter-process communication on the localhost, this can be using for the data exchange between two process.
82     ''' </summary>
83     ''' <remarks></remarks>
84     <[Namespace]("MMFSocket", Description:="MMFProtocol socket object for the inter-process communication on the localhost, this can be using for the data exchange between two process.")>
85     Public Class MMFSocket : Implements IDisposable
86
87         Dim _MMFReader As MSIOReader, _MMFWriter As MSWriter
88         Dim _UpdateFlag As Long
89         Dim _callBacks As DataArrival
90
91         Public Property NewMessageCallBack As ReadNewMessage
92
93         Public ReadOnly Property URI As String
94
95         ''' <summary>
96         ''' 
97         ''' </summary>
98         ''' <param name="uri"></param>
99         ''' <param name="chunkSize">默认的区块大小为100KB,这个对于一般的小文本传输已经足够了</param>
100         Sub New(uri As StringOptional chunkSize As Long = 100 * 1024)
101             _MMFWriter = New MSWriter(uri, chunkSize)
102             _MMFReader = New MSIOReader(uri, AddressOf __dataArrival, chunkSize)
103             _URI = uri
104         End Sub
105
106         Public Const MMF_PROTOCOL As String = "mmf://"
107
108         ''' <summary>
109         ''' 
110         ''' </summary>
111         ''' <param name="uri"></param>
112         ''' <param name="dataArrivals">
113         ''' Public Delegate Sub <see cref="__dataArrival"/>(byteData As <see cref="System.Byte"/>())
114         ''' 会优先于事件<see cref="__dataArrival"></see>的发生</param>
115         ''' <remarks></remarks>
116         Sub New(uri As String, dataArrivals As DataArrival)
117             Call Me.New(uri)
118             _callBacks = dataArrivals
119         End Sub
120
121         Public Sub SendMessage(byteData As Byte())
122             Me._UpdateFlag = _MMFReader.Read.udtBadge + 1
123
124             Dim bytData As Byte() = New MMFStream With {
125                 .byteData = byteData,
126                 .udtBadge = Me._UpdateFlag
127             }.Serialize
128
129             Call _MMFReader.Update(Me._UpdateFlag)
130             Call _MMFWriter.WriteStream(bytData)
131         End Sub
132
133         ''' <summary>
134         ''' 直接从映射文件之中读取数据
135         ''' </summary>
136         ''' <returns></returns>
137         Public Function ReadData() As Byte()
138             Return _MMFReader.Read.byteData
139         End Function
140
141         Public Sub SendMessage(raw As RawStream)
142             Call SendMessage(raw.Serialize)
143         End Sub
144
145         ''' <summary>
146         ''' 
147         ''' </summary>
148         ''' <param name="s"><see cref="System.Text.Encoding.UTF8"/></param>
149         Public Sub SendMessage(s As String)
150             Dim buf As Byte() = System.Text.Encoding.UTF8.GetBytes(s)
151             Call Me.SendMessage(buf)
152         End Sub
153
154         Public Function ReadString() As String
155             Dim buf As Byte() = ReadData()
156             Dim s As String = System.Text.Encoding.UTF8.GetString(buf)
157             Return s
158         End Function
159
160 #Region "IDisposable Support"
161         Private disposedValue As Boolean To detect redundant calls
162
163         ' IDisposable
164         Protected Overridable Sub Dispose(disposing As Boolean)
165             If Not Me.disposedValue Then
166                 If disposing Then
167                     ' TODO: dispose managed state (managed objects).
168                     Call Me._MMFWriter.Free
169                     Call Me._MMFReader.Free
170                 End If
171
172                 ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
173                 ' TODO: set large fields to null.
174             End If
175             Me.disposedValue = True
176         End Sub
177
178         ' TODO: override Finalize() only if Dispose(      disposing As Boolean) above has code to free unmanaged resources.
179         'Protected Overrides Sub Finalize()
180         '    ' Do not change this code.  Put cleanup code in Dispose(      disposing As Boolean) above.
181         '    Dispose(False)
182         '    MyBase.Finalize()
183         'End Sub
184
185         ' This code added by Visual Basic to correctly implement the disposable pattern.
186         Public Sub Dispose() Implements IDisposable.Dispose
187             Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
188             Dispose(True)
189             GC.SuppressFinalize(Me)
190         End Sub
191 #End Region
192
193         Public Overrides Function ToString() As String
194             Return $"{MMF_PROTOCOL}{_URI}"
195         End Function
196
197         Public Function Ping() As Boolean
198             Call SendMessage(s:=_PING_MESSAGE)
199             Call Threading.Thread.Sleep(100)
200
201             If PingResult = True Then
202                 PingResult = False
203                 Return True
204             Else
205                 Return False
206             End If
207         End Function
208
209         Private Const _PING_MESSAGE As String = "PINT_REQUEST::{BAB0B3FA-C3F3-42F2-A577-9AF57EBDB9C7}"
210         Private Const _PING_RETURNS As String = "PING_RETURNS::{BAB0B3FA-C3F3-42F2-A577-9AF57EBDB9C7}"
211
212         Dim PingResult As Boolean = False
213
214         Private Sub __dataArrival(data() As Byte)
215             Dim s_MSG As String = System.Text.Encoding.Unicode.GetString(data)
216
217             If String.Equals(s_MSG, _PING_MESSAGE) Then
218                 Call SendMessage(_PING_RETURNS)
219             ElseIf String.Equals(s_MSG, _PING_RETURNS) Then
220                 PingResult = True
221             Else
222                 If Not _callBacks Is Nothing Then
223                     Call _callBacks(data)
224                 End If
225
226                 If Not NewMessageCallBack Is Nothing Then
227                     Call NewMessageCallBack()(s_MSG)
228                 End If
229             End If
230         End Sub
231
232 #Region "ShellScript API"
233
234         <ExportAPI("MMFProtocol.New")>
235         Public Shared Function CreateObject(hostName As StringOptional handler As Action(Of Generic.IEnumerable(Of Byte)) = NothingAs MMFProtocol.MMFSocket
236             Dim CallBackHandle As DataArrival = New DataArrival(Sub(data As Byte()) handler(data))
237             Return New MMFSocket(hostName, CallBackHandle)
238         End Function
239
240         <ExportAPI("SendMessage")>
241         Public Shared Function SendMessage(socket As MMFSocket, data As Generic.IEnumerable(Of Byte)) As Boolean
242             Try
243                 Call socket.SendMessage(data.ToArray)
244                 Return True
245             Catch ex As Exception
246                 Return False
247             End Try
248         End Function
249
250         <ExportAPI("getMessage")>
251         Public Shared Function getMessage(data As Generic.IEnumerable(Of Byte), Optional encoding As String = ""As String
252             Return TextFileEncodingDetector.ToString(data, encoding)
253         End Function
254
255         <ExportAPI("Print.Message")>
256         Public Shared Function WriteMessage(data As Generic.IEnumerable(Of Byte)) As String
257             Dim Message As String = getMessage(data)
258             Call Console.WriteLine(Message)
259             Return Message
260         End Function
261 #End Region
262     End Class
263 End Namespace