import re import os import time import sys import urllib, urllib2 from subprocess import Popen, PIPE Request = urllib2.Request urlencode = urllib.urlencode urlopen = urllib2.urlopen from Config import WORKING_DIR, MAX_SIZE, \ SPECIAL_DOWNLOADERS, SPECIAL_DOWNLOADERS_MAX_SIZE, \ BIN_IDENTIFY class BadParamError(Exception): pass class Params(object): def __init__(self, classname="", **kwargs): self._working_dir = WORKING_DIR self._now = kwargs.get("now", str(int(time.time()))); self._classname = classname for key, value in kwargs.items(): setattr(self, key, value) def __iter__(self): for key, value in vars(self).iteritems(): yield key, value def err_warn(self, s, error=None): self._error_log(s, error=error); raise BadParamError("%s - %s" % (self._classname, s)) def __getattr__(self, key): try: return self.__getattribute__(key); except AttributeError: return None def err_fatal(self, s, error=None): self._log(s, error, fatal=True); sys.exit(1); def set_val(self, key, value, value_type=None, enum_values=None): try: if value_type == "color": value = self._color_sanitize(value) elif value_type == "float": value = float(value) elif value_type == "int": value = int(value) elif value_type == "bool": value = self._bool_correct(str(value)) elif value_type == "string": value = self.sanitize(str(value)) elif value_type == "img_url": if value: _filename = self._filename_temporary(key) _path = os.path.join(self._working_dir, _filename) self._image_download(value, _path) _mimetype = self._image_mimetype(_path) value = { 'url': value, 'path': _path, 'mimetype' : _mimetype } elif value_type == "enum": if value not in enum_values: raise ValueError elif value_type == "json": pass self.__setattr__(key, value) except Exception as e: self.err_warn("key: %s value: %s" % (key, value), error=str(e)) def sanitize (self, s): return re.sub(r'\W+', '', s) def _color_sanitize(self, s): if s == "": return "transparent" if re.match('(rgba?\([0-9]+,[0-9]+,[0-9]+\))|([a-zA-Z]+)|(\#[A-Ha-h0-9]+)', s): return s.replace(' ', ''); else: sys.stderr.write("Not a color: {}\n".format(s)) raise ValueError def _bool_correct(self, b): if type(b) == str: if re.match(r'true', b, re.IGNORECASE): return True elif re.match(r'false', b, re.IGNORECASE): return False elif type(b) == bool: return b raise ValueError def _filename_temporary(self, s): return "_tmp-{}-{}_{}".format(self._classname, self._now, s) def _error_log(self, s, error=None, fatal=False): message = "ERROR - BAD PARAM" if fatal: message += "- [FATAL] -" sys.stderr.write("{}:{} - {}\n".format(message, self._classname, s)) if error: sys.stderr.write("PARAM ERROR: {}\n".format(str(error))) def _image_download(self, url, path): max_size = MAX_SIZE if self.username in SPECIAL_DOWNLOADERS: max_size = SPECIAL_DOWNLOADERS_MAX_SIZE try: self._download(url, path, max_size=max_size) except Exception as e: self.err_warn("Download failed"); def _browser_request (self, url, data=None): headers = { 'User-Agent': 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', 'Accept': '*/*', } try: req = Request(url, data, headers) response = urlopen(req) except IOError as e: if hasattr(e, 'code'): sys.stderr.write( 'browser request error: %s - ERROR %s' % (url, e.code) ) raise IOError return response def _download(self, url, destination, max_size=MAX_SIZE): response = self._browser_request(url, None) rawimg = response.read() if len(rawimg) == 0: self.err_warn("got zero-length file") if len(rawimg) > max_size: self.err_warn("file too big: max size {} KB / {} is {} KB".format( str(MAX_SIZE/1024), destination, str(len(rawimg)/1024) ) ) f = open(destination, "w") f.write(rawimg) f.close() def _image_mimetype(self, f): try: mimetype = Popen( [BIN_IDENTIFY, f], stdout=PIPE ).communicate()[0].split(" ")[1].lower() return mimetype except Exception as e: sys.stderr.write("couldn't determine mimetype\n") raise e;