httpstate 0.0.13__tar.gz → 0.0.14__tar.gz
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.
- {httpstate-0.0.13 → httpstate-0.0.14}/PKG-INFO +29 -16
- {httpstate-0.0.13 → httpstate-0.0.14}/README.md +28 -15
- {httpstate-0.0.13 → httpstate-0.0.14}/pyproject.toml +1 -1
- {httpstate-0.0.13 → httpstate-0.0.14}/src/httpstate/__init__.py +6 -0
- {httpstate-0.0.13 → httpstate-0.0.14}/src/httpstate/httpstate.py +52 -18
- {httpstate-0.0.13 → httpstate-0.0.14}/.gitignore +0 -0
- {httpstate-0.0.13 → httpstate-0.0.14}/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: httpstate
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.14
|
|
4
4
|
Summary: HTTP State, httpstate.com
|
|
5
5
|
Author-email: "Alex Morales, HTTP State" <alex@httpstate.com>
|
|
6
6
|
License-Expression: AGPL-3.0
|
|
@@ -28,7 +28,7 @@ Import
|
|
|
28
28
|
import httpstate
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Pick any valid UUID v4. You can [generate one here](https://
|
|
31
|
+
Pick any valid UUID v4. You can [generate one here](https://uuid.httpstate.com).
|
|
32
32
|
|
|
33
33
|
We'll use `45fb3654-0e92-44da-aa21-ca409c6bdab3` or `45fb36540e9244daaa21ca409c6bdab3` (without dashes).
|
|
34
34
|
|
|
@@ -44,7 +44,7 @@ and retrieve it with
|
|
|
44
44
|
data = httpstate.get('45fb36540e9244daaa21ca409c6bdab3')
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
You can also get
|
|
47
|
+
You can also get realtime updates
|
|
48
48
|
|
|
49
49
|
```python
|
|
50
50
|
hs = httpstate.HttpState('45fb36540e9244daaa21ca409c6bdab3')
|
|
@@ -58,40 +58,53 @@ That's it! 🐙
|
|
|
58
58
|
|
|
59
59
|
### Functions
|
|
60
60
|
|
|
61
|
-
- `get(uuid)`
|
|
61
|
+
- `get(uuid)`
|
|
62
62
|
Get state of UUIDv4.
|
|
63
63
|
|
|
64
|
-
- `
|
|
64
|
+
- `post(uuid, data)`
|
|
65
|
+
Alias for `set`.
|
|
66
|
+
|
|
67
|
+
- `read(uuid)`
|
|
65
68
|
Alias for `get`.
|
|
66
69
|
|
|
67
|
-
- `set(uuid, data)`
|
|
70
|
+
- `set(uuid, data)`
|
|
68
71
|
Set state of UUIDv4.
|
|
69
72
|
|
|
70
|
-
- `write(uuid, data)`
|
|
73
|
+
- `write(uuid, data)`
|
|
71
74
|
Alias for `set`.
|
|
72
75
|
|
|
73
76
|
### HttpState Class
|
|
74
77
|
|
|
75
|
-
- `HttpState(uuid)`
|
|
78
|
+
- `HttpState(uuid)`
|
|
76
79
|
Create a reactive state instance of UUIDv4.
|
|
80
|
+
- `<HttpState>.data`
|
|
81
|
+
Property with the most up-to-date state value.
|
|
77
82
|
|
|
78
83
|
<br>
|
|
79
84
|
|
|
80
|
-
- `<HttpState>.get()`
|
|
85
|
+
- `<HttpState>.get()`
|
|
81
86
|
Get state.
|
|
82
|
-
- `<HttpState>.
|
|
87
|
+
- `<HttpState>.post(data)`
|
|
88
|
+
Alias for `set`.
|
|
89
|
+
- `<HttpState>.read()`
|
|
83
90
|
Alias for `get`.
|
|
84
|
-
- `<HttpState>.set(data)`
|
|
91
|
+
- `<HttpState>.set(data)`
|
|
85
92
|
Set state.
|
|
86
|
-
- `<HttpState>.write(data)`
|
|
93
|
+
- `<HttpState>.write(data)`
|
|
87
94
|
Alias for `set`.
|
|
88
95
|
|
|
89
96
|
<br>
|
|
90
97
|
|
|
91
|
-
- `<HttpState>.off(type, callback)`
|
|
92
|
-
Unsubscribe from
|
|
93
|
-
- `<HttpState>.on(type, callback)`
|
|
94
|
-
Subscribe to
|
|
98
|
+
- `<HttpState>.off(type, callback)`
|
|
99
|
+
Unsubscribe from realtime updates.
|
|
100
|
+
- `<HttpState>.on(type, callback)`
|
|
101
|
+
Subscribe to realtime updates.
|
|
102
|
+
- `change`: fired when state data changes. Callback receives current data as argument.
|
|
103
|
+
|
|
104
|
+
<br>
|
|
105
|
+
|
|
106
|
+
- `<HttpState>.delete()`
|
|
107
|
+
Cleanup and delete the instance.
|
|
95
108
|
|
|
96
109
|
---
|
|
97
110
|
|
|
@@ -14,7 +14,7 @@ Import
|
|
|
14
14
|
import httpstate
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
Pick any valid UUID v4. You can [generate one here](https://
|
|
17
|
+
Pick any valid UUID v4. You can [generate one here](https://uuid.httpstate.com).
|
|
18
18
|
|
|
19
19
|
We'll use `45fb3654-0e92-44da-aa21-ca409c6bdab3` or `45fb36540e9244daaa21ca409c6bdab3` (without dashes).
|
|
20
20
|
|
|
@@ -30,7 +30,7 @@ and retrieve it with
|
|
|
30
30
|
data = httpstate.get('45fb36540e9244daaa21ca409c6bdab3')
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
You can also get
|
|
33
|
+
You can also get realtime updates
|
|
34
34
|
|
|
35
35
|
```python
|
|
36
36
|
hs = httpstate.HttpState('45fb36540e9244daaa21ca409c6bdab3')
|
|
@@ -44,40 +44,53 @@ That's it! 🐙
|
|
|
44
44
|
|
|
45
45
|
### Functions
|
|
46
46
|
|
|
47
|
-
- `get(uuid)`
|
|
47
|
+
- `get(uuid)`
|
|
48
48
|
Get state of UUIDv4.
|
|
49
49
|
|
|
50
|
-
- `
|
|
50
|
+
- `post(uuid, data)`
|
|
51
|
+
Alias for `set`.
|
|
52
|
+
|
|
53
|
+
- `read(uuid)`
|
|
51
54
|
Alias for `get`.
|
|
52
55
|
|
|
53
|
-
- `set(uuid, data)`
|
|
56
|
+
- `set(uuid, data)`
|
|
54
57
|
Set state of UUIDv4.
|
|
55
58
|
|
|
56
|
-
- `write(uuid, data)`
|
|
59
|
+
- `write(uuid, data)`
|
|
57
60
|
Alias for `set`.
|
|
58
61
|
|
|
59
62
|
### HttpState Class
|
|
60
63
|
|
|
61
|
-
- `HttpState(uuid)`
|
|
64
|
+
- `HttpState(uuid)`
|
|
62
65
|
Create a reactive state instance of UUIDv4.
|
|
66
|
+
- `<HttpState>.data`
|
|
67
|
+
Property with the most up-to-date state value.
|
|
63
68
|
|
|
64
69
|
<br>
|
|
65
70
|
|
|
66
|
-
- `<HttpState>.get()`
|
|
71
|
+
- `<HttpState>.get()`
|
|
67
72
|
Get state.
|
|
68
|
-
- `<HttpState>.
|
|
73
|
+
- `<HttpState>.post(data)`
|
|
74
|
+
Alias for `set`.
|
|
75
|
+
- `<HttpState>.read()`
|
|
69
76
|
Alias for `get`.
|
|
70
|
-
- `<HttpState>.set(data)`
|
|
77
|
+
- `<HttpState>.set(data)`
|
|
71
78
|
Set state.
|
|
72
|
-
- `<HttpState>.write(data)`
|
|
79
|
+
- `<HttpState>.write(data)`
|
|
73
80
|
Alias for `set`.
|
|
74
81
|
|
|
75
82
|
<br>
|
|
76
83
|
|
|
77
|
-
- `<HttpState>.off(type, callback)`
|
|
78
|
-
Unsubscribe from
|
|
79
|
-
- `<HttpState>.on(type, callback)`
|
|
80
|
-
Subscribe to
|
|
84
|
+
- `<HttpState>.off(type, callback)`
|
|
85
|
+
Unsubscribe from realtime updates.
|
|
86
|
+
- `<HttpState>.on(type, callback)`
|
|
87
|
+
Subscribe to realtime updates.
|
|
88
|
+
- `change`: fired when state data changes. Callback receives current data as argument.
|
|
89
|
+
|
|
90
|
+
<br>
|
|
91
|
+
|
|
92
|
+
- `<HttpState>.delete()`
|
|
93
|
+
Cleanup and delete the instance.
|
|
81
94
|
|
|
82
95
|
---
|
|
83
96
|
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
# version 3 of the License, or (at your option) any later version.
|
|
8
8
|
|
|
9
9
|
import asyncio
|
|
10
|
+
import struct
|
|
10
11
|
import threading
|
|
12
|
+
import types
|
|
11
13
|
import urllib.error
|
|
12
14
|
import urllib.request
|
|
13
15
|
import websockets
|
|
@@ -26,11 +28,38 @@ def get(uuid:str) -> None|str:
|
|
|
26
28
|
except Exception:
|
|
27
29
|
return None
|
|
28
30
|
|
|
31
|
+
class MessageType:
|
|
32
|
+
def __init__(self, uuid:str, timestamp:int, type:int, value:bytes) -> None:
|
|
33
|
+
self.uuid:str = uuid
|
|
34
|
+
self.timestamp:int = timestamp
|
|
35
|
+
self.type:int = type
|
|
36
|
+
self.value:bytes = value
|
|
37
|
+
|
|
38
|
+
class Message:
|
|
39
|
+
@staticmethod
|
|
40
|
+
def unpack(b:bytes) -> MessageType:
|
|
41
|
+
length:int = b[0]
|
|
42
|
+
|
|
43
|
+
return MessageType(
|
|
44
|
+
uuid=b[1:1+length].decode('utf-8'),
|
|
45
|
+
timestamp=struct.unpack_from('>Q', b, 1+length)[0],
|
|
46
|
+
type=b[1+length+8],
|
|
47
|
+
value=b[1+length+9:],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
message:type = Message
|
|
51
|
+
|
|
52
|
+
def post(uuid:str, data:str) -> None|int:
|
|
53
|
+
return set(uuid, data)
|
|
54
|
+
|
|
55
|
+
def put(uuid:str, data:str) -> None|int:
|
|
56
|
+
return set(uuid, data)
|
|
57
|
+
|
|
29
58
|
def read(uuid:str) -> None|str:
|
|
30
59
|
return get(uuid)
|
|
31
60
|
|
|
32
61
|
def set(uuid:str, data:str) -> None|int:
|
|
33
|
-
req = urllib.request.Request(
|
|
62
|
+
req:urllib.request.Request = urllib.request.Request(
|
|
34
63
|
f'https://httpstate.com/{uuid}',
|
|
35
64
|
data=data.encode('utf-8'),
|
|
36
65
|
headers={ 'Content-Type':'text/plain;charset=UTF-8' },
|
|
@@ -50,7 +79,7 @@ def write(uuid:str, data:str) -> None|int:
|
|
|
50
79
|
|
|
51
80
|
# HTTP State
|
|
52
81
|
class HttpState:
|
|
53
|
-
def __init__(self, uuid:str):
|
|
82
|
+
def __init__(self, uuid:str) -> None:
|
|
54
83
|
self.data:None|str = None
|
|
55
84
|
self.el:None|asyncio.AbstractEventLoop = None
|
|
56
85
|
self.et:Dict[str, List[Callable[[None|str], None]]] = {}
|
|
@@ -67,8 +96,8 @@ class HttpState:
|
|
|
67
96
|
target=lambda : asyncio.run(self._ws())
|
|
68
97
|
).start()
|
|
69
98
|
|
|
70
|
-
def _el(self):
|
|
71
|
-
self.el = asyncio.new_event_loop()
|
|
99
|
+
def _el(self) -> None:
|
|
100
|
+
self.el:asyncio.AbstractEventLoop = asyncio.new_event_loop()
|
|
72
101
|
|
|
73
102
|
asyncio.set_event_loop(self.el)
|
|
74
103
|
|
|
@@ -76,29 +105,28 @@ class HttpState:
|
|
|
76
105
|
|
|
77
106
|
self.el.run_forever()
|
|
78
107
|
|
|
79
|
-
async def _ws(self):
|
|
80
|
-
self.ws = await websockets.connect(f"wss://httpstate.com/{self.uuid}")
|
|
108
|
+
async def _ws(self) -> None:
|
|
109
|
+
self.ws:websockets.WebSocketClientProtocol = await websockets.connect(f"wss://httpstate.com/{self.uuid}")
|
|
81
110
|
|
|
82
111
|
await self.ws.send(f'{{"open":"{self.uuid}"}}')
|
|
83
112
|
self.emit('open')
|
|
84
113
|
|
|
85
|
-
async def data():
|
|
114
|
+
async def data() -> None:
|
|
86
115
|
async for data in self.ws:
|
|
87
|
-
data =
|
|
116
|
+
data:MessageType = message.unpack(data)
|
|
88
117
|
|
|
89
118
|
if(
|
|
90
119
|
data
|
|
91
|
-
and
|
|
92
|
-
and data
|
|
93
|
-
and data[45] == '1'
|
|
120
|
+
and data.uuid == self.uuid
|
|
121
|
+
and data.type == 1
|
|
94
122
|
):
|
|
95
|
-
self.data = data
|
|
123
|
+
self.data:None|str = data.value.decode()
|
|
96
124
|
|
|
97
125
|
self.emit('change', self.data)
|
|
98
126
|
|
|
99
127
|
asyncio.create_task(data())
|
|
100
128
|
|
|
101
|
-
async def interval():
|
|
129
|
+
async def interval() -> None:
|
|
102
130
|
while True:
|
|
103
131
|
try:
|
|
104
132
|
await self.ws.ping()
|
|
@@ -111,10 +139,10 @@ class HttpState:
|
|
|
111
139
|
|
|
112
140
|
await asyncio.Event().wait()
|
|
113
141
|
|
|
114
|
-
def
|
|
142
|
+
def delete(self) -> None:
|
|
115
143
|
pass
|
|
116
144
|
|
|
117
|
-
def emit(self, type:str, data:None|str = None):
|
|
145
|
+
def emit(self, type:str, data:None|str = None) -> "HttpState":
|
|
118
146
|
for callback in self.et.get(type, []):
|
|
119
147
|
if(data is None):
|
|
120
148
|
callback()
|
|
@@ -124,7 +152,7 @@ class HttpState:
|
|
|
124
152
|
return self
|
|
125
153
|
|
|
126
154
|
def get(self) -> None|str:
|
|
127
|
-
data = get(self.uuid)
|
|
155
|
+
data:None|str = get(self.uuid)
|
|
128
156
|
|
|
129
157
|
if(data != self.data):
|
|
130
158
|
self.el.call_soon_threadsafe(lambda : self.emit('change', self.data))
|
|
@@ -133,7 +161,7 @@ class HttpState:
|
|
|
133
161
|
|
|
134
162
|
return self.data
|
|
135
163
|
|
|
136
|
-
def off(self, type:str, callback:Callable[[None|str], None]):
|
|
164
|
+
def off(self, type:str, callback:Callable[[None|str], None]) -> "HttpState":
|
|
137
165
|
if type in self.et:
|
|
138
166
|
try:
|
|
139
167
|
self.et[type].remove(callback)
|
|
@@ -145,13 +173,19 @@ class HttpState:
|
|
|
145
173
|
|
|
146
174
|
return self
|
|
147
175
|
|
|
148
|
-
def on(self, type:str, callback:Callable[[None|str], None]):
|
|
176
|
+
def on(self, type:str, callback:Callable[[None|str], None]) -> "HttpState":
|
|
149
177
|
if type not in self.et:
|
|
150
178
|
self.et[type] = []
|
|
151
179
|
|
|
152
180
|
self.et[type].append(callback)
|
|
153
181
|
|
|
154
182
|
return self
|
|
183
|
+
|
|
184
|
+
def post(self, data:str) -> None|int:
|
|
185
|
+
return self.set(data)
|
|
186
|
+
|
|
187
|
+
def put(self, data:str) -> None|int:
|
|
188
|
+
return self.set(data)
|
|
155
189
|
|
|
156
190
|
def read(self) -> None|str:
|
|
157
191
|
return self.get()
|
|
File without changes
|
|
File without changes
|