Work on notifications support
authorCryptoManiac <balthazar@yandex.ru>
Tue, 4 Aug 2015 19:18:03 +0000 (22:18 +0300)
committerCryptoManiac <balthazar@yandex.ru>
Tue, 4 Aug 2015 19:18:03 +0000 (22:18 +0300)
StratumLibrary/Stratum.cs

index 56520ed..20b05c4 100644 (file)
@@ -1,16 +1,19 @@
 \feffusing System;\r
 using System.Net;\r
+using System.Threading;\r
+using System.Net.Sockets;\r
 using Newtonsoft.Json.Linq;\r
 \r
 using System.Text;\r
-using System.Threading;\r
-using System.Net.Sockets;\r
+using System.Collections.Generic;\r
 \r
 namespace Stratum\r
 {\r
     public class Stratum\r
     {\r
         private Socket client;\r
+        private Dictionary<string, string> responses = new Dictionary<string, string>();\r
+        ManualResetEvent gotResponse = new ManualResetEvent(false);\r
 \r
         /// <summary>\r
         /// Constructor of Stratum interface class\r
@@ -32,10 +35,10 @@ namespace Stratum
             ConnectCallback = (IAsyncResult ar) =>\r
             {\r
                 // Retrieve socket from the state object\r
-                Socket cli = (Socket)ar.AsyncState;\r
+                Socket arClient = (Socket)ar.AsyncState;\r
 \r
                 // Complete the connection\r
-                cli.EndConnect(ar);\r
+                arClient.EndConnect(ar);\r
 \r
                 // Signal that connection has been established\r
                 connectDone.Set();\r
@@ -46,6 +49,9 @@ namespace Stratum
 \r
             // Wait for signal\r
             connectDone.WaitOne();\r
+\r
+            // Start receive handler\r
+            Receiver(client);\r
         }\r
 \r
         ~Stratum()\r
@@ -64,10 +70,10 @@ namespace Stratum
             SendCallback = (IAsyncResult ar) =>\r
             {\r
                 // Retrieve the socket from the state object\r
-                Socket cli = (Socket)ar.AsyncState;\r
+                Socket arClient = (Socket)ar.AsyncState;\r
 \r
                 // Complete sending the data to the remote device\r
-                int bytesSent = cli.EndSend(ar);\r
+                int bytesSent = arClient.EndSend(ar);\r
 \r
                 // Signal that all bytes have been sent\r
                 sendDone.Set();\r
@@ -119,75 +125,98 @@ namespace Stratum
 \r
         private StratumResponse<T> Invoke<T>(StratumRequest stratumReq)\r
         {\r
-            StratumResponse<T> rjson = null;\r
-\r
             // Serialize stratumReq into JSON string\r
             var reqJSON = Newtonsoft.Json.JsonConvert.SerializeObject(stratumReq) + '\n';\r
+            var reqId = (string) stratumReq.Id;\r
 \r
             // Send JSON data to the remote device.\r
             Send(client, reqJSON);\r
 \r
+            // Wait for response\r
+            gotResponse.WaitOne();\r
+\r
+            // Deserialize the response\r
+            string strResponse = responses[reqId];\r
+            StratumResponse<T> responseObj = Newtonsoft.Json.JsonConvert.DeserializeObject<StratumResponse<T>>(strResponse);\r
+            responses.Remove(reqId);\r
+\r
+            // Reset the state\r
+            gotResponse.Reset();\r
+\r
+            if (object.ReferenceEquals(null, responseObj))\r
+            {\r
+                try\r
+                {\r
+                    JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(strResponse) as JObject;\r
+                    throw new Exception(jo["Error"].ToString());\r
+                }\r
+                catch (Newtonsoft.Json.JsonSerializationException)\r
+                {\r
+                    throw new Exception("Inconsistent or empty response");\r
+                }\r
+            }\r
+\r
+            return responseObj;\r
+        }\r
+\r
+        private void Receiver(Socket client)\r
+        {\r
             // Create the reading state object.\r
             StratumReadState state = new StratumReadState(client);\r
 \r
-            // Receive event\r
-            ManualResetEvent receiveDone = new ManualResetEvent(false);\r
-\r
             Action<IAsyncResult> ReceiveCallback = null;\r
             ReceiveCallback = (IAsyncResult ar) =>\r
             {\r
                 // Retrieve the state object and the client socket \r
                 // from the asynchronous state object.\r
-                StratumReadState st = (StratumReadState)ar.AsyncState;\r
-                Socket ci = st.workSocket;\r
+                StratumReadState arStatus = (StratumReadState)ar.AsyncState;\r
+                Socket arClient = arStatus.workSocket;\r
 \r
                 // Read data from the remote device.\r
-                int bytesRead = ci.EndReceive(ar);\r
+                int bytesRead = arClient.EndReceive(ar);\r
 \r
                 if (bytesRead <= 0)\r
                     return;\r
 \r
-                lock (st.sb)\r
+                lock (arStatus.sb)\r
                 {\r
                     // There might be more data, so store the data received so far.\r
-                    st.sb.Append(Encoding.ASCII.GetString(st.buffer, 0, bytesRead));\r
+                    arStatus.sb.Append(Encoding.ASCII.GetString(arStatus.buffer, 0, bytesRead));\r
 \r
-                    if (st.buffer[bytesRead - 1] != '\n')\r
+                    if (arStatus.buffer[bytesRead - 1] == '\n')\r
                     {\r
-                        //  No EOL at the end of buffer, going to get the rest of data\r
-                        ci.BeginReceive(st.buffer, 0, StratumReadState.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), st);\r
-                    }\r
-                    else\r
-                    {\r
-                        string strResponse = st.sb.ToString();\r
+                        string strMessage = arStatus.sb.ToString();\r
+                        arStatus.sb.Clear();\r
 \r
-                        // Deserialize the response\r
-                        rjson = Newtonsoft.Json.JsonConvert.DeserializeObject<StratumResponse<T>>(strResponse);\r
-\r
-                        if (rjson == null)\r
+                        try\r
                         {\r
-                            try\r
+                            JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(strMessage) as JObject;\r
+                            string requestId = (string)jo["id"];\r
+\r
+                            if (!String.IsNullOrEmpty(requestId))\r
                             {\r
-                                JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(strResponse) as JObject;\r
-                                throw new Exception(jo["Error"].ToString());\r
+                                responses.Add(requestId, strMessage);\r
+\r
+                                gotResponse.Set();\r
                             }\r
-                            catch (Newtonsoft.Json.JsonSerializationException)\r
+                            else\r
                             {\r
-                                throw new Exception("Inconsistent or empty response");\r
+                                // TODO: notifications handling\r
+                                Console.WriteLine("Notification: {0}", strMessage);\r
                             }\r
                         }\r
-\r
-                        // Signal that all bytes have been received.\r
-                        receiveDone.Set();\r
+                        catch (Newtonsoft.Json.JsonSerializationException e)\r
+                        {\r
+                            // TODO: handle parse error\r
+                        }\r
                     }\r
                 }\r
+\r
+                arClient.BeginReceive(arStatus.buffer, 0, StratumReadState.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), arStatus);\r
             };\r
 \r
-            // Begin receiving the data from the remote device.\r
             client.BeginReceive(state.buffer, 0, StratumReadState.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);\r
-            receiveDone.WaitOne();\r
-\r
-            return rjson;\r
         }\r
     }\r
+\r
 }
\ No newline at end of file