예제 #1
0
        public static async Task <int> MainAsync()
        {
            Logger.LogInformation($"Starting DirectMethodCloudSender with the following settings:\r\n{Settings.Current}");

            try
            {
                string serviceClientConnectionString = Settings.Current.ServiceClientConnectionString;
                Uri    analyzerUrl = Settings.Current.AnalyzerUrl;

                ServiceClient  serviceClient  = ServiceClient.CreateFromConnectionString(serviceClientConnectionString, (TransportType)Settings.Current.TransportType);
                AnalyzerClient analyzerClient = new AnalyzerClient {
                    BaseUrl = analyzerUrl.AbsoluteUri
                };

                (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Logger);

                await CallDirectMethodFromCloud(serviceClient, Settings.Current.DirectMethodDelay, analyzerClient, cts);

                completed.Set();
                handler.ForEach(h => GC.KeepAlive(h));
                Logger.LogInformation("DirectMethodCloudSender Main() finished.");
            }
            catch (Exception ex)
            {
                Logger.LogError($"Error occurred during direct method cloud sender test setup.\r\n{ex}");
            }

            return(0);
        }
예제 #2
0
        static async Task <int> MainAsync()
        {
            Logger.LogInformation("DirectMethodCloudSender Main() started.");

            IConfiguration configuration = new ConfigurationBuilder()
                                           .SetBasePath(Directory.GetCurrentDirectory())
                                           .AddJsonFile("config/appsettings.json", optional: true)
                                           .AddEnvironmentVariables()
                                           .Build();

            string serviceClientConnectionString = Preconditions.CheckNonWhiteSpace(configuration.GetValue <string>("ServiceClientConnectionString"), nameof(serviceClientConnectionString));
            // Get device id of this device, exposed as a system variable by the iot edge runtime
            string   targetDeviceId = configuration.GetValue <string>("IOTEDGE_DEVICEID");
            string   targetModuleId = configuration.GetValue("TargetModuleId", "DirectMethodReceiver");
            TimeSpan dmDelay        = configuration.GetValue("DirectMethodDelay", TimeSpan.FromSeconds(5));
            Uri      analyzerUrl    = configuration.GetValue("AnalyzerUrl", new Uri("http://analyzer:15000"));

            AnalyzerClient analyzerClient = new AnalyzerClient {
                BaseUrl = analyzerUrl.AbsoluteUri
            };

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Logger);

            await CallDirectMethodFromCloud(serviceClientConnectionString, targetDeviceId, targetModuleId, dmDelay, analyzerClient, cts);

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            Logger.LogInformation("DirectMethodCloudSender Main() finished.");
            return(0);
        }
예제 #3
0
 public ReportedPropertyOperation(RegistryManager registryManager, ModuleClient moduleClient, AnalyzerClient analyzerClient, TwinEventStorage storage, TwinState twinState)
 {
     this.registryManager = registryManager;
     this.moduleClient    = moduleClient;
     this.analyzerClient  = analyzerClient;
     this.storage         = storage;
     this.twinState       = twinState;
 }
예제 #4
0
 public DesiredPropertyOperation(RegistryManager registryManager, ModuleClient moduleClient, AnalyzerClient analyzerClient, TwinEventStorage storage, TwinState twinState)
 {
     this.registryManager = registryManager;
     this.moduleClient    = moduleClient;
     this.analyzerClient  = analyzerClient;
     this.storage         = storage;
     this.twinState       = twinState;
     this.moduleClient.SetDesiredPropertyUpdateCallbackAsync(this.OnDesiredPropertyUpdateAsync, storage);
 }
예제 #5
0
 public TwinAllOperationsResultHandler(Uri analyzerClientUri, TwinEventStorage storage, string moduleId)
 {
     this.analyzerClient = new AnalyzerClient()
     {
         BaseUrl = analyzerClientUri.AbsoluteUri
     };
     this.moduleId = moduleId;
     this.storage  = storage;
 }
예제 #6
0
 static async Task ReportStatus(string moduleId, HttpStatusCode result, AnalyzerClient analyzerClient)
 {
     try
     {
         await analyzerClient.ReportResultAsync(new TestOperationResult { Source = moduleId, Result = result.ToString(), CreatedAt = DateTime.UtcNow, Type = Enum.GetName(typeof(TestOperationResultType), TestOperationResultType.LegacyDirectMethod) });
     }
     catch (Exception e)
     {
         Logger.LogError(e.ToString());
     }
 }
