From 12a758afc42b02ee374a3860bd491544c3438da5 Mon Sep 17 00:00:00 2001 From: Gert Wohlgemuth Date: Sat, 19 May 2018 15:38:33 -0700 Subject: [PATCH] introduced persistence objects --- freqtrade/aws/service/Persistence.py | 53 ++++++++++++++++++++++++++++ freqtrade/aws/service/Queue.py | 47 ++++++++++++++++++++++++ freqtrade/aws/service/__init__.py | 0 freqtrade/aws/strategy.py | 36 ++++++++----------- 4 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 freqtrade/aws/service/Persistence.py create mode 100644 freqtrade/aws/service/Queue.py create mode 100644 freqtrade/aws/service/__init__.py diff --git a/freqtrade/aws/service/Persistence.py b/freqtrade/aws/service/Persistence.py new file mode 100644 index 000000000..d19ae7005 --- /dev/null +++ b/freqtrade/aws/service/Persistence.py @@ -0,0 +1,53 @@ +import boto3 +import simplejson as json + + +class Persistence: + """ + simplistic persistence framework + """ + + def __init__(self, table): + """ + creates a new object with the associated table + :param table: + """ + + self.table = table + self.db = boto3.resource('dynamodb') + + def load(self, sample): + """ + loads a given object from the database storage + :param sample: + :return: + """ + + table = self.db.Table(self.table) + result = table.get_item( + Key={ + 'id': sample + } + ) + + if 'Item' in result: + return result['Item'] + else: + return None + + def save(self, object): + """ + + saves and object to the database storage with the specific key + + :param object: + :return: + """ + + table = self.db.Table(self.table) + + # force serialization to deal with decimal number tag + data = json.dumps(object, use_decimal=True) + data = json.loads(data, use_decimal=True) + print(data) + return table.put_item(Item=data) diff --git a/freqtrade/aws/service/Queue.py b/freqtrade/aws/service/Queue.py new file mode 100644 index 000000000..7f333a24a --- /dev/null +++ b/freqtrade/aws/service/Queue.py @@ -0,0 +1,47 @@ +import simplejson as json +import os +import boto3 + + +class Queue: + """ + abstraction of the underlaying queuing system to schedule a message to the backend for processing + """ + + def submit(self, object, routingKey): + """ + submits the given object to the queue associated with the + routing key. + The routing lambda function will than make sure it will be delivered to the right destination + + :param object: + :param routingKey: + :return: + """ + + # get topic refrence + client = boto3.client('sns') + + # if topic exists, we just reuse it + topic_arn = client.create_topic(Name=os.environ['topic'])['TopicArn'] + + serialized = json.dumps(object, use_decimal=True) + # submit item to queue for routing to the correct persistence + + result = client.publish( + TopicArn=topic_arn, + Message=json.dumps({'default': serialized}), + Subject="route:" + routingKey, + MessageStructure='json', + MessageAttributes={ + 'route': { + 'DataType': 'String', + 'StringValue': routingKey + } + }, + ) + + return { + "statusCode": result['ResponseMetadata']['HTTPStatusCode'], + "body": serialized + } diff --git a/freqtrade/aws/service/__init__.py b/freqtrade/aws/service/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/freqtrade/aws/strategy.py b/freqtrade/aws/strategy.py index f08beb3c1..4260b3a2f 100644 --- a/freqtrade/aws/strategy.py +++ b/freqtrade/aws/strategy.py @@ -1,31 +1,18 @@ -import os -import ctypes - -#for d, dirs, files in os.walk('lib'): -# for f in files: -# if f.endswith('.a') or f.endswith('.la'): -# continue -# print("loading: {}".format(f)) -# ctypes.cdll.LoadLibrary(os.path.join(d, f)) -# - - - from freqtrade.strategy.resolver import StrategyResolver +import os import simplejson as json +import uuid from jsonschema import validate from freqtrade.aws.schemas import __SUBMIT_STRATEGY_SCHEMA__ from base64 import urlsafe_b64decode +from freqtrade.aws.service.Persistence import Persistence +import time -__HTTP_HEADERS__ = { - 'Access-Control-Allow-Origin' : '*', - 'Access-Control-Allow-Credentials' : True -} def names(event, context): """ - returns the names of all registered strategies, but public and private + returns the names of all registered strategies, both public and private :param event: :param context: :return: @@ -80,11 +67,16 @@ def submit(event, context): # try to load the strategy StrategyResolver().compile(data['name'], strategy) - print("compiled strategy") + # generate id + data['id'] = str(uuid.uuid4()) + data['time'] = int(time.time() * 1000) + # save to DB + table = Persistence(os.environ['strategyTable']) + + result = table.save(data) return { - "statusCode": 200, - "headers": __HTTP_HEADERS__, - "body": json.dumps({"success":True}) + "statusCode": result['ResponseMetadata']['HTTPStatusCode'], + "body": json.dumps(result) }