diff --git a/issue92001_42002_52002_wsgi_protocol.diff b/issue92001_42002_52002_wsgi_protocol.diff new file mode 100644 index 0000000..7c8073e --- /dev/null +++ b/issue92001_42002_52002_wsgi_protocol.diff @@ -0,0 +1,104 @@ +Index: trytond/protocols/wsgi/__init__.py +=================================================================== +new file mode 100644 +--- /dev/null ++++ b/trytond/trytond/protocols/wsgi/__init__.py +@@ -0,0 +1,98 @@ ++# This file is part of Tryton. The COPYRIGHT file at the top level of ++# this repository contains the full copyright notices and license terms. ++import sys ++import json ++import traceback ++import StringIO ++import gzip ++from BaseHTTPServer import BaseHTTPRequestHandler, DEFAULT_ERROR_MESSAGE ++from trytond.protocols.jsonrpc import JSONDecoder, JSONEncoder ++from trytond.protocols.dispatcher import dispatch ++from trytond.config import config ++from trytond.pool import Pool ++from trytond.exceptions import UserError, UserWarning, NotLogged, \ ++ ConcurrencyException ++ ++ ++def get_jsonrpc_app(): ++ config.update_etc() ++ ++ Pool.start() ++ ++ def f(environ, start_response): ++ 'JSON-RPC dispatcher' ++ def error_response(code): ++ message, explain = BaseHTTPRequestHandler.responses[code] ++ start_response('%d %s' % (code, message), ++ [('Content-Type', 'text/html')]) ++ return [DEFAULT_ERROR_MESSAGE % locals()] ++ ++ if environ['REQUEST_METHOD'] == 'POST': ++ body = '' ++ try: ++ length = int(environ.get('CONTENT_LENGTH', '0')) ++ except ValueError: ++ length = 0 ++ body = environ['wsgi.input'].read(length) ++ if environ.get('HTTP_CONTENT_ENCODING') == 'gzip': ++ f = StringIO.StringIO(body) ++ gzf = gzip.GzipFile(mode="rb", fileobj=f) ++ try: ++ decoded = gzf.read() ++ except IOError: ++ return error_response(400) ++ f.close() ++ gzf.close() ++ body = decoded ++ try: ++ rawreq = json.loads(body, object_hook=JSONDecoder()) ++ except ValueError: ++ return error_response(501) ++ req_id = rawreq.get('id', 0) ++ method = rawreq['method'] ++ params = rawreq.get('params', []) ++ ++ response = {'id': req_id} ++ database_name = environ['PATH_INFO'][1:] ++ if database_name.startswith('sao/'): ++ database_name = database_name[4:] ++ method_list = method.split('.') ++ object_type = method_list[0] ++ object_name = '.'.join(method_list[1:-1]) ++ method = method_list[-1] ++ args = ( ++ environ['SERVER_NAME'], ++ int(environ['SERVER_PORT']), ++ 'JSON-RPC', ++ database_name, ++ params[0], ++ params[1], ++ object_type, ++ object_name, ++ method ++ ) + tuple(params[2:]) ++ try: ++ response['result'] = dispatch(*args) ++ except (UserError, UserWarning, NotLogged, ++ ConcurrencyException), exception: ++ response['error'] = exception.args ++ except Exception: ++ tb_s = ''.join(traceback.format_exception(*sys.exc_info())) ++ for path in sys.path: ++ tb_s = tb_s.replace(path, '') ++ # report exception back to server ++ response['error'] = (str(sys.exc_value), tb_s) ++ ++ start_response('200 OK', ++ [('Content-Type', 'application/json-rpc')]) ++ return [json.dumps(response, cls=JSONEncoder)] ++ else: ++ return error_response(501) ++ return f ++ ++ ++if __name__ == '__main__': ++ from wsgiref.simple_server import make_server ++ jsonrpc_app = get_jsonrpc_app() ++ httpd = make_server('', 8000, jsonrpc_app) ++ httpd.serve_forever() diff --git a/series b/series index 6274101..db942e8 100644 --- a/series +++ b/series @@ -40,10 +40,12 @@ issue10091002_1.diff issue9911002_80001.diff issue6021003_1.diff issue6951002_20001.diff +issue92001_42002_52002_wsgi_protocol.diff check-vies-issue12101002.patch stock_supply_production-performance-improvement.diff +top.diff issue15211002-sale-confirmed-to-done.diff purchase_translation.diff diff --git a/top.diff b/top.diff new file mode 100644 index 0000000..28d05ca --- /dev/null +++ b/top.diff @@ -0,0 +1,131 @@ +diff -r 649b0805fa93 trytond/protocols/dispatcher.py +--- a/trytond/trytond/protocols/dispatcher.py Fri Feb 20 09:11:59 2015 +0100 ++++ b/trytond/trytond/protocols/dispatcher.py Sun Apr 19 03:17:46 2015 +0200 +@@ -19,6 +19,8 @@ + ConcurrencyException + from trytond.rpc import RPC + ++import top ++ + logger = logging.getLogger(__name__) + + ir_configuration = Table('ir_configuration') +@@ -153,6 +155,16 @@ + with Transaction().start(database_name, user, + readonly=rpc.readonly) as transaction: + Cache.clean(database_name) ++ action_id = top.add({ ++ 'host': host, ++ 'port': port, ++ 'protocol': protocol, ++ 'database_name': database_name, ++ 'user': user, ++ 'object_name': object_name, ++ 'method': method, ++ 'args': repr(args)[:30], ++ }) + try: + c_args, c_kwargs, transaction.context, transaction.timestamp \ + = rpc.convert(obj, *args, **kwargs) +@@ -182,6 +194,8 @@ + logger.error(exception_message, exc_info=sys.exc_info()) + transaction.cursor.rollback() + raise ++ finally: ++ top.remove(action_id) + Cache.resets(database_name) + with Transaction().start(database_name, 0) as transaction: + pool = Pool(database_name) +diff -r 649b0805fa93 trytond/protocols/top.py +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ b/trytond/trytond/protocols/top.py Sun Apr 19 03:18:20 2015 +0200 +@@ -0,0 +1,89 @@ ++import random ++import signal ++import locale ++import sys ++from operator import itemgetter ++from datetime import datetime ++ ++current_actions = {} ++action_id = 0 ++ ++# Start Printing Tables ++# http://ginstrom.com/scribbles/2007/09/04/pretty-printing-a-table-in-python/ ++ ++def format_num(num): ++ """Format a number according to given places. ++ Adds commas, etc. Will truncate floats into ints!""" ++ ++ try: ++ inum = int(num) ++ return locale.format("%.*f", (0, inum), True) ++ ++ except (ValueError, TypeError): ++ return str(num) ++ ++def get_max_width(table, index): ++ """Get the maximum width of the given column index""" ++ return max([len(format_num(row[index])) for row in table]) ++ ++def pprint_table(table): ++ """ ++ Prints out a table of data, padded for alignment ++ @param table: The table to print. A list of lists. ++ Each row must have the same number of columns. ++ """ ++ col_paddings = [] ++ ++ for i in range(len(table[0])): ++ col_paddings.append(get_max_width(table, i)) ++ ++ for row in table: ++ # left col ++ print row[0].ljust(col_paddings[0] + 1), ++ # rest of the cols ++ for i in range(1, len(row)): ++ col = format_num(row[i]).ljust(col_paddings[i] + 2) ++ print col, ++ print ++ ++# End Printing Tables ++ ++def signal_user_handler(signal, frame): ++ print '-' * 30 ++ if current_actions: ++ key = current_actions.keys()[0] ++ header = sorted(current_actions[key].keys()) ++ header = ('id', 'database_name', 'user', 'protocol', 'host', 'port', ++ 'timestamp', 'elapsed', 'object_name', 'method', 'args') ++ table = [] ++ table.append([x.upper() for x in header]) ++ ++ for action in sorted(current_actions.values(), key=itemgetter('timestamp')): ++ row = [] ++ for key in header: ++ value = action.get(key, '') ++ if key == 'elapsed': ++ value = (datetime.now() - action['timestamp']).total_seconds() ++ if isinstance(value, datetime): ++ value = value.ctime() ++ row.append(value) ++ table.append(row) ++ pprint_table(table) ++ print '=' * 30 ++ ++signal.signal(signal.SIGUSR1, signal_user_handler) ++ ++ ++def add(value): ++ action_id = new_id() ++ value['timestamp'] = datetime.now() ++ value['elapsed'] = None ++ value['id'] = str(action_id) ++ current_actions[action_id] = value ++ return action_id ++ ++def remove(action_id): ++ del current_actions[action_id] ++ ++def new_id(): ++ return random.randint(0, 999999)