trodo-python 1.0.0__py3-none-any.whl → 1.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trodo/__init__.py +177 -134
- trodo/api/async_client.py +96 -96
- trodo/api/endpoints.py +21 -20
- trodo/api/http_client.py +90 -87
- trodo/auto/auto_event_manager.py +134 -134
- trodo/client.py +318 -195
- trodo/managers/group_manager.py +106 -106
- trodo/managers/people_manager.py +77 -77
- trodo/queue/batch_flusher.py +52 -52
- trodo/queue/event_queue.py +32 -32
- trodo/session/server_session.py +74 -74
- trodo/session/session_manager.py +74 -74
- trodo/types.py +154 -79
- trodo/user_context.py +224 -224
- trodo_python-1.2.0.dist-info/METADATA +358 -0
- trodo_python-1.2.0.dist-info/RECORD +23 -0
- trodo_python-1.0.0.dist-info/METADATA +0 -227
- trodo_python-1.0.0.dist-info/RECORD +0 -23
- {trodo_python-1.0.0.dist-info → trodo_python-1.2.0.dist-info}/WHEEL +0 -0
- {trodo_python-1.0.0.dist-info → trodo_python-1.2.0.dist-info}/top_level.txt +0 -0
trodo/managers/group_manager.py
CHANGED
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
"""Group management methods and GroupProfile proxy."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import Any, Callable, Dict, List, Optional, Union
|
|
6
|
-
|
|
7
|
-
from ..api import endpoints
|
|
8
|
-
from ..types import ApiResult
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class GroupProfile:
|
|
12
|
-
def __init__(
|
|
13
|
-
self,
|
|
14
|
-
http_client: object,
|
|
15
|
-
site_id: str,
|
|
16
|
-
distinct_id: str,
|
|
17
|
-
group_key: str,
|
|
18
|
-
group_id: str,
|
|
19
|
-
) -> None:
|
|
20
|
-
self._http = http_client
|
|
21
|
-
self._site_id = site_id
|
|
22
|
-
self._distinct_id = distinct_id
|
|
23
|
-
self._group_key = group_key
|
|
24
|
-
self._group_id = group_id
|
|
25
|
-
|
|
26
|
-
def _base(self) -> Dict[str, Any]:
|
|
27
|
-
return {
|
|
28
|
-
"siteId": self._site_id,
|
|
29
|
-
"userId": self._distinct_id,
|
|
30
|
-
"groupKey": self._group_key,
|
|
31
|
-
"groupId": self._group_id,
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
def _call(self, method: str, extra: Optional[Dict[str, Any]] = None) -> ApiResult:
|
|
35
|
-
payload = {**self._base(), **(extra or {})}
|
|
36
|
-
return self._http.post_group( # type: ignore[attr-defined]
|
|
37
|
-
f"{endpoints.GROUPS_PROFILE}/{method}", payload
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
def set(self, properties: Dict[str, Any]) -> ApiResult:
|
|
41
|
-
return self._call("set", {"properties": properties})
|
|
42
|
-
|
|
43
|
-
def set_once(self, properties: Dict[str, Any]) -> ApiResult:
|
|
44
|
-
return self._call("set_once", {"properties": properties})
|
|
45
|
-
|
|
46
|
-
def union(self, list_name: str, values: List[Any]) -> ApiResult:
|
|
47
|
-
return self._call("union", {"listName": list_name, "values": values})
|
|
48
|
-
|
|
49
|
-
def remove(self, list_name: str, value: Any) -> ApiResult:
|
|
50
|
-
return self._call("remove", {"listName": list_name, "value": value})
|
|
51
|
-
|
|
52
|
-
def unset(self, property: str) -> ApiResult:
|
|
53
|
-
return self._call("unset", {"property": property})
|
|
54
|
-
|
|
55
|
-
def increment(self, property: str, value: float = 1) -> ApiResult:
|
|
56
|
-
return self._call("increment", {"property": property, "value": value})
|
|
57
|
-
|
|
58
|
-
def append(self, property: str, value: Any) -> ApiResult:
|
|
59
|
-
return self._call("append", {"property": property, "value": value})
|
|
60
|
-
|
|
61
|
-
def delete(self) -> ApiResult:
|
|
62
|
-
return self._call("delete")
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class GroupManager:
|
|
66
|
-
def __init__(
|
|
67
|
-
self,
|
|
68
|
-
http_client: object,
|
|
69
|
-
site_id: str,
|
|
70
|
-
get_distinct_id: Callable[[], str],
|
|
71
|
-
) -> None:
|
|
72
|
-
self._http = http_client
|
|
73
|
-
self._site_id = site_id
|
|
74
|
-
self._get_distinct_id = get_distinct_id
|
|
75
|
-
|
|
76
|
-
def _base(self) -> Dict[str, Any]:
|
|
77
|
-
return {"siteId": self._site_id, "userId": self._get_distinct_id()}
|
|
78
|
-
|
|
79
|
-
def set_group(
|
|
80
|
-
self, group_key: str, group_id: Union[str, List[str]]
|
|
81
|
-
) -> ApiResult:
|
|
82
|
-
return self._http.post_group( # type: ignore[attr-defined]
|
|
83
|
-
endpoints.GROUPS_SET,
|
|
84
|
-
{**self._base(), "groupKey": group_key, "groupId": group_id},
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
def add_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
88
|
-
return self._http.post_group( # type: ignore[attr-defined]
|
|
89
|
-
endpoints.GROUPS_ADD,
|
|
90
|
-
{**self._base(), "groupKey": group_key, "groupId": group_id},
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
def remove_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
94
|
-
return self._http.post_group( # type: ignore[attr-defined]
|
|
95
|
-
endpoints.GROUPS_REMOVE,
|
|
96
|
-
{**self._base(), "groupKey": group_key, "groupId": group_id},
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
def get_group(self, group_key: str, group_id: str) -> GroupProfile:
|
|
100
|
-
return GroupProfile(
|
|
101
|
-
self._http,
|
|
102
|
-
self._site_id,
|
|
103
|
-
self._get_distinct_id(),
|
|
104
|
-
group_key,
|
|
105
|
-
group_id,
|
|
106
|
-
)
|
|
1
|
+
"""Group management methods and GroupProfile proxy."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
from ..api import endpoints
|
|
8
|
+
from ..types import ApiResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class GroupProfile:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
http_client: object,
|
|
15
|
+
site_id: str,
|
|
16
|
+
distinct_id: str,
|
|
17
|
+
group_key: str,
|
|
18
|
+
group_id: str,
|
|
19
|
+
) -> None:
|
|
20
|
+
self._http = http_client
|
|
21
|
+
self._site_id = site_id
|
|
22
|
+
self._distinct_id = distinct_id
|
|
23
|
+
self._group_key = group_key
|
|
24
|
+
self._group_id = group_id
|
|
25
|
+
|
|
26
|
+
def _base(self) -> Dict[str, Any]:
|
|
27
|
+
return {
|
|
28
|
+
"siteId": self._site_id,
|
|
29
|
+
"userId": self._distinct_id,
|
|
30
|
+
"groupKey": self._group_key,
|
|
31
|
+
"groupId": self._group_id,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def _call(self, method: str, extra: Optional[Dict[str, Any]] = None) -> ApiResult:
|
|
35
|
+
payload = {**self._base(), **(extra or {})}
|
|
36
|
+
return self._http.post_group( # type: ignore[attr-defined]
|
|
37
|
+
f"{endpoints.GROUPS_PROFILE}/{method}", payload
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def set(self, properties: Dict[str, Any]) -> ApiResult:
|
|
41
|
+
return self._call("set", {"properties": properties})
|
|
42
|
+
|
|
43
|
+
def set_once(self, properties: Dict[str, Any]) -> ApiResult:
|
|
44
|
+
return self._call("set_once", {"properties": properties})
|
|
45
|
+
|
|
46
|
+
def union(self, list_name: str, values: List[Any]) -> ApiResult:
|
|
47
|
+
return self._call("union", {"listName": list_name, "values": values})
|
|
48
|
+
|
|
49
|
+
def remove(self, list_name: str, value: Any) -> ApiResult:
|
|
50
|
+
return self._call("remove", {"listName": list_name, "value": value})
|
|
51
|
+
|
|
52
|
+
def unset(self, property: str) -> ApiResult:
|
|
53
|
+
return self._call("unset", {"property": property})
|
|
54
|
+
|
|
55
|
+
def increment(self, property: str, value: float = 1) -> ApiResult:
|
|
56
|
+
return self._call("increment", {"property": property, "value": value})
|
|
57
|
+
|
|
58
|
+
def append(self, property: str, value: Any) -> ApiResult:
|
|
59
|
+
return self._call("append", {"property": property, "value": value})
|
|
60
|
+
|
|
61
|
+
def delete(self) -> ApiResult:
|
|
62
|
+
return self._call("delete")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class GroupManager:
|
|
66
|
+
def __init__(
|
|
67
|
+
self,
|
|
68
|
+
http_client: object,
|
|
69
|
+
site_id: str,
|
|
70
|
+
get_distinct_id: Callable[[], str],
|
|
71
|
+
) -> None:
|
|
72
|
+
self._http = http_client
|
|
73
|
+
self._site_id = site_id
|
|
74
|
+
self._get_distinct_id = get_distinct_id
|
|
75
|
+
|
|
76
|
+
def _base(self) -> Dict[str, Any]:
|
|
77
|
+
return {"siteId": self._site_id, "userId": self._get_distinct_id()}
|
|
78
|
+
|
|
79
|
+
def set_group(
|
|
80
|
+
self, group_key: str, group_id: Union[str, List[str]]
|
|
81
|
+
) -> ApiResult:
|
|
82
|
+
return self._http.post_group( # type: ignore[attr-defined]
|
|
83
|
+
endpoints.GROUPS_SET,
|
|
84
|
+
{**self._base(), "groupKey": group_key, "groupId": group_id},
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def add_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
88
|
+
return self._http.post_group( # type: ignore[attr-defined]
|
|
89
|
+
endpoints.GROUPS_ADD,
|
|
90
|
+
{**self._base(), "groupKey": group_key, "groupId": group_id},
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def remove_group(self, group_key: str, group_id: str) -> ApiResult:
|
|
94
|
+
return self._http.post_group( # type: ignore[attr-defined]
|
|
95
|
+
endpoints.GROUPS_REMOVE,
|
|
96
|
+
{**self._base(), "groupKey": group_key, "groupId": group_id},
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def get_group(self, group_key: str, group_id: str) -> GroupProfile:
|
|
100
|
+
return GroupProfile(
|
|
101
|
+
self._http,
|
|
102
|
+
self._site_id,
|
|
103
|
+
self._get_distinct_id(),
|
|
104
|
+
group_key,
|
|
105
|
+
group_id,
|
|
106
|
+
)
|
trodo/managers/people_manager.py
CHANGED
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
"""People (user profile) methods."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
from typing import Any, Callable, Dict, List, Optional, Union
|
|
6
|
-
|
|
7
|
-
from ..api import endpoints
|
|
8
|
-
from ..types import ApiResult
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class PeopleManager:
|
|
12
|
-
def __init__(
|
|
13
|
-
self,
|
|
14
|
-
http_client: object,
|
|
15
|
-
site_id: str,
|
|
16
|
-
get_distinct_id: Callable[[], str],
|
|
17
|
-
) -> None:
|
|
18
|
-
self._http = http_client
|
|
19
|
-
self._site_id = site_id
|
|
20
|
-
self._get_distinct_id = get_distinct_id
|
|
21
|
-
|
|
22
|
-
def _base(self) -> Dict[str, Any]:
|
|
23
|
-
return {"siteId": self._site_id, "userId": self._get_distinct_id()}
|
|
24
|
-
|
|
25
|
-
def set(self, properties: Dict[str, Any]) -> ApiResult:
|
|
26
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
27
|
-
endpoints.PEOPLE_SET, {**self._base(), "properties": properties}
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
def set_once(self, properties: Dict[str, Any]) -> ApiResult:
|
|
31
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
32
|
-
endpoints.PEOPLE_SET_ONCE, {**self._base(), "properties": properties}
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
def unset(self, keys: Union[str, List[str]]) -> ApiResult:
|
|
36
|
-
k = [keys] if isinstance(keys, str) else keys
|
|
37
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
38
|
-
endpoints.PEOPLE_UNSET, {**self._base(), "keys": k}
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
def increment(self, key: str, amount: float = 1) -> ApiResult:
|
|
42
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
43
|
-
endpoints.PEOPLE_INCREMENT, {**self._base(), "key": key, "amount": amount}
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
def append(self, key: str, values: List[Any]) -> ApiResult:
|
|
47
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
48
|
-
endpoints.PEOPLE_APPEND, {**self._base(), "key": key, "values": values}
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
def union(self, key: str, values: List[Any]) -> ApiResult:
|
|
52
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
53
|
-
endpoints.PEOPLE_UNION, {**self._base(), "key": key, "values": values}
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
def remove(self, key: str, values: List[Any]) -> ApiResult:
|
|
57
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
58
|
-
endpoints.PEOPLE_REMOVE, {**self._base(), "key": key, "values": values}
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
def track_charge(
|
|
62
|
-
self, amount: float, properties: Optional[Dict[str, Any]] = None
|
|
63
|
-
) -> ApiResult:
|
|
64
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
65
|
-
endpoints.PEOPLE_TRACK_CHARGE,
|
|
66
|
-
{**self._base(), "amount": amount, "properties": properties or {}},
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
def clear_charges(self) -> ApiResult:
|
|
70
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
71
|
-
endpoints.PEOPLE_CLEAR_CHARGES, self._base()
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
def delete_user(self) -> ApiResult:
|
|
75
|
-
return self._http.post_people( # type: ignore[attr-defined]
|
|
76
|
-
endpoints.PEOPLE_DELETE_USER, self._base()
|
|
77
|
-
)
|
|
1
|
+
"""People (user profile) methods."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Callable, Dict, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
from ..api import endpoints
|
|
8
|
+
from ..types import ApiResult
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PeopleManager:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
http_client: object,
|
|
15
|
+
site_id: str,
|
|
16
|
+
get_distinct_id: Callable[[], str],
|
|
17
|
+
) -> None:
|
|
18
|
+
self._http = http_client
|
|
19
|
+
self._site_id = site_id
|
|
20
|
+
self._get_distinct_id = get_distinct_id
|
|
21
|
+
|
|
22
|
+
def _base(self) -> Dict[str, Any]:
|
|
23
|
+
return {"siteId": self._site_id, "userId": self._get_distinct_id()}
|
|
24
|
+
|
|
25
|
+
def set(self, properties: Dict[str, Any]) -> ApiResult:
|
|
26
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
27
|
+
endpoints.PEOPLE_SET, {**self._base(), "properties": properties}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def set_once(self, properties: Dict[str, Any]) -> ApiResult:
|
|
31
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
32
|
+
endpoints.PEOPLE_SET_ONCE, {**self._base(), "properties": properties}
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def unset(self, keys: Union[str, List[str]]) -> ApiResult:
|
|
36
|
+
k = [keys] if isinstance(keys, str) else keys
|
|
37
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
38
|
+
endpoints.PEOPLE_UNSET, {**self._base(), "keys": k}
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def increment(self, key: str, amount: float = 1) -> ApiResult:
|
|
42
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
43
|
+
endpoints.PEOPLE_INCREMENT, {**self._base(), "key": key, "amount": amount}
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def append(self, key: str, values: List[Any]) -> ApiResult:
|
|
47
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
48
|
+
endpoints.PEOPLE_APPEND, {**self._base(), "key": key, "values": values}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
def union(self, key: str, values: List[Any]) -> ApiResult:
|
|
52
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
53
|
+
endpoints.PEOPLE_UNION, {**self._base(), "key": key, "values": values}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def remove(self, key: str, values: List[Any]) -> ApiResult:
|
|
57
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
58
|
+
endpoints.PEOPLE_REMOVE, {**self._base(), "key": key, "values": values}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
def track_charge(
|
|
62
|
+
self, amount: float, properties: Optional[Dict[str, Any]] = None
|
|
63
|
+
) -> ApiResult:
|
|
64
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
65
|
+
endpoints.PEOPLE_TRACK_CHARGE,
|
|
66
|
+
{**self._base(), "amount": amount, "properties": properties or {}},
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def clear_charges(self) -> ApiResult:
|
|
70
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
71
|
+
endpoints.PEOPLE_CLEAR_CHARGES, self._base()
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def delete_user(self) -> ApiResult:
|
|
75
|
+
return self._http.post_people( # type: ignore[attr-defined]
|
|
76
|
+
endpoints.PEOPLE_DELETE_USER, self._base()
|
|
77
|
+
)
|
trodo/queue/batch_flusher.py
CHANGED
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
"""Background timer-based batch flusher."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import threading
|
|
6
|
-
from typing import Optional
|
|
7
|
-
|
|
8
|
-
from .event_queue import EventQueue
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class BatchFlusher:
|
|
12
|
-
def __init__(
|
|
13
|
-
self,
|
|
14
|
-
queue: EventQueue,
|
|
15
|
-
http_client: object,
|
|
16
|
-
flush_interval: float,
|
|
17
|
-
) -> None:
|
|
18
|
-
self._queue = queue
|
|
19
|
-
self._http = http_client
|
|
20
|
-
self._flush_interval = flush_interval
|
|
21
|
-
self._timer: Optional[threading.Timer] = None
|
|
22
|
-
self._lock = threading.Lock()
|
|
23
|
-
|
|
24
|
-
def start(self) -> None:
|
|
25
|
-
self._reschedule()
|
|
26
|
-
|
|
27
|
-
def stop(self) -> None:
|
|
28
|
-
with self._lock:
|
|
29
|
-
if self._timer:
|
|
30
|
-
self._timer.cancel()
|
|
31
|
-
self._timer = None
|
|
32
|
-
|
|
33
|
-
def flush(self) -> None:
|
|
34
|
-
events = self._queue.drain()
|
|
35
|
-
if not events:
|
|
36
|
-
return
|
|
37
|
-
self._http.post_bulk_events(events) # type: ignore[attr-defined]
|
|
38
|
-
|
|
39
|
-
def _reschedule(self) -> None:
|
|
40
|
-
with self._lock:
|
|
41
|
-
if self._timer:
|
|
42
|
-
self._timer.cancel()
|
|
43
|
-
t = threading.Timer(self._flush_interval, self._tick)
|
|
44
|
-
t.daemon = True
|
|
45
|
-
t.start()
|
|
46
|
-
self._timer = t
|
|
47
|
-
|
|
48
|
-
def _tick(self) -> None:
|
|
49
|
-
try:
|
|
50
|
-
self.flush()
|
|
51
|
-
finally:
|
|
52
|
-
self._reschedule()
|
|
1
|
+
"""Background timer-based batch flusher."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
from .event_queue import EventQueue
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BatchFlusher:
|
|
12
|
+
def __init__(
|
|
13
|
+
self,
|
|
14
|
+
queue: EventQueue,
|
|
15
|
+
http_client: object,
|
|
16
|
+
flush_interval: float,
|
|
17
|
+
) -> None:
|
|
18
|
+
self._queue = queue
|
|
19
|
+
self._http = http_client
|
|
20
|
+
self._flush_interval = flush_interval
|
|
21
|
+
self._timer: Optional[threading.Timer] = None
|
|
22
|
+
self._lock = threading.Lock()
|
|
23
|
+
|
|
24
|
+
def start(self) -> None:
|
|
25
|
+
self._reschedule()
|
|
26
|
+
|
|
27
|
+
def stop(self) -> None:
|
|
28
|
+
with self._lock:
|
|
29
|
+
if self._timer:
|
|
30
|
+
self._timer.cancel()
|
|
31
|
+
self._timer = None
|
|
32
|
+
|
|
33
|
+
def flush(self) -> None:
|
|
34
|
+
events = self._queue.drain()
|
|
35
|
+
if not events:
|
|
36
|
+
return
|
|
37
|
+
self._http.post_bulk_events(events) # type: ignore[attr-defined]
|
|
38
|
+
|
|
39
|
+
def _reschedule(self) -> None:
|
|
40
|
+
with self._lock:
|
|
41
|
+
if self._timer:
|
|
42
|
+
self._timer.cancel()
|
|
43
|
+
t = threading.Timer(self._flush_interval, self._tick)
|
|
44
|
+
t.daemon = True
|
|
45
|
+
t.start()
|
|
46
|
+
self._timer = t
|
|
47
|
+
|
|
48
|
+
def _tick(self) -> None:
|
|
49
|
+
try:
|
|
50
|
+
self.flush()
|
|
51
|
+
finally:
|
|
52
|
+
self._reschedule()
|
trodo/queue/event_queue.py
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
"""Thread-safe in-memory event queue."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import threading
|
|
6
|
-
from typing import List
|
|
7
|
-
|
|
8
|
-
from ..types import EventPayload
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class EventQueue:
|
|
12
|
-
def __init__(self, max_size: int = 500) -> None:
|
|
13
|
-
self._max_size = max_size
|
|
14
|
-
self._queue: List[EventPayload] = []
|
|
15
|
-
self._lock = threading.Lock()
|
|
16
|
-
|
|
17
|
-
def enqueue(self, event: EventPayload) -> bool:
|
|
18
|
-
"""Returns True if flush threshold reached."""
|
|
19
|
-
with self._lock:
|
|
20
|
-
self._queue.append(event)
|
|
21
|
-
return len(self._queue) >= self._max_size
|
|
22
|
-
|
|
23
|
-
def drain(self) -> List[EventPayload]:
|
|
24
|
-
"""Atomically take all queued events."""
|
|
25
|
-
with self._lock:
|
|
26
|
-
events = list(self._queue)
|
|
27
|
-
self._queue.clear()
|
|
28
|
-
return events
|
|
29
|
-
|
|
30
|
-
def size(self) -> int:
|
|
31
|
-
with self._lock:
|
|
32
|
-
return len(self._queue)
|
|
1
|
+
"""Thread-safe in-memory event queue."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
from ..types import EventPayload
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class EventQueue:
|
|
12
|
+
def __init__(self, max_size: int = 500) -> None:
|
|
13
|
+
self._max_size = max_size
|
|
14
|
+
self._queue: List[EventPayload] = []
|
|
15
|
+
self._lock = threading.Lock()
|
|
16
|
+
|
|
17
|
+
def enqueue(self, event: EventPayload) -> bool:
|
|
18
|
+
"""Returns True if flush threshold reached."""
|
|
19
|
+
with self._lock:
|
|
20
|
+
self._queue.append(event)
|
|
21
|
+
return len(self._queue) >= self._max_size
|
|
22
|
+
|
|
23
|
+
def drain(self) -> List[EventPayload]:
|
|
24
|
+
"""Atomically take all queued events."""
|
|
25
|
+
with self._lock:
|
|
26
|
+
events = list(self._queue)
|
|
27
|
+
self._queue.clear()
|
|
28
|
+
return events
|
|
29
|
+
|
|
30
|
+
def size(self) -> int:
|
|
31
|
+
with self._lock:
|
|
32
|
+
return len(self._queue)
|