Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d978f5b

Browse filesBrowse files
authored
xmpp wikibot for GCE (GoogleCloudPlatform#618)
* adding new xmpp wikibot example * xmpp wikibot for GCE
1 parent d14074a commit d978f5b
Copy full SHA for d978f5b

File tree

Expand file treeCollapse file tree

3 files changed

+243
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

3 files changed

+243
-0
lines changed
Open diff view settings
Collapse file

‎compute/xmpp_wikibot/README.md‎

Copy file name to clipboard
+75Lines changed: 75 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Wikibot example that can be run on Google Compute Engine
2+
3+
This sample shows how to use the [SleekXMPP](http://sleekxmpp.com/index.html)
4+
client and [Flask](http://flask.pocoo.org/) to build a simple chatbot that can
5+
be run on [Google Compute Engine](https://cloud.google.com/compute/). The
6+
chatbot does two things:
7+
8+
1. Sends messages to XMPP users via http get:
9+
* The server is running on port 5000
10+
* if running on virtual machine use:
11+
`http://<MACHINE IP>:5000/send_message?recipient=<RECIPIENT ADDRESS>&message=<MSG>`
12+
* If running locally use:
13+
`http://localhost:5000/send_message?recipient=<RECIPIENT ADDRESS>&message=<MSG>`
14+
15+
2. Responds to incoming messages with a Wikipedia page on the topic:
16+
* Send a message with a topic (e.g., 'Hawaii') to the XMPP account the
17+
server is using
18+
* It should respond with a Wikipedia page (when one exists)
19+
20+
## Setup
21+
22+
Follow the instructions at the
23+
[Compute Engine Quickstart Guide](https://cloud.google.com/compute/docs/quickstart-linux)
24+
on how to create a project, create a virtual machine, and connect to your
25+
instance via SSH. Once you have done this, you may jump to
26+
[Installing files and dependencies](#installing-files-and-dependencies).
27+
28+
You should also download the [Google Cloud SDK](https://cloud.google.com/sdk/).
29+
It will allow you to access many of the features of Google Compute Engine via
30+
your local machine.
31+
32+
**IMPORTANT** You must enable tcp traffic on port 5000 to send messages to the
33+
XMPP server. This can be done by running the following SDK commands:
34+
35+
gcloud config set project <YOUR PROJECT NAME>
36+
37+
gcloud compute firewall-rules create wikibot-server-rule --allow tcp:5000 --source-ranges=0.0.0.0/0
38+
39+
Or you can create a new firewall rule via the UI in the
40+
[Networks](https://console.cloud.google.com/networking/networks/list) section of
41+
the Google Cloud Console.
42+
43+
### Installing files and dependencies
44+
45+
First, install the `wikibot.py` and `requirements.txt` files onto your remote
46+
instance. See the guide on
47+
[Transferring Files](https://cloud.google.com/compute/docs/instances/transfer-files)
48+
for more information on how to do this using the Mac file browser, `scp`, or
49+
the Google Cloud SDK.
50+
51+
Before running or deploying this application, you must install the dependencies
52+
using [pip](http://pip.readthedocs.io/en/stable/):
53+
54+
pip install -r requirements.txt
55+
56+
57+
## Running the sample
58+
59+
You'll need to have an XMPP account prior to actually running the sample.
60+
If you do not have one, you can easily create an account at one of the many
61+
XMPP servers such as [Jabber.at](https://jabber.at/account/register/).
62+
Once you have an account, run the following command:
63+
64+
python wikibot.py '<YOUR XMPP USERNAME>' '<PASSWORD>'
65+
66+
Where the username (e.g., 'bob@jabber.at') and password for the account that
67+
you'd like to use for your chatbot are passed in as arguments.
68+
69+
Enter control-C to stop the server
70+
71+
72+
### Running on your local machine
73+
74+
You may also run the sample locally by simply copying `wikibot.py` to a project
75+
directory and installing all python dependencies there.
Collapse file
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Flask==0.11.1
2+
requests==2.11.1
3+
sleekxmpp==1.3.1
Collapse file

‎compute/xmpp_wikibot/wikibot.py‎

Copy file name to clipboard
+165Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Copyright 2016 Google Inc. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Wikibot server example using SleekXMPP client library"""
16+
17+
import argparse
18+
import getpass
19+
import json
20+
import logging
21+
import threading
22+
import urllib
23+
24+
from flask import Flask, request
25+
import requests
26+
import sleekxmpp
27+
28+
29+
app = Flask(__name__)
30+
31+
@app.route('/send_message', methods=['GET'])
32+
def send_message():
33+
recipient = request.args.get('recipient')
34+
message = request.args.get('message')
35+
36+
if chat_client and recipient and message:
37+
chat_client.send_message(mto=recipient, mbody=message)
38+
return 'message sent to {} with body: {}'.format(recipient, message)
39+
else:
40+
logging.info('chat client or recipient or message does not exist!')
41+
return 'message failed to send', 400
42+
43+
44+
def run_server(host='0.0.0.0'):
45+
app.run(threaded=False, use_reloader=False, host=host)
46+
47+
48+
class WikiBot(sleekxmpp.ClientXMPP):
49+
"""A simple SleekXMPP bot that will take messages, look up their content on
50+
wikipedia and provide a link to the page if it exists.
51+
"""
52+
53+
def __init__(self, jid, password):
54+
sleekxmpp.ClientXMPP.__init__(self, jid, password)
55+
56+
# The session_start event will be triggered when
57+
# the bot establishes its connection with the server
58+
# and the XML streams are ready for use. We want to
59+
# listen for this event so that we we can initialize
60+
# our roster.
61+
self.add_event_handler('session_start', self.start)
62+
63+
# The message event is triggered whenever a message
64+
# stanza is received. Be aware that that includes
65+
# MUC messages and error messages.
66+
self.add_event_handler('message', self.message)
67+
68+
def start(self, event):
69+
"""Process the session_start event.
70+
71+
Typical actions for the session_start event are requesting the roster
72+
and broadcasting an initial presence stanza.
73+
74+
Arguments:
75+
event -- An empty dictionary. The session_start event does not
76+
provide any additional data.
77+
"""
78+
self.send_presence()
79+
self.get_roster()
80+
81+
def message(self, msg):
82+
"""Process incoming message stanzas.
83+
84+
Be aware that this also includes MUC messages and error messages. It is
85+
usually a good idea to check the messages's type before processing or
86+
sending replies. If the message is the appropriate type, then the bot
87+
checks wikipedia to see if the message string exists as a page on the
88+
site. If so, it sends this link back to the sender in the reply.
89+
90+
Arguments:
91+
msg -- The received message stanza. See the SleekXMPP documentation
92+
for stanza objects and the Message stanza to see how it may be
93+
used.
94+
"""
95+
if msg['type'] in ('chat', 'normal'):
96+
msg_body = msg['body']
97+
logging.info('Message sent was: {}'.format(msg_body))
98+
encoded_body = urllib.quote_plus(msg_body)
99+
svrResponse = requests.get(
100+
'https://en.wikipedia.org/w/api.php?'
101+
'action=parse&prop=sections&format=json&page={}'.format(
102+
encoded_body))
103+
doc = json.loads(svrResponse.content)
104+
try:
105+
page_id = str(doc['parse']['pageid'])
106+
defn_url = 'https://en.wikipedia.org/?curid={}'.format(page_id)
107+
msg.reply('find out more about: "{}" here: {}'.format(
108+
msg_body, defn_url)).send()
109+
except KeyError as e:
110+
logging.info('key error: {0}'.format(e))
111+
msg.reply('I wasn\'t able to locate info on "{}" Sorry'.format(
112+
msg_body)).send()
113+
114+
115+
if __name__ == '__main__':
116+
# Setup the command line arguments.
117+
parser = argparse.ArgumentParser(
118+
description=__doc__,
119+
formatter_class=argparse.RawDescriptionHelpFormatter)
120+
121+
# Output verbosity options.
122+
parser.add_argument(
123+
'-q', '--quiet', help='set logging to ERROR', action='store_const',
124+
dest='loglevel', const=logging.ERROR, default=logging.INFO)
125+
parser.add_argument(
126+
'-d', '--debug', help='set logging to DEBUG', action='store_const',
127+
dest='loglevel', const=logging.DEBUG, default=logging.INFO)
128+
parser.add_argument(
129+
'-v', '--verbose', help='set logging to COMM', action='store_const',
130+
dest='loglevel', const=5, default=logging.INFO)
131+
132+
# JID and password options.
133+
parser.add_argument('-j', '--jid', help='JID to use', required=True)
134+
parser.add_argument('-p', '--password', help='password to use')
135+
136+
args = parser.parse_args()
137+
138+
# Setup logging.
139+
logging.basicConfig(level=args.loglevel,
140+
format='%(levelname)-8s %(message)s')
141+
142+
if args.password is None:
143+
args.password = getpass.getpass('Password: ')
144+
145+
# Setup the WikiBot and register plugins. Note that while plugins may
146+
# have interdependencies, the order in which you register them does
147+
# not matter.
148+
xmpp = WikiBot(args.jid, args.password)
149+
xmpp.register_plugin('xep_0030') # Service Discovery
150+
xmpp.register_plugin('xep_0004') # Data Forms
151+
xmpp.register_plugin('xep_0060') # PubSub
152+
xmpp.register_plugin('xep_0199') # XMPP Ping
153+
154+
chat_client = xmpp # set the global variable
155+
156+
# start the app server and run it as a thread so that the XMPP server may
157+
# also start
158+
threading.Thread(target=run_server).start()
159+
160+
# Connect to the XMPP server and start processing XMPP stanzas.
161+
if xmpp.connect():
162+
xmpp.process(block=True)
163+
print('Done')
164+
else:
165+
print('Unable to connect.')

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.