123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- # encoding-utf8
- '''Tracker communication.'''
- import functools
- import json
- import logging
- import requests
- import socket
- from terroroftinytown import six
- from terroroftinytown.client import VERSION
- from terroroftinytown.util.jsonutil import NativeStringJSONEncoder
- DEFAULT_USER_AGENT = 'Terroroftinytown/{0} (standalone library)'.format(VERSION)
- _logger = logging.getLogger(__name__)
- class TrackerError(Exception):
- pass
- def reraise_with_tracker_error(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except requests.RequestException as error:
- six.raise_from(TrackerError(str(error)), error)
- return wrapper
- class TrackerClient(object):
- def __init__(self, host, username, version=None, bind_address=None,
- user_agent=DEFAULT_USER_AGENT, scheme='http'):
- self.host = host
- self.username = username
- self.client_version = version
- if bind_address:
- self.bind_address(bind_address)
- self.user_agent = user_agent
- self.scheme = scheme
- @reraise_with_tracker_error
- def get_item(self):
- _logger.info('Contacting tracker.')
- response = requests.post(
- '{scheme}://{host}/api/get'.format(
- host=self.host,
- scheme=self.scheme),
- data={
- 'username': self.username,
- 'version': VERSION,
- 'client_version': self.client_version,
- },
- headers={
- 'User-Agent': self.user_agent
- },
- timeout=60,
- )
- response.raise_for_status()
- item = response.json()
- return item
- @reraise_with_tracker_error
- def upload_item(self, claim_id, tamper_key, results):
- _logger.info('Uploading to tracker.')
- response = requests.post(
- '{scheme}://{host}/api/done'.format(
- host=self.host,
- scheme=self.scheme),
- data={
- 'claim_id': claim_id,
- 'tamper_key': tamper_key,
- 'results': json.dumps(results, cls=NativeStringJSONEncoder),
- },
- timeout=60,
- )
- response.raise_for_status()
- @reraise_with_tracker_error
- def report_error(self, claim_id, tamper_key, message):
- _logger.info('Sending error report to tracker.')
- response = requests.post(
- '{scheme}://{host}/api/error'.format(
- host=self.host,
- scheme=self.scheme),
- data={
- 'claim_id': claim_id,
- 'tamper_key': tamper_key,
- 'message': message,
- },
- timeout=60,
- )
- response.raise_for_status()
- def bind_address(self, source_host):
- '''Set **all, global** socket connections to be outbound from this address'''
- # https://stackoverflow.com/questions/1150332/source-interface-with-python-and-urllib2
- real_socket_socket = socket.socket
- def bound_socket(*a, **k):
- sock = real_socket_socket(*a, **k)
- sock.bind((source_host, 0))
- return sock
- socket.socket = bound_socket
- # # https://stackoverflow.com/questions/12585317/requests-bind-to-an-ip
- # real_create_conn = socket.create_connection
- #
- # def set_src_addr(*args):
- # address, timeout = args[0], args[1]
- # source_address = (source_host, 0)
- # return real_create_conn(address, timeout, source_address)
- #
- # socket.create_connection = set_src_addr
|