3 using System.Threading;
\r
4 using System.Net.Sockets;
\r
5 using Newtonsoft.Json.Linq;
\r
8 using System.Collections.Generic;
\r
12 public class Stratum
\r
14 private Socket client;
\r
15 private Dictionary<string, string> responses = new Dictionary<string, string>();
\r
16 ManualResetEvent gotResponse = new ManualResetEvent(false);
\r
19 /// Constructor of Stratum interface class
\r
21 /// <param name="ipAddress">IPv4 address</param>
\r
22 /// <param name="port">Port number</param>
\r
23 public Stratum(string ipAddress, int port)
\r
25 // End point for the remote device
\r
26 IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ipAddress), port);
\r
28 // Create TCP socket
\r
29 client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
\r
31 // Connect done event
\r
32 ManualResetEvent connectDone = new ManualResetEvent(false);
\r
34 Action<IAsyncResult> ConnectCallback = null;
\r
35 ConnectCallback = (IAsyncResult ar) =>
\r
37 // Retrieve socket from the state object
\r
38 Socket arClient = (Socket)ar.AsyncState;
\r
40 // Complete the connection
\r
41 arClient.EndConnect(ar);
\r
43 // Signal that connection has been established
\r
47 // Connect to the remote device
\r
48 client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
\r
51 connectDone.WaitOne();
\r
53 // Start receive handler
\r
59 // Release the socket
\r
60 client.Shutdown(SocketShutdown.Both);
\r
64 private void Send(Socket client, String data)
\r
67 ManualResetEvent sendDone = new ManualResetEvent(false);
\r
69 Action<IAsyncResult> SendCallback = null;
\r
70 SendCallback = (IAsyncResult ar) =>
\r
72 // Retrieve the socket from the state object
\r
73 Socket arClient = (Socket)ar.AsyncState;
\r
75 // Complete sending the data to the remote device
\r
76 int bytesSent = arClient.EndSend(ar);
\r
78 // Signal that all bytes have been sent
\r
82 // Convert the string data to byte data using ASCII encoding.
\r
83 byte[] byteData = Encoding.ASCII.GetBytes(data);
\r
85 // Begin sending the data to the remote device.
\r
86 client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
\r
93 /// Invoke remote method
\r
95 /// <typeparam name="T">Return type</typeparam>
\r
96 /// <param name="method">Method name</param>
\r
97 /// <param name="arg">Argument</param>
\r
98 /// <returns>StratumResponse object</returns>
\r
99 public StratumResponse<T> Invoke<T>(string method, object arg)
\r
101 var req = new StratumRequest()
\r
104 Params = new object[] { arg }
\r
106 return Invoke<T>(req);
\r
110 /// Invoke remote method
\r
112 /// <typeparam name="T">Return type</typeparam>
\r
113 /// <param name="method">Method name</param>
\r
114 /// <param name="args">Arguments array</param>
\r
115 /// <returns>StratumResponse object</returns>
\r
116 public StratumResponse<T> Invoke<T>(string method, object[] args)
\r
118 var req = new StratumRequest()
\r
123 return Invoke<T>(req);
\r
126 private StratumResponse<T> Invoke<T>(StratumRequest stratumReq)
\r
128 // Serialize stratumReq into JSON string
\r
129 var reqJSON = Newtonsoft.Json.JsonConvert.SerializeObject(stratumReq) + '\n';
\r
130 var reqId = (string) stratumReq.Id;
\r
132 // Send JSON data to the remote device.
\r
133 Send(client, reqJSON);
\r
135 // Wait for response
\r
136 gotResponse.WaitOne();
\r
138 // Deserialize the response
\r
139 string strResponse = responses[reqId];
\r
140 StratumResponse<T> responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<StratumResponse<T>>(strResponse);
\r
141 responses.Remove(reqId);
\r
144 gotResponse.Reset();
\r
146 if (object.ReferenceEquals(null, responseObj))
\r
150 JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(strResponse) as JObject;
\r
151 throw new Exception(jo["Error"].ToString());
\r
153 catch (Newtonsoft.Json.JsonSerializationException)
\r
155 throw new Exception("Inconsistent or empty response");
\r
159 return responseObj;
\r
162 private void Receiver(Socket client)
\r
164 // Create the reading state object.
\r
165 StratumReadState state = new StratumReadState(client);
\r
167 Action<IAsyncResult> ReceiveCallback = null;
\r
168 ReceiveCallback = (IAsyncResult ar) =>
\r
170 // Retrieve the state object and the client socket
\r
171 // from the asynchronous state object.
\r
172 StratumReadState arStatus = (StratumReadState)ar.AsyncState;
\r
173 Socket arClient = arStatus.workSocket;
\r
175 // Read data from the remote device.
\r
176 int bytesRead = arClient.EndReceive(ar);
\r
178 if (bytesRead <= 0)
\r
183 // There might be more data, so store the data received so far.
\r
184 arStatus.sb.Append(Encoding.ASCII.GetString(arStatus.buffer, 0, bytesRead));
\r
186 if (arStatus.buffer[bytesRead - 1] == '\n')
\r
188 string strMessage = arStatus.sb.ToString();
\r
189 arStatus.sb.Clear();
\r
193 JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(strMessage) as JObject;
\r
194 string requestId = (string)jo["id"];
\r
196 if (!String.IsNullOrEmpty(requestId))
\r
198 responses.Add(requestId, strMessage);
\r
204 // TODO: notifications handling
\r
205 Console.WriteLine("Notification: {0}", strMessage);
\r
208 catch (Newtonsoft.Json.JsonSerializationException e)
\r
210 // TODO: handle parse error
\r
215 arClient.BeginReceive(arStatus.buffer, 0, StratumReadState.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), arStatus);
\r
218 client.BeginReceive(state.buffer, 0, StratumReadState.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
\r