예제 #7
0
 static async Task ReportStatus(string moduleId, MethodResponse response, AnalyzerClient analyzerClient)
 {
     try
     {
         await analyzerClient.ReportResultAsync(new TestOperationResult { Source = moduleId, Result = response.Status.ToString(), CreatedAt = DateTime.UtcNow, Type = "LegacyDirectMethod" });
     }
     catch (Exception e)
     {
         Logger.LogError(e.ToString());
     }
 }
예제 #8
0
 protected async Task CallAnalyzerToReportStatusAsync(AnalyzerClient analyzerClient, string moduleId, string status)
 {
     try
     {
         await analyzerClient.AddTwinStatusAsync(new ResponseStatus { ModuleId = moduleId, StatusCode = status, EnqueuedDateTime = DateTime.UtcNow });
     }
     catch (Exception e)
     {
         this.Logger.LogError($"Failed call to report status to analyzer: {e}");
     }
 }
예제 #9
0
 protected async Task CallAnalyzerToReportStatusAsync(AnalyzerClient analyzerClient, string moduleId, string status)
 {
     try
     {
         await analyzerClient.ReportResultAsync(new TestOperationResult { Source = moduleId, Result = status, CreatedAt = DateTime.UtcNow, Type = "LegacyTwin" });
     }
     catch (Exception e)
     {
         this.Logger.LogError($"Failed call to report status to analyzer: {e}");
     }
 }
예제 #10
0
        static async Task CallDirectMethodFromCloud(
            ServiceClient serviceClient,
            TimeSpan delay,
            AnalyzerClient analyzerClient,
            CancellationTokenSource cts)
        {
            Logger.LogInformation("CallDirectMethodFromCloud started.");

            CloudToDeviceMethod cloudToDeviceMethod = new CloudToDeviceMethod("HelloWorldMethod").SetPayloadJson("{ \"Message\": \"Hello\" }");
            string deviceId          = Settings.Current.DeviceId;
            string targetModuleId    = Settings.Current.TargetModuleId;
            int    directMethodCount = 1;

            while (!cts.Token.IsCancellationRequested)
            {
                Logger.LogInformation($"Calling Direct Method from cloud on device {Settings.Current.DeviceId} targeting module [{Settings.Current.TargetModuleId}] with count {directMethodCount}.");

                try
                {
                    CloudToDeviceMethodResult result = await serviceClient.InvokeDeviceMethodAsync(deviceId, targetModuleId, cloudToDeviceMethod, CancellationToken.None);

                    string statusMessage = $"Calling Direct Method from cloud with count {directMethodCount} returned with status code {result.Status}";
                    if (result.Status == (int)HttpStatusCode.OK)
                    {
                        Logger.LogDebug(statusMessage);
                    }
                    else
                    {
                        Logger.LogError(statusMessage);
                    }

                    await ReportStatus(targetModuleId, result, analyzerClient);

                    directMethodCount++;
                }
                catch (Exception e)
                {
                    Logger.LogError($"Exception caught with count {directMethodCount}: {e}");
                }

                await Task.Delay(delay, cts.Token);
            }

            Logger.LogInformation("CallDirectMethodFromCloud finished.");
            await serviceClient.CloseAsync();
        }
예제 #11
0
        static async Task CallDirectMethod(
            ModuleClient moduleClient,
            AnalyzerClient analyzerClient,
            TimeSpan delay,
            CancellationTokenSource cts)
        {
            var    request           = new MethodRequest("HelloWorldMethod", Encoding.UTF8.GetBytes("{ \"Message\": \"Hello\" }"));
            string deviceId          = Settings.Current.DeviceId;
            string targetModuleId    = Settings.Current.TargetModuleId;
            int    directMethodCount = 1;

            while (!cts.Token.IsCancellationRequested)
            {
                Logger.LogInformation($"Calling Direct Method on device {deviceId} targeting module {targetModuleId}.");

                try
                {
                    MethodResponse response = await moduleClient.InvokeMethodAsync(deviceId, targetModuleId, request);

                    string statusMessage = $"Calling Direct Method with count {directMethodCount} returned with status code {response.Status}";
                    if (response.Status == (int)HttpStatusCode.OK)
                    {
                        Logger.LogDebug(statusMessage);
                    }
                    else
                    {
                        Logger.LogError(statusMessage);
                    }

                    await ReportStatus(targetModuleId, response, analyzerClient);

                    directMethodCount++;
                }
                catch (Exception e)
                {
                    Logger.LogError(e, "Exception caught");
                }

                await Task.Delay(delay, cts.Token);
            }
        }
