Odoo 学习【一】http & rpc
HTTP
Odoo 中http类中的Root是wsgi应用的入口主程序。
入口,wsgi_server调用如下:
def application(environ, start_response):
if config['proxy_mode'] and '_X_FORWARDED_HOST' in environ:
return werkzeug.contrib.fixers.ProxyFix(application_unproxied)(environ, start_response)
else:
return application_unproxied(environ, start_response)
def application_unproxied(environ, start_response):
......
wsgi_handlers = [wsgi_xmlrpc]
wsgi_handlers += module_handlers # module_handlers 处理器注册表,在http.py注册了root处理器。
for handler in wsgi_handlers:
result = handler(environ, start_response)
if result is None:
continue
return result
注册root处理器,是一个单例对象,模块导入,就是单例的,handler是一个可调用对象,module_handlers维护了这样的一个列表。
# register main wsgi handler
root = Root() # 这是一个可调用对象。
openerp.service.wsgi_server.register_wsgi_handler(root)
def __call__(self, environ, start_response):
""" Handle a WSGI request
"""
if not self._loaded:
self._loaded = True
self.load_addons()
return self.dispatch(environ, start_response)
源码中,对dispath方法进行了进一步的包裹,Werkzeug 是一个 WSGI 工具包,environ包含了所有的信息,werkzeug.wrappers.Request对这个环境进行了进一步封装。在Odoo中则对这个原生的werkzeug.wrappers.Request对象进行了进一步的封装,可查看self.get_request方法。
dispatch
def dispatch(self, environ, start_response):
"""
Performs the actual WSGI dispatching for the application.
"""
try:
httprequest = werkzeug.wrappers.Request(environ)
httprequest.app = self
explicit_session = self.setup_session(httprequest)
self.setup_db(httprequest)
self.setup_lang(httprequest)
request = self.get_request(httprequest)
def _dispatch_nodb():
try:
func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match()
except werkzeug.exceptions.HTTPException, e:
return request._handle_exception(e)
request.set_handler(func, arguments, "none")
result = request.dispatch()
return result
with request:
db = request.session.db
if db:
openerp.modules.registry.RegistryManager.check_registry_signaling(db)
try:
with openerp.tools.mute_logger('openerp.sql_db'):
ir_http = request.registry['ir.http']
except (AttributeError, psycopg2.OperationalError):
# psycopg2 error or attribute error while constructing
# the registry. That means the database probably does
# not exists anymore or the code doesnt match the db.
# Log the user out and fall back to nodb
request.session.logout()
result = _dispatch_nodb()
else:
result = ir_http._dispatch()
openerp.modules.registry.RegistryManager.signal_caches_change(db)
else:
result = _dispatch_nodb()
response = self.get_response(httprequest, result, explicit_session)
return response(environ, start_response)
上述的封装过的request是一个上下文管理器,也就是定义了__enter__,__exit__方法。在WebRequest父类中,可窥斑见豹了,具体如下:
def __enter__(self):
_request_stack.push(self) # 压入请求栈中
return self
def __exit__(self, exc_type, exc_value, traceback):
_request_stack.pop() # 弹出请求栈
if self._cr:
if exc_type is None and not self._failed:
self._cr.commit()
self._cr.close()
# just to be sure no one tries to re-use the request
self.disable_db = True
self.uid = None
_request_stack是一个werkzeug.local.LocalStack()对象,LocalStack使用Local(类似于threading.local)实现的栈结构,可以将对象推入、弹出,也可以快速拿到栈顶,所有的修改在本线程(在绿色线程内优先使用Greenlet的ID)内可见。_request_stack是一个可调用对象的实例,_request_stack(),可快速拿到栈顶元素,request=_request_stack,这样访问导入request对象,也就永远是栈顶元素,即当前请求对象。
下面是真正的调度,不过什么也看不出,Command+左键进去。
result = ir_http._dispatch()
def _find_handler(self, return_rule=False):
return self.routing_map().bind_to_environ(request.httprequest.environ).match(return_rule=return_rule)
ir_http这个实例保存着所有已经安装模块的路由映射,route_map。_find_handler会根据request(Odoo栈顶请求请求).httprequest(werkzerg请求对象).environ信息,会在这个路由映射中查找出对应的处理规则。
def _dispatch(self):
# locate the controller method
try:
rule, arguments = self._find_handler(return_rule=True)
func = rule.endpoint
except werkzeug.exceptions.NotFound, e:
return self._handle_exception(e)
# check authentication level
try:
auth_method = self._authenticate(func.routing["auth"])
except Exception as e:
return self._handle_exception(e)
processing = self._postprocess_args(arguments, rule)
if processing:
return processing
# set and execute handler
try:
request.set_handler(func, arguments, auth_method)
result = request.dispatch()
if isinstance(result, Exception):
raise result
except Exception, e:
return self._handle_exception(e)
return result
get_request
推测,并进行进一步封装,根据分类,包装成JsonRequest和HttpRequest对象,它们都是的Odoo WebRequest的子类,包含了uid,环境,用户上下文等这些信息。
def get_request(self, httprequest):
# deduce type of request
if httprequest.args.get('jsonp'):
return JsonRequest(httprequest)
if httprequest.mimetype in ("application/json", "application/json-rpc"):
return JsonRequest(httprequest)
else:
return HttpRequest(httprequest)
RPC
Odoo WSGI Server应该也注意到还有一个wsgi_xmlrpc,也就是为了兼容xml-rpc,xml与json之间的转换,在源码中看出是最原始的wsgi的应用。
wsgi_xmlrpc
def wsgi_xmlrpc(environ, start_response):
if environ['REQUEST_METHOD'] == 'POST' and environ['PATH_INFO'].startswith('/xmlrpc/'):
length = int(environ['CONTENT_LENGTH'])
data = environ['wsgi.input'].read(length)
string_faultcode = True
if environ['PATH_INFO'].startswith('/xmlrpc/2/'):
service = environ['PATH_INFO'][len('/xmlrpc/2/'):]
string_faultcode = False
else:
service = environ['PATH_INFO'][len('/xmlrpc/'):]
params, method = xmlrpclib.loads(data)
return xmlrpc_return(start_response, service, method, params, string_faultcode)
xmlrpc_return
def xmlrpc_return(start_response, service, method, params, string_faultcode=False):
try:
result = openerp.http.dispatch_rpc(service, method, params)
response = xmlrpclib.dumps((result,), methodresponse=1, allow_none=False, encoding=None)
except Exception, e:
if string_faultcode:
response = xmlrpc_handle_exception_string(e)
else:
response = xmlrpc_handle_exception_int(e)
start_response("200 OK", [('Content-Type','text/xml'), ('Content-Length', str(len(response)))])
return [response]
Common RPC
在http.py模块下定义CommonController,对应的路由是/jsonrpc。
具体是通过dispath_rpc调用。
Odoo Service 目录下存在下面的四个文件,分别对应四种服务,都拥有dispatch()方法来,来调用各自模块下的方法。
- common.py
login、authenticate、version、about、set_loglevel - db.py
create_database、duplicate_database、drop、dump、restore、rename、change_admin_password、migrate_database、db_exist、list、list_lang、list_countries、server_version - model.py
execute、execute_kw、execute_workflow - report.py
report、report_get、render_report
DataSet RPC
在web DataSet 控制器定义的路由。
- /web/dataset/search_read
- /web/dataset/load
- /web/dataset/call
- /web/dataset/call_kw
- /web/dataset/call_buttion
- /web/dataset/exec_workflow
- /web/dataset/resequence
Odoo 学习【一】http & rpc的更多相关文章
- scala学习之实现RPC通信
最近学习scala,个人感觉非常灵活,实现rpc通信非常简单,函数式编程比较烧脑 1.搭建工程 创建scala maven 工程 项目pom文件 <project xmlns="htt ...
- odoo学习
odoo视图对应模型:model="ir.ui.view"> <record id="mrp_workcenter_view_light_inherit&qu ...
- odoo学习总结
odoo10总结 1.odoo中的向导应用. .py文件 # -*- coding: utf-8 -*-f ...
- 学习别人的rpc框架
https://my.oschina.net/huangyong/blog/361751 https://gitee.com/huangyong/rpc 在此文基础上的另一个实现,解决了原文中一些问题 ...
- Odoo 学习地址
Odoo官文文档: https://www.odoo.com/zh_cn/page/docs http://www.odoo.com/documentation/8.0/ Odoo中文文档推荐: ht ...
- 【转】Java学习---快速掌握RPC原理及实现
[原文]https://www.toutiao.com/i6592365493435236872/ RPC概述 RPC(Remote Procedure Call)即远程过程调用,也就是说两台服务器 ...
- RESTful源码学习笔记之RPC和 RESTful 什么区别
REST,即Representational State Transfer的缩写.翻译过来是表现层状态转换.如果一个架构符合REST原则,就称它为RESTful架构.啥叫json-rpc?接口调用通常 ...
- RESTful源码学习笔记之RPC和Restful深入理解
以下资料搜集自网络 0x00 RPC RPC 即远程过程调用(Remote Procedure Call Protocol,简称RPC),像调用本地服务(方法)一样调用服务器的服务(方法).通常的实现 ...
- odoo学习之:【转】控制menuitem的显示权限
作者原文:https://blog.csdn.net/wangnan537/article/details/43992771 在实际应用Odoo(OpenERP)的过程中, 会有对某用户组隐藏菜单的需 ...
随机推荐
- 【一天一道LeetCode】#344. Reverse String
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Write a ...
- inline内联函数
demo //带参数的宏 #define MYFUNC(a, b) ((a) < (b) ? (a) : (b)) inline int myfunc(int a, int b) { retur ...
- 关于大数据时代传统商业存储的思考: 中心存储 VS 分布式存储
尊重原创,转载请注明出处:http://anzhan.me ; http://blog.csdn.net/anzhsoft 今天和我们部门的老大1*1, 大家面对面沟通了一下到新的项目组的想法.而且也 ...
- 如何优化MySQL insert性能
对于一些数据量较大的系统,面临的问题除了是查询效率低下,还有一个很重要的问题就是插入时间长.我们就有一个业务系统,每天的数据导入需要4-5个钟.这种费时的操作其实是很有风险的,假设程序出了问题,想重跑 ...
- Gradle 1.12 翻译——第十五章. 任务详述
有关其他已翻译的章节请关注Github上的项目:https://github.com/msdx/gradledoc/tree/1.12,或访问:http://gradledoc.qiniudn.com ...
- Leetcode_125_Valid Palindrome
本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/41488377 Valid Palindrome Given ...
- OC内存管理-OC笔记
内存管理细节:http://blog.sina.com.cn/s/blog_814ecfa90102vus2.html 学习目标 1.[理解]内存管理 2.[掌握]第一个MRC程序 3.[掌握]内存管 ...
- 异常驱动的开发(Exception-Driven Development)
你的网站或应用程序存在哪些问题?如果你在等着用户来告诉你,那么你只能看到所有的问题中已经暴露的那极小的一部分.要知道,那只是"冰山一角"! 而且,如果你真的是在守株待兔,我不得不很 ...
- apache tomcat集群
今天花了大概两个小时完成了tomcat与apache的集群.现记录一下,也希望能帮助后来者. 建议看这篇博客前,先阅读一下鄙人拙作 tomcat整合apache 看完那个后,再进行集群,就很快了. 和 ...
- Android官方技术文档翻译——IntelliJ 项目迁移
本文译自Android官方技术文档<Migrating from IntelliJ Projects>,原文地址:http://tools.android.com/tech-docs/ne ...