<commit_before>"""
Set of classes to manipulate/display emails inside the webmail.
"""
import os
import re
import email

import chardet
from rfc6266 import parse_headers
import six

from django.conf import settings
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _

from modoboa.core.extensions import exts_pool
from modoboa.lib import u2u_decode
from modoboa.lib.email_utils import Email, EmailAddress

from . import imapheader
from .imaputils import (
    get_imapconnector, BodyStructure
)
from .utils import decode_payload

class ImapEmail(Email):

    """
    A class to represent an email fetched from an IMAP server.
    """

    headernames = [
        ('From', True),
        ('To', True),
        ('Cc', True),
        ('Date', True),
        ('Subject', True),
    ]

    def __init__(self, request, *args, **kwargs):
        super(ImapEmail, self).__init__(*args, **kwargs)
        self.request = request
        self.imapc = get_imapconnector(request)
        self.mbox, self.mailid = self.mailid.split(":")

    def _insert_contact_links(self, addresses):
        """Insert 'add to address book' links."""
        result = []
        title = _("Add to contacts")
        url = reverse("api:contact-list")
        link_tpl = (
            " "
            ""
        )
        for address in addresses:
            address += link_tpl.format(url, title)
            result.append(address)
        return result

    def fetch_headers(self, raw_addresses=False):
        """Fetch message headers from server."""
        msg = self.imapc.fetchmail(
            self.mbox, self.mailid, readonly=False,
            headers=self.headers_as_list
        )
        headers = msg["BODY[HEADER.FIELDS ({})]".format(self.headers_as_text)]
        self.fetch_body_structure(msg)
        msg = email.message_from_string(headers)
        contacts_plugin_installed = exts_pool.get_extension("modoboa_contacts")
        headers_with_address = ("From", "To", "Cc")
        for hdr in self.headernames:
            label = hdr[0]
            hdrvalue = self.get_header(msg, label, raw=raw_addresses)
            if not hdrvalue:
                continue
            if hdr[1]:
                if label in headers_with_address:
                    if contacts_plugin_installed and not raw_addresses:
                        hdrvalue = self._insert_contact_links(hdrvalue)
                    hdrvalue = ", ".join(hdrvalue)
                self.headers += [{"name": label, "value": hdrvalue}]
            label = re.sub("-", "_", label)
            setattr(self, label, hdrvalue)

    def get_header(self, msg, hdrname, **kwargs):
        """Look for a particular header.

        We also try to decode the default value.
        """
        hdrvalue = super(ImapEmail, self).get_header(msg, hdrname)
        if not hdrvalue:
            return ""
        try:
            key = re.sub("-", "_", hdrname).lower()
            hdrvalue = getattr(imapheader, "parse_%s" % key)(
                hdrvalue, **kwargs)
        except AttributeError:
            pass
        return hdrvalue

    def fetch_body_structure(self, msg=None):
        """Fetch BODYSTRUCTURE for email."""
        if msg is None:
            msg = self.imapc.fetchmail(
                self.mbox, self.mailid, readonly=False
            )
        self.bs = BodyStructure(msg["BODYSTRUCTURE"])
        self._find_attachments()
        if self.dformat not in ["plain", "html"]:
            self.dformat = self.request.user.parameters.get_value(
                self.dformat)
        fallback_fmt = "html" if self.dformat == "plain" else "plain"
        self.mformat = (
            self.dformat if self.dformat in self.bs.contents else fallback_fmt)

    @property
    def headers_as_list(self):
        return [hdr[0].upper() for hdr in self.headernames]

    @property
    def headers_as_text(self):
        return " ".join(self.headers_as_list)

    @property
    def body(self):
        """Load email's body.

        This operation has to be made "on demand" because it requires
        a communication with the IMAP server.
        """
        if self._body is None:
            self.fetch_body_structure()
            bodyc = u""
            for part in self.bs.contents[self.mformat]:
                pnum = part["pnum"]
                data = self.imapc._cmd(
                    "FETCH", self.mailid, "(BODY.PEEK[%s])" % pnum
                )
                content = decode_payload(
                    part["encoding"], data[int(self.mailid)]["BODY[%s]" % pnum]
                )
                if not isinstance(content, six.text_type):
                    charset = self._find_content_charset(part)
                    if charset is not None:
                        try:
                            content = content.decode(charset)
                        except (UnicodeDecodeError, LookupError):
                            result = chardet.detect(content)
                            content = content.decode(result["encoding"])
                bodyc += content
            self._fetch_inlines()
            self._body = getattr(self, "viewmail_%s" % self.mformat)(
                bodyc, links=self.links
            )
        return self._body

    @body.setter
    def body(self, value):
        self._body = value

    def _find_content_charset(self, part):
        for pos, elem in enumerate(part["params"]):
            if elem == "charset":
                return part["params"][pos + 1]
        return None

    def _find_attachments(self):
        """Retrieve attachments from the parsed body structure.

        We try to find and decode a file name for each attachment. If
        we failed, a generic name will be used (ie. part_1, part_2, ...).
        """
        for att in self.bs.attachments:
            attname = "part_%s" % att["pnum"]
            if "params" in att and att["params"] != "NIL":
                attname = u2u_decode.u2u_decode(att["params"][1]) \
                    .strip("\r\t\n")
            elif "disposition" in att and len(att["disposition"]) > 1:
                for pos, value in enumerate(att["disposition"][1]):
                    if not value.startswith("filename"):
                        continue
                    header = "%s; %s=%s" \
                        % (att['disposition'][0],
                           value,
                           att["disposition"][1][pos + 1].strip("\r\t\n"))
                    attname = parse_headers(header).filename_unsafe
                    if attname is None:
                        attname = u2u_decode.u2u_decode(
                            att["disposition"][1][pos + 1]
                        ).strip("\r\t\n")
                    break
            self.attachments[att["pnum"]] = attname

    def _fetch_inlines(self):
        """Store inline images on filesystem to display them."""
        for cid, params in list(self.bs.inlines.items()):
            if re.search(r"\.\.", cid):
                continue
            fname = "modoboa_webmail/%s_%s" % (self.mailid, cid)
            path = os.path.join(settings.MEDIA_ROOT, fname)
            params["fname"] = os.path.join(settings.MEDIA_URL, fname)
            if default_storage.exists(path):
                continue
            pdef, content = self.imapc.fetchpart(
                self.mailid, self.mbox, params["pnum"]
            )
            default_storage.save(
                path, ContentFile(decode_payload(params["encoding"], content)))

    def map_cid(self, url):
        m = re.match(".*cid:(.+)", url)
        if m:
            if m.group(1) in self.bs.inlines:
                return self.bs.inlines[m.group(1)]["fname"]
        return url

    def fetch_attachment(self, pnum):
        """Fetch an attachment from the IMAP server."""
        return self.imapc.fetchpart(self.mailid, self.mbox, pnum)