예제 #12
0
        static async Task Main()
        {
            Logger.LogInformation($"Starting twin tester with the following settings:\r\n{Settings.Current}");

            try
            {
                RegistryManager registryManager = RegistryManager.CreateFromConnectionString(Settings.Current.ServiceClientConnectionString);

                ModuleClient moduleClient = await ModuleUtil.CreateModuleClientAsync(
                    Settings.Current.TransportType,
                    ModuleUtil.DefaultTimeoutErrorDetectionStrategy,
                    ModuleUtil.DefaultTransientRetryStrategy,
                    Logger);

                await moduleClient.OpenAsync();

                AnalyzerClient analyzerClient = new AnalyzerClient {
                    BaseUrl = Settings.Current.AnalyzerUrl.AbsoluteUri
                };

                TwinEventStorage storage = new TwinEventStorage();
                storage.Init(Settings.Current.StoragePath, new SystemEnvironment(), Settings.Current.StorageOptimizeForPerformance);

                TwinOperator twinOperator = await TwinOperator.CreateAsync(registryManager, moduleClient, analyzerClient, storage);

                twinOperator.Start();

                (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Logger);
                await cts.Token.WhenCanceled();

                completed.Set();
                handler.ForEach(h => GC.KeepAlive(h));
                Logger.LogInformation("TwinTester exiting.");
            }
            catch (Exception ex)
            {
                Logger.LogError($"Error occurred during twin test setup.\r\n{ex}");
            }
        }
예제 #13
0
        public static async Task <int> MainAsync()
        {
            Logger.LogInformation($"Starting DirectMethodSender with the following settings:\r\n{Settings.Current}");

            try
            {
                ModuleClient moduleClient = await ModuleUtil.CreateModuleClientAsync(
                    Settings.Current.TransportType,
                    ModuleUtil.DefaultTimeoutErrorDetectionStrategy,
                    ModuleUtil.DefaultTransientRetryStrategy,
                    Logger);

                Uri            analyzerUrl    = Settings.Current.AnalyzerUrl;
                AnalyzerClient analyzerClient = new AnalyzerClient {
                    BaseUrl = analyzerUrl.AbsoluteUri
                };

                (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Logger);

                await CallDirectMethod(moduleClient, analyzerClient, Settings.Current.DirectMethodDelay, cts);

                await moduleClient.CloseAsync();

                await cts.Token.WhenCanceled();

                completed.Set();
                handler.ForEach(h => GC.KeepAlive(h));
                Logger.LogInformation("DirectMethodSender Main() finished.");
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Error occurred during direct method sender test setup");
            }

            return(0);
        }
예제 #14
0
 static async Task CallAnalyzerToReportStatusAsync(string moduleId, CloudToDeviceMethodResult result, AnalyzerClient analyzerClient)
 {
     try
     {
         await analyzerClient.AddDirectMethodStatusAsync(new ResponseStatus { ModuleId = moduleId, StatusCode = result.Status.ToString(), EnqueuedDateTime = DateTime.UtcNow });
     }
     catch (Exception e)
     {
         Logger.LogError($"Failed call to report status to analyzer: {e}");
     }
 }
예제 #15
0
        public static async Task <TwinOperator> CreateAsync(RegistryManager registryManager, ModuleClient moduleClient, AnalyzerClient analyzerClient, TwinEventStorage storage)
        {
            try
            {
                TwinState initializedState;
                Twin      twin = await registryManager.GetTwinAsync(Settings.Current.DeviceId, Settings.Current.ModuleId);

                Dictionary <string, DateTime> reportedPropertyUpdates = await storage.GetAllReportedPropertiesUpdatedAsync();

                Dictionary <string, DateTime> desiredPropertyUpdates = await storage.GetAllDesiredPropertiesUpdatedAsync();

                if (reportedPropertyUpdates.Count == 0 &&
                    desiredPropertyUpdates.Count == 0 &&
                    (await storage.GetAllDesiredPropertiesReceivedAsync()).Count == 0)
                {
                    Logger.LogInformation("No existing storage detected. Initializing new module twin for fresh run.");

                    // reset desired properties
                    Twin desiredPropertyResetTwin = await registryManager.ReplaceTwinAsync(Settings.Current.DeviceId, Settings.Current.ModuleId, new Twin(), twin.ETag);

                    // reset reported properties
                    TwinCollection eraseReportedProperties = GetReportedPropertiesResetTwin(desiredPropertyResetTwin);
                    await moduleClient.UpdateReportedPropertiesAsync(eraseReportedProperties);

                    await Task.Delay(TimeSpan.FromSeconds(10)); // give enough time for reported properties reset to reach cloud

                    twin = await registryManager.GetTwinAsync(Settings.Current.DeviceId, Settings.Current.ModuleId);

                    initializedState = new TwinState {
                        ReportedPropertyUpdateCounter = 0, DesiredPropertyUpdateCounter = 0, TwinETag = twin.ETag, LastTimeOffline = DateTime.MinValue
                    };
                }
                else
                {
                    Logger.LogInformation("Existing storage detected. Initializing reported / desired property update counters.");
                    initializedState = new TwinState {
                        ReportedPropertyUpdateCounter = GetNewPropertyCounter(reportedPropertyUpdates), DesiredPropertyUpdateCounter = GetNewPropertyCounter(desiredPropertyUpdates), TwinETag = twin.ETag, LastTimeOffline = DateTime.MinValue
                    };
                }

                Logger.LogInformation($"Start state of module twin: {JsonConvert.SerializeObject(twin, Formatting.Indented)}");
                return(new TwinOperator(registryManager, moduleClient, analyzerClient, storage, initializedState));
            }
            catch (Exception e)
            {
                throw new Exception($"Shutting down module. Initialization failure: {e}");
            }
        }
예제 #16
0
        static async Task CallDirectMethodFromCloud(
            string serviceClientConnectionString,
            string deviceId,
            string moduleId,
            TimeSpan delay,
            AnalyzerClient analyzerClient,
            CancellationTokenSource cts)
        {
            Logger.LogInformation("CallDirectMethodFromCloud started.");
            ServiceClient serviceClient = null;

            try
            {
                int count = 1;

                IotHubConnectionStringBuilder iotHubConnectionStringBuilder = IotHubConnectionStringBuilder.Create(serviceClientConnectionString);
                Logger.LogInformation($"Prepare to call Direct Method from cloud ({iotHubConnectionStringBuilder.IotHubName}) on device [{deviceId}] module [{moduleId}]");

                serviceClient = ServiceClient.CreateFromConnectionString(serviceClientConnectionString, Microsoft.Azure.Devices.TransportType.Amqp);
                var cloudToDeviceMethod = new CloudToDeviceMethod("HelloWorldMethod").SetPayloadJson("{ \"Message\": \"Hello\" }");

                while (!cts.Token.IsCancellationRequested)
                {
                    Logger.LogInformation($"Calling Direct Method from cloud ({iotHubConnectionStringBuilder.IotHubName}) on device [{deviceId}] module [{moduleId}] of count {count}.");

                    try
                    {
                        CloudToDeviceMethodResult result = await serviceClient.InvokeDeviceMethodAsync(deviceId, moduleId, cloudToDeviceMethod, CancellationToken.None);

                        if (result.Status == (int)HttpStatusCode.OK)
                        {
                            Logger.LogDebug($"Calling Direct Method from cloud with count {count} returned with status code {result.Status}.");
                        }
                        else
                        {
                            Logger.LogError($"Calling Direct Method from cloud with count {count} failed with status code {result.Status}.");
                        }

                        await CallAnalyzerToReportStatusAsync(moduleId, result, analyzerClient);

                        count++;
                    }
                    catch (Exception e)
                    {
                        Logger.LogError($"Exception caught with count {count}: {e}");
                    }

                    await Task.Delay(delay, cts.Token);
                }
            }
            catch (Exception e)
            {
                Logger.LogError($"Exception caught: {e}");
                throw;
            }
            finally
            {
                Logger.LogInformation("Close connection for service client and module client");
                if (serviceClient != null)
                {
                    await serviceClient.CloseAsync();
                }
            }

            Logger.LogInformation("CallDirectMethodFromCloud finished.");
        }
