From dcbdbecae06da5dbdedaf537040a1d92c3d57bf0 Mon Sep 17 00:00:00 2001 From: creslinux Date: Wed, 13 Jun 2018 22:18:49 +0000 Subject: [PATCH] Implemented local restful flask service and provided cmdline client Added only the "Daily" call so far, submitting for early review/feedback Called as example "./rest_client.py daily 3" This depends on listed as requirements. Flask==1.0.2 flask-jsonpify==1.5.0 (will do later) flask-restful==0.3.6 TODO: make loading optional, cleanly unload on close unit tests, take feedback, tidy output, add other Telegram functions, onwards local rest server is enabled/disabled from within config.json. E.g "localrest": { "enabled": true }, The server is enabled from within existing rpc manager and makes use of the existing superclass (RPC) Through making use of the existing hard work done in rpc.py It *should be easy to add the other Telegram calls into local_rpc_server.py The server is wrapped in a thread to be non-blocking The server and client accept serialised calls or not, used in daily to return json The client can be used from command line or in a python client script As example, from cmdline for last 3 days Daily DannyMBP:rpc creslin$ ./rest_client.py daily 3 [ [ "2018-06-13", "0.00000000 USDT", "0.000 USD", "0 trade" ], [ "2018-06-12", "0.00000000 USDT", "0.000 USD", "0 trade" ], [ "2018-06-11", "0.00000000 USDT", "0.000 USD", "0 trade" ] ] --- ...cal_rpc_server.py => local_rest_server.py} | 62 +++++++++---------- freqtrade/rpc/rest_client.py | 23 +++++++ 2 files changed, 54 insertions(+), 31 deletions(-) rename freqtrade/rpc/{local_rpc_server.py => local_rest_server.py} (57%) create mode 100755 freqtrade/rpc/rest_client.py diff --git a/freqtrade/rpc/local_rpc_server.py b/freqtrade/rpc/local_rest_server.py similarity index 57% rename from freqtrade/rpc/local_rpc_server.py rename to freqtrade/rpc/local_rest_server.py index 50b6b3a6d..940cc5942 100644 --- a/freqtrade/rpc/local_rpc_server.py +++ b/freqtrade/rpc/local_rest_server.py @@ -1,19 +1,19 @@ import threading -import time -import zerorpc import logging import json +from flask import Flask, request +from flask_restful import Resource, Api +from json import dumps from freqtrade.rpc.rpc import RPC logger = logging.getLogger(__name__) -class LocalRPCControls(object): - """ - zeroRPC - allows local cmdline calls to super class in rpc.py - as used by Telegram.py - """ + +class Daily(Resource): + # called by http://127.0.0.1:/daily?timescale=7 + # where 7 is the number of days to report back with. def __init__(self, freqtrade) -> None: """ @@ -24,18 +24,9 @@ class LocalRPCControls(object): self.freqtrade = freqtrade self._config = freqtrade.config - # # Example of calling none serialed call - # # without decorator - left if as template while in dev for me - # def add_42(self, n): - # """ Add 42 to an integer argument to make it cooler, and return the - # result. """ - # n = int(n) - # r = n + 42 - # s = str(r) - # return s - @zerorpc.stream - def daily(self, timescale): + def get(self): + timescale = request.args.get('timescale') logger.info("LocalRPC - Daily Command Called") timescale = int(timescale) @@ -43,18 +34,21 @@ class LocalRPCControls(object): self._config['stake_currency'], self._config['fiat_display_currency'] ) + if error == False: + stats = dumps(stats, indent=4, sort_keys=True, default=str) + return stats + else: + json.dumps(error) + return error - #Everything in stats to a string, serialised, then back to client. - stats = json.dumps(stats, indent=4, sort_keys=True, default=str) - return(error, stats) -class LocalRPCSuperWrap(RPC): +class LocalRestSuperWrap(RPC): """ - Telegram, this class send messages to Telegram + This class is for REST cmd line client """ def __init__(self, freqtrade) -> None: """ - Init the LocalRPCServer call, and init the super class RPC + Init the LocalRestServer call, and init the super class RPC :param freqtrade: Instance of a freqtrade bot :return: None """ @@ -73,11 +67,17 @@ class LocalRPCSuperWrap(RPC): """ Method that runs forever """ self._config = freqtrade.config + # TODO add IP address / port to bind to in config.json and use in below. - while True: - # Do something - logger.info('Starting Local RPC Listener') - s = zerorpc.Server(LocalRPCControls(freqtrade)) - s.bind("tcp://0.0.0.0:4242") - s.run() - time.sleep(self.interval) + logger.info('Starting Local Rest Server') + + my_freqtrade = freqtrade + app = Flask(__name__) + api = Api(app) + + # Our resources for restful apps go here, pass freqtrade object across + api.add_resource(Daily, '/daily', methods=['GET'], + resource_class_kwargs={'freqtrade': my_freqtrade}) # Route for returning daily + + #run the server + app.run(port='5002') diff --git a/freqtrade/rpc/rest_client.py b/freqtrade/rpc/rest_client.py new file mode 100755 index 000000000..5b39b7a0b --- /dev/null +++ b/freqtrade/rpc/rest_client.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +""" +Simple command line client into RPC commands +Can be used as an alternate to Telegram +""" + +from requests import get +from sys import argv + +if len(argv) == 1: + print('\nThis script accepts the following arguments') + print('- daily (int) - Where int is the number of days to report back. daily 3') + print('- there will be more....\n') + +if len(argv) == 3 and argv[1] == "daily": + if str.isnumeric(argv[2]): + get_url = 'http://localhost:5002/daily?timescale=' + argv[2] + d=get(get_url).json() + print(d) + else: + print("\nThe second argument to daily must be an integer, 1,2,3 etc") + +