summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLV-426 <lv-426@taproot.org.il>2015-01-04 17:16:12 +0200
committerLV-426 <lv-426@taproot.org.il>2015-01-04 17:16:12 +0200
commitf5494d9233d6f9967c614eef23dee1f29af056c9 (patch)
tree763da6c98efe56acb342aa09d8c4866624c6f32a /src
parentf1dd537689307329dfe42c88ee2e8fda3355eb84 (diff)
rhizi_api breakup: common, rest & websocket files
Diffstat (limited to 'src')
-rw-r--r--src/server/rhizi_api.py165
-rw-r--r--src/server/rhizi_server.py2
-rw-r--r--src/server/rz_api_common.py47
-rw-r--r--src/server/rz_api_rest.py116
-rw-r--r--src/server/rz_api_websocket.py42
-rw-r--r--src/server/rz_mesh.py32
6 files changed, 231 insertions, 173 deletions
diff --git a/src/server/rhizi_api.py b/src/server/rhizi_api.py
index 44edb660..f6a3f128 100644
--- a/src/server/rhizi_api.py
+++ b/src/server/rhizi_api.py
@@ -1,99 +1,38 @@
"""
Rhizi web API
-"""
-import os
-import db_controller as dbc
-import json
-import logging
-import traceback
-import crypt_util
-import flask
-from flask import jsonify
+@deprecated: destined to split into rz_api_rest & rz_api_websocket
+"""
+from datetime import datetime
from flask import Flask
-from flask import request
+from flask import escape
+from flask import jsonify
from flask import make_response
-from flask import session
from flask import redirect
-from flask import escape
-from flask import url_for
from flask import render_template
+from flask import request
from flask import send_from_directory
+from flask import session
+from flask import url_for
+import flask
+import json
+import logging
+import os
+import traceback
-from rz_kernel import RZ_Kernel
-
+import crypt_util
+import db_controller as dbc
from model.graph import Topo_Diff
-from model.graph import Attr_Diff
from model.model import Link
-from datetime import datetime
-
-log = logging.getLogger('rhizi')
-
-# injected: DB controller
-db_ctl = None
-
-def __sanitize_input(*args, **kw_args):
- pass
-
-def sanitize_input__node(n):
- """
- provide a control point as to which node fields are persisted
- """
- assert None != n.get('id'), 'invalid input: node: missing id'
-
-def sanitize_input__link(l):
- """
- provide a control point as to which link fields are persisted
- """
-
- # expected prop assertions
- assert None != l.get('id'), 'invalid input: link: missing id'
- assert None != l.get('__src_id'), 'invalid input: link: missing src id'
- assert None != l.get('__dst_id'), 'invalid input: link: missing dst id'
-
- # unexpected prop assertions
- assert None == l.get('__type'), 'client is sending us __type link property, it should not'
- assert None == l.get('name'), 'client is sending us name link property, it should not'
-
-def sanitize_input__topo_diff(topo_diff):
- for n in topo_diff.node_set_add:
- sanitize_input__node(n)
- for l in topo_diff.link_set_add:
- sanitize_input__link(l)
-
-def sanitize_input__attr_diff(attr_diff):
- pass # TODO: impl
-
-def _validate_obj__attr_diff(ad):
- # check for name attr changes, which are currently forbidden
- for n_id, node_attr_diff_set in ad['__type_node'].items():
- for attr_name in node_attr_diff_set['__attr_write'].keys():
- if 'id' == attr_name:
- raise Exception('validation error: Attr_Diff: forbidden attribute change: \'id\', n_id: ' + n_id)
-
-def __response_wrap(data=None, error=None):
- """
- wrap response data/errors as dict - this should always be used when returning
- data to allow easy return of list objects, assist in error case distinction, etc.
- """
- return dict(data=data, error=error)
-
-def __common_resp_handle(data=None, error=None):
- """
- provide common response handling
-
- @data must be json serializable
- @error will be serialized with str()
- """
- error_str = str(error) # convert any Exception objects to serializable form
- ret_data = __response_wrap(data, error_str)
- resp = jsonify(ret_data) # this will create a Flask Response object
+from rz_api_common import __sanitize_input
+from rz_api_common import sanitize_input__topo_diff
+from rz_api_rest import __common_resp_handle
+from rz_kernel import RZ_Kernel
- resp.headers['Access-Control-Allow-Origin'] = '*'
- # more response processing
+log = logging.getLogger('rhizi')
- return resp
+db_ctl = None # injected: DB controller
def __common_exec(op, on_success=__common_resp_handle, on_error=__common_resp_handle):
"""
@@ -183,70 +122,10 @@ def diff_commit__set():
return topo_diff;
topo_diff = sanitize_input(request)
+
op = dbc.DBO_topo_diff_commit(topo_diff)
return __common_exec(op)
-def diff_commit__topo():
- """
- REST API wrapper around diff_commit__topo():
- - extract topo_diff from request
- - handle success/error outcomes
- """
- def sanitize_input(req):
- topo_diff_dict = request.get_json()['topo_diff']
- topo_diff = Topo_Diff.from_json_dict(topo_diff_dict)
-
- sanitize_input__topo_diff(topo_diff)
- return topo_diff;
-
- try:
- topo_diff = sanitize_input(request)
- except Exception as e:
- return __common_resp_handle(error='malformed input')
-
- try:
- kernel = flask.current_app.kernel
- topo_diff = kernel.diff_commit__topo(db_ctl, topo_diff)
- topo_diff_json = topo_diff.to_json_dict()
- return __common_resp_handle(data=topo_diff_json)
- except Exception as e:
- log.error(e.message)
- log.error(traceback.print_exc())
- return __common_resp_handle(error=e)
-
-def diff_commit__attr():
- """
- commit a graph attribute diff
- """
- def sanitize_input(req):
- attr_diff_dict = request.get_json()['attr_diff']
- attr_diff = Attr_Diff.from_json_dict(attr_diff_dict)
-
- sanitize_input__attr_diff(attr_diff)
- return attr_diff;
-
- def on_error(e):
- # handle DB ERRORS, eg. name attr change error
- return __common_resp_handle(error='error occurred')
-
- try:
- attr_diff = sanitize_input(request)
- _validate_obj__attr_diff(attr_diff)
- except Exception as e:
- return __common_resp_handle(error='malformed input')
-
- try:
- kernel = flask.current_app.kernel
- attr_diff = kernel.diff_commit__attr(db_ctl, attr_diff)
- return __common_resp_handle(data=attr_diff)
- except Exception as e:
- log.error(e.message)
- log.error(traceback.print_exc())
- return __common_resp_handle(error=e)
-
-def diff_commit__vis():
- pass
-
def add_node_set():
"""
@deprecated: use topo_attr_commit
diff --git a/src/server/rhizi_server.py b/src/server/rhizi_server.py
index 216085fc..855c75ed 100644
--- a/src/server/rhizi_server.py
+++ b/src/server/rhizi_server.py
@@ -22,6 +22,7 @@ from flask import send_from_directory
from functools import wraps
from rz_mesh import init_ws_interface
from rz_kernel import RZ_Kernel
+import rz_api_rest
class Config(object):
"""
@@ -238,6 +239,7 @@ def init_webapp(cfg, kernel, db_ctl=None):
if None == db_ctl:
db_ctl = dbc.DB_Controller(cfg)
rhizi_api.db_ctl = db_ctl
+ rz_api_rest.db_ctl = db_ctl
webapp.rz_config = cfg
webapp.kernel = kernel
diff --git a/src/server/rz_api_common.py b/src/server/rz_api_common.py
new file mode 100644
index 00000000..68d9008d
--- /dev/null
+++ b/src/server/rz_api_common.py
@@ -0,0 +1,47 @@
+"""
+Common public API logic:
+ - object sanitization for inbound data
+ - object validation for inbound data
+ - sanitize_input__XXX: concerned with sanitizing potential currupt data arriving
+ from external sources.
+ - validae_object__XXX: concerned with validating the logical state of an object
+
+"""
+def __sanitize_input(*args, **kw_args):
+ pass
+
+def sanitize_input__node(n):
+ """
+ provide a control point as to which node fields are persisted
+ """
+ assert None != n.get('id'), 'invalid input: node: missing id'
+
+def sanitize_input__link(l):
+ """
+ provide a control point as to which link fields are persisted
+ """
+
+ # expected prop assertions
+ assert None != l.get('id'), 'invalid input: link: missing id'
+ assert None != l.get('__src_id'), 'invalid input: link: missing src id'
+ assert None != l.get('__dst_id'), 'invalid input: link: missing dst id'
+
+ # unexpected prop assertions
+ assert None == l.get('__type'), 'client is sending us __type link property, it should not'
+ assert None == l.get('name'), 'client is sending us name link property, it should not'
+
+def sanitize_input__topo_diff(topo_diff):
+ for n in topo_diff.node_set_add:
+ sanitize_input__node(n)
+ for l in topo_diff.link_set_add:
+ sanitize_input__link(l)
+
+def sanitize_input__attr_diff(attr_diff):
+ pass # TODO: impl
+
+def validate_obj__attr_diff(ad):
+ # check for name attr changes, which are currently forbidden
+ for n_id, node_attr_diff_set in ad['__type_node'].items():
+ for attr_name in node_attr_diff_set['__attr_write'].keys():
+ if 'id' == attr_name:
+ raise Exception('validation error: Attr_Diff: forbidden attribute change: \'id\', n_id: ' + n_id)
diff --git a/src/server/rz_api_rest.py b/src/server/rz_api_rest.py
new file mode 100644
index 00000000..bb5542d2
--- /dev/null
+++ b/src/server/rz_api_rest.py
@@ -0,0 +1,116 @@
+"""
+Rhizi REST web API:
+ - make use of rz_kernel for core logic execution
+ - make use of rz_api_common for common API logic
+
+"""
+from flask import Flask
+from flask import escape
+from flask import jsonify
+from flask import make_response
+from flask import redirect
+from flask import render_template
+from flask import request
+from flask import send_from_directory
+from flask import session
+from flask import url_for
+import flask
+import logging
+import traceback
+
+from model.graph import Attr_Diff
+from model.graph import Topo_Diff
+from rz_api_common import sanitize_input__attr_diff
+from rz_api_common import sanitize_input__topo_diff
+from rz_api_common import validate_obj__attr_diff
+
+
+log = logging.getLogger('rhizi')
+
+db_ctl = None # injected: DB controller
+
+def __response_wrap(data=None, error=None):
+ """
+ wrap response data/errors as dict - this should always be used when returning
+ data to allow easy return of list objects, assist in error case distinction, etc.
+ """
+ return dict(data=data, error=error)
+
+def __common_resp_handle(data=None, error=None):
+ """
+ provide common response handling
+
+ @data must be json serializable
+ @error will be serialized with str()
+ """
+ error_str = str(error) # convert any Exception objects to serializable form
+ ret_data = __response_wrap(data, error_str)
+ resp = jsonify(ret_data) # this will create a Flask Response object
+
+ resp.headers['Access-Control-Allow-Origin'] = '*'
+
+ # more response processing
+
+ return resp
+
+def diff_commit__topo():
+ """
+ REST API wrapper around diff_commit__topo():
+ - extract topo_diff from request
+ - handle success/error outcomes
+ """
+ def sanitize_input(req):
+ topo_diff_dict = request.get_json()['topo_diff']
+ topo_diff = Topo_Diff.from_json_dict(topo_diff_dict)
+
+ sanitize_input__topo_diff(topo_diff)
+ return topo_diff;
+
+ try:
+ topo_diff = sanitize_input(request)
+ except Exception as e:
+ return __common_resp_handle(error='malformed input')
+
+ try:
+ kernel = flask.current_app.kernel
+ topo_diff = kernel.diff_commit__topo(db_ctl, topo_diff)
+ topo_diff_json = topo_diff.to_json_dict()
+ return __common_resp_handle(data=topo_diff_json)
+ except Exception as e:
+ log.error(e.message)
+ log.error(traceback.print_exc())
+ return __common_resp_handle(error=e)
+
+def diff_commit__attr():
+ """
+ commit a graph attribute diff
+ """
+ def sanitize_input(req):
+ attr_diff_dict = request.get_json()['attr_diff']
+ attr_diff = Attr_Diff.from_json_dict(attr_diff_dict)
+
+ sanitize_input__attr_diff(attr_diff)
+ return attr_diff;
+
+ def on_error(e):
+ # handle DB ERRORS, eg. name attr change error
+ return __common_resp_handle(error='error occurred')
+
+ try:
+ attr_diff = sanitize_input(request)
+ validate_obj__attr_diff(attr_diff)
+ except Exception as e:
+ return __common_resp_handle(error='malformed input')
+
+ try:
+ kernel = flask.current_app.kernel
+ attr_diff = kernel.diff_commit__attr(db_ctl, attr_diff)
+ return __common_resp_handle(data=attr_diff)
+ except Exception as e:
+ log.error(e.message)
+ log.error(traceback.print_exc())
+ return __common_resp_handle(error=e)
+
+def diff_commit__vis():
+ pass
+
diff --git a/src/server/rz_api_websocket.py b/src/server/rz_api_websocket.py
new file mode 100644
index 00000000..15243db6
--- /dev/null
+++ b/src/server/rz_api_websocket.py
@@ -0,0 +1,42 @@
+"""
+Rhizi websocket web API
+"""
+
+import logging
+from socketio.mixins import BroadcastMixin
+from socketio.namespace import BaseNamespace
+
+
+log = logging.getLogger('rhizi')
+
+class WebSocket_Graph_NS(BaseNamespace, BroadcastMixin):
+ """
+ Rhizi '/graph' websocket namespace
+ """
+
+ def __init__(self, *args, **kw):
+ super(WebSocket_Graph_NS, self).__init__(*args, **kw)
+
+ def multicast_msg(self, msg_name, *args):
+ self.socket.server.log_multicast(msg_name)
+ super(WebSocket_Graph_NS, self).broadcast_event_not_me(msg_name, *args)
+
+ def _log_conn(self, prefix_msg):
+ rmt_addr = self.environ['REMOTE_ADDR']
+ rmt_port = self.environ['REMOTE_PORT']
+ sid = self.environ['socketio'].sessid
+ log.info('ws: %s: sid: %s, remote-socket: %s:%s' % (prefix_msg, sid, rmt_addr, rmt_port))
+
+ def recv_connect(self):
+ self._log_conn('conn open')
+
+ def recv_disconnect(self):
+ self._log_conn('conn close')
+
+ def on_diff_commit__topo(self, topo_diff):
+ log.info('ws: rx: topo diff: ' + str(topo_diff))
+ self.multicast_msg('diff_commit__topo', topo_diff)
+
+ def on_diff_commit__attr(self, attr_diff):
+ log.info('ws: rx: attr diff: ' + str(attr_diff))
+ self.multicast_msg('diff_commit__attr', attr_diff)
diff --git a/src/server/rz_mesh.py b/src/server/rz_mesh.py
index b20aa64b..1d077803 100644
--- a/src/server/rz_mesh.py
+++ b/src/server/rz_mesh.py
@@ -3,45 +3,17 @@ from flask import request
from geventwebsocket.handler import WebSocketHandler
import logging
from socketio import socketio_manage
-from socketio.mixins import BroadcastMixin
-from socketio.namespace import BaseNamespace
+
from socketio.server import SocketIOHandler
from socketio.server import SocketIOServer
from functools import wraps
from rz_kernel import RZ_Kernel
from model.graph import Attr_Diff, Topo_Diff
+from rz_api_websocket import WebSocket_Graph_NS
log = logging.getLogger('rhizi')
-class WebSocket_Graph_NS(BaseNamespace, BroadcastMixin):
- """
- Rhizi '/graph' websocket namespace
- """
- def multicast_msg(self, msg_name, *args):
- self.socket.server.log_multicast(msg_name)
- super(WebSocket_Graph_NS, self).broadcast_event_not_me(msg_name, *args)
-
- def _log_conn(self, prefix_msg):
- rmt_addr = self.environ['REMOTE_ADDR']
- rmt_port = self.environ['REMOTE_PORT']
- sid = self.environ['socketio'].sessid
- log.info('ws: %s: sid: %s, remote-socket: %s:%s' % (prefix_msg, sid, rmt_addr, rmt_port))
-
- def recv_connect(self):
- self._log_conn('conn open')
-
- def recv_disconnect(self):
- self._log_conn('conn close')
-
- def on_diff_commit__topo(self, topo_diff):
- log.info('ws: rx: topo diff: ' + str(topo_diff))
- self.multicast_msg('diff_commit__topo', topo_diff)
-
- def on_diff_commit__attr(self, attr_diff):
- log.info('ws: rx: attr diff: ' + str(attr_diff))
- self.multicast_msg('diff_commit__attr', attr_diff)
-
class RZ_WebSocket_Server(SocketIOServer):
"""
Rhizi customized SocketIOServer: