Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ActivityHandler class #757

Merged
merged 6 commits into from
Feb 11, 2019
Merged

Conversation

benbrown
Copy link
Contributor

@benbrown benbrown commented Feb 5, 2019

Note: Partity with microsoft/botbuilder-dotnet#1358

Description

Introducing ActivityHandler

This introduces a new class called ActivityHandler. ActivityHandlers have a .run() method that accepts the incoming turnContext created by adapter.processActivity. The ActivityHandler then emits events based on the activity type and other characteristics. These events can be handled by developer-defined functions.

The intention is to provide a flexible base class for bots. This should make it easier for developers to handle specific types of activities, and easier to understand the scope of activities a bot might receive. All activity types that might arrive via the Azure Bot Service are exposed as events, along with a few specialized events to - for example - distinguish whether a conversationUpdates represents member added versus members removed.

Here's a simple example, showing an "Echo bot" that replies to any incoming message with an echo.

const bot = new ActivityHandler();

server.post('/api/messages', (req, res) => {
    adapter.processActivity(req, res, async (context) => {
        // Route to main dialog.
        await bot.run(context);
    });
});


bot.onMessage(async (context, next) => { 
// do stuff
await context.sendActivity(`Echo: ${ context.activity.text }`);

// proceed with further processing
await next();
});

bot.onMembersAdded(async(context, next) => {
// send welcome messages to people listed in context.activity.membersAdded
await next();
});

Events

For all incoming activities, a Turn event will fire.

bot.onTurn(async (context, next) => { 
// this method receives every single incoming activity
await next();
});

Then, the type-specific event will fire. For example, ConversationUpdate:

bot.onConversationUpdate(async(context, next) => {
// this is a conversation update of some sort
await next();

Then, any sub-events will fire. For example, MembersAdded, which is a specialized version of ConversationUpdate:

bot.onMembersAdded(async(context, next) => {
// handle context.activity.membersAdded
await next();
});

Finally, a special Dialog event will fire that can be used to process Dialog activities. (see below)

Prevent Propagation of event

At any point in the processing chain, a handler may omit a call to await next() to prevent the event from continuing to be processed by other handlers.

This pattern can be used to capture interruptions or handle special events before they reach other handlers.

Using with Dialogs

In order to use an ActivityHandler along with the Dialogs system, use the onDialog() method, which fires at the very end of the processing chain.

bot.onDialog(async (context, next) => {

    if (context.activity.type === ActivityTypes.Message) {
        const dialogContext = await dialogSet.createContext(context);
        const results = await dialogContext.continueDialog();

        // fallback behavior is to run welcome dialog
        if (results.status === DialogTurnStatus.empty) {
             await dialogContext.beginDialog('hello');
        }

        await conversationState.saveChanges(context);
    }

    await next();

});

Specific Changes

  • Add ActivityHandler class
  • Add unit tests

Testing

Run unit tests using npm run test

@benbrown benbrown changed the title Benbrown/activityhandler DO NOT MERGE: Introduce ActivityHandler class Feb 5, 2019
@coveralls
Copy link

coveralls commented Feb 5, 2019

Pull Request Test Coverage Report for Build #1953

  • 84 of 97 (86.6%) changed or added relevant lines in 2 files are covered.
  • 2 unchanged lines in 1 file lost coverage.
  • Overall coverage decreased (-0.08%) to 84.141%

Changes Missing Coverage Covered Lines Changed/Added Lines %
libraries/botbuilder-core/src/ActivityHandler.ts 83 96 86.46%
Files with Coverage Reduction New Missed Lines %
libraries/botframework-config/src/botConfigurationBase.ts 2 85.59%
Totals Coverage Status
Change from base Build #1952: -0.08%
Covered Lines: 2915
Relevant Lines: 3338

💛 - Coveralls

@cleemullins cleemullins added the 4.3 February 14, 2019 Release label Feb 6, 2019
case ActivityTypes.MessageReaction:
await this.handle(context, 'MessageReaction', async() => {
if (context.activity.reactionsAdded && context.activity.reactionsAdded.length) {
await this.handle(context, 'MessageReactionAdded', runDialogs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming: shouldn't this be "MessageReactionsAdded" and "MessageReactionsRemoved"

(for consistency with the property name and the membersAdded etc.)

await this.handle(context, 'EndOfConversation', runDialogs);
break;
case ActivityTypes.Event:
await this.handle(context, 'Event', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should also handle event name "tokens/response"

@cleemullins cleemullins changed the title DO NOT MERGE: Introduce ActivityHandler class Introduce ActivityHandler class Feb 11, 2019
@cleemullins cleemullins merged commit 1e8397d into master Feb 11, 2019
@cleemullins cleemullins deleted the benbrown/activityhandler branch March 5, 2019 17:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
4.3 February 14, 2019 Release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants