|
1 #!/usr/bin/env python |
|
2 # |
|
3 # Copyright 2007 Google Inc. |
|
4 # |
|
5 # Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 # you may not use this file except in compliance with the License. |
|
7 # You may obtain a copy of the License at |
|
8 # |
|
9 # http://www.apache.org/licenses/LICENSE-2.0 |
|
10 # |
|
11 # Unless required by applicable law or agreed to in writing, software |
|
12 # distributed under the License is distributed on an "AS IS" BASIS, |
|
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 # See the License for the specific language governing permissions and |
|
15 # limitations under the License. |
|
16 # |
|
17 |
|
18 """XMPP webapp handler classes. |
|
19 |
|
20 This module provides handler classes for XMPP bots, including both basic |
|
21 messaging functionality and a command handler for commands such as "/foo bar" |
|
22 """ |
|
23 |
|
24 |
|
25 |
|
26 import logging |
|
27 from google.appengine.api import xmpp |
|
28 from google.appengine.ext import webapp |
|
29 |
|
30 |
|
31 class BaseHandler(webapp.RequestHandler): |
|
32 """A webapp baseclass for XMPP handlers. |
|
33 |
|
34 Implements a straightforward message delivery pattern. When a message is |
|
35 received, message_received is called with a Message object that encapsulates |
|
36 the relevant details. Users can reply using the standard XMPP API, or the |
|
37 convenient .reply() method on the Message object. |
|
38 """ |
|
39 |
|
40 def message_received(self, message): |
|
41 """Called when a message is sent to the XMPP bot. |
|
42 |
|
43 Args: |
|
44 message: Message: The message that was sent by the user. |
|
45 """ |
|
46 raise NotImplementedError() |
|
47 |
|
48 def handle_exception(self, exception, debug_mode): |
|
49 """Called if this handler throws an exception during execution. |
|
50 |
|
51 Args: |
|
52 exception: the exception that was thrown |
|
53 debug_mode: True if the web application is running in debug mode |
|
54 """ |
|
55 super(BaseHandler, self).handle_exception(exception, debug_mode) |
|
56 if self.xmpp_message: |
|
57 self.xmpp_message.reply('Oops. Something went wrong.') |
|
58 |
|
59 def post(self): |
|
60 try: |
|
61 self.xmpp_message = xmpp.Message(self.request.POST) |
|
62 except xmpp.InvalidMessageError, e: |
|
63 logging.error("Invalid XMPP request: Missing required field %s", e[0]) |
|
64 return |
|
65 self.message_received(self.xmpp_message) |
|
66 |
|
67 |
|
68 class CommandHandlerMixin(object): |
|
69 """A command handler for XMPP bots. |
|
70 |
|
71 Implements a command handler pattern. XMPP messages are processed by calling |
|
72 message_received. Message objects handled by this class are annotated with |
|
73 'command' and 'arg' fields. On receipt of a message starting with a forward |
|
74 or backward slash, the handler calls a method named after the command - eg, |
|
75 if the user sends "/foo bar", the handler will call foo_command(message). |
|
76 If no handler method matches, unhandled_command is called. The default behaviour |
|
77 of unhandled_command is to send the message "Unknown command" back to |
|
78 the sender. |
|
79 |
|
80 If the user sends a message not prefixed with a slash, |
|
81 text_message(message) is called. |
|
82 """ |
|
83 |
|
84 def unhandled_command(self, message): |
|
85 """Called when an unknown command is sent to the XMPP bot. |
|
86 |
|
87 Args: |
|
88 message: Message: The message that was sent by the user. |
|
89 """ |
|
90 message.reply('Unknown command') |
|
91 |
|
92 def text_message(self, message): |
|
93 """Called when a message not prefixed by a /command is sent to the XMPP bot. |
|
94 |
|
95 Args: |
|
96 message: Message: The message that was sent by the user. |
|
97 """ |
|
98 pass |
|
99 |
|
100 def message_received(self, message): |
|
101 """Called when a message is sent to the XMPP bot. |
|
102 |
|
103 Args: |
|
104 message: Message: The message that was sent by the user. |
|
105 """ |
|
106 if message.command: |
|
107 handler_name = '%s_command' % (message.command,) |
|
108 handler = getattr(self, handler_name, None) |
|
109 if handler: |
|
110 handler(message) |
|
111 else: |
|
112 self.unhandled_command(message) |
|
113 else: |
|
114 self.text_message(message) |
|
115 |
|
116 |
|
117 class CommandHandler(CommandHandlerMixin, BaseHandler): |
|
118 """A webapp implementation of CommandHandlerMixin.""" |
|
119 pass |