public virtual async Task <Status> BootInfrastructure([ActivityTrigger] StateActionContext stateCtxt, ILogger log,
                                                              [SignalR(HubName = UserManagementState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                              [Blob("state-api/{stateCtxt.StateDetails.EnterpriseAPIKey}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            return(await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                               stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Configuring Project Infrastructure...");

                var status = await harness.BootDAFInfrastructure(devOpsArch, stateCtxt.StateDetails.EnterpriseAPIKey, stateCtxt.StateDetails.Username);

                if (status)
                {
                    harness.UpdateBootOption("Infrastructure", status: Status.Initialized.Clone("Committing Environment Infrastructure as Code..."));
                }
                else
                {
                    harness.UpdateBootOption("Infrastructure", status: Status.GeneralError.Clone("Error Configuring Project Infrastructure, retrying."));
                }

                harness.UpdateStatus(status);

                return status;
            }));
        }
        public virtual async Task <Status> CanFinalize([ActivityTrigger] StateActionContext stateCtxt, ILogger log,
                                                       [SignalR(HubName = UserManagementState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                       [Blob("state-api/{stateCtxt.StateDetails.EnterpriseAPIKey}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            return(await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                               stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Checking if build and release are complete...");

                var canFinalize = await harness.CanFinalize(entMgr, stateCtxt.StateDetails.EnterpriseAPIKey, stateCtxt.StateDetails.Username);

                if (!canFinalize)
                {
                    var infraStatus = canFinalize;    //.Clone("Waiting for infrastructure deployment to finish...");

                    infraStatus.Code = Status.Initialized.Code;

                    harness.UpdateBootOption("Infrastructure", status: infraStatus);
                }
                else
                {
                    harness.UpdateBootOption("Infrastructure", status: canFinalize.Clone("Infrastructure Configured and Deployed"), loading: false);

                    harness.UpdateBootOption("Domain", status: Status.Initialized.Clone("Configuring Domain Security..."));
                }

                return canFinalize;
            }));
        }
        public virtual async Task <Status> UpdateStatus([ActivityTrigger] StateActionContext stateCtxt, ILogger log,
                                                        [SignalR(HubName = UserManagementState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                        [Blob("state-api/{stateCtxt.StateDetails.EnterpriseAPIKey}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            return(await stateBlob.WithStateHarness <UserManagementState, Status, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                              stateCtxt.ActionRequest, signalRMessages, log, async (harness, status) =>
            {
                log.LogInformation($"Booting micro-apps runtime...");

                harness.UpdateStatus(status);

                return Status.Success;
            }));
        }
        public virtual async Task <Status> SetTimeout([ActivityTrigger] StateActionContext stateCtxt,
                                                      [SignalR(HubName = IoTEnsembleState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                      [Blob("state-api/{stateCtxt.StateDetails.EnterpriseLookup}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            var status = await stateBlob.WithStateHarness <IoTEnsembleSharedState, TelemetrySyncRequest, IoTEnsembleSharedStateHarness>(stateCtxt.StateDetails,
                                                                                                                                        stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Setting telemetry IsTimedout to true...");

                harness.State.Telemetry.IsTelemetryTimedOut = true;

                return(Status.Success);
            }, preventStatusException : true);

            return(status);
        }
        public virtual async Task <Status> Sync([ActivityTrigger] StateActionContext stateCtxt,
                                                [SignalR(HubName = IoTEnsembleState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                [Blob("state-api/{stateCtxt.StateDetails.EnterpriseLookup}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob,
                                                [CosmosDB(
                                                     databaseName: "%LCU-WARM-STORAGE-DATABASE%",
                                                     collectionName: "%LCU-WARM-STORAGE-TELEMETRY-CONTAINER%",
                                                     ConnectionStringSetting = "LCU-WARM-STORAGE-CONNECTION-STRING")] DocumentClient docClient)
        {
            var status = await stateBlob.WithStateHarness <IoTEnsembleSharedState, TelemetrySyncRequest, IoTEnsembleSharedStateHarness>(stateCtxt.StateDetails,
                                                                                                                                        stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Setting Loading device telemetry from sync state...");

                if (harness.State.Telemetry == null)
                {
                    harness.State.Telemetry = new IoTEnsembleTelemetry();
                }

                harness.State.Telemetry.Loading = true;

                return(Status.Success);
            }, preventStatusException : true, withLock : false);

            if (status)
            {
                status = await stateBlob.WithStateHarness <IoTEnsembleSharedState, TelemetrySyncRequest, IoTEnsembleSharedStateHarness>(stateCtxt.StateDetails,
                                                                                                                                        stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Loading device telemetry from sync...");

                    var loaded = await harness.LoadTelemetry(secMgr, docClient);

                    harness.State.Telemetry.Loading = false;

                    return(loaded);
                }, preventStatusException : true, withLock : false);
            }

            return(status);
        }
        protected virtual async Task <Status> handleTelemetrySync(IDurableOrchestrationContext context, ILogger log, StateActionContext stateCtxt)
        {
            var synced = Status.GeneralError;

            //  Max telemetry sync cycle
            var operationTimeoutTime = context.CurrentUtcDateTime.AddMinutes(30);

            if (!context.IsReplaying)
            {
                log.LogInformation($"Instantiating telemtry sync loop for: {stateCtxt.ToJSON()}");
            }

            while (context.CurrentUtcDateTime < operationTimeoutTime)
            {
                if (!context.IsReplaying)
                {
                    log.LogInformation($"Waiting for telemetry sync for: {stateCtxt.ToJSON()}");
                }

                synced = await context.CallActivityAsync <Status>("TelemetrySyncOrchestration_Sync", stateCtxt);

                if (!synced)
                {
                    if (!context.IsReplaying)
                    {
                        log.LogInformation($"Error durring sync process: {synced.ToJSON()}");
                    }

                    //  TODO:  Need to call another activity to set the State.Telemetry.Enabled = false to keep it in sync, maybe set an error message

                    break;
                }
                else
                {
                    var refreshRate = synced.Metadata.ContainsKey("RefreshRate") ? synced.Metadata["RefreshRate"].ToString().As <int>() : 30;

                    // Wait for the next checkpoint
                    var nextCheckpoint = context.CurrentUtcDateTime.AddSeconds(refreshRate);

                    if (!context.IsReplaying)
                    {
                        log.LogInformation($"Continuing telemtry sync at {nextCheckpoint} for: {stateCtxt.ToJSON()}");
                    }

                    await context.CreateTimer(nextCheckpoint, CancellationToken.None);
                }
            }

            await context.CallActivityAsync <Status>("TelemetrySyncOrchestration_SetTimeout", stateCtxt);

            synced = await context.CallActivityAsync <Status>("TelemetrySyncOrchestration_Sync", stateCtxt);

            return(synced);
        }
        protected virtual async Task <Status> handleCanFinalize(IDurableOrchestrationContext context, ILogger log, StateActionContext stateCtxt)
        {
            var canFinalize = Status.GeneralError;

            var operationTimeoutTime = context.CurrentUtcDateTime.AddMinutes(30);

            // using (var timeoutCts = new CancellationTokenSource())
            // {
            //     while (true)
            //     {
            if (!context.IsReplaying)
            {
                log.LogInformation($"Waiting for organization infrastructure to boot for: {stateCtxt.ToJSON()}");
            }

            // var operationHasTimedOut = context.CurrentUtcDateTime > operationTimeoutTime;

            // if (operationHasTimedOut)
            // {
            //     if (!context.IsReplaying)
            //         log.LogError($"Booting organization infrastructure timedout for: {stateCtxt.ToJSON()}");

            //     context.SetCustomStatus("Organization Booting has timed out, please try again.");

            //     break;
            // }

            // // if (!context.IsReplaying)
            // {
            //     var deadline = context.CurrentUtcDateTime.AddSeconds(10);

            //     if (!context.IsReplaying)
            //         log.LogInformation($"Establishing delay timer until {deadline} for: {stateCtxt.ToJSON()}");

            //     await context.CreateTimer(deadline, 0, timeoutCts.Token);
            // }

            var retryOptions = new RetryOptions(TimeSpan.FromSeconds(10), 360)
            {
                Handle       = handleRetryException,
                RetryTimeout = TimeSpan.FromMinutes(30)
            };

            canFinalize = await context.CallActivityWithRetryAsync <Status>("BootOrganizationOrchestration_CanFinalize", retryOptions, stateCtxt);

            // if (canFinalize)
            // {
            //     timeoutCts.Cancel();

            //     break;
            // }
            //     }
            // }

            return(canFinalize);
        }
        public virtual async Task <Status> BootMicroApps([ActivityTrigger] StateActionContext stateCtxt, ILogger log,
                                                         [SignalR(HubName = UserManagementState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                         [Blob("state-api/{stateCtxt.StateDetails.EnterpriseAPIKey}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            var status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Booting micro-apps runtime...");

                var status = await harness.BootMicroAppsRuntime(entArch);

                if (status)
                {
                    harness.UpdateBootOption("MicroApps", status: Status.Initialized.Clone("Configuring Data Aplicationps Low-Code Unit™..."));
                }
                else
                {
                    harness.UpdateBootOption("MicroApps", status: Status.GeneralError.Clone("Error Configuring Micro-Applications Runtime, retrying."));
                }

                harness.UpdateStatus(status);

                return(status);
            });

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Booting Data Applications Low-Code Unit™...");

                    var status = await harness.BootDataApps(appDev);

                    if (status)
                    {
                        harness.UpdateBootOption("MicroApps", status: Status.Initialized.Clone("Configuring Data Flow Low-Code Unit™...."));
                    }
                    else
                    {
                        harness.UpdateBootOption("MicroApps", status: Status.GeneralError.Clone("Error Configuring Data Applications Low-Code Unit™, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Booting Data Flow Low-Code Unit™...");

                    var status = await harness.BootDataFlow(appDev);

                    if (status)
                    {
                        harness.UpdateBootOption("MicroApps", status: Status.Success.Clone("Micro-Applications Orechestration Configured"), loading: false);

                        harness.CompleteBoot();
                    }
                    else
                    {
                        harness.UpdateBootOption("MicroApps", status: Status.GeneralError.Clone("Error Configuring Data Flow Low-Code Unit™, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            return(status);
        }
        public virtual async Task <Status> BootDomain([ActivityTrigger] StateActionContext stateCtxt, ILogger log,
                                                      [SignalR(HubName = UserManagementState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                      [Blob("state-api/{stateCtxt.StateDetails.EnterpriseAPIKey}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            var status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Booting host auth app...");

                var status = await harness.BootHostAuthApp(entArch);

                if (status)
                {
                    harness.UpdateBootOption("Domain", status: Status.Initialized.Clone("Configuring Host..."));
                }
                else
                {
                    harness.UpdateBootOption("Domain", status: Status.GeneralError.Clone("Error Configuring Domain Security, retrying."));
                }

                harness.UpdateStatus(status);

                return(status);
            });

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Booting host...");

                    var status = await harness.BootHost(entArch, stateCtxt.StateDetails.EnterpriseAPIKey);

                    if (status)
                    {
                        harness.UpdateBootOption("Domain", status: Status.Initialized.Clone("Configuring Host SSL with Let's Encrypt..."));
                    }
                    else
                    {
                        harness.UpdateBootOption("Domain", status: Status.GeneralError.Clone("Error Configuring Host, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Booting host SSL with Let's Encrypt...");

                    var status = await harness.BootHostSSL(entArch, stateCtxt.StateDetails.EnterpriseAPIKey);

                    if (status)
                    {
                        harness.UpdateBootOption("Domain", status: Status.Success.Clone("Host Configured"), loading: false);

                        harness.UpdateBootOption("MicroApps", status: Status.Initialized.Clone("Downloading and installing Low-Code Unit™ micro-applications runtime..."));
                    }
                    else
                    {
                        harness.UpdateBootOption("Domain", status: Status.GeneralError.Clone("Error Configuring Host SSL with Let's Encrypt, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            return(status);
        }
        public virtual async Task <Status> BootDevOps([ActivityTrigger] StateActionContext stateCtxt, ILogger log,
                                                      [SignalR(HubName = UserManagementState.HUB_NAME)] IAsyncCollector <SignalRMessage> signalRMessages,
                                                      [Blob("state-api/{stateCtxt.StateDetails.EnterpriseAPIKey}/{stateCtxt.StateDetails.HubName}/{stateCtxt.StateDetails.Username}/{stateCtxt.StateDetails.StateKey}", FileAccess.ReadWrite)] CloudBlockBlob stateBlob)
        {
            var status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
            {
                log.LogInformation($"Configuring Project DevOps...");

                var status = await harness.BootIaC(devOpsArch, stateCtxt.StateDetails.EnterpriseAPIKey, stateCtxt.StateDetails.Username);

                if (status)
                {
                    harness.UpdateBootOption("DevOps", status: Status.Initialized.Clone("Configuring DevOps Environment Package Feeds..."));
                }
                else
                {
                    harness.UpdateBootOption("DevOps", status: Status.GeneralError.Clone("Error Configuring DevOps Environment, retrying."));
                }

                harness.UpdateStatus(status);

                return(status);
            });

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Configuring Project DevOps...");

                    var status = await harness.BootLCUFeeds(devOpsArch, stateCtxt.StateDetails.EnterpriseAPIKey, stateCtxt.StateDetails.Username);

                    if (status)
                    {
                        harness.UpdateBootOption("DevOps", status: Status.Initialized.Clone("Configuring DevOps Environment Task Library..."));
                    }
                    else
                    {
                        harness.UpdateBootOption("DevOps", status: Status.GeneralError.Clone("Error Configuring DevOps Environment Package Feed, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Configuring Project DevOps...");

                    var status = await harness.BootTaskLibrary(devOpsArch, stateCtxt.StateDetails.EnterpriseAPIKey, stateCtxt.StateDetails.Username);

                    if (status)
                    {
                        harness.UpdateBootOption("DevOps", status: Status.Initialized.Clone("Configuring DevOps Environment with Infrastructure as Code builds and releases..."));
                    }
                    else
                    {
                        harness.UpdateBootOption("DevOps", status: Status.GeneralError.Clone("Error Configuring DevOps Environment Task Library, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            if (status)
            {
                status = await stateBlob.WithStateHarness <UserManagementState, BootOrganizationRequest, UserManagementStateHarness>(stateCtxt.StateDetails,
                                                                                                                                     stateCtxt.ActionRequest, signalRMessages, log, async (harness, reqData) =>
                {
                    log.LogInformation($"Configuring Project DevOps...");

                    var status = await harness.BootIaCBuildsAndReleases(devOpsArch, stateCtxt.StateDetails.EnterpriseAPIKey, stateCtxt.StateDetails.Username);

                    if (status)
                    {
                        harness.UpdateBootOption("DevOps",
                                                 status: Status.Success.Clone("DevOps Environment Configured"),
                                                 loading: false);

                        harness.UpdateBootOption("Infrastructure", status: Status.Initialized.Clone("Deploying Environment Infrastructure..."));
                    }
                    else
                    {
                        harness.UpdateBootOption("DevOps", status: Status.GeneralError.Clone("Error Configuring DevOps Environment with Infrastructure as Code builds and releases, retrying."));
                    }

                    harness.UpdateStatus(status);

                    return(status);
                });
            }

            return(status);
        }