Skip to content

Instantly share code, notes, and snippets.

@karno
Created September 16, 2015 15:12
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 karno/88a98895f782fd0bd7ba to your computer and use it in GitHub Desktop.
Save karno/88a98895f782fd0bd7ba to your computer and use it in GitHub Desktop.
Masquerade system server program
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import io
import re
import threading
import time
from twitter import *
from config import *
from masquerade import *
def server_process():
# overwrite output encoding
auth = OAuth(
config['token']['key'],
config['token']['secret'],
config['consumer']['key'],
config['consumer']['secret'])
api = Twitter(auth=auth)
curprofkey = get_current_prof_key(api)
if curprofkey is None:
curprofkey = config['profiles'][0]['key']
print('* current profile is ' + curprofkey)
# backoff interval is 5 upto 320 (sec)
backoff = 5
shutdown = False
streamer = TwitterStream(domain='userstream.twitter.com', auth=auth)
while not shutdown:
try:
for status in streamer.user():
backoff = 5
if "text" in status and "retweeted_status" not in status:
# tweet (not retweet) received
if status['user']['screen_name'] in config['accept_accounts']:
# tweet from acceptable account
print_safely('accept:' + status['user']['screen_name'] + ': ' + status['text'])
text = status['text']
# process tweet
fired = False
# stage 1 - simple trigger
for pattern, key in config['simple_trigger'].items():
if re.match(pattern, text):
curprofkey = key
switch_profile_async(key)
fired = True
break
if fired:
continue
# stage 2 - global trigger
for pattern in config['global_trigger']:
result = re.match(pattern, text)
if result:
gd = result.groupdict()
for prof in config['profiles']:
# check global_trigger_key existence
if 'global_trigger_key' not in prof:
continue
# check global_trigger_key all contains required keys
gtkeys = prof['global_trigger_key']
for key, value in gd.items():
if key not in gtkeys or gtkeys[key] != value:
break
else:
# fired!
curprofkey = prof['key']
switch_profile_async(prof['key'])
fired = True
break
if fired:
break # the profile loop
if fired:
continue
# before stage 3, 4 - check existence of currrent profile key
curprof = None
for prof in config['profiles']:
if prof['key'] == curprofkey:
curprof = prof
break
else:
continue
# stage 3 - local trigger
if 'local_trigger' in curprof:
for pattern, key in curprof['local_trigger'].items():
if re.match(pattern, text):
curprofkey = key
switch_profile_async(key)
fired = True
break
if fired:
continue
# stage 4 - intro trigger
if 'intro' in curprof and curprof['intro'] is not None and \
'intro_trigger' in curprof:
for pattern in curprof['intro_trigger']:
if re.match(pattern, text):
print('tweeting introduction...')
api.statuses.update(status=curprof['intro'])
break
except KeyboardInterrupt:
shutdown = True
except:
print('user-stream error: ' + str(sys.exc_info()))
print('user-stream disconnected. try to reconnect...')
time.sleep(backoff)
backoff = backoff * backoff;
if backoff > 320:
backoff = 320
print('shutting down...')
def print_safely(text: str):
try:
print(text)
except (UnicodeEncodeError, UnicodeDecodeError):
print('contains unicode error')
def get_current_prof_key(api: Twitter):
""" get current profile, or default """
# acquire recent status of user's
try:
timeline = api.statuses.user_timeline(count=1)
user = timeline[0]['user']
targets = config['profile_match_key']
for prof in config['profiles']:
for target in targets:
if target not in user or target not in prof:
continue
if user[target] != prof[target]:
break
else:
return prof['key']
except:
# fail to acquision recent tweet
print("fail to acquire user's tweet.")
return None
def switch_profile_async(key: str):
switcher = AsyncProfSwitcher(key)
switcher.start()
class AsyncProfSwitcher(threading.Thread):
""" update twitter profile asynchronously. """
def __init__(self, key: str):
super(AsyncProfSwitcher, self).__init__()
self.key = key
def run(self):
switch_profile(self.key)
if __name__ == '__main__':
server_process()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment