-
Notifications
You must be signed in to change notification settings - Fork 6.6k
adding new xmpp wikibot example #596
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
Closed
Closed
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
b67799c
adding new xmpp wikibot example
mogar1980 f83d610
address merge comments
mogar1980 a8adbaf
updated readme formatting
mogar1980 0508f7f
updated readme formatting again
mogar1980 bad4349
server now runs on port 80
mogar1980 3f7b457
back to running server on port 5000
mogar1980 85c25d3
udated README with firewall setup instructions
mogar1980 82633a4
udated README with firewall setup instructions 2
mogar1980 49a7b53
minor cosmetic changes
mogar1980 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# Uncyclobot example that can be run on Google Compute Engine | ||
|
||
This sample shows how to use the [SleekXMPP](http://sleekxmpp.com/index.html) | ||
client and [Flask](http://flask.pocoo.org/) to build a simple chatbot that can | ||
be run on [Google Compute Engine](https://cloud.google.com/compute/). The | ||
chatbot does two things: | ||
|
||
1. Sends messages to XMPP users via http get: | ||
* The server is running on port 5000 | ||
* if running on virtual machine use: http://<MACHINE IP>:5000/send_message?recipient=<RECIPIENT ADDRESS>&message=<MSG> | ||
* If running locally use: http://localhost:5000/send_message?recipient=<RECIPIENT ADDRESS>&message=<MSG> | ||
|
||
2. Responds to incoming messages with a Uncyclopedia page on the topic: | ||
* Send a message with a topic (e.g., 'Hawaii') to the XMPP account the server is using | ||
* It should respond with a Uncyclopedia page (when one exists) | ||
|
||
## Setup | ||
|
||
Follow the instructions at the | ||
[Compute Engine Quickstart Guide](https://cloud.google.com/compute/docs/quickstart-linux) | ||
on how to create a project, create a virtual machine, and connect to your | ||
instance via SSH. Once you have done this, you may jump to | ||
[Installing files and dependencies](#installing-files-and-dependencies). | ||
|
||
You should also download the [Google Cloud SDK](https://cloud.google.com/sdk/). | ||
It will allow you to access many of the features of Google Compute Engine via | ||
your local machine. | ||
|
||
**IMPORTANT** You must enable tcp traffic on port 5000 to send messages to the | ||
XMPP server. This can be done by running the following SDK commands: | ||
|
||
gcloud config set project <YOUR PROJECT NAME> | ||
|
||
gcloud compute firewall-rules create wikibot-server-rule --allow tcp:5000 --source-ranges=0.0.0.0/0 | ||
|
||
Or you can create a new firewall rule via the UI in the | ||
[Networks](https://console.cloud.google.com/networking/networks/list) section of | ||
the Google Cloud Console. | ||
|
||
### Installing files and dependencies | ||
|
||
First, install the `wikibot.py` and `requirements.txt` files onto your remote | ||
instance. See the guide on | ||
[Transferring Files](https://cloud.google.com/compute/docs/instances/transfer-files) | ||
for more information on how to do this using the Mac file browser, `scp`, or | ||
the Google Cloud SDK. | ||
|
||
Before running or deploying this application, you must install the dependencies | ||
using [pip](http://pip.readthedocs.io/en/stable/): | ||
|
||
pip install -r requirements.txt | ||
|
||
|
||
## Running the sample | ||
|
||
You'll need to have an XMPP account prior to actually running the sample. | ||
If you do not have one, you can easily create an account at one of the many | ||
XMPP servers such as [Jabber.at](https://jabber.at/account/register/). | ||
Once you have an account, run the following command: | ||
|
||
python wikibot.py -j '<YOUR XMPP USERNAME>' -p '<PASSWORD>' | ||
|
||
Where the username (e.g., '[email protected]') and password for the account that | ||
you'd like to use for your chatbot are passed in as arguments. | ||
|
||
Enter control-Z to stop the server | ||
|
||
|
||
### Running on your local machine | ||
|
||
You may also run the sample locally by simply copying `wikibot.py` to a project | ||
directory and installing all python dependencies there. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Flask==0.11.1 | ||
requests==2.11.1 | ||
sleekxmpp==1.3.1 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
# Copyright 2016 Google Inc. All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Uncyclobot server example using SleekXMPP client library""" | ||
|
||
import json | ||
import logging | ||
from optparse import OptionParser | ||
import sys | ||
import threading | ||
import urllib | ||
|
||
from flask import Flask, request | ||
import requests | ||
import sleekxmpp | ||
|
||
# Python versions before 3.0 do not use UTF-8 encoding | ||
# by default. To ensure that Unicode is handled properly | ||
# throughout SleekXMPP, we will set the default encoding | ||
# ourselves to UTF-8. | ||
if sys.version_info < (3, 0): | ||
from sleekxmpp.util.misc_ops import setdefaultencoding | ||
setdefaultencoding('utf8') | ||
else: | ||
raw_input = input | ||
|
||
app = Flask(__name__) | ||
|
||
chat_client = None #this will be initialized when the wikibot is constructed | ||
|
||
@app.route('/send_message', methods=['GET']) | ||
def send_message(): | ||
try: | ||
recipient = request.args.get('recipient') | ||
message = request.args.get('message') | ||
except KeyError as e: | ||
logging.info('key error: {0}'.format(e)) | ||
|
||
if chat_client and recipient and message: | ||
chat_client.send_message(mto=recipient, mbody=message) | ||
return 'message sent to:' + recipient + ' with body:' + message | ||
else: | ||
logging.info('chat client or recipient or message does not exist!') | ||
return 'message failed to send' | ||
|
||
def run_server(): | ||
app.run(threaded=False, use_reloader=False, host='0.0.0.0') | ||
|
||
class UncycloBot(sleekxmpp.ClientXMPP): | ||
|
||
""" | ||
A simple SleekXMPP bot that will take messages, look up their content | ||
on wikipedia and provide a link to the page if it exists | ||
""" | ||
|
||
def __init__(self, jid, password): | ||
sleekxmpp.ClientXMPP.__init__(self, jid, password) | ||
|
||
# The session_start event will be triggered when | ||
# the bot establishes its connection with the server | ||
# and the XML streams are ready for use. We want to | ||
# listen for this event so that we we can initialize | ||
# our roster. | ||
self.add_event_handler('session_start', self.start) | ||
|
||
# The message event is triggered whenever a message | ||
# stanza is received. Be aware that that includes | ||
# MUC messages and error messages. | ||
self.add_event_handler('message', self.message) | ||
|
||
def start(self, event): | ||
""" | ||
Process the session_start event. | ||
Typical actions for the session_start event are | ||
requesting the roster and broadcasting an initial | ||
presence stanza. | ||
Arguments: | ||
event -- An empty dictionary. The session_start | ||
event does not provide any additional | ||
data. | ||
""" | ||
self.send_presence() | ||
self.get_roster() | ||
|
||
def message(self, msg): | ||
""" | ||
Process incoming message stanzas. Be aware that this also | ||
includes MUC messages and error messages. It is usually | ||
a good idea to check the messages's type before processing | ||
or sending replies. If the message is the appropriate type, | ||
then the bot checks wikipedia to see if the message string | ||
exists as a page on the site. If so, it sends this link back | ||
to the sender in the reply. | ||
Arguments: | ||
msg -- The received message stanza. See the SleekXMPP documentation | ||
for stanza objects and the Message stanza to see | ||
how it may be used. | ||
""" | ||
if msg['type'] in ('chat', 'normal'): | ||
msg_body = '%(body)s' % msg | ||
logging.info('Message sent was: ' + msg_body) | ||
encoded_body = urllib.quote_plus(msg_body) | ||
svr_response = requests.get('https://en.wikipedia.org/w/api.php?action=parse&prop=sections&format=json&page=' + encoded_body) | ||
doc = json.loads(svr_response.content) | ||
try: | ||
page_id = str(doc['parse']['pageid']) | ||
defn_url = 'https://en.wikipedia.org/?curid=' + page_id | ||
msg.reply("find out more about: '" + msg_body + "' here: " + defn_url).send() | ||
except KeyError as e: | ||
logging.info('key error: {0}'.format(e)) | ||
msg.reply("I wasn't able to locate info on: '" + msg_body + "' Sorry").send() | ||
|
||
|
||
|
||
|
||
if __name__ == '__main__': | ||
# Setup the command line arguments. | ||
optp = OptionParser() | ||
|
||
# Output verbosity options. | ||
optp.add_option('-q', '--quiet', help='set logging to ERROR', | ||
action='store_const', dest='loglevel', | ||
const=logging.ERROR, default=logging.INFO) | ||
optp.add_option('-d', '--debug', help='set logging to DEBUG', | ||
action='store_const', dest='loglevel', | ||
const=logging.DEBUG, default=logging.INFO) | ||
optp.add_option('-v', '--verbose', help='set logging to COMM', | ||
action='store_const', dest='loglevel', | ||
const=5, default=logging.INFO) | ||
|
||
# JID and password options. | ||
optp.add_option("-j", "--jid", dest="jid", | ||
help="JID to use") | ||
optp.add_option("-p", "--password", dest="password", | ||
help="password to use") | ||
|
||
opts, args = optp.parse_args() | ||
|
||
# Setup logging. | ||
logging.basicConfig(level=opts.loglevel, | ||
format='%(levelname)-8s %(message)s') | ||
|
||
|
||
# Setup the UncycloBot and register plugins. Note that while plugins may | ||
# have interdependencies, the order in which you register them does | ||
# not matter. | ||
xmpp = UncycloBot(opts.jid, opts.password) | ||
xmpp.register_plugin('xep_0030') # Service Discovery | ||
xmpp.register_plugin('xep_0004') # Data Forms | ||
xmpp.register_plugin('xep_0060') # PubSub | ||
xmpp.register_plugin('xep_0199') # XMPP Ping | ||
|
||
chat_client = xmpp # set the global variable | ||
|
||
# If you are connecting to Facebook and wish to use the | ||
# X-FACEBOOK-PLATFORM authentication mechanism, you will need | ||
# your API key and an access token. Then you'll set: | ||
# xmpp.credentials['api_key'] = 'THE_API_KEY' | ||
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN' | ||
|
||
# If you are connecting to MSN, then you will need an | ||
# access token, and it does not matter what JID you | ||
# specify other than that the domain is 'messenger.live.com', | ||
# so '[email protected]' will work. You can specify | ||
# the access token as so: | ||
# xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN' | ||
|
||
# If you are working with an OpenFire server, you may need | ||
# to adjust the SSL version used: | ||
# xmpp.ssl_version = ssl.PROTOCOL_SSLv3 | ||
|
||
# If you want to verify the SSL certificates offered by a server: | ||
# xmpp.ca_certs = "path/to/ca/cert" | ||
|
||
# start the app server and run it as a thread so that the XMPP server may also start | ||
threading.Thread(target=run_server).start() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer to have the web app start the xmpp server as a background thread, see here: http://stackoverflow.com/questions/14384739/how-can-i-add-a-background-thread-to-flask |
||
|
||
# Connect to the XMPP server and start processing XMPP stanzas. | ||
if xmpp.connect(): | ||
# If you do not have the dnspython library installed, you will need | ||
# to manually specify the name of the server if it does not match | ||
# the one in the JID. For example: | ||
# | ||
# if xmpp.connect(('<SERVER DOMAIN>.com', 5222)): | ||
# ... | ||
xmpp.process(block=True) | ||
print("Done") | ||
else: | ||
print("Unable to connect.") |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're using
.get
, there should never be aKeyError