1 #Region "Microsoft.VisualBasic::6864ab1abde87b67480f1e6467ea0b9e, Microsoft.VisualBasic.Core\ApplicationServices\Parallel\Threads\ServicesFolk.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     '     Module ServicesFolk
35     
36     '         Function: Folk, ReturnPortal
37     '         Class __getChildPortal
38     
39     '             Function: HandleRequest, WaitForPortal
40     
41     
42     
43     
44     ' /********************************************************************************/
45
46 #End Region
47
48 Imports System.Reflection
49 Imports Microsoft.VisualBasic.Net.Http
50 Imports Microsoft.VisualBasic.Net.Protocols
51 Imports Microsoft.VisualBasic.Win32
52 Imports SetValueAction = Microsoft.VisualBasic.Linq.SetValue(Of Microsoft.VisualBasic.Net.TcpSynchronizationServicesSocket)
53
54 Namespace Parallel
55
56     ''' <summary>
57     ''' 主服务和子服务之间的相互作用的特点是子服务不会知道主服务节点的数据接口,所有的交互都是通过子服务上面的一个模块来监听主服务来实现的
58     ''' 当主服务有数据需要向子服务更新的时候,会主动发送数据请求至子服务节点
59     ''' </summary>
60     ''' <remarks>当前的用户规模还比较小这里仅仅是实现了本地的调用,后面考虑到业务吞吐量的问题,会将服务的调用分开到两台物理主机之上</remarks>
61     Public Module ServicesFolk
62
63         ''' <summary>
64         ''' 函数返回子进程的交互数据通信的端口号
65         ''' </summary>
66         ''' <param name="assm"></param>
67         ''' <param name="CLI">命令行参数字符串,可以在这里加入一些其他的自定义数据</param>
68         ''' <returns>函数返回子服务的交互端口</returns>
69         Public Function Folk(assm As StringByRef CLI As StringOptional ByRef folked As Process = NothingAs Integer
70             Dim Portal As Integer
71
72             '开通一个临时的端口用来和子服务交互
73             Using TempListen As New Net.TcpSynchronizationServicesSocket(
74                 Net.TCPExtensions.GetFirstAvailablePort,
75                 Sub(ex) App.LogException(ex, MethodBase.GetCurrentMethod.GetFullName))
76
77                 Dim __getChildPortal As New __getChildPortal
78
79                 Call SetValueAction.InvokeSet(Of Net.Abstract.DataRequestHandler)(
80                      TempListen,
81                      NameOf(TempListen.Responsehandler),
82                      AddressOf __getChildPortal.HandleRequest)
83
84                 Call RunTask(AddressOf TempListen.Run)
85                 Call TempListen.WaitForStart()
86
87                 Dim path As String =
88                     If(assm.FileExists, FileIO.FileSystem.GetFileInfo(assm).FullName, $"{App.HOME}/{assm}")
89 #If DEBUG Then
90                 Call $"Invoke start  {path.ToFileURL}  @{MethodBase.GetCurrentMethod.GetFullName}".__DEBUG_ECHO
91 #End If
92                 Dim FolkSvr As Process =
93                     Process.Start(path, $"{CLI} {ParentPortal} {TempListen.LocalPort}")
94
95                 __getChildPortal.PID = FolkSvr.Id
96                 Portal = __getChildPortal.WaitForPortal
97                 folked = FolkSvr
98                 CLI = __getChildPortal.addArgs
99             End Using
100
101             Dim msg As String = $"Get folked child services {assm} local_services:={Portal}"
102
103             Call msg.__DEBUG_ECHO
104
105             If WindowsServices.Initialized Then
106                 Call ServicesLogs.WriteEntry(msg, EventLogEntryType.SuccessAudit)
107             End If
108
109             Return Portal
110         End Function
111
112         Private Class __getChildPortal
113
114             Public PID As Integer
115             Public Portal As Integer = -100
116             ''' <summary>
117             ''' 所返回来的额外的参数信息
118             ''' </summary>
119             Public addArgs As String
120
121             Public Function HandleRequest(uid As Long, request As RequestStream, remote As System.Net.IPEndPoint) As RequestStream
122                 If uid <> PID Then
123                     Return NetResponse.RFC_TOKEN_INVALID
124                 End If
125
126                 Dim result As String = request.GetUTF8String
127
128                 Portal = Scripting.CTypeDynamic(Of Integer)(result)
129                 addArgs = CommandLine.GetTokens(result).ElementAtOrDefault(1)
130
131                 Return NetResponse.RFC_OK
132             End Function
133
134             Public Function WaitForPortal() As Integer
135                 Do While Portal < 0
136                     Call Threading.Thread.Sleep(1)
137                 Loop
138
139                 Return Portal
140             End Function
141         End Class
142
143         Const ParentPortal As String = "--portal"
144
145         ''' <summary>
146         ''' 子服务向服务主节点返回端口号数据,这个方法需要要在子服务上面的服务程序启动之后再调用
147         ''' </summary>
148         ''' <param name="CLI"></param>
149         ''' <param name="Port"></param>
150         ''' <param name="addArgs">额外返回的参数信息</param>
151         ''' <returns></returns>
152         Public Function ReturnPortal(CLI As CommandLine.CommandLine, Port As IntegerOptional addArgs As String = ""As Boolean
153             Dim parentPortal As Integer = CLI.GetInt32(ServicesFolk.ParentPortal)
154             Dim Client As New Net.AsynInvoke("127.0.0.1", parentPortal)
155 #If DEBUG Then
156             Call $"{MethodBase.GetCurrentMethod.GetFullName} ==> ""{CLI}"" returns {Port}".__DEBUG_ECHO
157 #End If
158             Dim request As New RequestStream(Process.GetCurrentProcess.Id, 0, $"{CStr(Port)} ""{addArgs}""") With {
159                 .uid = Process.GetCurrentProcess.Id
160             }
161             Dim response As RequestStream = Client.SendMessage(request)
162             Return response.Protocol = HTTP_RFC.RFC_OK
163         End Function
164     End Module
165 End Namespace