class Modifier(ImapEmail):
    """Message modifier."""

    def __init__(self, form, request, *args, **kwargs):
        kwargs["dformat"] = request.user.parameters.get_value("editor")
        super(Modifier, self).__init__(request, *args, **kwargs)
        self.form = form
        self.fetch_headers(raw_addresses=True)
        getattr(self, "_modify_%s" % self.dformat)()

    def _modify_plain(self):
        self.body = re.sub("</?pre>", "", self.body)

    def _modify_html(self):
        if self.dformat == "html" and self.mformat != self.dformat:
            self.body = re.sub("</?pre>", "", self.body)
            self.body = re.sub("\n", "
", self.body)

    @property
    def subject(self):
        """Just a shortcut to return a subject in any case."""
        return self.Subject if hasattr(self, "Subject") else ""

class ReplyModifier(Modifier):
    """Modify a message to reply to it."""

    headernames = ImapEmail.headernames + [
        ("Reply-To", True),
        ("Message-ID", False)
    ]

    def __init__(self, *args, **kwargs):
        super(ReplyModifier, self).__init__(*args, **kwargs)

        self.textheader = u"%s %s" % (self.From, _("wrote:"))
        if self.dformat == "html":
            self.textheader = u"
{}
".format(self.textheader)
        if hasattr(self, "Message_ID"):
            self.form.fields["origmsgid"].initial = self.Message_ID
        if not hasattr(self, "Reply_To"):
            self.form.fields["to"].initial = self.From
        else:
            self.form.fields["to"].initial = self.Reply_To
        if self.request.GET.get("all", "0") == "1":  # reply-all
            self.form.fields["cc"].initial = ""
            toparse = self.To.split(",")
            if hasattr(self, 'Cc'):
                toparse += self.Cc.split(",")
            for addr in toparse:
                tmp = EmailAddress(addr)
                if tmp.address and tmp.address == self.request.user.username:
                    continue
                if self.form.fields["cc"].initial != "":
                    self.form.fields["cc"].initial += ", "
                self.form.fields["cc"].initial += tmp.fulladdress
        m = re.match(r"re\s*:\s*.+", self.subject.lower())
        if m:
            self.form.fields["subject"].initial = self.subject
        else:
            self.form.fields["subject"].initial = "Re: %s" % self.subject

    def _modify_plain(self):
        super(ReplyModifier, self)._modify_plain()
        lines = self.body.split('\n')
        body = ""
        for l in lines:
            if body != "":
                body += "\n"
            body += ">%s" % l
        self.body = body

class ForwardModifier(Modifier):

    """
    Modify a message so it can be forwarded.
    """

    def __init__(self, *args, **kwargs):
        super(ForwardModifier, self).__init__(*args, **kwargs)
        self._header()
        self.form.fields["subject"].initial = "Fwd: %s" % self.subject

    def __getfunc(self, name):
        return getattr(self, "%s_%s" % (name, self.dformat))

    def _header(self):
        self.textheader = self.__getfunc("_header_begin")() + "\n"
        self.textheader += \
            self.__getfunc("_header_line")(_("Subject"), self.subject)
        self.textheader += \
            self.__getfunc("_header_line")(_("Date"), self.Date)
        for hdr in ["From", "To", "Reply-To"]:
            try:
                key = re.sub("-", "_", hdr)
                value = getattr(self, key)
                self.textheader += \
                    self.__getfunc("_header_line")(_(hdr), value)
            except AttributeError:
                pass
        self.textheader += self.__getfunc("_header_end")()

    def _header_begin_plain(self):
        return "----- %s -----" % _("Original message")

    def _header_begin_html(self):
        return "----- %s -----" % _("Original message")

    def _header_line_plain(self, key, value):
        return "%s: %s\n" % (key, value)

    def _header_line_html(self, key, value):
        return "
%s: %s
" % (key, value)

    def _header_end_plain(self):
        return "\n"

    def _header_end_html(self):
        return ""
<commit_msg>Added full address display when forwarding a mail<commit_after>"""
Set of classes to manipulate/display emails inside the webmail.
"""
import os
import re
import email

import chardet
from rfc6266 import parse_headers
import six

from django.conf import settings
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.core.urlresolvers import reverse
from django.utils.html import escape
from django.utils.translation import ugettext as _

from modoboa.core.extensions import exts_pool
from modoboa.lib import u2u_decode
from modoboa.lib.email_utils import Email, EmailAddress

from . import imapheader
from .imaputils import (
    get_imapconnector, BodyStructure
)
from .utils import decode_payload

class ImapEmail(Email):

    """
    A class to represent an email fetched from an IMAP server.
    """

    headernames = [
        ('From', True),
        ('To', True),
        ('Cc', True),
        ('Date', True),
        ('Subject', True),
    ]

    def __init__(self, request, *args, **kwargs):
        super(ImapEmail, self).__init__(*args, **kwargs)
        self.request = request
        self.imapc = get_imapconnector(request)
        self.mbox, self.mailid = self.mailid.split(":")

    def _insert_contact_links(self, addresses):
        """Insert 'add to address book' links."""
        result = []
        title = _("Add to contacts")
        url = reverse("api:contact-list")
        link_tpl = (
            " "
            ""
        )
        for address in addresses:
            address += link_tpl.format(url, title)
            result.append(address)
        return result

    def fetch_headers(self, raw_addresses=False):
        """Fetch message headers from server."""
        msg = self.imapc.fetchmail(
            self.mbox, self.mailid, readonly=False,
            headers=self.headers_as_list
        )
        headers = msg["BODY[HEADER.FIELDS ({})]".format(self.headers_as_text)]
        self.fetch_body_structure(msg)
        msg = email.message_from_string(headers)
        contacts_plugin_installed = exts_pool.get_extension("modoboa_contacts")
        headers_with_address = ("From", "To", "Cc")
        for hdr in self.headernames:
            label = hdr[0]
            hdrvalue = self.get_header(msg, label, raw=raw_addresses)
            if not hdrvalue:
                continue
            if hdr[1]:
                if label in headers_with_address:
                    if contacts_plugin_installed and not raw_addresses:
                        hdrvalue = self._insert_contact_links(hdrvalue)
                    hdrvalue = ", ".join(hdrvalue)
                self.headers += [{"name": label, "value": hdrvalue}]
            label = re.sub("-", "_", label)
            setattr(self, label, hdrvalue)

    def get_header(self, msg, hdrname, **kwargs):
        """Look for a particular header.

        We also try to decode the default value.
        """
        hdrvalue = super(ImapEmail, self).get_header(msg, hdrname)
        if not hdrvalue:
            return ""
        try:
            key = re.sub("-", "_", hdrname).lower()
            hdrvalue = getattr(imapheader, "parse_%s" % key)(
                hdrvalue, **kwargs)
        except AttributeError:
            pass
        return hdrvalue

    def fetch_body_structure(self, msg=None):
        """Fetch BODYSTRUCTURE for email."""
        if msg is None:
            msg = self.imapc.fetchmail(
                self.mbox, self.mailid, readonly=False
            )
        self.bs = BodyStructure(msg["BODYSTRUCTURE"])
        self._find_attachments()
        if self.dformat not in ["plain", "html"]:
            self.dformat = self.request.user.parameters.get_value(
                self.dformat)
        fallback_fmt = "html" if self.dformat == "plain" else "plain"
        self.mformat = (
            self.dformat if self.dformat in self.bs.contents else fallback_fmt)

    @property
    def headers_as_list(self):
        return [hdr[0].upper() for hdr in self.headernames]

    @property
    def headers_as_text(self):
        return " ".join(self.headers_as_list)

    @property
    def body(self):
        """Load email's body.

        This operation has to be made "on demand" because it requires
        a communication with the IMAP server.
        """
        if self._body is None:
            self.fetch_body_structure()
            bodyc = u""
            for part in self.bs.contents[self.mformat]:
                pnum = part["pnum"]
                data = self.imapc._cmd(
                    "FETCH", self.mailid, "(BODY.PEEK[%s])" % pnum
                )
                content = decode_payload(
                    part["encoding"], data[int(self.mailid)]["BODY[%s]" % pnum]
                )
                if not isinstance(content, six.text_type):
                    charset = self._find_content_charset(part)
                    if charset is not None:
                        try:
                            content = content.decode(charset)
                        except (UnicodeDecodeError, LookupError):
                            result = chardet.detect(content)
                            content = content.decode(result["encoding"])
                bodyc += content
            self._fetch_inlines()
            self._body = getattr(self, "viewmail_%s" % self.mformat)(
                bodyc, links=self.links
            )
        return self._body

    @body.setter
    def body(self, value):
        self._body = value

    def _find_content_charset(self, part):
        for pos, elem in enumerate(part["params"]):
            if elem == "charset":
                return part["params"][pos + 1]
        return None

    def _find_attachments(self):
        """Retrieve attachments from the parsed body structure.

        We try to find and decode a file name for each attachment. If
        we failed, a generic name will be used (ie. part_1, part_2, ...).
        """
        for att in self.bs.attachments:
            attname = "part_%s" % att["pnum"]
            if "params" in att and att["params"] != "NIL":
                attname = u2u_decode.u2u_decode(att["params"][1]) \
                    .strip("\r\t\n")
            elif "disposition" in att and len(att["disposition"]) > 1:
                for pos, value in enumerate(att["disposition"][1]):
                    if not value.startswith("filename"):
                        continue
                    header = "%s; %s=%s" \
                        % (att['disposition'][0],
                           value,
                           att["disposition"][1][pos + 1].strip("\r\t\n"))
                    attname = parse_headers(header).filename_unsafe
                    if attname is None:
                        attname = u2u_decode.u2u_decode(
                            att["disposition"][1][pos + 1]
                        ).strip("\r\t\n")
                    break
            self.attachments[att["pnum"]] = attname

    def _fetch_inlines(self):
        """Store inline images on filesystem to display them."""
        for cid, params in list(self.bs.inlines.items()):
            if re.search(r"\.\.", cid):
                continue
            fname = "modoboa_webmail/%s_%s" % (self.mailid, cid)
            path = os.path.join(settings.MEDIA_ROOT, fname)
            params["fname"] = os.path.join(settings.MEDIA_URL, fname)
            if default_storage.exists(path):
                continue
            pdef, content = self.imapc.fetchpart(
                self.mailid, self.mbox, params["pnum"]
            )
            default_storage.save(
                path, ContentFile(decode_payload(params["encoding"], content)))

    def map_cid(self, url):
        m = re.match(".*cid:(.+)", url)
        if m:
            if m.group(1) in self.bs.inlines:
                return self.bs.inlines[m.group(1)]["fname"]
        return url

    def fetch_attachment(self, pnum):
        """Fetch an attachment from the IMAP server."""
        return self.imapc.fetchpart(self.mailid, self.mbox, pnum)

class Modifier(ImapEmail):
    """Message modifier."""

    def __init__(self, form, request, *args, **kwargs):
        kwargs["dformat"] = request.user.parameters.get_value("editor")
        super(Modifier, self).__init__(request, *args, **kwargs)
        self.form = form
        self.fetch_headers(raw_addresses=True)
        getattr(self, "_modify_%s" % self.dformat)()

    def _modify_plain(self):
        self.body = re.sub("</?pre>", "", self.body)

    def _modify_html(self):
        if self.dformat == "html" and self.mformat != self.dformat:
            self.body = re.sub("</?pre>", "", self.body)
            self.body = re.sub("\n", "
", self.body)

    @property
    def subject(self):
        """Just a shortcut to return a subject in any case."""
        return self.Subject if hasattr(self, "Subject") else ""

class ReplyModifier(Modifier):
    """Modify a message to reply to it."""

    headernames = ImapEmail.headernames + [
        ("Reply-To", True),
        ("Message-ID", False)
    ]

    def __init__(self, *args, **kwargs):
        super(ReplyModifier, self).__init__(*args, **kwargs)

        self.textheader = u"%s %s" % (self.From, _("wrote:"))
        if self.dformat == "html":
            self.textheader = u"
{}
".format(self.textheader)
        if hasattr(self, "Message_ID"):
            self.form.fields["origmsgid"].initial = self.Message_ID
        if not hasattr(self, "Reply_To"):
            self.form.fields["to"].initial = self.From
        else:
            self.form.fields["to"].initial = self.Reply_To
        if self.request.GET.get("all", "0") == "1":  # reply-all
            self.form.fields["cc"].initial = ""
            toparse = self.To.split(",")
            if hasattr(self, 'Cc'):
                toparse += self.Cc.split(",")
            for addr in toparse:
                tmp = EmailAddress(addr)
                if tmp.address and tmp.address == self.request.user.username:
                    continue
                if self.form.fields["cc"].initial != "":
                    self.form.fields["cc"].initial += ", "
                self.form.fields["cc"].initial += tmp.fulladdress
        m = re.match(r"re\s*:\s*.+", self.subject.lower())
        if m:
            self.form.fields["subject"].initial = self.subject
        else:
            self.form.fields["subject"].initial = "Re: %s" % self.subject

    def _modify_plain(self):
        super(ReplyModifier, self)._modify_plain()
        lines = self.body.split('\n')
        body = ""
        for l in lines:
            if body != "":
                body += "\n"
            body += ">%s" % l
        self.body = body

class ForwardModifier(Modifier):

    """Modify a message so it can be forwarded."""

    def __init__(self, *args, **kwargs):
        super(ForwardModifier, self).__init__(*args, **kwargs)
        self._header()
        self.form.fields["subject"].initial = "Fwd: %s" % self.subject

    def __getfunc(self, name):
        return getattr(self, "%s_%s" % (name, self.dformat))

    def _header(self):
        self.textheader = "{}\n".format(self.__getfunc("_header_begin")())
        self.textheader += (
            self.__getfunc("_header_line")(_("Subject"), self.subject))
        self.textheader += (
            self.__getfunc("_header_line")(_("Date"), self.Date))
        for hdr in ["From", "To", "Reply-To"]:
            try:
                key = re.sub("-", "_", hdr)
                value = getattr(self, key)
                self.textheader += (
                    self.__getfunc("_header_line")(_(hdr), value))
            except AttributeError:
                pass
        self.textheader += self.__getfunc("_header_end")()

    def _header_begin_plain(self):
        return "----- %s -----" % _("Original message")

    def _header_begin_html(self):
        return "----- %s -----" % _("Original message")

    def _header_line_plain(self, key, value):
        return "%s: %s\n" % (key, value)

    def _header_line_html(self, key, value):
        return "
%s: %s
" % (key, escape(value))

    def _header_end_plain(self):
        return "\n"

    def _header_end_html(self):
        return ""
<|endoftext|>


<commit_before>from decimal import Decimal
from django.db import models
import os
import glob
import time
import git
import datetime
import RPIO
import rollbar

class Pin(models.Model):
    name = models.CharField(max_length=200, null=False)
    description = models.CharField(max_length=200, null=False)
    pin_number = models.IntegerField(null=False)
    is_thermometer = models.BooleanField(default=False, null=False)

    updated_at = models.DateTimeField(auto_now_add=False, auto_now=True)
    created_at = models.DateTimeField(auto_now_add=True, auto_now=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if self.is_thermometer:
            try:
                self.thermometer = Thermometer('28')  # todo update this one day
            except:
                # rollbar.report_exc_info()
                # rollbar.report_message('could not set thermometer')
                self.thermometer = None

    def get_direction(self):
        return RPIO.OUT if self.is_thermometer is False else RPIO.IN

    def get_temp(self):
        if self.thermometer:
            time.sleep(3)
            self.thermometer.refresh()
            return self.thermometer.celsius

        return '?'

    def get_state(self):
        try:
            return RPIO.input(self.pin_number)
        except:
            rollbar.report_message('could not get_state')
            return None

    def get_state_opposite(self):
        return not self.get_state()

    def set_state(self, state):
        return RPIO.output(self.pin_number, RPIO.HIGH if state else RPIO.LOW)

    def set_state_upside_down(self, state):
        return RPIO.output(self.pin_number, RPIO.HIGH if not state else RPIO.LOW)

class Thermometer(object):
    def __init__(self, serial):
        self.celsius = 0
        self.fahrenheit = 0
        self.serial = serial

        self.refresh()

    def read_temp_raw(self):
        base_dir = '/sys/bus/w1/devices/'
        device_folder = glob.glob(base_dir + '{serial}*'.format(serial=self.serial))[0]
        device_file = device_folder + '/w1_slave'

        f = open(device_file, 'r')
        lines = f.readlines()
        f.close()
        return lines

    def read_temp(self):
        lines = self.read_temp_raw()

        while lines[0].strip()[-3:] != 'YES':
            time.sleep(0.2)
            lines = self.read_temp_raw()

        equals_pos = lines[1].find('t=')

        if equals_pos != -1:
            temp_string = lines[1][equals_pos + 2:]
            temp_c = float(temp_string) / 1000.0
            self.celsius = round(temp_c, 1)
            self.fahrenheit = ((self.celsius * 9) / 5.0) + 32

    def refresh(self):
        os.system('modprobe w1-gpio')
        os.system('modprobe w1-therm')

        self.read_temp()

class Git(object):
    def __init__(self):
        self.repo = git.Repo(os.getcwd())
        self.branch = 'origin/PiPool'

    def check(self):
        self.repo.remote().fetch()

        diff = self.repo.index.diff(self.branch)
        return bool(diff)

    def update(self):
        try:
            self.repo.remote().pull()
            return True
        except git.GitCommandError:
            rollbar.report_message('could not update git')
            return False

class TimeBand(models.Model):
    start_at = models.TimeField(null=True)
    end_at = models.TimeField(null=True)
    active = models.BooleanField(default=True, null=False)
    day_of_week = models.IntegerField(null=False)

class TempControl(models.Model):
    name = models.CharField(max_length=200, null=False)
    manuel = models.BooleanField(default=False, null=False)
    manuel_at = models.DateTimeField(null=True)
    temp = models.DecimalField(max_digits=5, decimal_places=2, null=False)
    range = models.DecimalField(max_digits=5, decimal_places=2, null=False, default=2)
    temp_pin_id = models.IntegerField(null=False)
    pump_pin_id = models.IntegerField(null=False)
    heater_pin_id = models.IntegerField(null=False)

    def __get_pin(self, id):
        return Pin.objects.filter(id=id).first()

    def __get_manuel_period(self):
        return 30

    def __allowed_to_run(self):
        now = datetime.datetime.now()
        time = now.time()
        result = False

        time_bands = TimeBand.objects.filter(active=True)

        for time_band in time_bands:
            if now.day == time_band.day_of_week:
                if time > time_band.start_at and time < time_band.end_at:
                    result = True
                    break

        return result

    def maintain(self):
        if self.manuel:
            future = datetime.datetime.now() + datetime.timedelta(minutes=self.__get_manuel_period())
            self.manuel_at = self.manuel_at.replace(tzinfo=None)
            future = future.replace(tzinfo=None)
            print(self.manuel_at)
            print(future)
            if self.manuel_at > future:
                self.manuel = False
                self.manuel_at = None
                self.save()

                self.__turn_off()
                return
        else:
            pass
            # todo finish: create view and way to edit
            # if not self.__allowed_to_run:
            #     self.__turn_off()
            #     return

        pin = self.__get_pin(self.temp_pin_id)

        if not pin:
            Exception("No pins has been set, unable to maintain")
        else:
            temp = Decimal(pin.get_temp())
            too_cold = self.temp - self.range

            if temp <= too_cold:
                self.__turn_on()
                return

            if temp >= self.temp:
                self.__turn_off()
                return

    def outside_turn_on(self):
        self.__set_state(True)

    def __turn_on(self):
        self.__set_state(True)

    def __turn_off(self):
        self.__set_state(False)

    def __set_state(self, state):
        pump = self.__get_pin(self.pump_pin_id)
        heater = self.__get_pin(self.heater_pin_id)

        if self.manuel:
            pump.set_state_upside_down(True)
            pump.set_state_upside_down(state)
        else:
            if state:
                pump.set_state_upside_down(state)
                time.sleep(3)
                heater.set_state_upside_down(state)
            else:
                heater.set_state_upside_down(state)
                time.sleep(3)
                pump.set_state_upside_down(state)
<commit_msg>remove print statments<commit_after>from decimal import Decimal
from django.db import models
import os
import glob
import time
import git
import datetime
import RPIO
import rollbar

class Pin(models.Model):
    name = models.CharField(max_length=200, null=False)
    description = models.CharField(max_length=200, null=False)
    pin_number = models.IntegerField(null=False)
    is_thermometer = models.BooleanField(default=False, null=False)

    updated_at = models.DateTimeField(auto_now_add=False, auto_now=True)
    created_at = models.DateTimeField(auto_now_add=True, auto_now=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        if self.is_thermometer:
            try:
                self.thermometer = Thermometer('28')  # todo update this one day
            except:
                # rollbar.report_exc_info()
                # rollbar.report_message('could not set thermometer')
                self.thermometer = None

    def get_direction(self):
        return RPIO.OUT if self.is_thermometer is False else RPIO.IN

    def get_temp(self):
        if self.thermometer:
            time.sleep(3)
            self.thermometer.refresh()
            return self.thermometer.celsius

        return '?'

    def get_state(self):
        try:
            return RPIO.input(self.pin_number)
        except:
            rollbar.report_message('could not get_state')
            return None

    def get_state_opposite(self):
        return not self.get_state()

    def set_state(self, state):
        return RPIO.output(self.pin_number, RPIO.HIGH if state else RPIO.LOW)

    def set_state_upside_down(self, state):
        return RPIO.output(self.pin_number, RPIO.HIGH if not state else RPIO.LOW)

class Thermometer(object):
    def __init__(self, serial):
        self.celsius = 0
        self.fahrenheit = 0
        self.serial = serial

        self.refresh()

    def read_temp_raw(self):
        base_dir = '/sys/bus/w1/devices/'
        device_folder = glob.glob(base_dir + '{serial}*'.format(serial=self.serial))[0]
        device_file = device_folder + '/w1_slave'

        f = open(device_file, 'r')
        lines = f.readlines()
        f.close()
        return lines

    def read_temp(self):
        lines = self.read_temp_raw()

        while lines[0].strip()[-3:] != 'YES':
            time.sleep(0.2)
            lines = self.read_temp_raw()

        equals_pos = lines[1].find('t=')

        if equals_pos != -1:
            temp_string = lines[1][equals_pos + 2:]
            temp_c = float(temp_string) / 1000.0
            self.celsius = round(temp_c, 1)
            self.fahrenheit = ((self.celsius * 9) / 5.0) + 32

    def refresh(self):
        os.system('modprobe w1-gpio')
        os.system('modprobe w1-therm')

        self.read_temp()

class Git(object):
    def __init__(self):
        self.repo = git.Repo(os.getcwd())
        self.branch = 'origin/PiPool'

    def check(self):
        self.repo.remote().fetch()

        diff = self.repo.index.diff(self.branch)
        return bool(diff)

    def update(self):
        try:
            self.repo.remote().pull()
            return True
        except git.GitCommandError:
            rollbar.report_message('could not update git')
            return False

class TimeBand(models.Model):
    start_at = models.TimeField(null=True)
    end_at = models.TimeField(null=True)
    active = models.BooleanField(default=True, null=False)
    day_of_week = models.IntegerField(null=False)

class TempControl(models.Model):
    name = models.CharField(max_length=200, null=False)
    manuel = models.BooleanField(default=False, null=False)
    manuel_at = models.DateTimeField(null=True)
    temp = models.DecimalField(max_digits=5, decimal_places=2, null=False)
    range = models.DecimalField(max_digits=5, decimal_places=2, null=False, default=2)
    temp_pin_id = models.IntegerField(null=False)
    pump_pin_id = models.IntegerField(null=False)
    heater_pin_id = models.IntegerField(null=False)

    def __get_pin(self, id):
        return Pin.objects.filter(id=id).first()

    def __get_manuel_period(self):
        return 30

    def __allowed_to_run(self):
        now = datetime.datetime.now()
        time = now.time()
        result = False

        time_bands = TimeBand.objects.filter(active=True)

        for time_band in time_bands:
            if now.day == time_band.day_of_week:
                if time > time_band.start_at and time < time_band.end_at:
                    result = True
                    break

        return result

    def maintain(self):
        if self.manuel:
            future = datetime.datetime.now() + datetime.timedelta(minutes=self.__get_manuel_period())
            self.manuel_at = self.manuel_at.replace(tzinfo=None)
            future = future.replace(tzinfo=None)

            if self.manuel_at > future:
                self.manuel = False
                self.manuel_at = None
                self.save()

                self.__turn_off()
                return
        else:
            pass
            # todo finish: create view and way to edit
            # if not self.__allowed_to_run:
            #     self.__turn_off()
            #     return

        pin = self.__get_pin(self.temp_pin_id)

        if not pin:
            Exception("No pins has been set, unable to maintain")
        else:
            temp = Decimal(pin.get_temp())
            cold = self.temp - self.range

            if temp <= cold:
                self.__turn_on()
                return

            if temp >= self.temp:
                self.__turn_off()
                return

    def outside_turn_on(self):
        self.__set_state(True)

    def __turn_on(self):
        self.__set_state(True)

    def __turn_off(self):
        self.__set_state(False)

    def __set_state(self, state):
        pump = self.__get_pin(self.pump_pin_id)
        heater = self.__get_pin(self.heater_pin_id)

        if self.manuel:
            pump.set_state_upside_down(True)
            pump.set_state_upside_down(state)
        else:
            if state:
                pump.set_state_upside_down(state)
                time.sleep(3)
                heater.set_state_upside_down(state)
            else:
                heater.set_state_upside_down(state)
                time.sleep(3)
                pump.set_state_upside_down(state)
<|endoftext|>


<commit_before>from __future__ import print_function, division
import serial
import time
import atexit
import json
import functools
import operator
import platform
import os
import inflection

from serial_device2 import SerialDevice, SerialDevices, find_serial_device_ports, WriteFrequencyError

try:
    from pkg_resources import get_distribution, DistributionNotFound
    _dist = get_distribution('modular_client')
    # Normalize case for Windows systems
    dist_loc = os.path.normcase(_dist.location)
    here = os.path.normcase(__file__)
    if not here.startswith(os.path.join(dist_loc, 'modular_client')):
        # not installed, but there is another version that *is*
        raise DistributionNotFound
except (ImportError,DistributionNotFound):
    __version__ = None
else:
    __version__ = _dist.version

DEBUG = False
BAUDRATE = 115200

class ModularClient(object):
    '''
    ModularClient contains an instance of serial_device2.SerialDevice
    and adds methods to it, like auto discovery of available modular
    devices in Linux, Windows, and Mac OS X. This class automatically
    creates methods from available functions reported by the modular
    device when it is running the appropriate firmware. This is the
    modular device client library for communicating with and calling
    remote methods on modular device servers.

    Example Usage:

    dev = ModularClient() # Might automatically find device if one available
    # if it is not found automatically, specify port directly
    dev = ModularClient(port='/dev/ttyACM0') # Linux specific port
    dev = ModularClient(port='/dev/tty.usbmodem262471') # Mac OS X specific port
    dev = ModularClient(port='COM3') # Windows specific port
    dev.get_device_id()
    dev.get_methods()

    '''
    _TIMEOUT = 0.05
    _WRITE_WRITE_DELAY = 0.05
    _RESET_DELAY = 2.0
    _METHOD_ID_GET_METHOD_IDS = 0

    def __init__(self,*args,**kwargs):
        name = None
        form_factor = None
        serial_number = None
        if 'debug' in kwargs:
            self.debug = kwargs['debug']
        else:
            kwargs.update({'debug': DEBUG})
            self.debug = DEBUG
        if 'try_ports' in kwargs:
            try_ports = kwargs.pop('try_ports')
        else:
            try_ports = None
        if 'baudrate' not in kwargs:
            kwargs.update({'baudrate': BAUDRATE})
        elif (kwargs['baudrate'] is None) or (str(kwargs['baudrate']).lower() == 'default'):
            kwargs.update({'baudrate': BAUDRATE})
        if 'timeout' not in kwargs:
            kwargs.update({'timeout': self._TIMEOUT})
        if 'write_write_delay' not in kwargs:
            kwargs.update({'write_write_delay': self._WRITE_WRITE_DELAY})
        if 'name' in kwargs:
            name = kwargs.pop('name')
        if 'form_factor' in kwargs:
            form_factor = kwargs.pop('form_factor')
        if 'serial_number' in kwargs:
            serial_number = kwargs.pop('serial_number')
        if ('port' not in kwargs) or (kwargs['port'] is None):
            port =  find_modular_device_port(baudrate=kwargs['baudrate'],
                                             name=name,
                                             form_factor=form_factor,
                                             serial_number=serial_number,
                                             try_ports=try_ports,
                                             debug=kwargs['debug'])
            kwargs.update({'port': port})

        t_start = time.time()
        self._serial_device = SerialDevice(*args,**kwargs)
        atexit.register(self._exit_modular_client)
        time.sleep(self._RESET_DELAY)
        self._method_dict = self._get_method_dict()
        self._method_dict_inv = dict([(v,k) for (k,v) in self._method_dict.iteritems()])
        self._create_methods()
        t_end = time.time()
        self._debug_print('Initialization time =', (t_end - t_start))

    def _debug_print(self, *args):
        if self.debug:
            print(*args)

    def _exit_modular_client(self):
        pass

    def _args_to_request(self,*args):
        request = json.dumps(args,separators=(',',':'))
        request += '\n';
        return request

    def _handle_response(self,response,request_id):
        if response is None:
            error_message = 'Did not receive server response.'
            raise IOError, error_message
        try:
            response_dict = json_string_to_dict(response)
        except Exception, e:
            error_message = 'Unable to parse server response {0}.'.format(str(e))
            raise IOError, error_message
        try:
            id  = response_dict.pop('id')
        except KeyError:
            error_message = 'Server response does not contain id member.'
            raise IOError, error_message
        if not id == request_id:
            raise IOError, 'Response id does not match request id.'
        try:
            error = response_dict.pop('error')
            try:
                message = error.pop('message')
            except KeyError:
                message = ''
            try:
                data = error.pop('data')
            except KeyError:
                data = ''
            try:
                code = error.pop('code')
            except KeyError:
                code = ''
            error_message = '(from server) message: {0}, data: {1}, code: {2}'.format(message,data,code)
            raise IOError, error_message
        except KeyError:
            pass
        try:
            result  = response_dict.pop('result')
        except KeyError:
            error_message = 'Server response does not contain result member.'
            raise IOError, error_message
        return result

    def _send_request_get_result(self,*args):
        '''
        Sends request to server over serial port and
        returns response result
        '''
        request = self._args_to_request(*args)
        self._debug_print('request', request)
        response = self._serial_device.write_read(request,use_readline=True,check_write_freq=True)
        self._debug_print('response', response)
        result = self._handle_response(response,args[0])
        return result

    def _get_method_dict(self):
        method_dict = self._send_request_get_result(self._METHOD_ID_GET_METHOD_IDS)
        return method_dict

    def _send_request_by_method_name(self,name,*args):
        method_id = self._method_dict[name]
        method_args = [method_id]
        method_args.extend(args)
        result = self._send_request_get_result(*method_args)
        return result

    def _method_func_base(self,method_name,*args):
        if len(args) == 1 and type(args[0]) is dict:
            args_dict = args[0]
            args_list = self._args_dict_to_list(args_dict)
        else:
            args_list = args
        result = self._send_request_by_method_name(method_name,*args_list)
        return result

    def _create_methods(self):
        self._method_func_dict = {}
        for method_id, method_name in sorted(self._method_dict_inv.items()):
            method_func = functools.partial(self._method_func_base, method_name)
            setattr(self,inflection.underscore(method_name),method_func)
            self._method_func_dict[method_name] = method_func

    def _args_dict_to_list(self,args_dict):
        key_set = set(args_dict.keys())
        order_list = sorted([(num,name) for (name,num) in order_dict.iteritems()])
        args_list = [args_dict[name] for (num, name) in order_list]
        return args_list

    def close(self):
        '''
        Close the device serial port.
        '''
        self._serial_device.close()

    def get_port(self):
        return self._serial_device.port

    def get_methods(self):
        '''
        Get a list of modular methods automatically attached as class methods.
        '''
        return [inflection.underscore(key) for key in self._method_dict.keys()]

    def call_server_method(self,method_name,*args):
        method_name = inflection.camelize(method_name,False)
        return self._send_request_get_result(method_name,*args)

    def send_json_request(self,request):
        '''
        Sends json request to device over serial port and returns result
        '''
        request_python = json.loads(request)
        try:
            request_id = request_python["id"]
        except TypeError:
            pass
        except KeyError:
            error_message = 'Request does not contain an id.'
            raise IOError, error_message
        try:
            request_python["method"] = inflection.camelize(request_python["method"],False)
        except TypeError:
            pass
        except KeyError:
            error_message = 'Request does not contain a method.'
            raise IOError, error_message
        try:
            request_python[0] = inflection.camelize(request_python[0],False)
            request_id = request_python[0]
        except IndexError:
            error_message = 'Request does not contain a method.'
            raise IOError, error_message
        request = json.dumps(request_python,separators=(',',':'))
        request += '\n'
        self._debug_print('request', request)
        response = self._serial_device.write_read(request,use_readline=True,check_write_freq=True)
        self._debug_print('response', response)
        result = self._handle_response(response,request_id)
        return result

    def convert_to_json(self,python_to_convert,response_indent=None):
        '''
        Convert python object to json string.
        '''
        converted_json = json.dumps(python_to_convert,separators=(',',':'),indent=response_indent)
        return converted_json

class ModularClients(dict):
    '''
    ModularClients inherits from dict and automatically populates it
    with ModularClients on all available serial ports. Access each
    individual client with three keys, the device name, the
    form_factor, and the serial_number. If you want to connect
    multiple ModularClients with the same name and form_factor at the
    same time, first make sure they have unique serial_numbers by
    connecting each device one by one and using the set_serial_number
    method on each device.

    Example Usage:

    devs = ModularClients()  # Might automatically find all available devices
    # if they are not found automatically, specify ports to use
    devs = ModularClients(use_ports=['/dev/ttyUSB0','/dev/ttyUSB1']) # Linux
    devs = ModularClients(use_ports=['/dev/tty.usbmodem262471','/dev/tty.usbmodem262472']) # Mac OS X
    devs = ModularClients(use_ports=['COM3','COM4']) # Windows
    devs.items()
    dev = devs[name][form_factor][serial_number]

    '''
    def __init__(self,*args,**kwargs):
        if ('use_ports' not in kwargs) or (kwargs['use_ports'] is None):
            modular_device_ports = find_modular_device_ports(*args,**kwargs)
        else:
            modular_device_ports = use_ports

        for port in modular_device_ports:
            kwargs.update({'port': port})
            self._add_device(*args,**kwargs)

    def _add_device(self,*args,**kwargs):
        dev = ModularClient(*args,**kwargs)
        device_id = dev.get_device_id()
        name = device_id['name']
        form_factor = device_id['form_factor']
        serial_number = device_id['serial_number']
        if name not in self:
            self[name] = {}
        if form_factor not in self[name]:
            self[name][form_factor] = {}
        self[name][form_factor][serial_number] = dev

def check_dict_for_key(d,k,dname=''):
    if not k in d:
        if not dname:
            dname = 'dictionary'
        raise IOError, '{0} does not contain {1}'.format(dname,k)

def json_string_to_dict(json_string):
    json_dict =  json.loads(json_string,object_hook=json_decode_dict)
    return json_dict

def json_decode_dict(data):
    '''
    Object hook for decoding dictionaries from serialized json data. Ensures that
    all strings are unpacked as str objects rather than unicode.
    '''
    rv = {}
    for key, value in data.iteritems():
        if isinstance(key, unicode):
            key = key.encode('utf-8')
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        elif isinstance(value, list):
            value = json_decode_list(value)
        elif isinstance(value, dict):
            value = json_decode_dict(value)
        rv[key] = value
    return rv

def json_decode_list(data):
    '''
    Object hook for decoding lists from serialized json data. Ensures that
    all strings are unpacked as str objects rather than unicode.
    '''
    rv = []
    for item in data:
        if isinstance(item, unicode):
            item = item.encode('utf-8')
        elif isinstance(item, list):
            item = json_decode_list(item)
        elif isinstance(item, dict):
            item = json_decode_dict(item)
        rv.append(item)
    return rv

def find_modular_device_ports(baudrate=None,
                              name=None,
                              form_factor=None,
                              serial_number=None,
                              try_ports=None,
                              debug=DEBUG,
                              *args,
                              **kwargs):
    serial_device_ports = find_serial_device_ports(try_ports=try_ports, debug=debug)
    os_type = platform.system()
    if os_type == 'Darwin':
        serial_device_ports = [x for x in serial_device_ports if 'tty.usbmodem' in x or 'tty.usbserial' in x]

    if type(name) is str:
        name = [name]
    if type(form_factor) is str:
        form_factor = [form_factor]
    if type(serial_number) is int:
        serial_number = [serial_number]

    modular_device_ports = {}
    for port in serial_device_ports:
        try:
            dev = ModularClient(port=port,baudrate=baudrate,debug=debug)
            device_id = dev.get_device_id()
            if ((name is None ) and (device_id['name'] is not None)) or (device_id['name'] in name):
                if ((form_factor is None) and (device_id['form_factor'] is not None)) or (device_id['form_factor'] in form_factor):
                    if ((serial_number is None) and (device_id['serial_number'] is not None)) or (device_id['serial_number'] in serial_number):
                        modular_device_ports[port] = {'name': device_id['name'],
                                                      'form_factor': device_id['form_factor'],
                                                      'serial_number': device_id['serial_number']}
            dev.close()
        except (serial.SerialException, IOError):
            pass
    return modular_device_ports

def find_modular_device_port(baudrate=None,
                             name=None,
                             form_factor=None,
                             serial_number=None,
                             try_ports=None,
                             debug=DEBUG):
    modular_device_ports = find_modular_device_ports(baudrate=baudrate,
                                                     name=name,
                                                     form_factor=form_factor,
                                                     serial_number=serial_number,
                                                     try_ports=try_ports,
                                                     debug=debug)
    if len(modular_device_ports) == 1:
        return modular_device_ports.keys()[0]
    elif len(modular_device_ports) == 0:
        serial_device_ports = find_serial_device_ports(try_ports)
        err_string = 'Could not find any Modular devices. Check connections and permissions.\n'
        err_string += 'Tried ports: ' + str(serial_device_ports)
        raise RuntimeError(err_string)
    else:
        err_string = 'Found more than one Modular device. Specify port or name and/or form_factor and/or serial_number.\n'
        err_string += 'Matching ports: ' + str(modular_device_ports)
        raise RuntimeError(err_string)

# -----------------------------------------------------------------------------------------
if __name__ == '__main__':

    debug = False
    dev = ModularClient(debug=debug)
<commit_msg>Changes to work with Python 3.<commit_after>from __future__ import print_function, division
import serial
import time
import atexit
import json
import functools
import operator
import platform
import os
import inflection

from serial_device2 import SerialDevice, SerialDevices, find_serial_device_ports, WriteFrequencyError

try:
    from pkg_resources import get_distribution, DistributionNotFound
    _dist = get_distribution('modular_client')
    # Normalize case for Windows systems
    dist_loc = os.path.normcase(_dist.location)
    here = os.path.normcase(__file__)
    if not here.startswith(os.path.join(dist_loc, 'modular_client')):
        # not installed, but there is another version that *is*
        raise DistributionNotFound
except (ImportError,DistributionNotFound):
    __version__ = None
else:
    __version__ = _dist.version

DEBUG = False
BAUDRATE = 115200

class ModularClient(object):
    '''
    ModularClient contains an instance of serial_device2.SerialDevice
    and adds methods to it, like auto discovery of available modular
    devices in Linux, Windows, and Mac OS X. This class automatically
    creates methods from available functions reported by the modular
    device when it is running the appropriate firmware. This is the
    modular device client library for communicating with and calling
    remote methods on modular device servers.

    Example Usage:

    dev = ModularClient() # Might automatically find device if one available
    # if it is not found automatically, specify port directly
    dev = ModularClient(port='/dev/ttyACM0') # Linux specific port
    dev = ModularClient(port='/dev/tty.usbmodem262471') # Mac OS X specific port
    dev = ModularClient(port='COM3') # Windows specific port
    dev.get_device_id()
    dev.get_methods()

    '''
    _TIMEOUT = 0.05
    _WRITE_WRITE_DELAY = 0.05
    _RESET_DELAY = 2.0
    _METHOD_ID_GET_METHOD_IDS = 0

    def __init__(self,*args,**kwargs):
        name = None
        form_factor = None
        serial_number = None
        if 'debug' in kwargs:
            self.debug = kwargs['debug']
        else:
            kwargs.update({'debug': DEBUG})
            self.debug = DEBUG
        if 'try_ports' in kwargs:
            try_ports = kwargs.pop('try_ports')
        else:
            try_ports = None
        if 'baudrate' not in kwargs:
            kwargs.update({'baudrate': BAUDRATE})
        elif (kwargs['baudrate'] is None) or (str(kwargs['baudrate']).lower() == 'default'):
            kwargs.update({'baudrate': BAUDRATE})
        if 'timeout' not in kwargs:
            kwargs.update({'timeout': self._TIMEOUT})
        if 'write_write_delay' not in kwargs:
            kwargs.update({'write_write_delay': self._WRITE_WRITE_DELAY})
        if 'name' in kwargs:
            name = kwargs.pop('name')
        if 'form_factor' in kwargs:
            form_factor = kwargs.pop('form_factor')
        if 'serial_number' in kwargs:
            serial_number = kwargs.pop('serial_number')
        if ('port' not in kwargs) or (kwargs['port'] is None):
            port =  find_modular_device_port(baudrate=kwargs['baudrate'],
                                             name=name,
                                             form_factor=form_factor,
                                             serial_number=serial_number,
                                             try_ports=try_ports,
                                             debug=kwargs['debug'])
            kwargs.update({'port': port})

        t_start = time.time()
        self._serial_device = SerialDevice(*args,**kwargs)
        atexit.register(self._exit_modular_client)
        time.sleep(self._RESET_DELAY)
        self._method_dict = self._get_method_dict()
        self._method_dict_inv = dict([(v,k) for (k,v) in self._method_dict.iteritems()])
        self._create_methods()
        t_end = time.time()
        self._debug_print('Initialization time =', (t_end - t_start))

    def _debug_print(self, *args):
        if self.debug:
            print(*args)

    def _exit_modular_client(self):
        pass

    def _args_to_request(self,*args):
        request = json.dumps(args,separators=(',',':'))
        request += '\n';
        return request

    def _handle_response(self,response,request_id):
        if response is None:
            error_message = 'Did not receive server response.'
            raise IOError(error_message)
        try:
            response_dict = json_string_to_dict(response)
        except Exception, e:
            error_message = 'Unable to parse server response {0}.'.format(str(e))
            raise IOError(error_message)
        try:
            id  = response_dict.pop('id')
        except KeyError:
            error_message = 'Server response does not contain id member.'
            raise IOError(error_message)
        if not id == request_id:
            raise IOError('Response id does not match request id.')
        try:
            error = response_dict.pop('error')
            try:
                message = error.pop('message')
            except KeyError:
                message = ''
            try:
                data = error.pop('data')
            except KeyError:
                data = ''
            try:
                code = error.pop('code')
            except KeyError:
                code = ''
            error_message = '(from server) message: {0}, data: {1}, code: {2}'.format(message,data,code)
            raise IOError(error_message)
        except KeyError:
            pass
        try:
            result  = response_dict.pop('result')
        except KeyError:
            error_message = 'Server response does not contain result member.'
            raise IOError(error_message)
        return result

    def _send_request_get_result(self,*args):
        '''
        Sends request to server over serial port and
        returns response result
        '''
        request = self._args_to_request(*args)
        self._debug_print('request', request)
        response = self._serial_device.write_read(request,use_readline=True,check_write_freq=True)
        self._debug_print('response', response)
        result = self._handle_response(response,args[0])
        return result

    def _get_method_dict(self):
        method_dict = self._send_request_get_result(self._METHOD_ID_GET_METHOD_IDS)
        return method_dict

    def _send_request_by_method_name(self,name,*args):
        method_id = self._method_dict[name]
        method_args = [method_id]
        method_args.extend(args)
        result = self._send_request_get_result(*method_args)
        return result

    def _method_func_base(self,method_name,*args):
        if len(args) == 1 and type(args[0]) is dict:
            args_dict = args[0]
            args_list = self._args_dict_to_list(args_dict)
        else:
            args_list = args
        result = self._send_request_by_method_name(method_name,*args_list)
        return result

    def _create_methods(self):
        self._method_func_dict = {}
        for method_id, method_name in sorted(self._method_dict_inv.items()):
            method_func = functools.partial(self._method_func_base, method_name)
            setattr(self,inflection.underscore(method_name),method_func)
            self._method_func_dict[method_name] = method_func

    def _args_dict_to_list(self,args_dict):
        key_set = set(args_dict.keys())
        order_list = sorted([(num,name) for (name,num) in order_dict.iteritems()])
        args_list = [args_dict[name] for (num, name) in order_list]
        return args_list

    def close(self):
        '''
        Close the device serial port.
        '''
        self._serial_device.close()

    def get_port(self):
        return self._serial_device.port

    def get_methods(self):
        '''
        Get a list of modular methods automatically attached as class methods.
        '''
        return [inflection.underscore(key) for key in self._method_dict.keys()]

    def call_server_method(self,method_name,*args):
        method_name = inflection.camelize(method_name,False)
        return self._send_request_get_result(method_name,*args)

    def send_json_request(self,request):
        '''
        Sends json request to device over serial port and returns result
        '''
        request_python = json.loads(request)
        try:
            request_id = request_python["id"]
        except TypeError:
            pass
        except KeyError:
            error_message = 'Request does not contain an id.'
            raise IOError(error_message)
        try:
            request_python["method"] = inflection.camelize(request_python["method"],False)
        except TypeError:
            pass
        except KeyError:
            error_message = 'Request does not contain a method.'
            raise IOError(error_message)
        try:
            request_python[0] = inflection.camelize(request_python[0],False)
            request_id = request_python[0]
        except IndexError:
            error_message = 'Request does not contain a method.'
            raise IOError(error_message)
        request = json.dumps(request_python,separators=(',',':'))
        request += '\n'
        self._debug_print('request', request)
        response = self._serial_device.write_read(request,use_readline=True,check_write_freq=True)
        self._debug_print('response', response)
        result = self._handle_response(response,request_id)
        return result

    def convert_to_json(self,python_to_convert,response_indent=None):
        '''
        Convert python object to json string.
        '''
        converted_json = json.dumps(python_to_convert,separators=(',',':'),indent=response_indent)
        return converted_json

class ModularClients(dict):
    '''
    ModularClients inherits from dict and automatically populates it
    with ModularClients on all available serial ports. Access each
    individual client with three keys, the device name, the
    form_factor, and the serial_number. If you want to connect
    multiple ModularClients with the same name and form_factor at the
    same time, first make sure they have unique serial_numbers by
    connecting each device one by one and using the set_serial_number
    method on each device.

    Example Usage:

    devs = ModularClients()  # Might automatically find all available devices
    # if they are not found automatically, specify ports to use
    devs = ModularClients(use_ports=['/dev/ttyUSB0','/dev/ttyUSB1']) # Linux
    devs = ModularClients(use_ports=['/dev/tty.usbmodem262471','/dev/tty.usbmodem262472']) # Mac OS X
    devs = ModularClients(use_ports=['COM3','COM4']) # Windows
    devs.items()
    dev = devs[name][form_factor][serial_number]

    '''
    def __init__(self,*args,**kwargs):
        if ('use_ports' not in kwargs) or (kwargs['use_ports'] is None):
            modular_device_ports = find_modular_device_ports(*args,**kwargs)
        else:
            modular_device_ports = use_ports

        for port in modular_device_ports:
            kwargs.update({'port': port})
            self._add_device(*args,**kwargs)

    def _add_device(self,*args,**kwargs):
        dev = ModularClient(*args,**kwargs)
        device_id = dev.get_device_id()
        name = device_id['name']
        form_factor = device_id['form_factor']
        serial_number = device_id['serial_number']
        if name not in self:
            self[name] = {}
        if form_factor not in self[name]:
            self[name][form_factor] = {}
        self[name][form_factor][serial_number] = dev

def check_dict_for_key(d,k,dname=''):
    if not k in d:
        if not dname:
            dname = 'dictionary'
        raise IOError('{0} does not contain {1}'.format(dname,k))

def json_string_to_dict(json_string):
    json_dict =  json.loads(json_string,object_hook=json_decode_dict)
    return json_dict

def json_decode_dict(data):
    '''
    Object hook for decoding dictionaries from serialized json data. Ensures that
    all strings are unpacked as str objects rather than unicode.
    '''
    rv = {}
    for key, value in data.iteritems():
        if isinstance(key, unicode):
            key = key.encode('utf-8')
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        elif isinstance(value, list):
            value = json_decode_list(value)
        elif isinstance(value, dict):
            value = json_decode_dict(value)
        rv[key] = value
    return rv

def json_decode_list(data):
    '''
    Object hook for decoding lists from serialized json data. Ensures that
    all strings are unpacked as str objects rather than unicode.
    '''
    rv = []
    for item in data:
        if isinstance(item, unicode):
            item = item.encode('utf-8')
        elif isinstance(item, list):
            item = json_decode_list(item)
        elif isinstance(item, dict):
            item = json_decode_dict(item)
        rv.append(item)
    return rv

def find_modular_device_ports(baudrate=None,
                              name=None,
                              form_factor=None,
                              serial_number=None,
                              try_ports=None,
                              debug=DEBUG,
                              *args,
                              **kwargs):
    serial_device_ports = find_serial_device_ports(try_ports=try_ports, debug=debug)
    os_type = platform.system()
    if os_type == 'Darwin':
        serial_device_ports = [x for x in serial_device_ports if 'tty.usbmodem' in x or 'tty.usbserial' in x]

    if type(name) is str:
        name = [name]
    if type(form_factor) is str:
        form_factor = [form_factor]
    if type(serial_number) is int:
        serial_number = [serial_number]

    modular_device_ports = {}
    for port in serial_device_ports:
        try:
            dev = ModularClient(port=port,baudrate=baudrate,debug=debug)
            device_id = dev.get_device_id()
            if ((name is None ) and (device_id['name'] is not None)) or (device_id['name'] in name):
                if ((form_factor is None) and (device_id['form_factor'] is not None)) or (device_id['form_factor'] in form_factor):
                    if ((serial_number is None) and (device_id['serial_number'] is not None)) or (device_id['serial_number'] in serial_number):
                        modular_device_ports[port] = {'name': device_id['name'],
                                                      'form_factor': device_id['form_factor'],
                                                      'serial_number': device_id['serial_number']}
            dev.close()
        except (serial.SerialException, IOError):
            pass
    return modular_device_ports

def find_modular_device_port(baudrate=None,
                             name=None,
                             form_factor=None,
                             serial_number=None,
                             try_ports=None,
                             debug=DEBUG):
    modular_device_ports = find_modular_device_ports(baudrate=baudrate,
                                                     name=name,
                                                     form_factor=form_factor,
                                                     serial_number=serial_number,
                                                     try_ports=try_ports,
                                                     debug=debug)
    if len(modular_device_ports) == 1:
        return modular_device_ports.keys()[0]
    elif len(modular_device_ports) == 0:
        serial_device_ports = find_serial_device_ports(try_ports)
        err_string = 'Could not find any Modular devices. Check connections and permissions.\n'
        err_string += 'Tried ports: ' + str(serial_device_ports)
        raise RuntimeError(err_string)
    else:
        err_string = 'Found more than one Modular device. Specify port or name and/or form_factor and/or serial_number.\n'
        err_string += 'Matching ports: ' + str(modular_device_ports)
        raise RuntimeError(err_string)

# -----------------------------------------------------------------------------------------
if __name__ == '__main__':

    debug = False
    dev = ModularClient(debug=debug)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import logging

from celery import Celery, Task
from celery.utils.log import get_task_logger
from celerybeatmongo.schedulers import MongoScheduler

log = logging.getLogger(__name__)

class ContextTask(Task):
    abstract = True
    schedulable = None
    current_app = None

    def __call__(self, *args, **kwargs):
        with self.current_app.app_context():
            return super(ContextTask, self).__call__(*args, **kwargs)

class JobTask(ContextTask):
    abstract = True

    @property
    def log(self):
        return get_task_logger(self.name)

class Scheduler(MongoScheduler):
    def apply_async(self, entry, **kwargs):
        '''A MongoScheduler storing the last task_id'''
        result = super(Scheduler, self).apply_async(entry, **kwargs)
        entry._task.last_run_id = result.id
        return result

celery = Celery(task_cls=ContextTask)

def task(*args, **kwargs):
    return celery.task(*args, **kwargs)

def job(name, **kwargs):
    '''A shortcut decorator for declaring jobs'''
    return celery.task(name=name, schedulable=True, base=JobTask,
                       bind=True, **kwargs)

def get_logger(name):
    logger = get_task_logger(name)
    return logger

def connect(signal):
    def wrapper(func):
        t = task(func)

        def call_task(item, **kwargs):
            t.delay(item, **kwargs)

        signal.connect(call_task, weak=False)
        return t
    return wrapper

@job('log-test')
def helloworld(self):
    self.log.debug('This is a DEBUG message')
    self.log.info('This is an INFO message')
    self.log.warning('This is a WARNING message')
    self.log.error('This is a ERROR message')

@job('error-test')
def error_test_task(self):
    self.log.info('There should be an error soon')
    raise Exception('There is an error')

def schedulables():
    return [task for task in celery.tasks.values() if task.schedulable]

def init_app(app):
    celery.main = app.import_name

    default_name = app.config.get('MONGODB_DB', 'celery')
    app.config.setdefault('CELERY_MONGODB_SCHEDULER_DB', default_name)

    from udata.models import db
    with app.app_context():
        default_url = 'mongodb://{host}:{port}'.format(
            host=db.connection.host, port=db.connection.port)
    app.config.setdefault('CELERY_MONGODB_SCHEDULER_URL', default_url)

    celery.conf.update(app.config)

    ContextTask.current_app = app

    # Load core tasks
    import udata.core.metrics.tasks  # noqa
    import udata.core.tags.tasks  # noqa
    import udata.core.activity.tasks  # noqa
    import udata.core.dataset.tasks  # noqa
    import udata.core.reuse.tasks  # noqa
    import udata.core.user.tasks  # noqa
    import udata.core.organization.tasks  # noqa
    import udata.core.followers.tasks  # noqa
    import udata.core.issues.tasks  # noqa
    import udata.core.discussions.tasks  # noqa
    import udata.core.badges.tasks  # noqa
    import udata.harvest.tasks  # noqa

    # Load plugins tasks
    for plugin in app.config['PLUGINS']:
        name = 'udata_{0}.tasks'.format(plugin)
        try:
            __import__(name)
        except ImportError:
            pass
        except Exception as e:
            log.error('Error importing %s: %s', name, e)

    return celery
<commit_msg>fix for workers not getting right connection string<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

import logging

from celery import Celery, Task
from celery.utils.log import get_task_logger
from celerybeatmongo.schedulers import MongoScheduler

log = logging.getLogger(__name__)

class ContextTask(Task):
    abstract = True
    schedulable = None
    current_app = None

    def __call__(self, *args, **kwargs):
        with self.current_app.app_context():
            return super(ContextTask, self).__call__(*args, **kwargs)

class JobTask(ContextTask):
    abstract = True

    @property
    def log(self):
        return get_task_logger(self.name)

class Scheduler(MongoScheduler):
    def apply_async(self, entry, **kwargs):
        '''A MongoScheduler storing the last task_id'''
        result = super(Scheduler, self).apply_async(entry, **kwargs)
        entry._task.last_run_id = result.id
        return result

celery = Celery(task_cls=ContextTask)

def task(*args, **kwargs):
    return celery.task(*args, **kwargs)

def job(name, **kwargs):
    '''A shortcut decorator for declaring jobs'''
    return celery.task(name=name, schedulable=True, base=JobTask,
                       bind=True, **kwargs)

def get_logger(name):
    logger = get_task_logger(name)
    return logger

def connect(signal):
    def wrapper(func):
        t = task(func)

        def call_task(item, **kwargs):
            t.delay(item, **kwargs)

        signal.connect(call_task, weak=False)
        return t
    return wrapper

@job('log-test')
def helloworld(self):
    self.log.debug('This is a DEBUG message')
    self.log.info('This is an INFO message')
    self.log.warning('This is a WARNING message')
    self.log.error('This is a ERROR message')

@job('error-test')
def error_test_task(self):
    self.log.info('There should be an error soon')
    raise Exception('There is an error')

def schedulables():
    return [task for task in celery.tasks.values() if task.schedulable]

def init_app(app):
    celery.main = app.import_name

    default_name = app.config.get('MONGODB_DB', 'celery')
    app.config.setdefault('CELERY_MONGODB_SCHEDULER_DB', default_name)

    from udata.models import db
    with app.app_context():
        default_url = 'mongodb://{0}:{1}'.format(*db.connection.client.address)
    app.config.setdefault('CELERY_MONGODB_SCHEDULER_URL', default_url)

    celery.conf.update(app.config)

    ContextTask.current_app = app

    # Load core tasks
    import udata.core.metrics.tasks  # noqa
    import udata.core.tags.tasks  # noqa
    import udata.core.activity.tasks  # noqa
    import udata.core.dataset.tasks  # noqa
    import udata.core.reuse.tasks  # noqa
    import udata.core.user.tasks  # noqa
    import udata.core.organization.tasks  # noqa
    import udata.core.followers.tasks  # noqa
    import udata.core.issues.tasks  # noqa
    import udata.core.discussions.tasks  # noqa
    import udata.core.badges.tasks  # noqa
    import udata.harvest.tasks  # noqa

    # Load plugins tasks
    for plugin in app.config['PLUGINS']:
        name = 'udata_{0}.tasks'.format(plugin)
        try:
            __import__(name)
        except ImportError:
            pass
        except Exception as e:
            log.error('Error importing %s: %s', name, e)

    return celery
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import re

from module.plugins.Hoster import Hoster
from module.network.RequestFactory import getURL
from module.plugins.ReCaptcha import ReCaptcha

def getInfo(urls):
    result = []

    for url in urls:
        html = getURL(url).replace("\n", "")
        html = html.replace("\t", "")
        if "File could not be found" in html:
            result.append((url, 0, 1, url))
            continue

        m = re.search(OronCom.FILE_INFO_PATTERN, html)
        if m:
            name = m.group(1)
            hSize = float(m.group(2).replace(",", "."))
            pow = {'Kb': 1, 'Mb': 2, 'Gb': 3}[m.group(3)]
            size = int(hSize * 1024 ** pow)
        else:
            name = url
            size = 0

        result.append((name, size, 2, url))
    yield result

class OronCom(Hoster):
    __name__ = "OronCom"
    __type__ = "hoster"
    __pattern__ = r"http://(?:www.)?oron.com/"
    __version__ = "0.11"
    __description__ = "File Hoster: Oron.com"
    __author_name__ = ("chrox", "DHMH")
    __author_mail__ = ("chrox@pyload.org", "DHMH@pyload.org")

    FILE_INFO_PATTERN = r'Dateiname: (.*)
Größe: ([0-9,.]+) (Kb|Mb|Gb)'

    def init(self):
        self.resumeDownload = self.multiDL = True if self.account else False
        self.chunkLimit = 1
        self.file_id = re.search(r'http://(?:www.)?oron.com/([a-zA-Z0-9]+)', self.pyfile.url).group(1)
        self.logDebug("File id is %s" % self.file_id)
        self.pyfile.url = "http://oron.com/" + self.file_id

    def process(self, pyfile):
        req.load("http://oron.com/?op=change_lang&lang=german")
        self.html = self.load(self.pyfile.url, ref=False, decode=True).encode("utf-8").replace("\n", "")
        if "File could not be found" in self.html or "Datei nicht gefunden" in self.html:
            self.offline()
        self.html = self.html.replace("\t", "")
        m = re.search(self.FILE_INFO_PATTERN, self.html)
        if m:
            pyfile.name = m.group(1)
            hSize = float(m.group(2))
            pow = {'Kb': 1, 'Mb': 2, 'Gb': 3}[m.group(3)]
            pyfile.size = int(hSize * 1024 ** pow)
            self.logDebug("File Size: %d" % pyfile.size)
        else:
            self.logDebug("Name and/or size not found.")

        if self.account:
            self.handlePremium()
        else:
            self.handleFree()

    def handleFree(self):
        req.load("http://oron.com/?op=change_lang&lang=german")
        self.html = self.load(self.pyfile.url, ref=False, decode=True).replace("\n", "")
        if "download1" in self.html:
            post_url = "http://oron.com/" + self.file_id
            post_dict = {'op': 'download1',
                         'usr_login': '',
                         'id': self.file_id,
                         'fname': self.pyfile.name,
                         'referer': '',
                         'method_free': ' Regular Download '}

            self.html = self.load(post_url, post=post_dict, ref=False, decode=True).encode("utf-8")
            if '
' in self.html:
                time_list = re.findall(r'\d+(?=\s[a-z]+,)|\d+(?=\s.*?until)', self.html)
                tInSec = 0
                for t in time_list:
                    tInSec += int(t) * 60 ** (len(time_list) - time_list.index(t) - 1)
                self.setWait(tInSec, True)
                self.wait()
                self.retry()

            if "download2" in self.html:
                post_dict['op'] = 'download2'
                post_dict['method_free'] = 'Regular Download'
                post_dict['method_premium'] = ''
                post_dict['down_direct'] = '1'
                post_dict['btn_download'] = ' Create Download Link '
                del(post_dict['fname'])

                re_captcha = ReCaptcha(self)
                downloadLink = None
                for i in range(5):
                    m = re.search('name="rand" value="(.*?)">', self.html)
                    post_dict['rand'] = m.group(1)
                    challengeId = re.search(r'/recaptcha/api/challenge[?k=]+([^"]+)', self.html)
                    challenge, result = re_captcha.challenge(challengeId.group(1))
                    post_dict['recaptcha_challenge_field'] = challenge
                    post_dict['recaptcha_response_field'] = result
                    self.html = self.load(post_url, post=post_dict)
                    m = re.search('
(.*?)
', self.html)
                    if m:
                        if m.group(1) == "Wrong captcha":
                            self.invalidCaptcha()
                            self.logDebug("Captcha failed")
                    if 'class="atitle">Download File' in self.html:
                        self.correctCaptcha()
                        downloadLink = re.search('href="(.*?)" class="atitle"', self.html)
                        break

                if not downloadLink:
                    self.fail("Could not find download link")

                self.logDebug("Download url found: %s" % downloadLink.group(1))
                self.download(downloadLink.group(1))
        else:
            self.logError("error in parsing site")

    def handlePremium(self):
        info = self.account.getAccountInfo(self.user, True)
        self.logDebug("Traffic left: %s" % info['trafficleft'])
        self.logDebug("File Size: %d" % int(self.pyfile.size / 1024))

        if int(self.pyfile.size / 1024) > info["trafficleft"]:
            self.logInfo(_("Not enough traffic left"))
            self.account.empty(self.user)
            self.fail(_("Traffic exceeded"))

        post_url = "http://oron.com/" + self.file_id
        m = re.search('name="rand" value="(.*?)">', self.html)
        rand = m.group(1)
        post_dict = {'down_direct': '1', 'id': self.file_id, 'op': 'download2', 'rand': rand, 'referer': '',
                     'method_free': '', 'method_premium': '1'}

        self.html = self.load(post_url, post=post_dict, ref=False, decode=True).encode("utf-8")
        link = re.search('href="(.*?)" class="atitle"', self.html).group(1)
        self.download(link)<commit_msg>OronCom fix<commit_after># -*- coding: utf-8 -*-
import re

from module.plugins.Hoster import Hoster
from module.network.RequestFactory import getURL
from module.plugins.ReCaptcha import ReCaptcha

def getInfo(urls):
    result = []

    for url in urls:
        html = getURL(url).replace("\n", "")
        html = html.replace("\t", "")
        if "File could not be found" in html:
            result.append((url, 0, 1, url))
            continue

        m = re.search(OronCom.FILE_INFO_PATTERN, html)
        if m:
            name = m.group(1)
            hSize = float(m.group(2).replace(",", "."))
            pow = {'Kb': 1, 'Mb': 2, 'Gb': 3}[m.group(3)]
            size = int(hSize * 1024 ** pow)
        else:
            name = url
            size = 0

        result.append((name, size, 2, url))
    yield result

class OronCom(Hoster):
    __name__ = "OronCom"
    __type__ = "hoster"
    __pattern__ = r"http://(?:www.)?oron.com/"
    __version__ = "0.11"
    __description__ = "File Hoster: Oron.com"
    __author_name__ = ("chrox", "DHMH")
    __author_mail__ = ("chrox@pyload.org", "DHMH@pyload.org")

    FILE_INFO_PATTERN = r'Dateiname: (.*)
Größe: ([0-9,.]+) (Kb|Mb|Gb)'

    def init(self):
        self.resumeDownload = self.multiDL = True if self.account else False
        self.chunkLimit = 1
        self.file_id = re.search(r'http://(?:www.)?oron.com/([a-zA-Z0-9]+)', self.pyfile.url).group(1)
        self.logDebug("File id is %s" % self.file_id)
        self.pyfile.url = "http://oron.com/" + self.file_id

    def process(self, pyfile):
        #self.load("http://oron.com/?op=change_lang&lang=german")
        # already logged in, so the above line shouldn't be necessary
        self.html = self.load(self.pyfile.url, ref=False, decode=True).encode("utf-8").replace("\n", "")
        if "File could not be found" in self.html or "Datei nicht gefunden" in self.html:
            self.offline()
        self.html = self.html.replace("\t", "")
        m = re.search(self.FILE_INFO_PATTERN, self.html)
        if m:
            pyfile.name = m.group(1)
            hSize = float(m.group(2))
            pow = {'Kb': 1, 'Mb': 2, 'Gb': 3}[m.group(3)]
            pyfile.size = int(hSize * 1024 ** pow)
            self.logDebug("File Size: %d" % pyfile.size)
        else:
            self.logDebug("Name and/or size not found.")

        if self.account:
            self.handlePremium()
        else:
            self.handleFree()

    def handleFree(self):
        #self.load("http://oron.com/?op=change_lang&lang=german")
        # already logged in, so the above line shouldn't be necessary
        self.html = self.load(self.pyfile.url, ref=False, decode=True).replace("\n", "")
        if "download1" in self.html:
            post_url = "http://oron.com/" + self.file_id
            post_dict = {'op': 'download1',
                         'usr_login': '',
                         'id': self.file_id,
                         'fname': self.pyfile.name,
                         'referer': '',
                         'method_free': ' Regular Download '}

            self.html = self.load(post_url, post=post_dict, ref=False, decode=True).encode("utf-8")
            if '
' in self.html:
                time_list = re.findall(r'\d+(?=\s[a-z]+,)|\d+(?=\s.*?until)', self.html)
                tInSec = 0
                for t in time_list:
                    tInSec += int(t) * 60 ** (len(time_list) - time_list.index(t) - 1)
                self.setWait(tInSec, True)
                self.wait()
                self.retry()

            if "download2" in self.html:
                post_dict['op'] = 'download2'
                post_dict['method_free'] = 'Regular Download'
                post_dict['method_premium'] = ''
                post_dict['down_direct'] = '1'
                post_dict['btn_download'] = ' Create Download Link '
                del(post_dict['fname'])

                re_captcha = ReCaptcha(self)
                downloadLink = None
                for i in range(5):
                    m = re.search('name="rand" value="(.*?)">', self.html)
                    post_dict['rand'] = m.group(1)
                    challengeId = re.search(r'/recaptcha/api/challenge[?k=]+([^"]+)', self.html)
                    challenge, result = re_captcha.challenge(challengeId.group(1))
                    post_dict['recaptcha_challenge_field'] = challenge
                    post_dict['recaptcha_response_field'] = result
                    self.html = self.load(post_url, post=post_dict)
                    m = re.search('
(.*?)
', self.html)
                    if m:
                        if m.group(1) == "Wrong captcha":
                            self.invalidCaptcha()
                            self.logDebug("Captcha failed")
                    if 'class="atitle">Download File' in self.html:
                        self.correctCaptcha()
                        downloadLink = re.search('href="(.*?)" class="atitle"', self.html)
                        break

                if not downloadLink:
                    self.fail("Could not find download link")

                self.logDebug("Download url found: %s" % downloadLink.group(1))
                self.download(downloadLink.group(1))
        else:
            self.logError("error in parsing site")

    def handlePremium(self):
        info = self.account.getAccountInfo(self.user, True)
        self.logDebug("Traffic left: %s" % info['trafficleft'])
        self.logDebug("File Size: %d" % int(self.pyfile.size / 1024))

        if int(self.pyfile.size / 1024) > info["trafficleft"]:
            self.logInfo(_("Not enough traffic left"))
            self.account.empty(self.user)
            self.fail(_("Traffic exceeded"))

        post_url = "http://oron.com/" + self.file_id
        m = re.search('name="rand" value="(.*?)">', self.html)
        rand = m.group(1)
        post_dict = {'down_direct': '1', 'id': self.file_id, 'op': 'download2', 'rand': rand, 'referer': '',
                     'method_free': '', 'method_premium': '1'}

        self.html = self.load(post_url, post=post_dict, ref=False, decode=True).encode("utf-8")
        link = re.search('href="(.*?)" class="atitle"', self.html).group(1)
        self.download(link)<|endoftext|>


<commit_before># coding: utf-8
from modernrpc.core import ENTRY_POINT_KEY, PROTOCOL_KEY, get_method, rpc_method, get_all_method_names, RPCRequest, \
    HANDLER_KEY, XMLRPC_PROTOCOL
from modernrpc.exceptions import RPCInvalidParams, RPCException, RPC_INTERNAL_ERROR

@rpc_method(name='system.listMethods')
def __system_listMethods(**kwargs):
    """Returns a list of all methods available in the current entry point"""
    entry_point = kwargs.get(ENTRY_POINT_KEY)
    protocol = kwargs.get(PROTOCOL_KEY)

    return get_all_method_names(entry_point, protocol, sort_methods=True)

@rpc_method(name='system.methodSignature')
def __system_methodSignature(method_name, **kwargs):
    """
    Returns an array describing the signature of the given method name.

    The result is an array with:
     - Return type as first elements
     - Types of method arguments from element 1 to N
    :param method_name: Name of a method available for current entry point (and protocol)
    :param kwargs:
    :return: An array describing types of return values and method arguments
    """
    entry_point = kwargs.get(ENTRY_POINT_KEY)
    protocol = kwargs.get(PROTOCOL_KEY)

    method = get_method(method_name, entry_point, protocol)
    if method is None:
        raise RPCInvalidParams('The method {} is not found in the system. Unable to retrieve signature.')
    return method.signature

@rpc_method(name='system.methodHelp')
def __system_methodHelp(method_name, **kwargs):
    """
    Returns the documentation of the given method name.

    :param method_name: Name of a method available for current entry point (and protocol)
    :param kwargs:
    :return: Documentation text for the RPC method
    """
    entry_point = kwargs.get(ENTRY_POINT_KEY)
    protocol = kwargs.get(PROTOCOL_KEY)

    method = get_method(method_name, entry_point, protocol)
    if method is None:
        raise RPCInvalidParams('The method {} is not found in the system. Unable to retrieve method help.')
    return method.html_doc

@rpc_method(name='system.multicall', protocol=XMLRPC_PROTOCOL)
def __system_multiCall(calls, **kwargs):
    """
    Call multiple RPC methods at once.

    :param calls: An array of struct like {"methodName": string, "params": array }
    :param kwargs: Internal data
    :type calls: list
    :type kwargs: dict
    :return:
    """
    if not isinstance(calls, list):
        raise RPCInvalidParams('system.multicall first argument should be a list, {} given.'.format(type(calls)))

    handler = kwargs.get(HANDLER_KEY)

    results = []

    for call in calls:
        rpc_request = RPCRequest(call['methodName'], args=call.get('params'))

        try:
            result = rpc_request.execute(handler)

            # From https://mirrors.talideon.com/articles/multicall.html:
            # "Notice that regular return values are always nested inside a one-element array. This allows you to
            # return structs from functions without confusing them with faults."
            results.append([result])

        except RPCException as e:
            results.append({
                'faultCode': e.code,
                'faultString': e.message,
            })
        except Exception as e:
            results.append({
                'faultCode': RPC_INTERNAL_ERROR,
                'faultString': str(e),
            })

    return results
<commit_msg>Fixed error returned by system.listMethods() and system.methodHelp()<commit_after># coding: utf-8
from modernrpc.core import ENTRY_POINT_KEY, PROTOCOL_KEY, get_method, rpc_method, get_all_method_names, RPCRequest, \
    HANDLER_KEY, XMLRPC_PROTOCOL
from modernrpc.exceptions import RPCInvalidParams, RPCException, RPC_INTERNAL_ERROR

@rpc_method(name='system.listMethods')
def __system_listMethods(**kwargs):
    """Returns a list of all methods available in the current entry point"""
    entry_point = kwargs.get(ENTRY_POINT_KEY)
    protocol = kwargs.get(PROTOCOL_KEY)

    return get_all_method_names(entry_point, protocol, sort_methods=True)

@rpc_method(name='system.methodSignature')
def __system_methodSignature(method_name, **kwargs):
    """
    Returns an array describing the signature of the given method name.

    The result is an array with:
     - Return type as first elements
     - Types of method arguments from element 1 to N
    :param method_name: Name of a method available for current entry point (and protocol)
    :param kwargs:
    :return: An array describing types of return values and method arguments
    """
    entry_point = kwargs.get(ENTRY_POINT_KEY)
    protocol = kwargs.get(PROTOCOL_KEY)

    method = get_method(method_name, entry_point, protocol)
    if method is None:
        raise RPCInvalidParams('Unknown method {}. Unable to retrieve signature.'.format(method_name))
    return method.signature

@rpc_method(name='system.methodHelp')
def __system_methodHelp(method_name, **kwargs):
    """
    Returns the documentation of the given method name.

    :param method_name: Name of a method available for current entry point (and protocol)
    :param kwargs:
    :return: Documentation text for the RPC method
    """
    entry_point = kwargs.get(ENTRY_POINT_KEY)
    protocol = kwargs.get(PROTOCOL_KEY)

    method = get_method(method_name, entry_point, protocol)
    if method is None:
        raise RPCInvalidParams('Unknown method {}. Unable to retrieve its documentation.'.format(method_name))
    return method.html_doc

@rpc_method(name='system.multicall', protocol=XMLRPC_PROTOCOL)
def __system_multiCall(calls, **kwargs):
    """
    Call multiple RPC methods at once.

    :param calls: An array of struct like {"methodName": string, "params": array }
    :param kwargs: Internal data
    :type calls: list
    :type kwargs: dict
    :return:
    """
    if not isinstance(calls, list):
        raise RPCInvalidParams('system.multicall first argument should be a list, {} given.'.format(type(calls)))

    handler = kwargs.get(HANDLER_KEY)

    results = []

    for call in calls:
        rpc_request = RPCRequest(call['methodName'], args=call.get('params'))

        try:
            result = rpc_request.execute(handler)

            # From https://mirrors.talideon.com/articles/multicall.html:
            # "Notice that regular return values are always nested inside a one-element array. This allows you to
            # return structs from functions without confusing them with faults."
            results.append([result])

        except RPCException as e:
            results.append({
                'faultCode': e.code,
                'faultString': e.message,
            })
        except Exception as e:
            results.append({
                'faultCode': RPC_INTERNAL_ERROR,
                'faultString': str(e),
            })

    return results
<|endoftext|>


<commit_before>#!/usr/bin/python
#
# cpu_meter.py: reads dstat CPU usage (usr+sys) periodically and send it to cloudbit.
# (requires dstat installed)
#
# Usage: > python cpu_meter.py
#

import subprocess
import re

# cloudBit params
CBIT_ACCESS_TOKEN='<<PUT YOUR ACCESS TOKEN HERE>>'
CBIT_DEVICE_ID='<<PUT YOUR DEVICE ID HERE>>'

PATTERN_DSTAT_CPU_IDLE = re.compile(r'[^,]+,[^,]+,([\d\.]+),.*')

def exec_dstat():
    p = subprocess.Popen('dstat --output dstat.csv', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

def read_dstat():
    p = subprocess.Popen('tail -n 1 -f dstat.csv', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while True:
        yield p.stdout.readline().strip()

def extract_cpu_usage(line):
    m = PATTERN_DSTAT_CPU_IDLE.match(l)
    if m:
        return str(int(100.0 - float(m.group(1))))
    else:
        return None

def post_cbit(value):
    cmd = 'curl -i -X POST -H "Authorization: Bearer ' + CBIT_ACCESS_TOKEN + '" https://api-http.littlebitscloud.cc/devices/' + CBIT_DEVICE_ID + '/output -d percent=' + value + ' -d duration_ms=10000'
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    print 'Executing: ' + cmd

# main
exec_dstat()
for l in read_dstat():
    v = extract_cpu_usage(l)
    if v:
        post_cbit(v)

<commit_msg>Fixed cpu_meter.py<commit_after>#!/usr/bin/python
#
# cpu_meter.py: reads dstat CPU usage (usr+sys) periodically and send it to cloudbit.
# (requires dstat installed)
#
# Usage: > python cpu_meter.py
#

import subprocess
import re

# cloudBit params
CBIT_ACCESS_TOKEN='<<PUT YOUR ACCESS TOKEN HERE>>'
CBIT_DEVICE_ID='<<PUT YOUR DEVICE ID HERE>>'

PATTERN_DSTAT_CPU_IDLE = re.compile(r'[^,]+,[^,]+,([\d\.]+),.*')

def exec_dstat():
    p = subprocess.Popen('dstat --output dstat.csv', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

def read_dstat():
    p = subprocess.Popen('tail -n 1 -f dstat.csv', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while True:
        yield p.stdout.readline().strip()

def extract_cpu_usage(line):
    m = PATTERN_DSTAT_CPU_IDLE.match(line)
    if m:
        return str(int(100.0 - float(m.group(1))))
    else:
        return None

def post_cbit(value):
    cmd = 'curl -i -X POST -H "Authorization: Bearer ' + CBIT_ACCESS_TOKEN + '" https://api-http.littlebitscloud.cc/devices/' + CBIT_DEVICE_ID + '/output -d percent=' + value + ' -d duration_ms=10000'
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    print 'Executing: ' + cmd

# main
exec_dstat()
for l in read_dstat():
    v = extract_cpu_usage(l)
    if v:
        post_cbit(v)

<|endoftext|>