├── swift_rpc ├── __init__.py ├── serialize.py ├── log.py ├── aeslib.py ├── rsalib.py ├── mq.py ├── server │ ├── __init__.py │ └── handlers.py └── client │ └── __init__.py ├── .gitignore ├── api.py ├── test_client.py ├── multi_rqworker.py ├── setup.py ├── LICENSE.txt ├── test_server.py ├── config.py └── README.md /swift_rpc/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | dist 4 | swift_rpc.egg-info/ 5 | -------------------------------------------------------------------------------- /swift_rpc/serialize.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import msgpack 3 | 4 | def serialize(source, default=lambda x: x.to_msgpack()): 5 | return msgpack.packb(source, default=default) 6 | 7 | def deserialize(source): 8 | return msgpack.unpackb(source) 9 | -------------------------------------------------------------------------------- /api.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import time 3 | def go(*args,**kwargs): 4 | print 'this go func in MQ' 5 | return "You said " 6 | 7 | def test_mq(*args,**kwargs): 8 | time.sleep(10) 9 | print 'mq...' 10 | return "You said " 11 | 12 | __all__ = ('go','test_mq') 13 | -------------------------------------------------------------------------------- /test_client.py: -------------------------------------------------------------------------------- 1 | from swift_rpc.client import RPCClient 2 | 3 | client = RPCClient('localhost:8080',encryption='aes',encryption_key='123xiaorui456789') 4 | print client.test('hi') 5 | print client.test_args('welcome','xiaorui.cc',name='nima') 6 | 7 | client = RPCClient('localhost:8080',encryption='base64') 8 | print client.test('hi') 9 | print client.test_args('welcome','xiaorui.cc',name='nima') 10 | -------------------------------------------------------------------------------- /swift_rpc/log.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import logging 3 | 4 | def get_logger(LOGFILE): 5 | logger = logging.getLogger('mylogger') 6 | logger.setLevel(logging.DEBUG) 7 | fh = logging.FileHandler(LOGFILE) 8 | fh.setLevel(logging.DEBUG) 9 | ch = logging.StreamHandler() 10 | ch.setLevel(logging.DEBUG) 11 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 12 | fh.setFormatter(formatter) 13 | ch.setFormatter(formatter) 14 | logger.addHandler(fh) 15 | logger.addHandler(ch) 16 | return logger 17 | 18 | logger = get_logger('debug.log') 19 | 20 | -------------------------------------------------------------------------------- /multi_rqworker.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import sys 4 | import signal 5 | import redis 6 | import multiprocessing 7 | from rq import Worker, Queue, Connection 8 | listen = ['high', 'default', 'low'] 9 | redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379') 10 | conn = redis.from_url(redis_url) 11 | 12 | def sigint_handler(signum,frame): 13 | for i in pid_list: 14 | os.kill(i,signal.SIGKILL) 15 | logging.info("exit...") 16 | sys.exit() 17 | 18 | def worker(): 19 | logging.info('this is worker') 20 | with Connection(conn): 21 | worker = Worker(map(Queue, listen)) 22 | worker.work() 23 | 24 | pid_list = [] 25 | signal.signal(signal.SIGINT,sigint_handler) 26 | if __name__ == '__main__': 27 | pool = multiprocessing.Pool(processes=4) 28 | for i in xrange(3): 29 | pool.apply_async(worker,) 30 | for i in multiprocessing.active_children(): 31 | pid_list.append(i.pid) 32 | pid_list.append(os.getpid()) 33 | pool.close() 34 | pool.join() 35 | -------------------------------------------------------------------------------- /swift_rpc/aeslib.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import sys 3 | from Crypto.Cipher import AES 4 | from binascii import b2a_hex, a2b_hex 5 | 6 | class prpcrypt(): 7 | def __init__(self, key): 8 | self.key = key 9 | self.mode = AES.MODE_CBC 10 | 11 | def encrypt(self, text): 12 | cryptor = AES.new(self.key, self.mode, self.key) 13 | length = 16 14 | count = len(text) 15 | add = length - (count % length) 16 | text = text + ('\0' * add) 17 | self.ciphertext = cryptor.encrypt(text) 18 | return b2a_hex(self.ciphertext) 19 | 20 | def decrypt(self, text): 21 | cryptor = AES.new(self.key, self.mode, self.key) 22 | plain_text = cryptor.decrypt(a2b_hex(text)) 23 | return plain_text.rstrip('\0') 24 | 25 | if __name__ == '__main__': 26 | pc = prpcrypt('123xiaorui456789') 27 | e = pc.encrypt("00000") 28 | d = pc.decrypt(e) 29 | print e, d 30 | e = pc.encrypt("welcome to mysql blog, xiaorui.cc") 31 | d = pc.decrypt(e) 32 | print e, d 33 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import os 3 | from setuptools import setup, find_packages 4 | 5 | def read(fname): 6 | return open(os.path.join(os.path.dirname(__file__), fname)).read() 7 | 8 | setup( 9 | name = "swift_rpc", 10 | version = "2.5", 11 | author = "ruifengyun", 12 | author_email = "rfyiamcool@163.com", 13 | description = "tornado rpc", 14 | license = "MIT", 15 | keywords = ["tornado","fengyun"], 16 | url = "https://github.com/rfyiamcool", 17 | packages = find_packages(), 18 | long_description = read('README.md'), 19 | install_requires=['ConfigParser','redis','rq','msgpack-python'], 20 | classifiers = [ 21 | 'Development Status :: 2 - Pre-Alpha', 22 | 'Intended Audience :: Developers', 23 | 'License :: OSI Approved :: MIT License', 24 | 'Programming Language :: Python :: 2.7', 25 | 'Programming Language :: Python :: 3.0', 26 | 'Topic :: Software Development :: Libraries :: Python Modules', 27 | ] 28 | ) 29 | 30 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 fengyun rui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /swift_rpc/rsalib.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import rsa 3 | 4 | def create_key(): 5 | (pubkey, privkey) = rsa.newkeys(1024) 6 | pub = pubkey.save_pkcs1() 7 | pubfile = open('public.pem','w+') 8 | pubfile.write(pub) 9 | pubfile.close() 10 | 11 | pri = privkey.save_pkcs1() 12 | prifile = open('private.pem','w+') 13 | prifile.write(pri) 14 | prifile.close() 15 | 16 | def load_public(): 17 | with open('public.pem') as publickfile: 18 | p = publickfile.read() 19 | pubkey = rsa.PublicKey.load_pkcs1(p) 20 | return pubkey 21 | 22 | def load_private(): 23 | with open('private.pem') as privatefile: 24 | p = privatefile.read() 25 | privkey = rsa.PrivateKey.load_pkcs1(p) 26 | return privkey 27 | 28 | def encrypt(message): 29 | crypto = rsa.encrypt(message, pubkey) 30 | return crypto 31 | 32 | def decrypt(crypto): 33 | message = rsa.decrypt(crypto, privkey) 34 | return message 35 | 36 | pubkey = load_public() 37 | privkey = load_private() 38 | 39 | if __name__ == "__main__": 40 | message = 'hello' 41 | en_str = encrypt(message) 42 | print en_str 43 | print decrypt(en_str) 44 | -------------------------------------------------------------------------------- /test_server.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import sys 3 | reload(sys) 4 | sys.setdefaultencoding("utf-8") 5 | 6 | import time 7 | from tornado import gen 8 | from swift_rpc.server import RPCServer 9 | from swift_rpc.mq import rq_conn 10 | from swift_rpc.mq import redis_conn 11 | from swift_rpc.mq import fetch 12 | from config import * 13 | import config 14 | from api import * 15 | 16 | def test(args): 17 | return "this is test %s"%(args) 18 | 19 | def test_args(a,b,name='xiaorui.cc'): 20 | print a,b,name 21 | return "this is test %s %s"%(a,name) 22 | 23 | def get_result(job_id): 24 | return redis_conn.hgetall(job_id) 25 | 26 | def test_block(args): 27 | time.sleep(5) 28 | return "You said " 29 | 30 | @gen.coroutine 31 | def test_async(arg): 32 | return gen.Return("this is test_async async %s" % arg) 33 | 34 | if __name__ == "__main__": 35 | server = RPCServer(config) 36 | server.register(test) 37 | server.register(test_args) 38 | server.register(get_result) 39 | server.register_async(test_async) 40 | server.register_pool(test_block) 41 | server.register_mq(test_mq) 42 | server.register_mq(go) 43 | server.start(RPC_HOST,RPC_PORT) 44 | -------------------------------------------------------------------------------- /swift_rpc/mq.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | from serialize import serialize, deserialize 3 | from config import * 4 | from rq import Queue 5 | from rq.job import Job 6 | import redis 7 | 8 | class MessageQueue(object): 9 | 10 | def __init__(self, host, port): 11 | self._conn = redis.Redis(connection_pool=redis.BlockingConnectionPool(max_connections=15, host=host, port=port)) 12 | 13 | def set(self,k,v): 14 | self._conn.set(k,v) 15 | 16 | def get(self,k): 17 | return self._conn.get(k) 18 | 19 | def push(self, queue, msg): 20 | self._conn.rpush(queue, serialize(msg)) 21 | 22 | def spop(self, queue): 23 | msg = self._conn.spop(queue) 24 | return deserialize(msg) if msg else msg 25 | 26 | def pushleft(self, queue, msg): 27 | self._conn.lpush(queue, serialize(msg)) 28 | 29 | def llen(self,k): 30 | return self._conn.llen(k) 31 | 32 | def keys(self, pattern="*"): 33 | return self._conn.keys(pattern) 34 | 35 | redis_conn = MessageQueue(REDIS_HOST,REDIS_PORT)._conn 36 | rq_conn = Queue(connection=redis_conn) 37 | fetch = Job.fetch 38 | 39 | if __name__ == "__main__": 40 | job_id = 'rq:job:d65aade8-5304-48d3-8477-9ac16f7cefd8' 41 | job_id = job_id.split(':')[2] 42 | res = fetch(job_id.decode("utf-8", "ignore"),redis_conn) 43 | print res.to_dict() 44 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | 3 | REDIS_HOST = '127.0.0.1' 4 | REDIS_PORT = 6379 5 | 6 | RPC_HOST = '127.0.0.1' 7 | RPC_PORT = 8080 8 | 9 | SAFE_UA_MODE = True 10 | UA_ALLOW = ['swift_rpc'] 11 | 12 | SAFE_TOKEN_MODE = False 13 | TOKEN_ALLOW = [''] 14 | 15 | REMOTE_IP_MODE = False 16 | REMOTE_ALLOW = [''] 17 | 18 | ENCRYPTION_AES= "123xiaorui456789" 19 | 20 | LOGCONFIG = { 21 | "version": 1, 22 | "disable_existing_loggers": False, 23 | "formatters": { 24 | "simple": { 25 | "format": "%(asctime)s %(name)-15s %(levelname)-8s %(processName)-10s %(message)s" 26 | }, 27 | "detail": { 28 | "format": "[%(asctime)s] [%(levelname)s] [%(name)s] [%(funcName)s():%(lineno)s] [PID:%(process)d TID:%(thread)d] %(message)s" 29 | } 30 | }, 31 | 32 | "handlers": { 33 | "console": { 34 | "class": "logging.StreamHandler", 35 | "level": "DEBUG", 36 | "formatter": "detail", 37 | "stream": "ext://sys.stdout" 38 | }, 39 | 'file': { 40 | 'class': 'logging.handlers.RotatingFileHandler', 41 | 'level': 'INFO', 42 | 'formatter': 'simple', 43 | 'filename': 'debug.log', 44 | 'mode': 'a', 45 | 'maxBytes': 10485760, 46 | 'backupCount': 5, 47 | }, 48 | 49 | }, 50 | 51 | "loggers": { 52 | "transmit": { 53 | "level":"DEBUG", 54 | "propagate": False, 55 | "handlers": ["console","file"] 56 | }, 57 | }, 58 | 59 | "root": { 60 | "level": "INFO", 61 | "handlers": ["console","file"] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /swift_rpc/server/__init__.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | from tornado import ( 3 | gen, 4 | ioloop, 5 | log, 6 | web 7 | ) 8 | 9 | from tornado.httpserver import HTTPServer 10 | from .handlers import _AsyncBase, _Base, _ThreadPoolBase, _MessageQueueBase 11 | from swift_rpc.log import get_logger 12 | 13 | class RPCServer(object): 14 | 15 | def __init__(self,config): 16 | self.config = config 17 | self._routes = [] 18 | self.log = log.logging.getLogger("transmit.%s" % __name__) 19 | log.logging.config.dictConfig(config.LOGCONFIG) 20 | #log.enable_pretty_logging(logger=self.log) 21 | self.register_async(self._getroutes) 22 | 23 | @gen.coroutine 24 | def _getroutes(self): 25 | raise gen.Return([v.__name__ for _, v in self._routes]) 26 | 27 | def _make(self, func, base): 28 | name = func.__name__ 29 | handler = type(name, (base,), {'func': [func],'config':self.config}) 30 | self._routes.append((r'/{0}'.format(name), handler)) 31 | self.log.info('Registered {0} command {1}'.format(base.TYPE, name)) 32 | 33 | def register(self, func): 34 | self._make(func, _Base) 35 | 36 | def register_async(self, func): 37 | self._make(func, _AsyncBase) 38 | 39 | def register_pool(self, func): 40 | self._make(func, _ThreadPoolBase) 41 | 42 | def register_mq(self, func): 43 | self._make(func, _MessageQueueBase) 44 | 45 | def start(self, host, port): 46 | self.log.info('Starting server on port {0}'.format(port)) 47 | # app = web.Application(self._routes, debug=True) 48 | server = HTTPServer(web.Application(self._routes, debug=True),xheaders=True) 49 | server.listen(int(port), host) 50 | ioloop.IOLoop.current().start() 51 | 52 | __all__ = ('RPCServer') 53 | 54 | if __name__ == "__main__": 55 | pass 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # swift_rpc 2 | 3 | swift_rpc是用tornado实现的rpc服务,而且支持多种方式加密传输, 现在开放了四个调度接口: 4 | 5 | 1. register 普通接口调用模式,最纯粹最简单 6 | 2. register_async 借助于tornado gen.coroutine实现的非堵塞调用 7 | 3. register_pool 借助于futures.ThreadPoolExecutor实现线程池 8 | 4. register_mq 通过mq异步调用方法,适合后端长时间运算或耗时的调用 9 | 10 | [更多的关于swift的开发信息](http://xiaorui.cc) 11 | 12 | # TO DO 13 | 1. 加入jwt认证机制 14 | 15 | Change Log: 16 | 17 | Version: 2.1 18 | 1. 解决Nginx针对RPC负载均衡时,无法正常获取remote_ip 19 | 20 | Version: 2.2 21 | 1. rq enqueue塞入任务队列时的一个bug,已经绕过解决 22 | 23 | Version: 2.3 24 | 1. 解决了curl调用rq的get_result时出现的0x80 code异常 25 | 26 | Version: 2.4 27 | 1. 日志及加密模式 28 | 29 | Version: 2.5 30 | 1. 加入自定义的AES加密算法支持 31 | 32 | Future: 33 | 1. json web token和rsa组合 34 | 2. 完善文档 35 | 36 | 37 | 测试json body的args,kwargs: 38 | ``` 39 | curl -H "Content-Type: application/json" -H "User-Agent: swift_rpc" -X GET -d '{"args":"[123,456]","kwargs":{"name":1}}' http://localhost:8080/test_args 40 | curl -H "Content-Type: application/json" -H "User-Agent: swift_rpc" -X GET -d '{"args":"123"}' http://localhost:8080/test 41 | ``` 42 | 43 | 测试选择加密模式: 44 | ``` 45 | curl -H "Encryption: base64" -H "Content-Type: application/json" -H "User-Agent: swift_rpc" -X GET -d '{"args": [123, 456], "kwargs": {"name": 1}}' http://localhost:8080/test_args 46 | ``` 47 | 48 | 测试arguments的args,kwargs: 49 | ``` 50 | curl -H "User-Agent: swift_rpc" -X GET -d "args=123" http://localhost:8080/test 51 | ``` 52 | 53 | Tornado RPC Server Usage: 54 | 55 | ``` 56 | #coding:utf-8 57 | import sys 58 | reload(sys) 59 | sys.setdefaultencoding("utf-8") 60 | 61 | import time 62 | from tornado import gen 63 | from swift_rpc.server import RPCServer 64 | from swift_rpc.mq import rq_conn 65 | from swift_rpc.mq import redis_conn 66 | from swift_rpc.mq import fetch 67 | from config import * 68 | from api import * 69 | 70 | def test(args): 71 | return "this is test %s"%(args) 72 | 73 | def test_args(a,b,name='xiaorui.cc'): 74 | print a,b,name 75 | return "this is test %s %s"%(a,name) 76 | 77 | def get_result(job_id): 78 | return redis_conn.hgetall(job_id) 79 | 80 | def test_block(args): 81 | time.sleep(5) 82 | return "You said " 83 | 84 | @gen.coroutine 85 | def test_async(arg): 86 | return gen.Return("this is test_async async %s" % arg) 87 | 88 | if __name__ == "__main__": 89 | server = RPCServer() 90 | server.register(test) 91 | server.register(test_args) 92 | server.register(get_result) 93 | server.register_async(test_async) 94 | server.register_pool(test_block) 95 | server.register_mq(test_mq) 96 | server.register_mq(go) 97 | server.start(RPC_HOST,RPC_PORT) 98 | ``` 99 | 100 | swift_rpc client Usage: 101 | 102 | ``` 103 | from swift_rpc.client import RPCClient 104 | 105 | client = RPCClient('localhost:8080') 106 | print client.test('hi') 107 | print client.test_args('welcome','xiaorui.cc',name='nima') 108 | ``` 109 | 110 | 111 | -------------------------------------------------------------------------------- /swift_rpc/client/__init__.py: -------------------------------------------------------------------------------- 1 | import json 2 | import base64 3 | import requests 4 | from urlparse import urljoin 5 | from swift_rpc.aeslib import prpcrypt 6 | 7 | class _RPC(object): 8 | 9 | def __init__(self, server, name, encryption, encryption_key): 10 | self.encryption = encryption 11 | self.encryption_key = encryption_key 12 | self.__HEADERS__ = {'User-Agent': 'swift_rpc','Content-Type':'application/json'} 13 | if encryption: 14 | self.__HEADERS__['Encryption'] = self.encryption 15 | self._name = name 16 | self._url = urljoin(server, name) 17 | 18 | def crypto_parser(self,params): 19 | if not self.encryption: 20 | data = params 21 | if self.encryption == "base64": 22 | data = base64.encodestring(params) 23 | elif self.encryption == "aes": 24 | salt = prpcrypt(self.encryption_key) 25 | data = salt.encrypt(params) 26 | return data if data else params 27 | 28 | def __call__(self, *args, **kwargs): 29 | params = {} 30 | params['args'] = args 31 | params['kwargs'] = kwargs 32 | post_data = json.dumps(params) 33 | if self.encryption: 34 | post_data = self.crypto_parser(post_data) 35 | try: 36 | resp = requests.get(self._url, data=post_data, headers=self.__HEADERS__) 37 | except Exception as e: 38 | raise RPCClient.FailedCall(e) 39 | 40 | if resp.status_code == 404: 41 | raise RPCClient.MissingMethod( 42 | 'No remote method found for {0}'.format(self._name)) 43 | 44 | try: 45 | ret = json.loads(resp.content) 46 | except Exception as e: 47 | raise RPCClient.InvalidSerializationError(e) 48 | 49 | if 'error' in ret: 50 | raise RPCClient.FailedCall(ret['error']) 51 | 52 | return ret['response'] 53 | 54 | class RPCClient(object): 55 | 56 | class FailedCall(Exception): pass 57 | class InvalidSerializationError(Exception): pass 58 | class MissingMethod(Exception): pass 59 | 60 | __UNALLOWED__ = [ 61 | 'trait_names', 62 | '_getAttributeNames', 63 | ] 64 | 65 | def __init__(self, server,encryption=None, encryption_key=None, unallowed_calls=[], load_remotes=True): 66 | self.encryption = encryption 67 | self.encryption_key = encryption_key 68 | if server.startswith('http'): 69 | self._server = server 70 | else: 71 | self._server = 'http://{0}'.format(server) 72 | self._unallowed = unallowed_calls + self.__UNALLOWED__ 73 | if load_remotes: 74 | self.__loadremoteroutes() 75 | 76 | def __send(self, name): 77 | return _RPC(self._server, name, self.encryption,self.encryption_key) 78 | 79 | def __remoteroutes(self): 80 | return self._getroutes() 81 | 82 | def __loadremoteroutes(self): 83 | for route in self.__remoteroutes(): 84 | setattr(self, route, self.__send(route)) 85 | 86 | def __getattr__(self, name): 87 | return None if name in self._unallowed else self.__send(name) 88 | 89 | 90 | __all__ = ('RPCClient') 91 | -------------------------------------------------------------------------------- /swift_rpc/server/handlers.py: -------------------------------------------------------------------------------- 1 | #coding:utf-8 2 | import json 3 | import base64 4 | from tornado import gen, log, web 5 | from tornado.concurrent import run_on_executor 6 | from concurrent.futures import ThreadPoolExecutor 7 | from swift_rpc.mq import rq_conn,redis_conn 8 | from swift_rpc.aeslib import prpcrypt 9 | 10 | class _Handler(web.RequestHandler): 11 | __ALLOWEDUA__ = ('swift_rpc') 12 | 13 | @gen.coroutine 14 | def initialize(self): 15 | self.log = log.logging.getLogger() 16 | self.log.setLevel(log.logging.INFO) 17 | 18 | @gen.coroutine 19 | def prepare(self): 20 | if self.config.SAFE_UA_MODE: 21 | ua = self.request.headers.get('User-Agent') 22 | #if ua not in self.__ALLOWEDUA__: 23 | if ua not in self.config.UA_ALLOW: 24 | self.log.info('Received request from UA {0}'.format(ua)) 25 | self.write({'error': 'User agent not allowed: {0}'.format(ua)}) 26 | self.finish() 27 | 28 | if self.config.SAFE_TOKEN_MODE: 29 | token = self.request.headers.get('Token') 30 | if token not in self.TOKEN_ALLOW: 31 | self.log.info('Received request from Token {0}'.format(token)) 32 | self.write({'error': 'Token not allowed: {0}'.format(token)}) 33 | self.finish() 34 | 35 | if self.config.REMOTE_IP_MODE: 36 | remote_ip = self.request.headers.get("X-Real-IP") 37 | remote_ip = remote_ip if remote_ip else self.request.remote_ip 38 | if remote_ip not in self.config.REMOTE_ALLOW: 39 | self.log.info('Received request from REMOTE IP {0}'.format(remote_ip)) 40 | self.write({'error': 'IP not allowed: {0}'.format(remote_ip)}) 41 | self.finish() 42 | 43 | @gen.coroutine 44 | def args_kwargs(self): 45 | args = [] 46 | if self.request.headers.get('Content-Type') == "application/json": 47 | de_string = self.request.body 48 | encryption = self.request.headers.get('Encryption') 49 | if encryption == "base64": 50 | de_string = base64.decodestring(self.request.body) 51 | elif encryption == "aes": 52 | salt = prpcrypt(self.config.ENCRYPTION_AES) 53 | de_string = salt.decrypt(self.request.body) 54 | data = json.loads(de_string) 55 | args = data.get('args',[]) 56 | kwargs = data.get('kwargs',{}) 57 | raise gen.Return((args, kwargs)) 58 | 59 | if 'args' in self.request.arguments: 60 | args = self.request.arguments['args'] 61 | del self.request.arguments['args'] 62 | kwargs = dict([(k, v[0]) for k, v in self.request.arguments.items()]) 63 | raise gen.Return((args, kwargs)) 64 | 65 | class _Base(_Handler): 66 | 67 | TYPE = 'synchronous' 68 | 69 | @gen.coroutine 70 | def get(self): 71 | args, kwargs = yield self.args_kwargs() 72 | try: 73 | self.write({'response': self.func[0](*args, **kwargs)}) 74 | except Exception as e: 75 | self.write({'error': str(e)}) 76 | 77 | class _AsyncBase(_Handler): 78 | TYPE = 'asynchronous' 79 | 80 | @gen.coroutine 81 | def get(self): 82 | args, kwargs = yield self.args_kwargs() 83 | try: 84 | ret = yield self.func[0](*args, **kwargs) 85 | # return JSON so we get the correct type of the return value 86 | self.write({'response': ret}) 87 | except Exception as e: 88 | self.write({'error': str(e)}) 89 | 90 | class _ThreadPoolBase(_Handler): 91 | executor = ThreadPoolExecutor(200) 92 | TYPE = 'threadpool' 93 | 94 | @gen.coroutine 95 | def get(self): 96 | args, kwargs = yield self.args_kwargs() 97 | try: 98 | data = yield self.run(self.func,args,kwargs) 99 | self.write({'response': data}) 100 | except Exception as e: 101 | self.write({'error': str(e)+"aa"}) 102 | 103 | @run_on_executor 104 | def run(self,func,args,kwargs): 105 | return self.func[0](*args, **kwargs) 106 | 107 | class _MessageQueueBase(_Handler): 108 | TYPE = 'mqasync' 109 | 110 | @gen.coroutine 111 | def get(self): 112 | args, kwargs = yield self.args_kwargs() 113 | try: 114 | job = rq_conn.enqueue('api.'+self.func[0].func_name,*args,**kwargs) 115 | """ 116 | will fix better 117 | # r.lpush('task',msgpack.packb([self.func[0].func_name,args,kwargs])) 118 | """ 119 | self.write({'response': 'commit','job':job.key}) 120 | except Exception as e: 121 | self.write({'error': str(e)}) 122 | 123 | if __name__ == "__main__": 124 | pass 125 | --------------------------------------------------------------------------------