예제 #17
0
 static async Task ReportStatus(string moduleId, CloudToDeviceMethodResult result, AnalyzerClient analyzerClient)
 {
     try
     {
         await analyzerClient.ReportResultAsync(new TestOperationResult { Source = moduleId, Result = result.Status.ToString(), CreatedAt = DateTime.UtcNow, Type = "LegacyDirectMethod" });
     }
     catch (Exception e)
     {
         Logger.LogError(e, "Failed call to report status to analyzer");
     }
 }
예제 #18
0
        public static async Task <int> MainAsync()
        {
            Logger.LogInformation($"Starting DirectMethodSender with the following settings:\r\n{Settings.Current}");

            (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Logger);
            DirectMethodSenderBase directMethodClient       = null;
            ModuleClient           reportClient             = null;
            Option <Uri>           analyzerUrl              = Settings.Current.AnalyzerUrl;
            Option <Uri>           testReportCoordinatorUrl = Settings.Current.TestResultCoordinatorUrl;

            try
            {
                Guid batchId = Guid.NewGuid();
                Logger.LogInformation($"Batch Id={batchId}");

                directMethodClient = await CreateClientAsync(Settings.Current.InvocationSource);

                reportClient = await ModuleUtil.CreateModuleClientAsync(
                    Settings.Current.TransportType,
                    ModuleUtil.DefaultTimeoutErrorDetectionStrategy,
                    ModuleUtil.DefaultTransientRetryStrategy,
                    Logger);

                Logger.LogInformation($"Load gen delay start for {Settings.Current.TestStartDelay}.");
                await Task.Delay(Settings.Current.TestStartDelay, cts.Token);

                DateTime testStartAt = DateTime.UtcNow;
                while (!cts.Token.IsCancellationRequested && IsTestTimeUp(testStartAt))
                {
                    (HttpStatusCode result, long dmCounter) = await directMethodClient.InvokeDirectMethodAsync(cts);

                    // TODO: Create an abstract class to handle the reporting client generation
                    if (testReportCoordinatorUrl.HasValue)
                    {
                        await testReportCoordinatorUrl.ForEachAsync(
                            async (Uri uri) =>
                        {
                            TestResultCoordinatorClient trcClient = new TestResultCoordinatorClient {
                                BaseUrl = uri.AbsoluteUri
                            };
                            await ModuleUtil.ReportStatus(
                                trcClient,
                                Logger,
                                Settings.Current.ModuleId + ".send",
                                ModuleUtil.FormatDirectMethodTestResultValue(
                                    Settings.Current.TrackingId.Expect(() => new ArgumentException("TrackingId is empty")),
                                    batchId.ToString(),
                                    dmCounter.ToString(),
                                    result.ToString()),
                                TestOperationResultType.DirectMethod.ToString());
                        });
                    }
                    else
                    {
                        await analyzerUrl.ForEachAsync(
                            async (Uri uri) =>
                        {
                            AnalyzerClient analyzerClient = new AnalyzerClient {
                                BaseUrl = uri.AbsoluteUri
                            };
                            await ReportStatus(Settings.Current.TargetModuleId, result, analyzerClient);
                        },
                            async() =>
                        {
                            await reportClient.SendEventAsync("AnyOutput", new Message(Encoding.UTF8.GetBytes("Direct Method call succeeded.")));
                        });
                    }

                    await Task.Delay(Settings.Current.DirectMethodDelay, cts.Token);
                }

                await cts.Token.WhenCanceled();
            }
            catch (Exception e)
            {
                Logger.LogError(e, "Error occurred during direct method sender test setup");
            }
            finally
            {
                // Implicit CloseAsync()
                directMethodClient?.Dispose();
                reportClient?.Dispose();
            }

            completed.Set();
            handler.ForEach(h => GC.KeepAlive(h));
            Logger.LogInformation("DirectMethodSender Main() finished.");
            return(0);
        }
예제 #19
0
 private TwinOperator(RegistryManager registryManager, ModuleClient moduleClient, AnalyzerClient analyzerClient, TwinEventStorage storage, TwinState twinState)
 {
     this.reportedPropertyOperation = new ReportedPropertyOperation(registryManager, moduleClient, analyzerClient, storage, twinState);
     this.desiredPropertyOperation  = new DesiredPropertyOperation(registryManager, moduleClient, analyzerClient, storage, twinState);
 }