From 51990ebbaa1033e419c82e9d2d6aaa8b9a61d9c2 Mon Sep 17 00:00:00 2001 From: Caner Candan <candan@info.univ-angers.fr> Date: Tue, 14 Jan 2014 15:06:44 +0100 Subject: [PATCH] + added initial API files --- api/__init__.py | 93 +++++++++++++++++++++++++++++++++++++ api/hdc/__init__.py | 25 ++++++++++ api/hdc/amendments.py | 37 +++++++++++++++ api/hdc/transactions.py | 31 +++++++++++++ api/pks/__init__.py | 31 +++++++++++++ api/ucg/__init__.py | 37 +++++++++++++++ api/ucg/peering/__init__.py | 52 +++++++++++++++++++++ api/ucg/peering/peers.py | 74 +++++++++++++++++++++++++++++ parser.py | 69 +++++++++++++++++++++++++++ ucoin.py | 52 +++++++++++++++++++++ 10 files changed, 501 insertions(+) create mode 100644 api/__init__.py create mode 100644 api/hdc/__init__.py create mode 100644 api/hdc/amendments.py create mode 100644 api/hdc/transactions.py create mode 100644 api/pks/__init__.py create mode 100644 api/ucg/__init__.py create mode 100644 api/ucg/peering/__init__.py create mode 100644 api/ucg/peering/peers.py create mode 100644 parser.py create mode 100755 ucoin.py diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 00000000..b49f3ca2 --- /dev/null +++ b/api/__init__.py @@ -0,0 +1,93 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +__all__ = ['api'] + +__author__ = 'Caner Candan' +__version__ = '0.0.1' +__nonsense__ = 'uCoin' + +import requests + +URL = 'http://mycurrency.candan.fr:8081' +AUTH = False + +class API: + """APIRequest is a class used as an interface. The intermediate derivated classes are the modules and the leaf classes are the API requests.""" + + def __init__(self, module, url=URL, auth=AUTH): + """ + Asks a module in order to create the url used then by derivated classes. + + Arguments: + - `module`: module name + - `url`: url defining the host and port of the server + - `auth`: enables to get multipart/signed messages. + """ + + self.url = '%s/%s' % (url, module) + self.headers = {} + + if auth: self.headers['Accept'] = 'multipart/signed' + + def reverse_url(self, path): + """ + Reverses the url using self.url and path given in parameter. + + Arguments: + - `path`: the request path + """ + + return self.url + path + + def get(self): + """interface purpose for GET request""" + + pass + + def post(self): + """interface purpose for POST request""" + + pass + + def requests_get(self, path): + """ + Requests GET wrapper in order to use API parameters. + + Arguments: + - `path`: the request path + """ + + return requests.get(self.reverse_url(path), headers=self.headers) + + def requests_post(self, path): + """ + Requests POST wrapper in order to use API parameters. + + Arguments: + - `path`: the request path + """ + + return requests.post(self.reverse_url(path), headers=self.headers) + + def merkle_easy_parser(self, path): + root = self.requests_get(path + '?leaves=true').json() + for leaf in root['leaves']: + yield self.requests_get(path + '?leaf=%s' % leaf).json()['leaf'] + +from . import pks, ucg, hdc diff --git a/api/hdc/__init__.py b/api/hdc/__init__.py new file mode 100644 index 00000000..18ac7c9e --- /dev/null +++ b/api/hdc/__init__.py @@ -0,0 +1,25 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from .. import API + +class HDC(API): + def __init__(self, module='hdc'): + super().__init__(module) + +from . import amendments, transactions diff --git a/api/hdc/amendments.py b/api/hdc/amendments.py new file mode 100644 index 00000000..7ff67704 --- /dev/null +++ b/api/hdc/amendments.py @@ -0,0 +1,37 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from . import HDC + +class Base(HDC): + def __init__(self): + super().__init__('hdc/amendments') + +class List(Base): + """GET the list of amendments through the previousHash value.""" + + def get(self): + """creates a generator with one amendment per iteration.""" + + current = self.requests_get('/current').json() + yield current + + while 'previousHash' in current and current['previousHash']: + current['previousNumber'] = current['number']-1 + current = self.requests_get('/view/%(previousNumber)d-%(previousHash)s/self' % current).json() + yield current diff --git a/api/hdc/transactions.py b/api/hdc/transactions.py new file mode 100644 index 00000000..8f25dea4 --- /dev/null +++ b/api/hdc/transactions.py @@ -0,0 +1,31 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from . import HDC + +class Base(HDC): + def __init__(self): + super().__init__('hdc/transactions') + +class All(Base): + """GET all the transactions stored by this node.""" + + def get(self): + """creates a generator with one transaction per iteration.""" + + return self.merkle_easy_parser('/all') diff --git a/api/pks/__init__.py b/api/pks/__init__.py new file mode 100644 index 00000000..f7a0e0e7 --- /dev/null +++ b/api/pks/__init__.py @@ -0,0 +1,31 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from .. import API + +class PKS(API): + def __init__(self, module='pks'): + super().__init__(module) + +class All(PKS): + """GET all the received public keys.""" + + def get(self): + """creates a generator with one public key per iteration.""" + + return self.merkle_easy_parser('/all') diff --git a/api/ucg/__init__.py b/api/ucg/__init__.py new file mode 100644 index 00000000..96c61e41 --- /dev/null +++ b/api/ucg/__init__.py @@ -0,0 +1,37 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from .. import API + +class UCG(API): + def __init__(self, module='ucg'): + super().__init__(module) + +class Pubkey(UCG): + """GET the public key of the peer.""" + + def get(self): + return self.requests_get('/pubkey').text + +class Peering(UCG): + """GET peering information about a peer.""" + + def get(self): + return self.requests_get('/peering').json() + +from . import peering diff --git a/api/ucg/peering/__init__.py b/api/ucg/peering/__init__.py new file mode 100644 index 00000000..8a34fabb --- /dev/null +++ b/api/ucg/peering/__init__.py @@ -0,0 +1,52 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from .. import UCG + +class Base(UCG): + def __init__(self): + super().__init__('ucg/peering') + +class Keys(Base): + """GET PGP keys' fingerprint this node manages, i.e. this node will have transactions history and follow ohter nodes for this history.""" + + def get(self): + """creates a generator with one transaction per iteration.""" + + return self.merkle_easy_parser('/keys') + +class Peer(Base): + """GET the peering informations of this node.""" + + def get(self): + """returns peering entry of the node.""" + + return self.requests_get('/peer').json() + +class Peers(Base): + """GET peering entries of every node inside the currency network.""" + + def get(self): + """creates a generator with one peering entry per iteration.""" + + return self.merkle_easy_parser('/peers') + + def post(self): + pass + +from . import peers diff --git a/api/ucg/peering/peers.py b/api/ucg/peering/peers.py new file mode 100644 index 00000000..80eba079 --- /dev/null +++ b/api/ucg/peering/peers.py @@ -0,0 +1,74 @@ +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from . import UCG + +class Base(UCG): + def __init__(self): + super().__init__('ucg/peering/peers') + +class Stream(Base): + """GET a list of peers this node is listening to/by for ANY incoming transaction.""" + + def __init__(self, request, pgp_fingerprint=None): + """ + Use the pgp fingerprint parameter in order to fit the result. + + Arguments: + - `request`: select the stream request + - `pgp_fingerprint`: pgp fingerprint to use as a filter + """ + + super().__init__() + + self.request = request + self.pgp_fingerprint = pgp_fingerprint + + def get(self): + """returns the corresponding peer list.""" + + if not self.pgp_fingerprint: + return self.requests_get('/%s' % self.request).json() + + return self.requests_get('/%s/%s' % (self.request, self.pgp_fingerprint)).json() + +class UpStream(Stream): + """GET a list of peers this node is listening to for ANY incoming transaction.""" + + def __init__(self, pgp_fingerprint=None): + """ + Use the pgp fingerprint parameter in order to fit the result. + + Arguments: + - `pgp_fingerprint`: pgp fingerprint to use as a filter + """ + + super().__init__('upstream', pgp_fingerprint) + +class DownStream(Stream): + """GET a list of peers this node is listening by for ANY incoming transaction.""" + + def __init__(self, pgp_fingerprint=None): + """ + Use the pgp fingerprint parameter in order to fit the result. + + Arguments: + - `pgp_fingerprint`: pgp fingerprint to use as a filter + """ + + super().__init__('downstream', pgp_fingerprint) diff --git a/parser.py b/parser.py new file mode 100644 index 00000000..84552a97 --- /dev/null +++ b/parser.py @@ -0,0 +1,69 @@ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 +# as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +import argparse, logging, sys +from collections import OrderedDict + +class Parser(argparse.ArgumentParser): + """Wrapper class added logging support""" + + def __init__(self, description='', verbose='quiet', formatter_class=argparse.ArgumentDefaultsHelpFormatter): + """ + We add all the common options to manage verbosity. + """ + + argparse.ArgumentParser.__init__(self, description=description, formatter_class=formatter_class) + + self.levels = OrderedDict([('debug', logging.DEBUG), + ('info', logging.INFO), + ('warning', logging.WARNING), + ('error', logging.ERROR), + ('quiet', logging.CRITICAL), + ]) + + self.add_argument('--verbose', '-v', choices=[x for x in self.levels.keys()], default=verbose, help='set a verbosity level') + self.add_argument('--levels', '-l', action='store_true', default=False, help='list all the verbosity levels') + self.add_argument('--output', '-o', help='all the logging messages are redirected to the specified filename.') + self.add_argument('--debug', '-d', action='store_const', const='debug', dest='verbose', help='Diplay all the messages.') + self.add_argument('--info', '-i', action='store_const', const='info', dest='verbose', help='Diplay the info messages.') + self.add_argument('--warning', '-w', action='store_const', const='warning', dest='verbose', help='Only diplay the warning and error messages.') + self.add_argument('--error', '-e', action='store_const', const='error', dest='verbose', help='Only diplay the error messages') + self.add_argument('--quiet', '-q', action='store_const', const='quiet', dest='verbose', help='Quiet level of verbosity only displaying the critical error messages.') + + def __call__(self): + args = self.parse_args() + + if args.levels: + print("Here's the verbose levels available:") + for keys in self.levels.keys(): + print("\t", keys) + sys.exit() + + if (args.output): + logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + filename=args.output, filemode='a' + ) + else: + logging.basicConfig( + level=self.levels.get(args.verbose, logging.NOTSET), + format='%(name)-12s: %(levelname)-8s %(message)s' + ) + + return args diff --git a/ucoin.py b/ucoin.py new file mode 100755 index 00000000..85d57afe --- /dev/null +++ b/ucoin.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Authors: +# Caner Candan <caner@candan.fr>, http://caner.candan.fr +# + +from parser import Parser +from pprint import pprint +import api + +URL = 'http://mycurrency.candan.fr:8081' +AUTH = False + +def action_peering(): + pprint(api.ucg.Peering().get()) + +def action_amendments(): + for am in api.hdc.amendments.List().get(): + print(am['number']) + +def action_transactions(): + for tx in api.hdc.transactions.All().get(): + print(tx['hash']) + +if __name__ == '__main__': + parser = Parser(description='ucoin client.', verbose='error') + + parser.add_argument('--peering', '-p', help='get peering', + action='store_const', dest='action', const=action_peering) + + parser.add_argument('--amendments', '-a', help='get amendments list', + action='store_const', dest='action', const=action_amendments) + + parser.add_argument('--transactions', '-t', help='get transactions list', + action='store_const', dest='action', const=action_transactions) + + args = parser() + + if args.action: args.action() -- GitLab