Skip to content

Commit 6735c0e

Browse files
Initial Commit
1 parent 077bb66 commit 6735c0e

26 files changed

+7182
-0
lines changed

Api/ApiClient.vb

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
' =======================================================================================
2+
'
3+
' This file is part of neth-proxy.
4+
'
5+
' neth-proxy is free software: you can redistribute it and/or modify
6+
' it under the terms Of the GNU General Public License As published by
7+
' the Free Software Foundation, either version 3 Of the License, Or
8+
' (at your option) any later version.
9+
'
10+
' neth-proxy is distributed In the hope that it will be useful,
11+
' but WITHOUT ANY WARRANTY; without even the implied warranty Of
12+
' MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
' GNU General Public License For more details.
14+
'
15+
' You should have received a copy Of the GNU General Public License
16+
' along with neth-proxy. If not, see < http://www.gnu.org/licenses/ >.
17+
'
18+
' =======================================================================================
19+
20+
Imports nethproxy.Core
21+
Imports nethproxy.Sockets
22+
Imports System.Json
23+
Imports System.Net
24+
Imports System.Net.Sockets
25+
Imports System.Text
26+
27+
Namespace Api
28+
29+
Public Class ApiClient
30+
31+
' Pointers to singletons
32+
Private _settings As Core.Settings
33+
Private _clntmgr As Clients.ClientsManager
34+
35+
' The base socket handler
36+
Private WithEvents _socket As AsyncSocket = Nothing
37+
38+
' Logging Context
39+
Private _context As String = "Api"
40+
Private _lockObj As New Object
41+
42+
Public ReadOnly Property Id As String ' Unique identifier
43+
44+
#Region " Constructor"
45+
46+
Private Sub New()
47+
End Sub
48+
49+
50+
Public Sub New(ByRef acceptedSocket As Socket)
51+
52+
' Retrieve singletons
53+
_settings = App.Instance.Settings
54+
_clntmgr = App.Instance.ClntMgr
55+
56+
' Start a new async socket
57+
_Id = acceptedSocket.RemoteEndPoint.ToString()
58+
_socket = New AsyncSocket(acceptedSocket, "Api")
59+
_socket.BeginReceive()
60+
61+
End Sub
62+
63+
64+
#End Region
65+
66+
#Region " Properties"
67+
68+
''' <summary>
69+
''' Whether or not this socket is connected
70+
''' </summary>
71+
''' <returns></returns>
72+
Public ReadOnly Property IsConnected
73+
Get
74+
If _socket Is Nothing Then Return False
75+
Return _socket.IsConnected
76+
End Get
77+
End Property
78+
79+
''' <summary>
80+
''' Returns the remote endpoint of the underlying socket
81+
''' </summary>
82+
''' <returns>True / False</returns>
83+
Public ReadOnly Property RemoteEndPoint As IPEndPoint
84+
Get
85+
If _socket Is Nothing Then Return Nothing
86+
Return _socket.RemoteEndPoint
87+
End Get
88+
End Property
89+
90+
''' <summary>
91+
''' Returns how much time this connection has been idle
92+
''' </summary>
93+
''' <returns>A <see cref="TimeSpan"/> object</returns>
94+
Public ReadOnly Property IdleDuration As TimeSpan
95+
Get
96+
If _socket Is Nothing Then Return New TimeSpan(0, 0, 0)
97+
Return _socket.IdleDuration
98+
End Get
99+
End Property
100+
101+
''' <summary>
102+
''' Gets the time of connection of this worker
103+
''' </summary>
104+
''' <returns></returns>
105+
Public ReadOnly Property ConnectedTimeStamp As DateTime
106+
Get
107+
If _socket Is Nothing Then Return DateTime.MinValue
108+
Return _socket.ConnectedTimestamp
109+
End Get
110+
End Property
111+
112+
''' <summary>
113+
''' Gets the duration of this worker's connection
114+
''' </summary>
115+
''' <returns></returns>
116+
Public ReadOnly Property ConnectionDuration As TimeSpan
117+
Get
118+
If _socket Is Nothing Then
119+
Return New TimeSpan(0, 0, 0)
120+
End If
121+
Return _socket.ConnectionDuration
122+
End Get
123+
End Property
124+
125+
126+
127+
#End Region
128+
129+
#Region " Events"
130+
131+
Public Event Disconnected(ByRef sender As ApiClient)
132+
133+
#End Region
134+
135+
#Region " Methods"
136+
137+
''' <summary>
138+
''' Issues immediate disconnection of the underlying socket
139+
''' and signals client disconnection
140+
''' </summary>
141+
Public Sub Disconnect()
142+
143+
_socket.Disconnect()
144+
If DisconnectedEvent IsNot Nothing Then RaiseEvent Disconnected(Me)
145+
146+
End Sub
147+
148+
''' <summary>
149+
''' Handles the incoming message
150+
''' </summary>
151+
''' <param name="message">A Json object string</param>
152+
Private Sub ProcessMessage(message As String)
153+
154+
' Out message received
155+
If _settings.LogVerbosity >= 9 Then Logger.Log(9, "<< " & message, _context)
156+
157+
Dim jReq As JsonObject = Nothing
158+
Dim jRes As JsonObject = New JsonObject
159+
Dim msgId As Integer = 0
160+
Dim msgMethod As String = String.Empty
161+
162+
jRes("id") = Nothing
163+
jRes("jsonrpc") = "2.0"
164+
165+
166+
Try
167+
168+
jReq = JsonValue.Parse(message)
169+
With jReq
170+
If .ContainsKey("id") Then .TryGetValue("id", msgId)
171+
If .ContainsKey("method") Then .TryGetValue("method", msgMethod)
172+
If Not .ContainsKey("jsonrpc") Then Throw New Exception("Missing jsonrpc member")
173+
If Not .Item("jsonrpc") = "2.0" Then Throw New Exception("Invalid jsonrpc value")
174+
End With
175+
176+
Catch ex As Exception
177+
178+
' Invalid format of json
179+
Logger.Log(0, String.Format("Json parse failed from api client {1} : {0}", ex.GetBaseException.Message, Id), _context)
180+
jRes("error") = New JsonObject From {
181+
New KeyValuePair(Of String, JsonValue)("code", -32700),
182+
New KeyValuePair(Of String, JsonValue)("message", ex.GetBaseException.Message)
183+
}
184+
_socket.Send(jRes.ToString)
185+
186+
Return
187+
188+
End Try
189+
190+
' Apply message id
191+
' as we respond with the same
192+
jRes("id") = msgId
193+
194+
195+
' Handle message
196+
Select Case True
197+
198+
Case msgMethod = "ping"
199+
200+
' Reply to proxy check of liveness
201+
jRes("result") = "pong"
202+
_socket.Send(jRes.ToString)
203+
204+
Case msgMethod = "quit"
205+
206+
' Close the underlying connection
207+
jRes("result") = True
208+
_socket.Send(jRes.ToString)
209+
210+
Call Disconnect()
211+
212+
Case msgMethod = "workers.getlist"
213+
214+
' Retrieve a list of connected miners
215+
Dim jArr As Json.JsonArray = New Json.JsonArray
216+
Dim cList As List(Of Clients.Client) = _clntmgr.Clients.ToList()
217+
If cList.Count > 0 Then
218+
219+
' Sort workers by name
220+
cList.Sort(Function(x As Clients.Client, y As Clients.Client)
221+
Return x.WorkerOrId.CompareTo(y.WorkerOrId)
222+
End Function)
223+
Dim i As Integer = 0
224+
225+
For Each c As Clients.Client In cList.OrderBy(Function(s) s.WorkerOrId)
226+
i += 1
227+
Dim jItem As New JsonObject From {
228+
New KeyValuePair(Of String, JsonValue)("index", i),
229+
New KeyValuePair(Of String, JsonValue)("connected", c.IsConnected),
230+
New KeyValuePair(Of String, JsonValue)("runtime", c.ConnectionDuration.TotalSeconds()),
231+
New KeyValuePair(Of String, JsonValue)("worker", c.WorkerOrId),
232+
New KeyValuePair(Of String, JsonValue)("hashrate", c.HashRate),
233+
New KeyValuePair(Of String, JsonValue)("submitted", c.SolutionsSubmitted),
234+
New KeyValuePair(Of String, JsonValue)("stales", c.KnownStaleSolutions),
235+
New KeyValuePair(Of String, JsonValue)("accepted", c.SolutionsAccepted),
236+
New KeyValuePair(Of String, JsonValue)("rejected", c.SolutionsRejected),
237+
New KeyValuePair(Of String, JsonValue)("lastsubmit", c.LastSubmittedTimestamp.ToString())}
238+
jArr.Add(jItem)
239+
240+
Next
241+
242+
jRes("result")("count") = i
243+
244+
245+
Else
246+
247+
jRes("result")("count") = 0
248+
249+
End If
250+
251+
jRes("result")("workers") = jArr
252+
_socket.Send(jRes.ToString)
253+
254+
Case Else
255+
256+
' Any other not implemented (yet ?)
257+
jRes("error") = New JsonObject From {
258+
New KeyValuePair(Of String, JsonValue)("code", -32700),
259+
New KeyValuePair(Of String, JsonValue)("message", "Method Not implement or Not available")
260+
}
261+
_socket.Send(jRes.ToString)
262+
Logger.Log(0, String.Format("Client {0} sent invalid method {1}", Id, msgMethod), _context)
263+
264+
End Select
265+
266+
267+
End Sub
268+
269+
''' <summary>
270+
''' Sends the specified message through the underlying socket
271+
''' </summary>
272+
''' <param name="message"></param>
273+
Public Sub Send(ByVal message As String)
274+
275+
_socket.Send(message)
276+
277+
End Sub
278+
279+
280+
281+
#End Region
282+
283+
#Region " Async Socket Event Handlers"
284+
285+
Private Sub OnSocketConnected(ByRef sender As AsyncSocket) Handles _socket.Connected
286+
Logger.Log(3, String.Format("New API connection from {0}", sender.RemoteEndPoint.ToString()), _context)
287+
End Sub
288+
289+
Private Sub OnSocketDisconnected(ByRef sender As AsyncSocket) Handles _socket.Disconnected
290+
291+
Disconnect()
292+
293+
End Sub
294+
295+
Private Sub OnSocketMessageReceived(ByRef sender As AsyncSocket, ByVal message As String) Handles _socket.MessageReceived
296+
297+
' Queue the message processing
298+
ProcessMessage(message)
299+
300+
End Sub
301+
302+
#End Region
303+
304+
End Class
305+
306+
End Namespace

0 commit comments

Comments
 (0)