1 #Region "Microsoft.VisualBasic::ab3c4c8a2c451e14dce950d548490d07, Microsoft.VisualBasic.Core\ApplicationServices\Parallel\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 Microsoft.VisualBasic.CommandLine.Reflection
60 Imports Microsoft.VisualBasic.Net.Protocols
61 Imports Microsoft.VisualBasic.Parallel.MMFProtocol.MapStream
62 Imports Microsoft.VisualBasic.Text
63
64 Namespace Parallel.MMFProtocol
65
66     ''' <summary>
67     ''' 客户端接受到的数据需要经过反序列化解码方能读取
68     ''' </summary>
69     ''' <param name="data"></param>
70     ''' <remarks></remarks>
71     Public Delegate Sub DataArrival(data As Byte())
72     ''' <summary>
73     ''' 
74     ''' </summary>
75     ''' <param name="message">UTF8 string</param>
76     Public Delegate Sub ReadNewMessage(message As String)
77
78     ''' <summary>
79     ''' MMFProtocol socket object for the inter-process communication on the localhost, this can be using for the data exchange between two process.
80     ''' </summary>
81     ''' <remarks></remarks>
82     <[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.")>
83     Public Class MMFSocket : Implements IDisposable
84
85         Dim _MMFReader As MSIOReader, _MMFWriter As MSWriter
86         Dim _UpdateFlag As Long
87         Dim _callBacks As DataArrival
88
89         Public Property NewMessageCallBack As ReadNewMessage
90
91         Public ReadOnly Property URI As String
92
93         ''' <summary>
94         ''' 
95         ''' </summary>
96         ''' <param name="uri"></param>
97         ''' <param name="chunkSize">默认的区块大小为100KB,这个对于一般的小文本传输已经足够了</param>
98         Sub New(uri As StringOptional chunkSize As Long = 100 * 1024)
99             _MMFWriter = New MSWriter(uri, chunkSize)
100             _MMFReader = New MSIOReader(uri, AddressOf __dataArrival, chunkSize)
101             _URI = uri
102         End Sub
103
104         Public Const MMF_PROTOCOL As String = "mmf://"
105
106         ''' <summary>
107         ''' 
108         ''' </summary>
109         ''' <param name="uri"></param>
110         ''' <param name="dataArrivals">
111         ''' Public Delegate Sub <see cref="__dataArrival"/>(byteData As <see cref="System.Byte"/>())
112         ''' 会优先于事件<see cref="__dataArrival"></see>的发生</param>
113         ''' <remarks></remarks>
114         Sub New(uri As String, dataArrivals As DataArrival)
115             Call Me.New(uri)
116             _callBacks = dataArrivals
117         End Sub
118
119         Public Sub SendMessage(byteData As Byte())
120             Me._UpdateFlag = _MMFReader.Read.udtBadge + 1
121
122             Dim bytData As Byte() = New MMFStream With {
123                 .byteData = byteData,
124                 .udtBadge = Me._UpdateFlag
125             }.Serialize
126
127             Call _MMFReader.Update(Me._UpdateFlag)
128             Call _MMFWriter.WriteStream(bytData)
129         End Sub
130
131         ''' <summary>
132         ''' 直接从映射文件之中读取数据
133         ''' </summary>
134         ''' <returns></returns>
135         Public Function ReadData() As Byte()
136             Return _MMFReader.Read.byteData
137         End Function
138
139         Public Sub SendMessage(raw As RawStream)
140             Call SendMessage(raw.Serialize)
141         End Sub
142
143         ''' <summary>
144         ''' 
145         ''' </summary>
146         ''' <param name="s"><see cref="System.Text.Encoding.UTF8"/></param>
147         Public Sub SendMessage(s As String)
148             Dim buf As Byte() = System.Text.Encoding.UTF8.GetBytes(s)
149             Call Me.SendMessage(buf)
150         End Sub
151
152         Public Function ReadString() As String
153             Dim buf As Byte() = ReadData()
154             Dim s As String = System.Text.Encoding.UTF8.GetString(buf)
155             Return s
156         End Function
157
158 #Region "IDisposable Support"
159         Private disposedValue As Boolean To detect redundant calls
160
161         ' IDisposable
162         Protected Overridable Sub Dispose(disposing As Boolean)
163             If Not Me.disposedValue Then
164                 If disposing Then
165                     ' TODO: dispose managed state (managed objects).
166                     Call Me._MMFWriter.Free
167                     Call Me._MMFReader.Free
168                 End If
169
170                 ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
171                 ' TODO: set large fields to null.
172             End If
173             Me.disposedValue = True
174         End Sub
175
176         ' TODO: override Finalize() only if Dispose(      disposing As Boolean) above has code to free unmanaged resources.
177         'Protected Overrides Sub Finalize()
178         '    ' Do not change this code.  Put cleanup code in Dispose(      disposing As Boolean) above.
179         '    Dispose(False)
180         '    MyBase.Finalize()
181         'End Sub
182
183         ' This code added by Visual Basic to correctly implement the disposable pattern.
184         Public Sub Dispose() Implements IDisposable.Dispose
185             Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
186             Dispose(True)
187             GC.SuppressFinalize(Me)
188         End Sub
189 #End Region
190
191         Public Overrides Function ToString() As String
192             Return $"{MMF_PROTOCOL}{_URI}"
193         End Function
194
195         Public Function Ping() As Boolean
196             Call SendMessage(s:=_PING_MESSAGE)
197             Call Threading.Thread.Sleep(100)
198
199             If PingResult = True Then
200                 PingResult = False
201                 Return True
202             Else
203                 Return False
204             End If
205         End Function
206
207         Private Const _PING_MESSAGE As String = "PINT_REQUEST::{BAB0B3FA-C3F3-42F2-A577-9AF57EBDB9C7}"
208         Private Const _PING_RETURNS As String = "PING_RETURNS::{BAB0B3FA-C3F3-42F2-A577-9AF57EBDB9C7}"
209
210         Dim PingResult As Boolean = False
211
212         Private Sub __dataArrival(data() As Byte)
213             Dim s_MSG As String = System.Text.Encoding.Unicode.GetString(data)
214
215             If String.Equals(s_MSG, _PING_MESSAGE) Then
216                 Call SendMessage(_PING_RETURNS)
217             ElseIf String.Equals(s_MSG, _PING_RETURNS) Then
218                 PingResult = True
219             Else
220                 If Not _callBacks Is Nothing Then
221                     Call _callBacks(data)
222                 End If
223
224                 If Not NewMessageCallBack Is Nothing Then
225                     Call NewMessageCallBack()(s_MSG)
226                 End If
227             End If
228         End Sub
229
230 #Region "ShellScript API"
231
232         <ExportAPI("MMFProtocol.New")>
233         Public Shared Function CreateObject(hostName As StringOptional handler As Action(Of Generic.IEnumerable(Of Byte)) = NothingAs MMFProtocol.MMFSocket
234             Dim CallBackHandle As DataArrival = New DataArrival(Sub(data As Byte()) handler(data))
235             Return New MMFSocket(hostName, CallBackHandle)
236         End Function
237
238         <ExportAPI("SendMessage")>
239         Public Shared Function SendMessage(socket As MMFSocket, data As Generic.IEnumerable(Of Byte)) As Boolean
240             Try
241                 Call socket.SendMessage(data.ToArray)
242                 Return True
243             Catch ex As Exception
244                 Return False
245             End Try
246         End Function
247
248         <ExportAPI("getMessage")>
249         Public Shared Function getMessage(data As Generic.IEnumerable(Of Byte), Optional encoding As String = ""As String
250             Return TextFileEncodingDetector.ToString(data, encoding)
251         End Function
252
253         <ExportAPI("Print.Message")>
254         Public Shared Function WriteMessage(data As Generic.IEnumerable(Of Byte)) As String
255             Dim Message As String = getMessage(data)
256             Call Console.WriteLine(Message)
257             Return Message
258         End Function
259 #End Region
260     End Class
261 End Namespace