// Sends a proactive message to the user. private async Task CompleteJobAsync( BotAdapter adapter, string botId, JobLog.JobData jobInfo, CancellationToken cancellationToken = default(CancellationToken)) { await adapter.ContinueConversationAsync(botId, jobInfo.Conversation, CreateCallback(jobInfo), cancellationToken); }
// Creates and "starts" a new job. private JobLog.JobData CreateJob(ITurnContext turnContext, JobLog jobLog) { JobLog.JobData jobInfo = new JobLog.JobData { TimeStamp = DateTime.Now.ToBinary(), Conversation = turnContext.Activity.GetConversationReference(), }; jobLog[jobInfo.TimeStamp] = jobInfo; return(jobInfo); }
// Creates and "starts" a new job. private JobLog.JobData CreateJob(ITurnContext turnContext, JobLog jobLog) { JobLog.JobData jobInfo = new JobLog.JobData { TimeStamp = DateTime.Now.ToBinary(), Conversation = turnContext.Activity.GetConversationReference(), }; jobLog[jobInfo.TimeStamp] = jobInfo; #region eigen meuk jobLog[jobInfo.TimeStamp].TimeElapsed += async(messagge) => { await turnContext.Adapter.ContinueConversationAsync(AppId, jobInfo.Conversation, CreateTimerCallback($"{messagge} from {jobInfo.TimeStamp}"), default(CancellationToken)); }; #endregion return(jobInfo); }
// Creates the turn logic to use for the proactive message. private BotCallbackHandler CreateCallback(JobLog.JobData jobInfo) { return(async(turnContext, token) => { // Get the job log from state, and retrieve the job. JobLog jobLog = await _jobLogPropertyAccessor.GetAsync(turnContext, () => new JobLog()); // Perform bookkeeping. jobLog[jobInfo.TimeStamp].Completed = true; // Set the new property await _jobLogPropertyAccessor.SetAsync(turnContext, jobLog); // Now save it into the JobState await _jobState.SaveChangesAsync(turnContext); // Send the user a proactive confirmation message. await turnContext.SendActivityAsync($"Job {jobInfo.TimeStamp} is complete."); }); }
/// <summary> /// Every conversation turn will call this method. /// Proactive messages use existing conversations (turns) with the user to deliver proactive messages. /// Proactive messages can be ad-hoc or dialog-based. This is demonstrating ad-hoc, which doesn't /// have to consider an interruption to an existing conversation, which may upset the dialog flow. /// Note: The Email channel may send a proactive message outside the context of a active conversation. /// </summary> /// <param name="turnContext">A <see cref="ITurnContext"/> containing all the data needed /// for processing this conversation turn. </param> /// <param name="cancellationToken">(Optional) A <see cref="CancellationToken"/> that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute.</returns> /// <remarks> /// In the scenario, the bot is being called by users as normal (to start jobs and such) and by some /// theoretical service (to signal when jobs are complete). The service is sending activities to the /// bot on a separate conversation from the user conversations.</remarks> public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken)) { // See https://aka.ms/about-bot-activity-message to learn more about the message and other activity types. if (turnContext.Activity.Type != ActivityTypes.Message) { // Handle non-message activities. await OnSystemActivityAsync(turnContext); } else { // Get the job log. // The job log is a dictionary of all outstanding jobs in the system. JobLog jobLog = await _jobLogPropertyAccessor.GetAsync(turnContext, () => new JobLog()); // Get the user's text input for the message. var text = turnContext.Activity.Text.Trim().ToLowerInvariant(); switch (text) { case "run": case "run job": // Start a virtual job for the user. JobLog.JobData job = CreateJob(turnContext, jobLog); // Set the new property await _jobLogPropertyAccessor.SetAsync(turnContext, jobLog); // Now save it into the JobState await _jobState.SaveChangesAsync(turnContext); await turnContext.SendActivityAsync( $"We're starting job {job.TimeStamp} for you. We'll notify you when it's complete."); break; case "show": case "show jobs": // Display information for all jobs in the log. if (jobLog.Count > 0) { await turnContext.SendActivityAsync( "| Job number | Conversation ID | Completed |<br>" + "| :--- | :---: | :---: |<br>" + string.Join("<br>", jobLog.Values.Select(j => $"| {j.TimeStamp} | {j.Conversation.Conversation.Id.Split('|')[0]} | {j.Completed} |"))); } else { await turnContext.SendActivityAsync("The job log is empty."); } break; default: // Check whether this is simulating a job completed event. string[] parts = text?.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (parts != null && parts.Length == 2 && parts[0].Equals("done", StringComparison.InvariantCultureIgnoreCase) && long.TryParse(parts[1], out long jobNumber)) { if (!jobLog.TryGetValue(jobNumber, out JobLog.JobData jobInfo)) { await turnContext.SendActivityAsync($"The log does not contain a job {jobInfo.TimeStamp}."); } else if (jobInfo.Completed) { await turnContext.SendActivityAsync($"Job {jobInfo.TimeStamp} is already complete."); } else { await turnContext.SendActivityAsync($"Completing job {jobInfo.TimeStamp}."); // Send the proactive message. await CompleteJobAsync(turnContext.Adapter, AppId, jobInfo); } } break; } if (!turnContext.Responded) { await turnContext.SendActivityAsync(WelcomeText); } } }