Skip to content

Instantly share code, notes, and snippets.

@Terrance
Last active October 30, 2016 13:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Terrance/b5f2137bc5ce193194da7d9135f8db2d to your computer and use it in GitHub Desktop.
Save Terrance/b5f2137bc5ce193194da7d9135f8db2d to your computer and use it in GitHub Desktop.
Proof-of-concept web-based joining of Hangouts conversations, using Flask and hangups. Warning: in its current state, allows any user to be invited to any conversation available to the hangups user.
import asyncio
import os
import shlex
from threading import Thread
import time
from emoji import emojize
from flask import Flask, redirect, render_template, request, session, url_for
import hangups
from hangups import hangouts_pb2
from oauth2client.contrib.flask_util import UserOAuth2
class HangupsThread(Thread):
def __init__(self):
super(HangupsThread, self).__init__(daemon=True)
self.loop = asyncio.get_event_loop()
self.client = hangups.Client(hangups.auth.get_auth_stdin("data/hangups_token.txt"))
self.ready = False
def run(self):
asyncio.set_event_loop(self.loop)
self.client.on_connect.add_observer(self.on_connect)
self.client.on_reconnect.add_observer(self.on_connect)
self.client.on_disconnect.add_observer(self.on_disconnect)
print("[hangups] Connecting...")
self.loop.run_until_complete(self.client.connect())
def on_connect(self):
print("[hangups] Connected!")
asyncio.async(self.get_users_chats())
def on_disconnect(self):
print("[hangups] Disconnected. Retry in 5 seconds.")
self.ready = False
time.sleep(5)
print("[hangups] Reconnecting...")
self.loop.run_until_complete(self.client.connect())
@asyncio.coroutine
def get_users_chats(self):
print("[hangups] Fetching users and chats...")
self.users, self.chats = yield from hangups.conversation.build_user_conversation_list(self.client)
print("[hangups] Got users and chats.")
self.chats.on_event.add_observer(self.on_event)
self.ready = True
def on_event(self, event):
print("[hangups] Conversation got a {0}.".format(type(event).__name__))
if isinstance(event, hangups.ChatMessageEvent):
print("[hangups] Received text message:")
print(event.text)
print("-- EOF --")
self.parse_message(event.timestamp, event.user_id, event.conversation_id, event.text)
def parse_message(self, timestamp, user, chat, msg):
pass
@asyncio.coroutine
def invite_to_hangout(self, user, chat):
event_request_header = hangouts_pb2.EventRequestHeader(conversation_id=hangouts_pb2.ConversationId(id=chat),
client_generated_id=self.client.get_client_generated_id(),
expected_otr=hangouts_pb2.OFF_THE_RECORD_STATUS_ON_THE_RECORD)
request = hangouts_pb2.AddUserRequest(request_header=self.client.get_request_header(),
invitee_id=[hangouts_pb2.InviteeID(gaia_id=user)],
event_request_header=event_request_header)
print("[hangups] Inviting {0} to {1}.".format(user, chat))
yield from self.client.add_user(request)
print("[hangups] Invite sent.")
@asyncio.coroutine
def send_message(self, chat, msg):
message_content = hangouts_pb2.MessageContent(segment=[hangups.ChatMessageSegment(msg).serialize()])
event_request_header = hangouts_pb2.EventRequestHeader(conversation_id=hangouts_pb2.ConversationId(id=chat),
client_generated_id=self.client.get_client_generated_id())
request = hangouts_pb2.SendChatMessageRequest(request_header=self.client.get_request_header(),
message_content=message_content,
event_request_header=event_request_header)
print("[hangups] Sending message to {0}:".format(chat))
print(msg)
print("-- EOF --")
yield from self.client.send_chat_message(request)
print("[hangups] Message sent.")
app = Flask(__name__)
app.debug = True
app.secret_key = os.urandom(24)
app.config["GOOGLE_OAUTH2_CLIENT_SECRETS_FILE"] = "data/client_secrets.json"
oauth = UserOAuth2(app, access_type="online")
hup = HangupsThread()
hup.start()
@app.route("/")
def index():
return render_template("index.jinja2", creds=oauth.credentials)
@app.route("/login")
def login():
return redirect(oauth.authorize_url("/"))
@app.route("/logout")
def logout():
session.clear()
return redirect(url_for("index"))
@app.route("/join/<chat>")
@oauth.required
def join(chat):
if hup.ready:
asyncio.async(hup.invite_to_hangout(oauth.credentials.id_token["sub"], chat))
asyncio.async(hup.send_message(chat, emojize(":raising_hand: Invited {0} from website." \
.format(oauth.credentials.id_token["email"]), use_aliases=True)))
return render_template("join.jinja2", success=hup.ready)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment