From f26510848501fdaedb5e4ed922c672a5d52cdde4 Mon Sep 17 00:00:00 2001 From: William Luke Date: Tue, 2 Nov 2021 18:50:14 +0300 Subject: [PATCH] add eth-server --- apps/cic-eth/cic_eth/api/api_task.py | 13 +-- apps/cic-eth/cic_eth/graphql/app.py | 23 +++-- apps/cic-eth/cic_eth/graphql/config.py | 10 ++ apps/cic-eth/cic_eth/graphql/schema.py | 96 +++++++++++-------- .../cic_eth/runnable/daemons/server.py | 2 +- apps/cic-eth/requirements.txt | 1 + docker-compose.yml | 49 +++++++++- test.sh | 49 ++++++++++ 8 files changed, 187 insertions(+), 56 deletions(-) create mode 100644 apps/cic-eth/cic_eth/graphql/config.py create mode 100644 test.sh diff --git a/apps/cic-eth/cic_eth/api/api_task.py b/apps/cic-eth/cic_eth/api/api_task.py index db2e537a..fa12ecc6 100644 --- a/apps/cic-eth/cic_eth/api/api_task.py +++ b/apps/cic-eth/cic_eth/api/api_task.py @@ -9,13 +9,14 @@ import logging # external imports import celery from chainlib.chain import ChainSpec -from hexathon import strip_0x - # local imports from cic_eth.api.base import ApiBase from cic_eth.enum import LockEnum +from hexathon import strip_0x app = celery.current_app +print(app.backend) + #logg = logging.getLogger(__name__) logg = logging.getLogger() @@ -488,9 +489,9 @@ class Api(ApiBase): s_balance_incoming.link(s_balance_outgoing) last_in_chain = s_balance_outgoing - one = celery.chain(s_tokens, s_balance) - two = celery.chain(s_tokens, s_balance_incoming) - three = celery.chain(s_tokens, s_balance_outgoing) + one = s_tokens | s_balance + two = s_tokens | s_balance_incoming + three = s_tokens | s_balance_outgoing t = None if self.callback_param != None: @@ -500,7 +501,7 @@ class Api(ApiBase): t = celery.chord([one, two, three])(s_result) else: # TODO: Chord is inefficient with only one chain, but assemble_balances must be able to handle different structures in order to avoid chord - one = celery.chain(s_tokens, s_balance) + one = s_tokens | s_balance if self.callback_param != None: s_result.link(self.callback_success).on_error(self.callback_error) t = celery.chord([one])(s_result) diff --git a/apps/cic-eth/cic_eth/graphql/app.py b/apps/cic-eth/cic_eth/graphql/app.py index d669df77..6b5f9a04 100644 --- a/apps/cic-eth/cic_eth/graphql/app.py +++ b/apps/cic-eth/cic_eth/graphql/app.py @@ -1,11 +1,18 @@ -from cic_eth.graphql.schema import schema +import os + +import cic_eth.cli +from cic_eth.graphql.config import config from flask import Flask from flask_graphql import GraphQLView +from cic_eth.graphql.schema import schema - +app = cic_eth.cli.CeleryApp.from_config(config) +app.set_default() +print(app) def create_app(): - app = Flask(__name__) - app.add_url_rule( + flask_app = Flask(__name__) + + flask_app.add_url_rule( '/graphql', view_func=GraphQLView.as_view( 'graphql', @@ -13,12 +20,12 @@ def create_app(): graphiql=True ) ) - @app.route("/") + @flask_app.route("/") def test(): return "Test ok!" - return app + return flask_app if __name__ == "__main__": - app = create_app() - app.run(host='0.0.0.0', port=5000) + flask_app = create_app() + flask_app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/apps/cic-eth/cic_eth/graphql/config.py b/apps/cic-eth/cic_eth/graphql/config.py new file mode 100644 index 00000000..ace3630d --- /dev/null +++ b/apps/cic-eth/cic_eth/graphql/config.py @@ -0,0 +1,10 @@ +import cic_eth.cli + +arg_flags = cic_eth.cli.argflag_std_base +local_arg_flags = cic_eth.cli.argflag_local_taskcallback +argparser = cic_eth.cli.ArgumentParser(arg_flags) + +argparser.process_local_flags(local_arg_flags) +args = argparser.parse_args() +config = cic_eth.cli.Config.from_args(args, arg_flags, local_arg_flags) + diff --git a/apps/cic-eth/cic_eth/graphql/schema.py b/apps/cic-eth/cic_eth/graphql/schema.py index 652d9055..dc25a5ff 100644 --- a/apps/cic-eth/cic_eth/graphql/schema.py +++ b/apps/cic-eth/cic_eth/graphql/schema.py @@ -1,41 +1,26 @@ # standard imports import json +import logging import sys import uuid -import celery -import cic_eth.cli import redis from cic_eth.api.api_task import Api +from cic_eth.graphql.config import config from graphene import (Boolean, Field, Float, Int, List, Mutation, ObjectType, Schema, String) -arg_flags = cic_eth.cli.argflag_std_base -local_arg_flags = cic_eth.cli.argflag_local_taskcallback -argparser = cic_eth.cli.ArgumentParser(arg_flags) - -argparser.process_local_flags(local_arg_flags) -args = argparser.parse_args() -config = cic_eth.cli.Config.from_args(args, arg_flags, local_arg_flags) - -celery_app = celery.Celery(backend=config.get('CELERY_RESULT_URL'), broker=config.get('CELERY_BROKER_URL')) chain_spec = config.get('CHAIN_SPEC') redis_host = config.get('REDIS_HOST') redis_port = config.get('REDIS_PORT') redis_db = config.get('REDIS_DB') celery_queue = config.get('CELERY_QUEUE') +logging.basicConfig(level=logging.DEBUG) + +log = logging.getLogger(__name__) + -def init_api(redis_channel: str): - api = Api( - chain_spec, - queue=celery_queue, - callback_param='{}:{}:{}:{}'.format( - redis_host, redis_port, redis_db, redis_channel), - callback_task='cic_eth.callbacks.redis.redis', - callback_queue=celery_queue, - ) - return api def call(method, *args): @@ -45,9 +30,15 @@ def call(method, *args): ps.subscribe(redis_channel) ps.get_message() # Subscription Object print(f"Channel init {redis_channel}") - api = init_api(redis_channel) print(args) - + api = Api( + chain_spec, + queue=celery_queue, + callback_param='{}:{}:{}:{}'.format( + redis_host, redis_port, redis_db, redis_channel), + callback_task='cic_eth.callbacks.redis.redis', + callback_queue=celery_queue, + ) getattr(api, method)(*args) ps.get_message() # returns None !? @@ -58,6 +49,7 @@ def call(method, *args): 'got no new address from cic-eth before timeout: {}\n'.format(e)) sys.exit(1) ps.unsubscribe() + print(o) m = json.loads(o['data']) return m["result"] @@ -82,12 +74,19 @@ class TokenBalance(ObjectType): return str(int(parent.balance_network) + int(parent.balance_incoming) - int(parent.balance_outgoing)) + class Query(ObjectType): default_token = Field(Token) def resolve_default_token(parent, info): + # always pass an object for `me` field - data = call('default_token') + api = Api( + chain_spec, + queue=celery_queue, + ) + task = api.default_token() + data = task.get() print(data) return Token(**data) @@ -95,8 +94,14 @@ class Query(ObjectType): token_symbol=String(), include_pending=Boolean()) def resolve_balance(root, info, address, token_symbol, include_pending=True): - data = call('balance', address, token_symbol, include_pending) - print(data) + api = Api( + chain_spec, + queue=celery_queue, + ) + task = api.balance(address=address, token_symbol=token_symbol, include_pending=include_pending) + data = task.get() #api call('balance', address, token_symbol, include_pending) + log.debug(data) + print(data, file=sys.stdout) #[{'address': '3ff776b6f888980def9d4220858803f9dc5e341e', 'converters': [], 'balance_network': 0}] return map(lambda token: TokenBalance( address=token.get("address"), @@ -111,7 +116,13 @@ class Query(ObjectType): required=True), limit=Int(default_value=10)) def resolve_transactions(root, info, address, limit): - data = call('list', address, limit) + + api = Api( + chain_spec, + queue=celery_queue, + ) + task = api.list(address=address, limit=limit) + data = task.get() print(data) #[{'address': '3ff776b6f888980def9d4220858803f9dc5e341e', 'converters': [], 'balance_network': 0}] return "test" @@ -126,8 +137,12 @@ class CreateAccount(Mutation): def mutate(root, info, password, register=True): print(password, register) - - address = call('create_account', password, register) + api = Api( + chain_spec, + queue=celery_queue, + ) + + address = call('create_account',password, register) return CreateAccount(address=f"0x{address}") @@ -145,10 +160,10 @@ class Transfer(Mutation): value, token_symbol): print(from_address, to_address, value, token_symbol) - - redis_channel = str(uuid.uuid4()) - - api = init_api(redis_channel) + api = Api( + chain_spec, + queue=celery_queue, + ) t = api.transfer(from_address, to_address, int(value * (10**6)), token_symbol) print(f"t {t}") @@ -172,12 +187,15 @@ class TransferFrom(Mutation): to_address, value, token_symbol, spender_address): - - data = call('transfer_from', from_address, - to_address, - value, - token_symbol, spender_address) - return data + api = Api( + chain_spec, + queue=celery_queue, + ) + task = api.transfer_from(from_address=from_address, + to_address=to_address, + value=value, + token_symbol=token_symbol, spender_address=spender_address) + return task.get() class MyMutations(ObjectType): diff --git a/apps/cic-eth/cic_eth/runnable/daemons/server.py b/apps/cic-eth/cic_eth/runnable/daemons/server.py index 52494882..e8d6ccfe 100644 --- a/apps/cic-eth/cic_eth/runnable/daemons/server.py +++ b/apps/cic-eth/cic_eth/runnable/daemons/server.py @@ -8,7 +8,6 @@ from urllib.parse import parse_qsl, urlparse import cic_eth.cli import redis -from cic_eth.api.api_task import Api logging.basicConfig(level=logging.WARNING) logg = logging.getLogger() @@ -22,6 +21,7 @@ args = argparser.parse_args() config = cic_eth.cli.Config.from_args(args, arg_flags, local_arg_flags) celery_app = cic_eth.cli.CeleryApp.from_config(config) +from cic_eth.api.api_task import Api # uwsgi application diff --git a/apps/cic-eth/requirements.txt b/apps/cic-eth/requirements.txt index c9a796d2..370e9bd7 100644 --- a/apps/cic-eth/requirements.txt +++ b/apps/cic-eth/requirements.txt @@ -2,6 +2,7 @@ celery==4.4.7 chainlib-eth>=0.0.10a16,<0.1.0 semver==2.13.0 crypto-dev-signer>=0.4.15rc2,<0.5.0 +uwsgi==2.0.19.1 graphene>=2.0 flask>=2.0.2 Flask-GraphQL>=2.0.1 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index bfc1072f..a18f95c6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -121,8 +121,6 @@ services: # queue handling for outgoing transactions and incoming transactions cic-eth-tasker: image: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}/cic-eth:${TAG:-latest} - ports: - - 5000:5000 build: context: apps/cic-eth dockerfile: docker/Dockerfile @@ -170,6 +168,53 @@ services: set +a ./start_tasker.sh --aux-all -q cic-eth -vv + cic-eth-server: + image: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}/cic-eth:${TAG:-latest} + ports: + - 5000:5000 + build: + context: apps/cic-eth + dockerfile: docker/Dockerfile + args: + DOCKER_REGISTRY: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics} + PIP_INDEX_URL: ${PIP_INDEX_URL:-https://pypi.org/simple} + EXTRA_PIP_INDEX_URL: ${EXTRA_PIP_INDEX_URL:-https://pip.grassrootseconomics.net:8433} + EXTRA_PIP_ARGS: $EXTRA_PIP_ARGS + environment: + CIC_REGISTRY_ADDRESS: $CIC_REGISTRY_ADDRESS + RPC_PROVIDER: ${RPC_PROVIDER:-http://evm:8545} + CHAIN_SPEC: ${CHAIN_SPEC:-evm:byzantium:8996:bloxberg} + DATABASE_HOST: ${DATABASE_HOST:-postgres} + DATABASE_PORT: ${DATABASE_PORT:-5432} + DATABASE_NAME: ${DATABASE_NAME:-cic_eth} + DATABASE_PASSWORD: ${DATABASE_PASSWORD:-tralala} + DATABASE_USER: ${DATABASE_USER:-grassroots} + DATABASE_ENGINE: ${DATABASE_ENGINE:-postgres} + DATABASE_DRIVER: ${DATABASE_DRIVER:-psycopg2} + DATABASE_DEBUG: ${DATABASE_DEBUG:-0} + DATABASE_POOL_SIZE: 0 + REDIS_PORT: 6379 + REDIS_HOST: redis + CELERY_BROKER_URL: ${CELERY_BROKER_URL:-redis://redis} + CELERY_RESULT_URL: ${CELERY_RESULT_URL:-redis://redis} + CELERY_DEBUG: ${CELERY_DEBUG:-1} + SIGNER_PROVIDER: ${SIGNER_PROVIDER:-http://cic-signer:8000} + SIGNER_SECRET: ${SIGNER_SECRET:-deadbeef} + TASKS_TRACE_QUEUE_STATUS: ${TASKS_TRACE_QUEUE_STATUS:-1} + restart: unless-stopped + depends_on: + - cic-eth-tasker + volumes: + - signer-data:/run/crypto-dev-signer + - contract-config:/tmp/cic/config/:ro + command: + - /bin/bash + - -c + - | + set -a + if [[ -f /tmp/cic/config/env_reset ]]; then source /tmp/cic/config/env_reset; fi + set +a + python /root/cic_eth/graphql/app.py -vv cic-eth-tracker: image: ${DEV_DOCKER_REGISTRY:-registry.gitlab.com/grassrootseconomics}/cic-eth:${TAG:-latest} diff --git a/test.sh b/test.sh new file mode 100644 index 00000000..5035f28a --- /dev/null +++ b/test.sh @@ -0,0 +1,49 @@ +# 0000 +# 0001 +# 0010 +# 0011 +# 0100 +# 0101 +# 0111 +# 1000 +# 1001 +# 1010 +# 1011 +# 1100 +# 1101 +# 1111 + +RUN_MASK=31 +LAST_BIT_POS=5 + +RUN_MASK_HIGHEST=0 + +for ((i=$LAST_BIT_POS; i>0; i--)); do + b=$((2**$((i-1)))) + if [ $((b & $RUN_MASK)) -gt 0 ]; then + RUN_MASK_HIGHEST=$i + break + fi +done + +echo $RUN_MASK_HIGHEST + + + +bit=1 +for ((i=0; i<$LAST_BIT_POS; i++)); do + runlevel="RUNLEVEL $bit" + if [[ $((RUN_MASK & $bit)) -eq ${bit} ]]; then + s="$runlevel - ${description[$i]}" + >&2 echo -e "\033[;96mRUNNING $s\033[;39m" + # source $((i+1))_${files[$i]}.sh + if [ $? -ne "0" ]; then + >&2 echo -e "\033[;31mFAILED $s\033[;39m" + exit 1; + fi + >&2 echo -e "\033[;32mSUCCEEDED $s\033[;39m" + >&2 echo -e "\033[;96mConfiguration state after $runlevel execution\033[;39m" + # confini-dump --schema-dir ./config + fi + bit=$((bit*2)) +done