From 35482711a89399a41bffb492b46c56cbceea31e4 Mon Sep 17 00:00:00 2001 From: Marko Budiselic <mbudiselicbuda@gmail.com> Date: Sat, 5 Mar 2016 10:10:57 +0100 Subject: [PATCH] demo substitutor implementation --- api/resources/ping.hpp | 15 ++++ api/response_json.hpp | 6 +- api/restful/restful_resource.hpp | 2 +- demo/demo_server.docker | 12 +-- demo/demo_server_init.py | 53 +++++++++++++ demo/demo_server_run.py | 31 -------- demo/memgraph_demo.build | 5 -- demo/memgraph_demo.docker | 8 -- demo/memgraph_server.docker | 10 +++ demo/neo4j_demo.run | 5 -- demo/requirements.txt | 18 +++++ ...{memgraph_demo.run => run_memgraph_server} | 0 demo/run_neo4j_server | 5 ++ demo/simulation/executor.py | 21 +++-- demo/simulation/task.py | 9 +++ demo/simulation/web_server.py | 70 +++++++++-------- demo/substitutor.py | 77 +++++++++++++++++++ 17 files changed, 251 insertions(+), 96 deletions(-) create mode 100644 api/resources/ping.hpp create mode 100644 demo/demo_server_init.py delete mode 100644 demo/demo_server_run.py delete mode 100755 demo/memgraph_demo.build delete mode 100644 demo/memgraph_demo.docker create mode 100644 demo/memgraph_server.docker delete mode 100755 demo/neo4j_demo.run create mode 100644 demo/requirements.txt rename demo/{memgraph_demo.run => run_memgraph_server} (100%) create mode 100755 demo/run_neo4j_server create mode 100644 demo/substitutor.py diff --git a/api/resources/ping.hpp b/api/resources/ping.hpp new file mode 100644 index 000000000..ff993dda4 --- /dev/null +++ b/api/resources/ping.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "api/restful/resource.hpp" + +#pragma url /ping +class Ping : public Resource<Ping, GET> +{ +public: + using Resource::Resource; + + void get(sp::Request& req, sp::Response& res) + { + return res.send(http::Status::NoContent, ""); + } +}; diff --git a/api/response_json.hpp b/api/response_json.hpp index 8a0a26231..5c659e271 100644 --- a/api/response_json.hpp +++ b/api/response_json.hpp @@ -45,9 +45,9 @@ std::string vertex_create_response(const Vertex::Accessor& vertex_accessor) writer->String("data"); writer->StartObject(); - RapidJsonStringWriter dataBuffer(writer); - auto properties = vertex_accessor.properties(); - properties.accept(dataBuffer); + // RapidJsonStringWriter dataBuffer(writer); + // auto properties = vertex_accessor.properties(); + // properties.accept(dataBuffer); writer->EndObject(); writer->EndObject(); diff --git a/api/restful/restful_resource.hpp b/api/restful/restful_resource.hpp index 72eed6639..8c7482bbd 100644 --- a/api/restful/restful_resource.hpp +++ b/api/restful/restful_resource.hpp @@ -5,7 +5,7 @@ #include "speedy/speedy.hpp" #include "utils/crtp.hpp" -#include "storage/model/properties/jsonwriter.hpp" +#include "storage/model/properties/traversers/jsonwriter.hpp" /** @brief GET handler method for the resource * Contains the code for registering GET handler for a URL to Speedy diff --git a/demo/demo_server.docker b/demo/demo_server.docker index 38df666d5..b0bca606f 100644 --- a/demo/demo_server.docker +++ b/demo/demo_server.docker @@ -1,15 +1,17 @@ FROM ubuntu:16.04 RUN apt-get update -RUN apt-get install -y python3.5 python3-pip -RUN apt-get install -y python3-setuptools +RUN apt-get install -y python3.5 python3.5-dev python3-pip python3-setuptools # RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* -RUN pip3 install flask requests +RUN pip3 install flask COPY simulation /app/simulation -COPY demo_server_run.py /app/demo_server_run.py +COPY demo_server_run.py /app/demo_server_init.py WORKDIR /app -CMD ["python3", "demo_server_run.py"] +ENV MEMGRAPH_DEMO prod + +# uwsgi --http-socket 0.0.0.0:8080 --module demo_server_init:app --master --enable-threads +CMD ["python3", "demo_server_init.py"] diff --git a/demo/demo_server_init.py b/demo/demo_server_init.py new file mode 100644 index 000000000..6f1932824 --- /dev/null +++ b/demo/demo_server_init.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' +The demo server init script. Environment could be configured +via the MEMGRAPH_DEMO environtment variable. Available environments +are: debug, prod. +''' + +import os +import logging + +from simulation.web_server import SimulationWebServer + + +def fetch_env(env_name, default=None): + ''' + Fetches environment variable. + ''' + if env_name in os.environ: + return os.environ[env_name] + + return default + + +environment = fetch_env('MEMGRAPH_DEMO', 'debug') +wsgi = fetch_env('MEMGRAPH_DEMO_WSGI', 'werkzeug') + + +def _init(): + ''' + Initialzies logging level and server. + ''' + if environment == 'prod': + logging.basicConfig(level=logging.WARNING) + elif environment == 'test': + logging.basicConfig(level=logging.INFO) + else: + logging.basicConfig(level=logging.DEBUG) + + return SimulationWebServer().server + + +app = _init() + + +if __name__ == '__main__': + if wsgi == 'gevent': + from gevent.wsgi import WSGIServer + http_server = WSGIServer(('', 8080), app) + http_server.serve_forever() + else: + app.run(host="0.0.0.0", port=8080) diff --git a/demo/demo_server_run.py b/demo/demo_server_run.py deleted file mode 100644 index ff628aced..000000000 --- a/demo/demo_server_run.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import os -import logging - -from simulation.web_server import SimulationWebServer - - -def main(): - ''' - The demo server run script. Environment could be configured - via the MEMGRAPH_DEMO environtment variable. Available environments - are: debug, prod. - ''' - if 'MEMGRAPH_DEMO' in os.environ: - environment = os.environ['MEMGRAPH_DEMO'] - else: - environment = "debug" - - frontend_server = SimulationWebServer() - - if environment == 'prod': - logging.basicConfig(level=logging.WARNING) - frontend_server.run("0.0.0.0", 8080, False) - elif environment == 'debug': - logging.basicConfig(level=logging.INFO) - frontend_server.run("0.0.0.0", 8080, True) - -if __name__ == '__main__': - main() diff --git a/demo/memgraph_demo.build b/demo/memgraph_demo.build deleted file mode 100755 index 5462c4406..000000000 --- a/demo/memgraph_demo.build +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -cd .. -docker rmi memgraph_demo -docker build -t memgraph_demo -f demo/memgraph_demo.docker . diff --git a/demo/memgraph_demo.docker b/demo/memgraph_demo.docker deleted file mode 100644 index dfd379cd7..000000000 --- a/demo/memgraph_demo.docker +++ /dev/null @@ -1,8 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update -RUN apt-get install -y git - -RUN git clone https://pullbot:JnSdamFGKOanF1@phabricator.tomicevic.com/diffusion/MG/memgraph.git - -CMD ["/bin/bash"] diff --git a/demo/memgraph_server.docker b/demo/memgraph_server.docker new file mode 100644 index 000000000..f4614ab62 --- /dev/null +++ b/demo/memgraph_server.docker @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 + +RUN apt-get update +RUN apt-get install -y git + +RUN mkdir /app +WORKDIR /app +RUN git clone --recursive https://${MEMGRAPH_PULL_USER}:${MEMGRAPH_PULL_PASS}@phabricator.tomicevic.com/diffusion/MG/memgraph.git + +CMD ["/bin/bash"] diff --git a/demo/neo4j_demo.run b/demo/neo4j_demo.run deleted file mode 100755 index c55b522fe..000000000 --- a/demo/neo4j_demo.run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -docker stop neo4j_demo -docker rm neo4j_demo -docker run -d --name neo4j_demo --net=host -p 7474:7474 neo4j diff --git a/demo/requirements.txt b/demo/requirements.txt new file mode 100644 index 000000000..5652c67de --- /dev/null +++ b/demo/requirements.txt @@ -0,0 +1,18 @@ +Flask==0.10.1 +Jinja2==2.8 +MarkupSafe==0.23 +Werkzeug==0.11.4 +decorator==4.0.9 +gevent==1.1rc5 +greenlet==0.4.9 +ipython==4.1.1 +ipython-genutils==0.1.0 +itsdangerous==0.24 +path.py==8.1.2 +pexpect==4.0.1 +pickleshare==0.6 +ptyprocess==0.5.1 +requests==2.9.1 +simplegeneric==0.8.1 +traitlets==4.1.0 +uWSGI==2.0.12 diff --git a/demo/memgraph_demo.run b/demo/run_memgraph_server similarity index 100% rename from demo/memgraph_demo.run rename to demo/run_memgraph_server diff --git a/demo/run_neo4j_server b/demo/run_neo4j_server new file mode 100755 index 000000000..37fce1bdf --- /dev/null +++ b/demo/run_neo4j_server @@ -0,0 +1,5 @@ +#!/bin/bash + +docker stop neo4j_server +docker rm neo4j_server +docker run -d --name neo4j_server --net=host -p 7474:7474 neo4j diff --git a/demo/simulation/executor.py b/demo/simulation/executor.py index 8d415fc70..ab7717abe 100644 --- a/demo/simulation/executor.py +++ b/demo/simulation/executor.py @@ -3,7 +3,7 @@ import time import logging import itertools -import requests +import urllib.request from concurrent.futures import ProcessPoolExecutor from .epoch_result import SimulationEpochResult @@ -61,13 +61,16 @@ class SimulationExecutor(object): :param query: str, query string ''' - requests.post('http://localhost:7474/db/data/transaction/commit', - json={ - "statements": [ - {"statement": query} - ] - }, - headers={'Authorization': 'Basic bmVvNGo6cGFzcw=='}) + # requests.post('http://localhost:7474/db/data/transaction/commit', + # json={ + # "statements": [ + # {"statement": query} + # ] + # }, + # headers={'Authorization': 'Basic bmVvNGo6cGFzcw=='}) + # requests.get('http://localhost:7474/db/data/ping') + response = urllib.request.urlopen('http://localhost:7474/db/data/ping') + response.read() def iteration(self, task): ''' @@ -108,6 +111,8 @@ class SimulationExecutor(object): with self.pool() as executor: + log.info('pool iter') + # execute all tasks futures = [executor.submit(self.iteration, task) for task in self.params.tasks diff --git a/demo/simulation/task.py b/demo/simulation/task.py index bdb9bc3e8..0c8f267c7 100644 --- a/demo/simulation/task.py +++ b/demo/simulation/task.py @@ -13,3 +13,12 @@ class SimulationTask(object): ''' self.id = id self.query = query + + def json_data(self): + ''' + :returns: dict with all elements + ''' + return { + "id": self.id, + "query": self.query + } diff --git a/demo/simulation/web_server.py b/demo/simulation/web_server.py index 083833b58..08e2bbe1b 100644 --- a/demo/simulation/web_server.py +++ b/demo/simulation/web_server.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- +import json import logging import threading from flask import Flask, request, jsonify @@ -11,7 +12,7 @@ from .task import SimulationTask log = logging.getLogger(__name__) -class SimulationWebServer(): +class SimulationWebServer(object): ''' Memgraph demo fontend server. For now it wraps the flask server. ''' @@ -20,44 +21,45 @@ class SimulationWebServer(): ''' Instantiates the flask web server. ''' - self.server = Flask(__name__) self.is_simulation_running = False self.simulation_stats = None self.simulation_params = SimulationParams() - self.simulation_executor = \ - SimulationExecutor().setup(self.simulation_params) + self.simulation_executor = SimulationExecutor() + self.server = Flask(__name__) + self.setup_routes() + self.server.before_first_request(self.before_first_request) def setup_routes(self): ''' - Setup all available rutes: - GET /ping - POST /tasks - POST /start - POST /stop - GET /stats - GET /params - POST /params + Setup all routes. ''' - self.server.add_url_rule('/ping', 'ping', self.ping) - self.server.add_url_rule('/tasks', 'tasks', self.tasks, - methods=['POST']) - self.server.add_url_rule('/start', 'start', self.start, - methods=['POST']) - self.server.add_url_rule('/stop', 'stop', self.stop, - methods=['POST']) - self.server.add_url_rule('/stats', 'stats', self.stats, - methods=['GET']) - self.server.add_url_rule('/params', 'params_get', self.params_get, - methods=['GET']) - self.server.add_url_rule('/params', 'params_set', self.params_set, - methods=['POST']) + self.add_route('/ping', self.ping, 'GET') + self.add_route('/tasks', self.tasks_get, 'GET') + self.add_route('/tasks', self.tasks_set, 'POST') + self.add_route('/start', self.start, 'POST') + self.add_route('/stop', self.stop, 'POST') + self.add_route('/stats', self.stats, 'GET') + self.add_route('/params', self.params_get, 'GET') + self.add_route('/params', self.params_set, 'POST') - def run(self, host="127.0.0.1", port=8080, debug=False): + def before_first_request(self): ''' - Runs the server. Before run, routes are initialized. + Initializes simulation executor before first request. ''' - self.setup_routes() - self.server.run(host=host, port=port, debug=debug) + log.info('before first request') + self.simulation_executor.setup(self.simulation_params) + + def add_route(self, route, code_method, http_method): + ''' + Registers URL rule + + :param route: str, route string + :param object_method: object method responsible for the + request handling + :param http_method: name of http method + ''' + self.server.add_url_rule(route, '%s_%s' % (route, http_method), + code_method, methods=[http_method]) def ping(self): ''' @@ -65,7 +67,15 @@ class SimulationWebServer(): ''' return ('', 204) - def tasks(self): + def tasks_get(self): + ''' + Retutns all defined tasks. + ''' + return json.dumps( + [task.json_data() for task in self.simulation_params.tasks] + ) + + def tasks_set(self): ''' Register tasks. Task is object that encapsulates single query data. ''' diff --git a/demo/substitutor.py b/demo/substitutor.py new file mode 100644 index 000000000..7125fb0a5 --- /dev/null +++ b/demo/substitutor.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +import sys +import random +import string + + +char_options = string.ascii_lowercase + string.digits + + +def random_integer(start=0, end=sys.maxsize): + ''' + :returns: random integer between start and end + ''' + return random.randint(start, end) + + +def random_float(start=0, end=1): + ''' + :returns: random float between start and end (uniform distribution) + ''' + return random.uniform(start, end) + + +def random_bool(): + ''' + :returns: random bool value + ''' + return bool(random.getrandbits(1)) + + +def random_string(size=5): + ''' + :param size: int, string size + + :returns: random string of specific size build from ascii_lowercase chars + and digits + ''' + return ''.join([random.choice(char_options) + for _ in range(size)]) + + +placeholders = { + '#': random_integer, + '@': random_float, + '*': random_bool, + '^': random_string +} + + +def substitute(text='', placeholders=placeholders): + ''' + Substitutes chars in text with values generated from functions placed + in placeholders dict. + + :param text: str, substitutable text + :param placeholders: dict, key is char that will be substituted, value + is function that is going to be used to generate + a new value + ''' + return ''.join((c if c not in placeholders else str(placeholders[c]()) + for c in iter(text))) + + +if __name__ == '__main__': + + def test_1(): + print([f() for f in [random_integer, random_float, + random_bool, random_string]]) + + def test_2(): + return substitute('int # float @ bool * string ^') + + def test_3(): + print(test_2()) + + test_3()