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