Projekt

Obecné

Profil

Stáhnout (16.1 KB) Statistiky
| Větev: | Tag: | Revize:
1
<!doctype html>
2
<html lang="en">
3
<head>
4
<meta charset="utf-8">
5
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
6
<meta name="generator" content="pdoc 0.10.0" />
7
<title>usb_detector.api_client API documentation</title>
8
<meta name="description" content="" />
9
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
10
<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
11
<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
12
<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
13
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
14
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
15
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
16
<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
17
</head>
18
<body>
19
<main>
20
<article id="content">
21
<header>
22
<h1 class="title">Module <code>usb_detector.api_client</code></h1>
23
</header>
24
<section id="section-intro">
25
<details class="source">
26
<summary>
27
<span>Expand source code</span>
28
</summary>
29
<pre><code class="python">import json
30
import requests
31
import logging
32
from time import sleep
33
from diskcache import Deque
34
from requests import HTTPError, ConnectionError
35
from requests.exceptions import InvalidSchema
36

    
37

    
38
_uri = None     # server uri (url, port, and endpoint)
39
_cache = None   # cache (failed payloads)
40
_config = None  # instance of Config
41

    
42

    
43
def api_client_set_config(config):
44
    &#34;&#34;&#34;Initializes the client API module.
45

    
46
    This function is meant to be called prior to calling any other function
47
    of the API module. It stores the instance of Config (config manager)
48
    into a private variable. It also initializes the cache for unsuccessful
49
    payloads and constructs a URI (endpoint on the server side).
50

    
51
    :param config: instance of Config which holds all values defined
52
                   in the configuration file.
53
    &#34;&#34;&#34;
54
    # Store the variables globally within the module (file).
55
    global _config, _cache, _uri
56

    
57
    # Store the instance of Config and initialize the cache.
58
    _config = config
59
    _cache = _init_cache()
60

    
61
    # Creates the URI which is made of the server url, port, and path (endpoint).
62
    _uri = config.server_url + &#34;:&#34; + config.server_port + config.server_endpoint
63

    
64

    
65
def _init_cache():
66
    &#34;&#34;&#34; Initializes and returns a disk-based cache.
67

    
68
    The cache holds payloads that the application failed
69
    to send to the server. It periodically attempts to resend
70
    them to the server. All parameters can be seen in the
71
    configuration file.
72

    
73
    :return: instance of a new cache (Deque - FIFO)
74
    &#34;&#34;&#34;
75
    return Deque(directory=_config.cache_dir)
76

    
77

    
78
def send_data(payload: dict):
79
    &#34;&#34;&#34;Sends a payload off to the server.
80

    
81
    This function is called whenever a USB is connected
82
    or disconnected. If there is no internet connection or the
83
    server is not up and running, the payload will be stored
84
    into the disk cache.
85

    
86
    :param payload: payload to be sent to the server
87
    &#34;&#34;&#34;
88
    # Make sure that the URI has been constructed properly.
89
    # It is supposed to be done by calling the api_client_set_config function
90
    # with appropriate parameters.
91
    if _uri is None:
92
        logging.warning(f&#34;sending payload = {payload} failed because uri is set to None&#34;)
93
        _cache_failed_payload(payload)
94
        return
95
    try:
96
        logging.info(f&#34;sending payload = {payload} to {_uri}&#34;)
97
        response = requests.post(url=_uri, data=json.dumps(payload))
98
        logging.info(f&#34;response text: {response.text}&#34;)
99
    except (ConnectionError, InvalidSchema):
100
        logging.warning(f&#34;sending payload = {payload} to {_uri} failed&#34;)
101
        _cache_failed_payload(payload)
102
    except HTTPError as error:
103
        logging.error(f&#34;HTTP Error ({_uri}) payload = {payload}, {error}&#34;)
104
        _cache_failed_payload(payload)
105

    
106

    
107
def _cache_failed_payload(payload: dict):
108
    &#34;&#34;&#34; Caches a payload.
109

    
110
    This function is called when the application fails to send a payload
111
    to the server. The payload gets stored into a file-based cache from which
112
    it will be periodically retrieved as the client will attempt to send
113
    it to the server again. All parameters regarding the cache can be found
114
    in the configuration file.
115

    
116
    :param payload: payload to be cached
117
    &#34;&#34;&#34;
118
    # If the cache is &#34;full&#34;, discard the oldest record.
119
    if len(_cache) &gt;= _config.cache_max_entries:
120
        oldest_payload = _cache.pop()
121
        logging.warning(f&#34;cache is full - discarding payload = {oldest_payload}&#34;)
122

    
123
    # Store the payload into the cache.
124
    logging.info(f&#34;adding payload = {payload} into cache&#34;)
125
    _cache.append(payload)
126

    
127

    
128
def _resend_cached_payloads():
129
    &#34;&#34;&#34;Reattempts to send cached payloads to the server (API).
130

    
131
    In the configuration file, there is a predefined number of
132
    payloads that can be sent to the server with each call of this function.
133
    This function is called periodically from api_client_run in order
134
    to resend failed payloads to the server.
135

    
136
    &#34;&#34;&#34;
137
    # Calculate how many payload will be sent to the server
138
    retries = min(_config.cache_max_retries, len(_cache))
139
    logging.info(f&#34;emptying the cache ({retries} records)&#34;)
140

    
141
    # Send the payloads to the server one by one.
142
    for _ in range(0, retries):
143
        payload = _cache.pop()
144
        send_data(payload)
145

    
146

    
147
def api_client_run():
148
    &#34;&#34;&#34; Keeps resending failed payloads to the server.
149

    
150
    This function is instantiated as a thread that periodically
151
    calls the _resend_cached_payloads function in order to empty
152
    the cache (failed payloads). The period can be set in the
153
    configuration file.
154
    &#34;&#34;&#34;
155
    while True:
156
        # Resend a predefined amount of failed payloads to the server.
157
        _resend_cached_payloads()
158

    
159
        # Sleep for a predefined amount of seconds.
160
        sleep(_config.cache_retry_period_seconds)</code></pre>
161
</details>
162
</section>
163
<section>
164
</section>
165
<section>
166
</section>
167
<section>
168
<h2 class="section-title" id="header-functions">Functions</h2>
169
<dl>
170
<dt id="usb_detector.api_client.api_client_run"><code class="name flex">
171
<span>def <span class="ident">api_client_run</span></span>(<span>)</span>
172
</code></dt>
173
<dd>
174
<div class="desc"><p>Keeps resending failed payloads to the server.</p>
175
<p>This function is instantiated as a thread that periodically
176
calls the _resend_cached_payloads function in order to empty
177
the cache (failed payloads). The period can be set in the
178
configuration file.</p></div>
179
<details class="source">
180
<summary>
181
<span>Expand source code</span>
182
</summary>
183
<pre><code class="python">def api_client_run():
184
    &#34;&#34;&#34; Keeps resending failed payloads to the server.
185

    
186
    This function is instantiated as a thread that periodically
187
    calls the _resend_cached_payloads function in order to empty
188
    the cache (failed payloads). The period can be set in the
189
    configuration file.
190
    &#34;&#34;&#34;
191
    while True:
192
        # Resend a predefined amount of failed payloads to the server.
193
        _resend_cached_payloads()
194

    
195
        # Sleep for a predefined amount of seconds.
196
        sleep(_config.cache_retry_period_seconds)</code></pre>
197
</details>
198
</dd>
199
<dt id="usb_detector.api_client.api_client_set_config"><code class="name flex">
200
<span>def <span class="ident">api_client_set_config</span></span>(<span>config)</span>
201
</code></dt>
202
<dd>
203
<div class="desc"><p>Initializes the client API module.</p>
204
<p>This function is meant to be called prior to calling any other function
205
of the API module. It stores the instance of Config (config manager)
206
into a private variable. It also initializes the cache for unsuccessful
207
payloads and constructs a URI (endpoint on the server side).</p>
208
<p>:param config: instance of Config which holds all values defined
209
in the configuration file.</p></div>
210
<details class="source">
211
<summary>
212
<span>Expand source code</span>
213
</summary>
214
<pre><code class="python">def api_client_set_config(config):
215
    &#34;&#34;&#34;Initializes the client API module.
216

    
217
    This function is meant to be called prior to calling any other function
218
    of the API module. It stores the instance of Config (config manager)
219
    into a private variable. It also initializes the cache for unsuccessful
220
    payloads and constructs a URI (endpoint on the server side).
221

    
222
    :param config: instance of Config which holds all values defined
223
                   in the configuration file.
224
    &#34;&#34;&#34;
225
    # Store the variables globally within the module (file).
226
    global _config, _cache, _uri
227

    
228
    # Store the instance of Config and initialize the cache.
229
    _config = config
230
    _cache = _init_cache()
231

    
232
    # Creates the URI which is made of the server url, port, and path (endpoint).
233
    _uri = config.server_url + &#34;:&#34; + config.server_port + config.server_endpoint</code></pre>
234
</details>
235
</dd>
236
<dt id="usb_detector.api_client.send_data"><code class="name flex">
237
<span>def <span class="ident">send_data</span></span>(<span>payload: dict)</span>
238
</code></dt>
239
<dd>
240
<div class="desc"><p>Sends a payload off to the server.</p>
241
<p>This function is called whenever a USB is connected
242
or disconnected. If there is no internet connection or the
243
server is not up and running, the payload will be stored
244
into the disk cache.</p>
245
<p>:param payload: payload to be sent to the server</p></div>
246
<details class="source">
247
<summary>
248
<span>Expand source code</span>
249
</summary>
250
<pre><code class="python">def send_data(payload: dict):
251
    &#34;&#34;&#34;Sends a payload off to the server.
252

    
253
    This function is called whenever a USB is connected
254
    or disconnected. If there is no internet connection or the
255
    server is not up and running, the payload will be stored
256
    into the disk cache.
257

    
258
    :param payload: payload to be sent to the server
259
    &#34;&#34;&#34;
260
    # Make sure that the URI has been constructed properly.
261
    # It is supposed to be done by calling the api_client_set_config function
262
    # with appropriate parameters.
263
    if _uri is None:
264
        logging.warning(f&#34;sending payload = {payload} failed because uri is set to None&#34;)
265
        _cache_failed_payload(payload)
266
        return
267
    try:
268
        logging.info(f&#34;sending payload = {payload} to {_uri}&#34;)
269
        response = requests.post(url=_uri, data=json.dumps(payload))
270
        logging.info(f&#34;response text: {response.text}&#34;)
271
    except (ConnectionError, InvalidSchema):
272
        logging.warning(f&#34;sending payload = {payload} to {_uri} failed&#34;)
273
        _cache_failed_payload(payload)
274
    except HTTPError as error:
275
        logging.error(f&#34;HTTP Error ({_uri}) payload = {payload}, {error}&#34;)
276
        _cache_failed_payload(payload)</code></pre>
277
</details>
278
</dd>
279
</dl>
280
</section>
281
<section>
282
</section>
283
</article>
284
<nav id="sidebar">
285
<h1>Index</h1>
286
<div class="toc">
287
<ul></ul>
288
</div>
289
<ul id="index">
290
<li><h3>Super-module</h3>
291
<ul>
292
<li><code><a title="usb_detector" href="index.html">usb_detector</a></code></li>
293
</ul>
294
</li>
295
<li><h3><a href="#header-functions">Functions</a></h3>
296
<ul class="">
297
<li><code><a title="usb_detector.api_client.api_client_run" href="#usb_detector.api_client.api_client_run">api_client_run</a></code></li>
298
<li><code><a title="usb_detector.api_client.api_client_set_config" href="#usb_detector.api_client.api_client_set_config">api_client_set_config</a></code></li>
299
<li><code><a title="usb_detector.api_client.send_data" href="#usb_detector.api_client.send_data">send_data</a></code></li>
300
</ul>
301
</li>
302
</ul>
303
</nav>
304
</main>
305
<footer id="footer">
306
<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
307
</footer>
308
</body>
309
</html>
(1-1/5)