Passed
Push — master ( 86e01c...dbaced )
by John
02:16
created

TclCheckMixin.do_check_errorhandle()   A

Complexity

Conditions 4

Size

Total Lines 11
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
nop 4
dl 0
loc 11
rs 9.2
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
15
class TclCheckMixin:
0 ignored issues
show
Unused Code introduced by
The variable __class__ seems to be unused.
Loading history...
16
    """A mixin component for TCL's update request API."""
17
18
    def prep_check_url(self, https=True):
19
        """Prepare URL for update request."""
20
        protocol = "https://" if https else "http://"
21
        url = protocol + self.g2master + "/check.php"
22
        return url
23
24
    def prep_check(self, device=None, https=True):
25
        """Prepare URL and parameters for update request."""
26
        url = self.prep_check_url(https)
27
        params = OrderedDict()
28
        if device:
29
            # Need to support both ways for now
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
        else:
42
            params["id"] = self.serid
43
            params["curef"] = self.curef
44
            params["fv"] = self.fv
45
            params["mode"] = self.mode.value
46
            params["type"] = self.ftype
47
            params["cltp"] = self.cltp.value
48
            params["cktp"] = self.cktp.value
49
            params["rtd"] = self.rtd.value
50
            params["chnl"] = self.chnl.value
51
            #params["osvs"] = self.osvs
52
            #params["ckot"] = self.ckot.value
53
        return url, params
54
55
    def do_check(self, device=None, https=True, timeout=10, max_tries=5):
56
        """Perform update request with given parameters."""
57
        url, params = self.prep_check(device, https)
58
        last_response = None
59
        for _ in range(0, max_tries):
60
            try:
61
                reqtime_start = time.perf_counter()
62
                req = self.sess.get(url, params=params, timeout=timeout)
63
                reqtime = time.perf_counter() - reqtime_start
64
                reqtime_avg = self.check_time_avg()
65
                self.check_time_add(reqtime)
66
                last_response = req
67
                if req.status_code == 200:
68
                    self.master_server_vote_on_time(reqtime, reqtime_avg)
69
                    req.encoding = "utf-8"  # Force encoding as server doesn't give one
70
                    self.write_dump(req.text)
71
                    return req.text
72
                elif req.status_code not in [500, 502, 503]:
73
                    self.do_check_errorhandle(req, reqtime, reqtime_avg)
74
            except requests.exceptions.Timeout:
75
                pass
76
            # Something went wrong, try a different server
77
            self.master_server_downvote()
78
            self.g2master = self.get_master_server()
79
            url = self.prep_check_url(https)
80
        raise requests.exceptions.RetryError("Max tries ({}) reached.".format(max_tries), response=last_response)
81
82
    def do_check_errorhandle(self, req, reqtime, reqtime_avg):
83
        """Handle non-HTTP 200 results for ``do_check``."""
84
        errcodes = defaultdict(lambda: "HTTP {}.".format(req.status_code))
85
        errcodes[204] = "No update available."
86
        errcodes[404] = "No data for requested CUREF/FV combination."
87
        if req.status_code in [204, 404]:
88
            self.master_server_vote_on_time(reqtime, reqtime_avg)
89
        elif req.status_code not in [500, 502, 503]:
90
            self.master_server_downvote()
91
            req.raise_for_status()
92
        raise requests.exceptions.HTTPError(errcodes[req.status_code], response=req)
93
94
    @staticmethod
95
    def parse_check(xmlstr):
96
        """Parse output of ``do_check``."""
97
        root = ElementTree.fromstring(xmlstr)
98
        curef = root.find("CUREF").text
99
        fvver = root.find("VERSION").find("FV").text
100
        tvver = root.find("VERSION").find("TV").text
101
        fw_id = root.find("FIRMWARE").find("FW_ID").text
102
        fileinfo = root.find("FIRMWARE").find("FILESET").find("FILE")
103
        fileid = fileinfo.find("FILE_ID").text
104
        filename = fileinfo.find("FILENAME").text
105
        filesize = fileinfo.find("SIZE").text
106
        filehash = fileinfo.find("CHECKSUM").text
107
        return curef, fvver, tvver, fw_id, fileid, filename, filesize, filehash
108