Passed
Push — master ( b687c4...0b7ae5 )
by Markus
01:54
created

tcllib.tclcheck.TclCheckMixin.prep_check()   A

Complexity

Conditions 1

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nop 3
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
# pylint: disable=C0111,C0326,C0103
5
6
"""Tools to interface with TCL's update request API."""
7
8
import time
9
from collections import OrderedDict, defaultdict
10
11
import requests
12
from defusedxml import ElementTree
13
14
from .devices import Device
15
16
17
class TclCheckMixin:
0 ignored issues
show
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
18
    """A mixin component for TCL's update request API."""
19
20
    def prep_check_url(self, https=True):
21
        """Prepare URL for update request."""
22
        protocol = "https://" if https else "http://"
23
        url = protocol + self.g2master + "/check.php"
24
        return url
25
26
    def prep_check(self, device: Device, https=True):
27
        """Prepare URL and parameters for update request."""
28
        url = self.prep_check_url(https)
29
        params = OrderedDict()
30
        params["id"] = device.imei
31
        params["curef"] = device.curef
32
        params["fv"] = device.fwver
33
        params["mode"] = device.mode
34
        params["type"] = device.type
35
        params["cltp"] = device.cltp
36
        params["cktp"] = device.cktp
37
        params["rtd"] = device.rtd
38
        params["chnl"] = device.chnl
39
        #params["osvs"] = device.osvs
40
        #params["ckot"] = device.ckot
41
        return url, params
42
43
    def do_check(self, device: Device, https=True, timeout=10, max_tries=5):
44
        """Perform update request with given parameters."""
45
        url, params = self.prep_check(device, https)
46
        last_response = None
47
        for _ in range(0, max_tries):
48
            try:
49
                reqtime_start = time.perf_counter()
50
                req = self.sess.get(url, params=params, timeout=timeout)
51
                reqtime = time.perf_counter() - reqtime_start
52
                self.check_time_add(reqtime)
53
                last_response = req
54
                if req.status_code == 200:
55
                    self.master_server_vote_on_time(reqtime)
56
                    req.encoding = "utf-8"  # Force encoding as server doesn't give one
57
                    self.write_dump(req.text)
58
                    return req.text
59
                elif req.status_code not in [500, 502, 503]:
60
                    self.do_check_errorhandle(req, reqtime)
61
            except requests.exceptions.Timeout:
62
                pass
63
            # Something went wrong, try a different server
64
            self.master_server_downvote()
65
            self.g2master = self.get_master_server()
66
            url = self.prep_check_url(https)
67
        raise requests.exceptions.RetryError("Max tries ({}) reached.".format(max_tries), response=last_response)
68
69
    def do_check_errorhandle(self, req, reqtime):
70
        """Handle non-HTTP 200 results for ``do_check``."""
71
        errcodes = defaultdict(lambda: "HTTP {}.".format(req.status_code))
72
        errcodes[204] = "No update available."
73
        errcodes[404] = "No data for requested CUREF/FV combination."
74
        if req.status_code in [204, 404]:
75
            self.master_server_vote_on_time(reqtime)
76
        elif req.status_code not in [500, 502, 503]:
77
            self.master_server_downvote()
78
            req.raise_for_status()
79
        raise requests.exceptions.HTTPError(errcodes[req.status_code], response=req)
80
81
    @staticmethod
82
    def parse_check(xmlstr):
83
        """Parse output of ``do_check``."""
84
        root = ElementTree.fromstring(xmlstr)
85
        curef = root.find("CUREF").text
86
        fvver = root.find("VERSION").find("FV").text
87
        tvver = root.find("VERSION").find("TV").text
88
        fw_id = root.find("FIRMWARE").find("FW_ID").text
89
        fileinfo = root.find("FIRMWARE").find("FILESET").find("FILE")
90
        fileid = fileinfo.find("FILE_ID").text
91
        filename = fileinfo.find("FILENAME").text
92
        filesize = fileinfo.find("SIZE").text
93
        filehash = fileinfo.find("CHECKSUM").text
94
        return curef, fvver, tvver, fw_id, fileid, filename, filesize, filehash
95