Skip to content

Instantly share code, notes, and snippets.

@ericflo
Created November 12, 2009 20:18
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 ericflo/233239 to your computer and use it in GitHub Desktop.
Save ericflo/233239 to your computer and use it in GitHub Desktop.
from uuid import uuid1
from simplejson import dumps, loads
from urlparse import urlparse
from httplib import HTTPConnection
class Client(object):
def __init__(self, server):
self.server = server
url_parts = urlparse(server)
self.port = url_parts.port
self.host, _, _ = url_parts.netloc.partition(':')
self.headers = {'Content-Type': 'application/json'}
def __getattr__(self, obj):
return self._request(obj)
def _request(self, method):
def _inner(*args, **kwargs):
data = dumps({
'id': str(uuid1()),
'method': method,
'args': args,
'kwargs': kwargs,
})
conn = HTTPConnection(self.host, self.port)
conn.request('POST', '/', data, self.headers)
response = conn.getresponse().read()
decoded_response = loads(response)
conn.close()
error = decoded_response.get('error')
if error is not None:
raise ValueError(error)
return decoded_response.get('result')
return _inner
import sys
import traceback
from simplejson import dumps, loads
from werkzeug import Request, Response
from werkzeug.exceptions import HTTPException, NotFound, BadRequest
def create_app(methods=None):
methods = methods or {}
@Request.application
def application(request):
try:
# Parse the JSON in the request
try:
data = loads(request.stream.read())
except ValueError:
raise BadRequest()
# Grab the function to execute
try:
method = methods.get(data['method'])
except (KeyError, IndexError):
raise BadRequest()
if method is None:
raise NotFound()
# Get the args and kwargs
args = data.get('args', [])
kwargs = data.get('kwargs', {})
kwargs = dict(((k.encode('utf-8'), v) for k, v in kwargs.iteritems()))
# Attempt to call the method with the params, or catch the
# exception and pass that back to the client
try:
response = Response(dumps({
'id': data.get('id'),
'result': method(*args, **kwargs),
}))
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
print e
response = Response(dumps({
'id': data.get('id'),
'error': ''.join(traceback.format_exception(*sys.exc_info())),
}))
# Finish up and return the response
response.headers['Content-Type'] = 'application/json'
response.headers['Content-Length'] = len(response.data)
response.status_code = 200
return response
except HTTPException, e:
# If an http exception is caught we can return it as response
# because those exceptions render standard error messages when
# called as wsgi application.
return e
return application
def run_server(app, port):
from cherrypy import wsgiserver
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', port), app,
numthreads=10)
try:
server.start()
except KeyboardInterrupt:
server.stop()
import datetime
import struct
import tc
import time
from struct import pack
from simplejson import dumps, loads
DBNAME = '/var/tokyocabinet/plays.bdb'
TS_LENGTH = 16
MAX_TS = 9999999999999999
NINES = '9' * TS_LENGTH
ZEROES = '0' * TS_LENGTH
from rpcutils import create_app, run_server
DB = None
def _get_db():
global DB
if DB is None:
DB = tc.BDB(DBNAME, tc.TDBOWRITER | tc.TDBOCREAT)
return DB
def add_play(game_id, user_id, date, fb, session_key=None):
db = _get_db()
ts = str(MAX_TS - int(time.time() * 1e6)).zfill(TS_LENGTH)
keys = (
'all-%s' % (ts,),
'user-%s-%s' % (str(user_id).zfill(TS_LENGTH), ts),
'game-%s-%s' % (str(game_id).zfill(TS_LENGTH), ts),
)
doc = dumps({
'game_id': game_id,
'session_key': session_key,
'user_id': user_id,
'fb': fb,
'date': date,
})
for key in keys:
db.put(key, doc)
count_key = 'playcount-%s' % (game_id,)
try:
db.putkeep(count_key, struct.pack('i', 1))
except tc.Error:
db.addint(count_key, 1)
day_count_key = 'playcount-%s-%s' % (game_id, date.split()[0])
try:
db.putkeep(day_count_key, struct.pack('i', 1))
except tc.Error:
db.addint(day_count_key, 1)
return True
def get_plays_for_game(game_id, fb_only=False, limit=20):
db = _get_db()
game_id = str(game_id).zfill(TS_LENGTH)
b = 'game-%s-%s' % (game_id, ZEROES)
e = 'game-%s-%s' % (game_id, NINES)
resp = map(loads, [db[k] for k in db.range(b, False, e, True, limit)])
if fb_only:
resp = filter(lambda x: x['fb'], resp)
return resp
def get_plays_for_user(user_id, fb_only=False, limit=20):
db = _get_db()
user_id = str(user_id).zfill(TS_LENGTH)
b = 'user-%s-%s' % (user_id, ZEROES)
e = 'user-%s-%s' % (user_id, NINES)
resp = map(loads, [db[k] for k in db.range(b, False, e, True, limit)])
if fb_only:
resp = filter(lambda x: x['fb'], resp)
return resp
def get_plays(limit=20, fb_only=False):
db = _get_db()
b = 'all-%s' % (ZEROES,)
e = 'all-%s' % (NINES,)
resp = map(loads, [db[k] for k in db.range(b, False, e, True, limit)])
if fb_only:
resp = filter(lambda x: x['fb'], resp)
return resp
def get_counts_for_game(game_id):
db = _get_db()
count_key = 'playcount-%s' % (game_id,)
try:
count = struct.unpack('i', db[count_key])[0]
except KeyError:
count = 0
today = datetime.date.today()
last_week = today - datetime.timedelta(days=7)
last_month = today - datetime.timedelta(days=30)
week_count = 0
month_count = 0
day = last_month
while day <= today:
day_count_key = 'playcount-%s-%s' % (game_id, day.strftime('%Y-%m-%d'))
try:
day_count = struct.unpack('i', db[day_count_key])[0]
except KeyError:
day_count = 0
month_count += day_count
if day >= last_week:
week_count += day_count
day += datetime.timedelta(days=1)
return {
'week': week_count,
'month': month_count,
'alltime': count,
}
application = create_app({
'add_play': add_play,
'get_plays_for_game': get_plays_for_game,
'get_plays_for_user': get_plays_for_user,
'get_plays': get_plays,
'get_counts_for_game': get_counts_for_game,
})
if __name__ == '__main__':
run_server(application, 4000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment