public NesSystem() { Router = new DeviceRouter("Router"); _cpu6502Device = new Cpu6502Device("Cpu", Router); Router.Install(new RamDevice("Ram", 0x800, 0x2000, 0x0000, 0x7FF)); Router.Install(new GamepadsDevice("Gamepads")); Router.Install(new ApuDevice("Apu")); Router.Install(new PpuDevice("Ppu", Router)); Router.Install(_cpu6502Device); Reset(); }
private async Task ProcessMessage(EventData eventData, long partitionKey, RbTraceLog rbTraceLog) { // Receive a message and system properties string iothub_deviceId = (string)eventData.SystemProperties["iothub-connection-device-id"]; DateTime iothub_enqueuedTimeUtc = (DateTime)eventData.SystemProperties.EnqueuedTimeUtc; string text_message = Encoding.UTF8.GetString(eventData.Body.Array); // RbTrace (Table Storage) if (rbTraceLevel == RbTraceType.Detail) { rbTraceLog.WriteLog($"Received a message. Partition({partitionKey}), DeviceId({iothub_deviceId}), Message:{text_message}"); } // Loop of retry for reconfiguration on SQL Database int loopCounter = 0; while (true) { JObject jo_message = null; // Routing switch bool devRouting = false; bool appRouting = false; try { // Check RbHeader if (text_message.IndexOf(RbFormatType.RbHeader) < 0) { rbTraceLog.WriteLog(RbExceptionMessage.RbHeaderNotFound + $" Partition({partitionKey}), DeviceId({iothub_deviceId}), Message:{text_message}"); return; } // Check RbHeader simplly jo_message = JsonConvert.DeserializeObject <JObject>(text_message); var jo_rbh = (JObject)jo_message[RbFormatType.RbHeader]; var v_rbhRoutingType = jo_rbh[RbHeaderElement.RoutingType]; if (v_rbhRoutingType == null) { rbTraceLog.WriteError("W001", "** Message skipped because RoutingType is null **", jo_message); return; } string s_rbhRoutingType = (string)v_rbhRoutingType; if (s_rbhRoutingType == RbRoutingType.LOG || s_rbhRoutingType == string.Empty) { // RoutingType == LOG -> only using IoT Hub with Stream Analytics return; } // Check RbHeader in detail RbHeaderBuilder hdBuilder = new RbHeaderBuilder(jo_message, iothub_deviceId); RbHeader rbh = null; try { rbh = hdBuilder.ValidateJsonSchema(); } catch (Exception ex) { rbTraceLog.WriteError("W002", "** Message skipped because of bad RbHeader **", ex); return; } // Check StorageQueueSendEnabled property in RbHeader prevStorageQueueSendEnabled = storageQueueSendEnabled; string messageStorageQueueSendEnabled = null; if (storageQueueSendEnabled != "true") { try { messageStorageQueueSendEnabled = (string)jo_rbh[typeStorageQueueSendEnabled]; } catch { messageStorageQueueSendEnabled = null; } if (messageStorageQueueSendEnabled == "true") { storageQueueSendEnabled = messageStorageQueueSendEnabled; } } // Check RoutingType (CALL, D2D, CONTROL) if (rbh.RoutingType == RbRoutingType.CALL || rbh.RoutingType == RbRoutingType.CALL_ASYNC) { appRouting = true; } else if (rbh.RoutingType == RbRoutingType.D2D) { devRouting = true; if (rbh.AppProcessingId != string.Empty) { appRouting = true; } } else if (rbh.RoutingType == RbRoutingType.CONTROL) { devRouting = false; appRouting = false; } else { rbTraceLog.WriteError("W003", "** Message skipped because of bad RoutingType **", jo_message); return; } // Device Router builds RbHeader DeviceRouter dr = null; if (devRouting) { dr = new DeviceRouter(rbh, sqlConnectionString); rbh = dr.GetDeviceRouting(); string new_header = JsonConvert.SerializeObject(rbh); jo_message[RbFormatType.RbHeader] = JsonConvert.DeserializeObject <JObject>(new_header); } else { rbh.TargetDeviceId = rbh.SourceDeviceId; rbh.TargetType = RbTargetType.Device; } // Application Routing JArray ja_messages = null; if (appRouting) { // Application Call Logic JObject jo_temp; string rbBodyString; try { jo_temp = (JObject)jo_message[RbFormatType.RbBody]; rbBodyString = JsonConvert.SerializeObject(jo_temp); } catch (Exception ex) { rbTraceLog.WriteError("E001", $"** RbBody is not regular JSON format ** {ex.ToString()}", jo_message); return; } try { if (rbh.RoutingType == RbRoutingType.CALL_ASYNC) { await CallAppsWithQueue(rbh, rbBodyString, partitionKey.ToString()); } else { ja_messages = await CallAppsWithHttp(rbh, rbBodyString, partitionKey.ToString()); } } catch (Exception ex) { rbTraceLog.WriteError("E002", $"** Error occured in CallApps ** {ex.ToString()}", jo_message); return; } } else { ja_messages = new JArray(); ja_messages.Add(jo_message); } // Send C2D Message if (rbh.RoutingType == RbRoutingType.CALL || rbh.RoutingType == RbRoutingType.D2D || rbh.RoutingType == RbRoutingType.CONTROL) { if (storageQueueSendEnabled == "true") { // Send C2D message to Queue storage RbC2dMessageToQueue c2dsender = null; c2dsender = new RbC2dMessageToQueue(ja_messages, storageQueueConnString, sqlConnectionString); await c2dsender.SendToDeviceAsync(); } else { // Send C2D message to IoT Hub RbC2dMessageSender c2dsender = null; c2dsender = new RbC2dMessageSender(ja_messages, iotHubConnectionString, sqlConnectionString); await c2dsender.SendToDeviceAsync(); } // StorageQueueSendEnabled property in RbHeader storageQueueSendEnabled = prevStorageQueueSendEnabled; } // Get out of retry loop because of normal completion break; } catch (Exception ex) { rbTraceLog.WriteError("E003", $"** Critical error occured ** {ex.ToString()}", jo_message); bool continueLoop = false; if (ex != null && ex is SqlException) { foreach (SqlError error in (ex as SqlException).Errors) { if (sqlErrorListForRetry.Contains(error.Number)) { continueLoop = true; break; // Exit foreach loop } } if (continueLoop) { ++loopCounter; rbTraceLog.WriteLog($"Transaction retry has started. Count({loopCounter})"); if (loopCounter > maxLoopCounter) { break; // Get out of retry loop because counter reached max number } else { Thread.Sleep(sleepInterval); } } else { break; // Get out of retry loop because of another sql error } } else { throw; } } } }
async Task IEventProcessor.ProcessEventsAsync(PartitionContext context, IEnumerable <EventData> messages) { try { #region *** Handling unexpected exceptions *** DateTime startDateTimeUtc = DateTime.UtcNow; int messagecnt = 0; bool sqlex_on = false; foreach (EventData eventData in messages) { try { // Go forward read pointer await context.CheckpointAsync(); } catch (Exception ex) { // Handling the exception of Microsoft.ServiceBus.Messaging.LeaseLostException // This exception is usually able to occur. ApplicationException ae = new ApplicationException(checkpointExMessage, ex); throw ae; } ++messagecnt; int retryCount = 0; bool devRouting = false; bool appRouting = false; bool rbHeaderNotFound = false; string sqlConnString = rbSqlConnectionString; string iothub_deviceId = (string)eventData.SystemProperties["iothub-connection-device-id"]; DateTime iothub_enqueuedTimeUtc = (DateTime)eventData.SystemProperties["EnqueuedTimeUtc"]; string text_message = string.Empty; // Retry loop logic for SQLDB reconfiguration exception while (true) { text_message = Encoding.UTF8.GetString(eventData.GetBytes()); string text_message_100 = text_message.Substring(0, 100); if (text_message_100.IndexOf(RbFormatType.RbHeader) < 0) { rbHeaderNotFound = true; RbTraceLog.WriteLog(string.Format(RbExceptionMessage.RbHeaderNotFound + " Partition:{0}, Message:{1}, DeviceId:{2}", context.Lease.PartitionId, text_message_100, iothub_deviceId)); } if (rbTraceLevel == RbTraceType.Detail) { DateTime dt = iothub_enqueuedTimeUtc; TimeSpan ts = DateTime.UtcNow - dt; RbTraceLog.WriteLog(string.Format("RoboticsEventProcessor Message received. Delayed time:{0}, Partition:{1}, DeviceId:{2}, Message:{3}", ts.ToString(), context.Lease.PartitionId, iothub_deviceId, text_message)); if (ts > new TimeSpan(0, 0, 5)) { RbTraceLog.WriteLog(string.Format("** Delayed time is over 5 seconds !! ** DelayedTime:{0}, Partition:{1}, DeviceId:{2}, Message:{3}", ts.ToString(), context.Lease.PartitionId, iothub_deviceId, text_message)); } } JObject jo_message = null; if (!rbHeaderNotFound) // Skip invalid data { try { jo_message = JsonConvert.DeserializeObject <JObject>(text_message); // Check RbHeader simplly var jo_rbh = (JObject)jo_message[RbFormatType.RbHeader]; if (jo_rbh != null) { string jo_rbh_RoutingType = (string)jo_rbh[RbHeaderElement.RoutingType]; // Check RoutingType (LOG, null) if (jo_rbh_RoutingType == null) { RbTraceLog.WriteError("W001", "** Message skipped because RoutingType is null **", jo_message); goto LoopExitLabel; } else if (jo_rbh_RoutingType == RbRoutingType.LOG) { // RoutingType == LOG -> only using IoT Hub with Stream Analytics goto LoopExitLabel; } } // Check RbHeader in detail RbHeaderBuilder hdBuilder = new RbHeaderBuilder(jo_message, iothub_deviceId); RbHeader rbh = hdBuilder.ValidateJsonSchema(); // Check RoutingType (CALL, D2D, CONTROL) if (rbh.RoutingType == RbRoutingType.CALL) { appRouting = true; } else if (rbh.RoutingType == RbRoutingType.D2D) { devRouting = true; if (rbh.AppProcessingId != string.Empty) { appRouting = true; } } else if (rbh.RoutingType == RbRoutingType.CONTROL) { devRouting = false; appRouting = false; } else { RbTraceLog.WriteError("W002", "** Message skipped because of bad RoutingType **", jo_message); goto LoopExitLabel; } // Device Router builds RbHeader DeviceRouter dr = null; if (devRouting) { dr = new DeviceRouter(rbh, sqlConnString); rbh = dr.GetDeviceRouting(); string new_header = JsonConvert.SerializeObject(rbh); jo_message[RbFormatType.RbHeader] = JsonConvert.DeserializeObject <JObject>(new_header); } else { rbh.TargetDeviceId = rbh.SourceDeviceId; rbh.TargetType = RbTargetType.Device; } // Application Routing JArray ja_messages = null; if (appRouting) { // Application Call Logic JObject jo_temp = (JObject)jo_message[RbFormatType.RbBody]; string rbBodyString = JsonConvert.SerializeObject(jo_temp); ja_messages = CallApps(rbh, rbBodyString, context.Lease.PartitionId); } else if (rbh.RoutingType != RbRoutingType.CONTROL) { ja_messages = new JArray(); ja_messages.Add(jo_message); } // RoutingType="CONTROL" and AppProcessingId="ReqAppInfo" if (rbh.RoutingType == RbRoutingType.CONTROL) { if (rbh.AppProcessingId == null) { RbTraceLog.WriteError("W003", "** Message skipped because AppProcessingId is null when CONTROL RoutingType **", jo_message); goto LoopExitLabel; } else if (rbh.AppProcessingId == RbControlType.ReqAppInfo) { ja_messages = ProcessControlMessage(rbh); } else { RbTraceLog.WriteError("W004", "** Message skipped because of bad AppProcessingId when CONTROL RoutingType **", jo_message); goto LoopExitLabel; } } // Send C2D Message if (rbh.RoutingType == RbRoutingType.CALL || rbh.RoutingType == RbRoutingType.D2D || rbh.RoutingType == RbRoutingType.CONTROL) { if (rbStorageQueueSendEnabled) { // Send C2D message to Queue storage RbC2dMessageToQueue c2dsender = null; c2dsender = new RbC2dMessageToQueue(ja_messages, rbStorageQueueConnString, sqlConnString); c2dsender.SendToDevice(); } else { // Send C2D message to IoT Hub RbC2dMessageSender c2dsender = null; c2dsender = new RbC2dMessageSender(ja_messages, rbIotHubConnString, sqlConnString); c2dsender.SendToDevice(); } } // C2D Message Logging to Event Hub if (rbC2dLogEnabled) { RbEventHubs rbEventHubs = new RbEventHubs(rbC2dLogEventHubConnString, rbC2dLogEventHubName); foreach (JObject jo in ja_messages) { string str_message = JsonConvert.SerializeObject(jo); rbEventHubs.SendMessage(str_message, iothub_deviceId); } } } catch (Exception ex) { sqlex_on = false; if (ex != null && ex is SqlException) // "is" matches extended type as well { foreach (SqlError error in (ex as SqlException).Errors) { if (sqlErrorListForRetry.Contains(error.Number)) { sqlex_on = true; break; // Exit foreach loop } } if (sqlex_on) { ++retryCount; if (retryCount > maxRetryCount) { sqlex_on = false; RbTraceLog.WriteError("E001", ex.ToString(), jo_message); } else { RbTraceLog.WriteLog($"Transaction retry has started. Count({retryCount})"); Thread.Sleep(sleepTime); } } else { RbTraceLog.WriteError("E001", ex.ToString(), jo_message); } } else { RbTraceLog.WriteError("E001", ex.ToString(), jo_message); } } } if (!sqlex_on) { goto LoopExitLabel; } } // Label - Loop exit LoopExitLabel :; if (rbTraceLevel == RbTraceType.Detail) { TimeSpan ts = DateTime.UtcNow - startDateTimeUtc; RbTraceLog.WriteLog(string.Format("RoboticsEventProcessor Message processed. Duration:{0}, Partition:{1}, DeviceId{2}, Message:{3}", ts.ToString(), context.Lease.PartitionId, iothub_deviceId, text_message)); } } #endregion *** Handling unexpected exceptions *** } catch (Exception ex) { if (ex.Message == checkpointExMessage) { RbTraceLog.WriteLog("** Retrying message processing because of CheckPointAsync error ** Info => " + ex.InnerException.ToString()); } else { RbTraceLog.WriteError("E999", ex.ToString()); } } }