# -*- coding: utf-8 -*- from __future__ import absolute_import import json import urllib3 from .errors import NSQHttpError from .version import __version__ USERAGENT = 'gnsq/{}'.format(__version__) def _encode(value): if isinstance(value, bytes): return value return value.encode('utf-8') def _encode_dict(value): if value is None: return None return {_encode(k): _encode(v) for k, v in value.items()} class HTTPClient(object): @classmethod def from_url(cls, url, **kwargs): """Create a client from a url.""" url = urllib3.util.parse_url(url) if url.host: kwargs.setdefault('host', url.host) if url.port: kwargs.setdefault('port', url.port) if url.scheme == 'https': kwargs.setdefault('connection_class', urllib3.HTTPSConnectionPool) return cls(**kwargs) def __init__(self, host, port, useragent=USERAGENT, connection_class=urllib3.HTTPConnectionPool, **kwargs): self.useragent = useragent self._connection = connection_class(host, port, **kwargs) @property def scheme(self): return self._connection.scheme @property def host(self): return self._connection.host @property def port(self): return self._connection.port @property def address(self): return '{}://{}:{}/'.format(self.scheme, self.host, self.port) def _request(self, method, url, headers={}, fields=None, **kwargs): headers = dict(headers) headers.setdefault('Accept', 'application/vnd.nsq version=1.0') headers.setdefault('User-Agent', self.useragent) response = self._connection.request_encode_url( method, url, headers=_encode_dict(headers), fields=_encode_dict(fields), **kwargs) if 'application/json' in response.getheader('content-type', ''): return self._http_check_json(response) return self._http_check(response) def _http_check(self, response): if response.status != 200: raise NSQHttpError('http error <{}>'.format(response.status)) return response.data def _http_check_json(self, response): try: data = json.loads(response.data.decode('utf-8')) except ValueError: return self._http_check(response) if response.status != 200: status_txt = data.get('status_txt', 'http error') raise NSQHttpError('{} <{}>'.format(status_txt, response.status)) # Handle 1.0.0-compat vs 0.x versions try: return data['data'] except KeyError: return data def __repr__(self): return '<{!s} {!r}>'.format(type(self).__name__, self.address)