Home > Python, 前端技术 > 让Kohana直接支持python——RPC篇

让Kohana直接支持python——RPC篇

December 12th, 2011

上一篇中,我们实现了基础的TCP Server,数据通过json协议进行传输

接下来,我们需要处理RPC请求的核心部分。
我们来看,在PHP代码中写:

  1. $myObj = new Foo_Bar();
  2. $myObj->test();

我们要python端做哪些事情


首先,我们要让python找到对应的模块加载(按kohana规则,这个模块叫 classes/foo/bar.py)
其次,我们用php new了一个python对象,对象名为Foo_Bar,接着,调用了test方法
在RPC请求中,我们先要通知python去new这个对象,并且将这个实例保存下来
再次,当我们调用test()方法时,python要知道调用这个方法的对象实例是我们刚才保存下来的那个Foo_Bar实例。所以这里,我们必须要维持一个唯一的id,作为这个实例的标识。
id有两个作用,一是避免对象的重复构造,二是让python知道该用哪个对象去调用方法。

对于让python找到对应的模块加载,这个可以放在php的autoload中进行,只要在autoload的过程中,将对应的路径classes加入到python的sys.path中,并且写好classes/foo/__init__.py,那么在python中通过import或__import__就能将正确的模块加载进来了。

至于new正确的python对象,只需要将Foo_Bar解析成foo.bar.Foo_Bar,应该不难。这只是简单的正则替换而已。

有了class,我们根据guid构造出实例,并且将这个实例保存在对应的guid的字典字段中。

完整的代码并不复杂:

  1. # coding=utf-8
  2.  
  3. import sys
  4. import uuid
  5. from types import *
  6.  
  7. class Handler():
  8.     def __init__(self):
  9.         self.rpc_instances = {}
  10.     def execute(self, data):
  11.         rpc_instances = self.rpc_instances;
  12.  
  13.         if('paths' in data): #set auto loading paths
  14.             data['paths'].reverse()
  15.             for i in range(len(data['paths'])):
  16.                 path = data['paths'][i] + 'classes'
  17.                 if(path not in sys.path):
  18.                     sys.path.insert(1, path)
  19.        
  20.         #call the object instance func - {id, func, args[class, init]}
  21.         if('id' in data):
  22.             if(data['id'] in rpc_instances):    #the object has been created
  23.                 o = rpc_instances[data['id']]
  24.             else:                               #create new object instance
  25.                 c = self.find_class(data['class'])
  26.                 o = apply(c, data['init'])
  27.                 rpc_instances[data['id']] = o 
  28.             resapply(getattr(o, data['func']), data['args']) or '' 
  29.  
  30.         #call class func - {class, [func, args]}
  31.         else:
  32.             c = self.find_class(data['class'])
  33.             #if not 'func', only to test wether the class exists or not
  34.             if(not ('func' in data)): #TODO: get the detail info of the class?
  35.                 res = True
  36.             else:
  37.                 res = apply(getattr(c, data['func']), data['args']) or ''
  38.        
  39.         if(type(res) is InstanceType):
  40.             uid = str(uuid.uuid4())
  41.             rpc_instances[uid] = res
  42.             res = {'@id':uid, '@class':res.__class__.__name__, '@init':[]}  
  43.        
  44.         return {'err':'ok', 'data':res}
  45.  
  46.     def find_class(self, class_name):
  47.         #resolve the path from class name like 'Model_Logic_Test'
  48.         path = map(lambda s: s.lower(), class_name.split('_'))
  49.         p = __import__(".".join(path))
  50.  
  51.         for i in range(len(path)):
  52.             if(i > 0):
  53.                 p = getattr(p, path[i])
  54.    
  55.         return getattr(p, class_name)

Python, 前端技术

  1. 青青思念
    December 26th, 2011 at 21:35 | #1

    月影也用 Kohana 这个框架吗,看来CI系列的框架真的很深入人心哦。
    10年在选择框架时,还是2.*系列,现在已经3.2了,发展很快。
    当时考虑到文档和上手成本,犹豫了很久选了ci。

    这种让php调用python的方法挺新颖的!