|
3 | 3 | # License: MIT (see LICENSE file)
|
4 | 4 |
|
5 | 5 |
|
| 6 | +import random |
| 7 | +import logging |
| 8 | +from btctxstore.services.interface import BlockchainService |
6 | 9 |
|
7 |
| -class Insight(BlockchainService): |
8 | 10 |
|
9 |
| - def __init__(self, testnet=False, dryrun=False): |
10 |
| - super(Insight, self).__init__(testnet=testnet, dryrun=dryrun) |
| 11 | +_log = logging.getLogger(__name__) |
| 12 | + |
| 13 | + |
| 14 | +class Automatic(BlockchainService): |
| 15 | + |
| 16 | + def __init__(self, testnet=False, dryrun=False, service_classes=[]): |
| 17 | + super(Automatic, self).__init__(testnet=testnet, dryrun=dryrun) |
| 18 | + if not service_classes: |
| 19 | + raise ValueError() |
| 20 | + self.services = [] |
| 21 | + for service_class in service_classes: |
| 22 | + self.services.append(service_class(testnet=testnet, dryrun=dryrun)) |
| 23 | + |
| 24 | + def _select_service(self): |
| 25 | + return random.choice(self.services) |
| 26 | + |
| 27 | + def _select_other_service(self, service): |
| 28 | + for other_service in self.services: |
| 29 | + if other_service is not service: |
| 30 | + return other_service |
| 31 | + raise Exception("Not enough services!") |
11 | 32 |
|
12 | 33 | def get_tx(self, txid):
|
13 |
| - """TODO doc string""" |
14 |
| - raise NotImplementedError() |
| 34 | + service = self._select_service() |
| 35 | + try: |
| 36 | + return service.get_tx(txid) |
| 37 | + except Exception as e: |
| 38 | + # try only once with another service |
| 39 | + # if two independant services fail something is wrong |
| 40 | + # there are also only two working services right now ... |
| 41 | + name = service.__class__.__name__ |
| 42 | + msg = "Service call to {0} failed: {1}" |
| 43 | + _log.error(msg.format(name, repr(e))) |
| 44 | + other_service = self._select_other_service(service) |
| 45 | + return other_service.get_tx(txid) |
15 | 46 |
|
16 | 47 | def send_tx(self, tx):
|
17 |
| - """TODO doc string""" |
18 |
| - raise NotImplementedError() |
| 48 | + service = self._select_service() |
| 49 | + try: |
| 50 | + return service.send_tx(tx) |
| 51 | + except Exception as e: |
| 52 | + # try only once with another service |
| 53 | + # if two independant services fail something is wrong |
| 54 | + # there are also only two working services right now ... |
| 55 | + name = service.__class__.__name__ |
| 56 | + msg = "Service call to {0} failed: {1}" |
| 57 | + _log.error(msg.format(name, repr(e))) |
| 58 | + other_service = self._select_other_service(service) |
| 59 | + return other_service.send_tx(tx) |
| 60 | + |
| 61 | + # TODO override spendables_for_addresses in case implementation optimizes |
19 | 62 |
|
20 | 63 | def spendables_for_address(self, bitcoin_address):
|
21 |
| - """TODO doc string""" |
22 |
| - raise NotImplementedError() |
| 64 | + service = self._select_service() |
| 65 | + try: |
| 66 | + return service.spendables_for_address(bitcoin_address) |
| 67 | + except Exception as e: |
| 68 | + # try only once with another service |
| 69 | + # if two independant services fail something is wrong |
| 70 | + # there are also only two working services right now ... |
| 71 | + name = service.__class__.__name__ |
| 72 | + msg = "Service call to {0} failed: {1}" |
| 73 | + _log.error(msg.format(name, repr(e))) |
| 74 | + other_service = self._select_other_service(service) |
| 75 | + return other_service.spendables_for_address(bitcoin_address) |
0 commit comments