httpstate 0.0.15__tar.gz → 0.0.19__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.15 → httpstate-0.0.19}/PKG-INFO +2 -2
- {httpstate-0.0.15 → httpstate-0.0.19}/pyproject.toml +2 -2
- {httpstate-0.0.15 → httpstate-0.0.19}/src/httpstate/__init__.py +2 -2
- httpstate-0.0.19/src/httpstate/httpstate.py +263 -0
- httpstate-0.0.15/src/httpstate/httpstate.py +0 -203
- {httpstate-0.0.15 → httpstate-0.0.19}/.gitignore +0 -0
- {httpstate-0.0.15 → httpstate-0.0.19}/LICENSE +0 -0
- {httpstate-0.0.15 → httpstate-0.0.19}/README.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: httpstate
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.19
|
|
4
4
|
Summary: HTTPState, httpstate.com
|
|
5
5
|
Author-email: "Alex Morales, HTTPState" <alex@httpstate.com>
|
|
6
6
|
License-Expression: AGPL-3.0
|
|
@@ -9,7 +9,7 @@ Keywords: httpstate
|
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
11
|
Requires-Python: >=3.10
|
|
12
|
-
Requires-Dist: websockets>=
|
|
12
|
+
Requires-Dist: websockets>=15.0
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
|
|
15
15
|
# httpstate (python)
|
|
@@ -8,7 +8,7 @@ classifiers = [
|
|
|
8
8
|
"Operating System :: OS Independent",
|
|
9
9
|
"Programming Language :: Python :: 3"
|
|
10
10
|
]
|
|
11
|
-
dependencies = ["websockets>=
|
|
11
|
+
dependencies = ["websockets>=15.0"]
|
|
12
12
|
description = "HTTPState, httpstate.com"
|
|
13
13
|
keywords = ["httpstate"]
|
|
14
14
|
license = "AGPL-3.0"
|
|
@@ -16,7 +16,7 @@ license-files = ["LICEN[CS]E*"]
|
|
|
16
16
|
name = "httpstate"
|
|
17
17
|
readme = "README.md"
|
|
18
18
|
requires-python = ">=3.10"
|
|
19
|
-
version = "0.0.
|
|
19
|
+
version = "0.0.19"
|
|
20
20
|
|
|
21
21
|
[project.url]
|
|
22
22
|
Homepage = "https://httpstate.com"
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# HTTPState, https://httpstate.com/
|
|
2
|
+
# Copyright (C) Alex Morales, 2026
|
|
3
|
+
|
|
4
|
+
# Unless otherwise stated in particular files or directories, this software is free software.
|
|
5
|
+
# You can redistribute it and/or modify it under the terms of the GNU Affero
|
|
6
|
+
# General Public License as published by the Free Software Foundation, either
|
|
7
|
+
# version 3 of the License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import datetime
|
|
11
|
+
import json
|
|
12
|
+
import struct
|
|
13
|
+
import threading
|
|
14
|
+
import urllib.error
|
|
15
|
+
import urllib.request
|
|
16
|
+
import websockets
|
|
17
|
+
|
|
18
|
+
from typing import Callable, Dict, List
|
|
19
|
+
|
|
20
|
+
def get(uuid:str, args:None|Dict = None) -> None|str|dict:
|
|
21
|
+
try:
|
|
22
|
+
req:urllib.request.Request = urllib.request.Request(f'https://httpstate.com/{uuid}')
|
|
23
|
+
|
|
24
|
+
if args and args.get('Authorization'):
|
|
25
|
+
req.add_header('Authorization', args.get('Authorization'))
|
|
26
|
+
|
|
27
|
+
with urllib.request.urlopen(req) as f:
|
|
28
|
+
if f.status == 200:
|
|
29
|
+
data:str = f.read().decode('utf-8', 'replace')
|
|
30
|
+
|
|
31
|
+
if(
|
|
32
|
+
not args
|
|
33
|
+
or (
|
|
34
|
+
not args.get('ETag')
|
|
35
|
+
and not args.get('Last-Modified')
|
|
36
|
+
)
|
|
37
|
+
):
|
|
38
|
+
return data
|
|
39
|
+
else:
|
|
40
|
+
return {
|
|
41
|
+
**({ 'ETag':f.headers.get('ETag') } if args.get('ETag') else {}),
|
|
42
|
+
**({ 'Last-Modified':f.headers.get('Last-Modified') } if args.get('Last-Modified') else {}),
|
|
43
|
+
'data':data
|
|
44
|
+
}
|
|
45
|
+
except urllib.error.HTTPError as e:
|
|
46
|
+
if e.code == 401:
|
|
47
|
+
raise Exception('401 Unauthorized')
|
|
48
|
+
elif e.code == 404:
|
|
49
|
+
raise Exception('404 Not Found')
|
|
50
|
+
elif e.code == 429:
|
|
51
|
+
raise Exception('429 Too Many Requests')
|
|
52
|
+
except Exception as e:
|
|
53
|
+
print(datetime.datetime.now().isoformat(), 'get.error', e)
|
|
54
|
+
|
|
55
|
+
raise e
|
|
56
|
+
|
|
57
|
+
class MessageType:
|
|
58
|
+
def __init__(self, uuid:str, timestamp:int, type:int, value:bytes) -> None:
|
|
59
|
+
self.uuid:str = uuid
|
|
60
|
+
self.timestamp:int = timestamp
|
|
61
|
+
self.type:int = type
|
|
62
|
+
self.value:bytes = value
|
|
63
|
+
|
|
64
|
+
class Message:
|
|
65
|
+
@staticmethod
|
|
66
|
+
def unpack(b:bytes) -> None|MessageType:
|
|
67
|
+
header:int = b[0]
|
|
68
|
+
|
|
69
|
+
if header == 0:
|
|
70
|
+
length:int = b[1]
|
|
71
|
+
|
|
72
|
+
return MessageType(
|
|
73
|
+
uuid=b[2:2+length].decode('utf-8'),
|
|
74
|
+
timestamp=struct.unpack_from('>Q', b, 2+length)[0],
|
|
75
|
+
type=b[2+length+8],
|
|
76
|
+
value=b[2+length+9:]
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
message:type = Message
|
|
80
|
+
|
|
81
|
+
def post(uuid:str, data:None|str = None, args:None|Dict = None) -> None|int:
|
|
82
|
+
return set(uuid, data, args)
|
|
83
|
+
|
|
84
|
+
def put(uuid:str, data:None|str = None, args:None|Dict = None) -> None|int:
|
|
85
|
+
return set(uuid, data, args)
|
|
86
|
+
|
|
87
|
+
def read(uuid:str, args:None|Dict = None) -> None|str|dict:
|
|
88
|
+
return get(uuid, args)
|
|
89
|
+
|
|
90
|
+
def set(uuid:str, data:None|str = None, args:None|Dict = None) -> None|int:
|
|
91
|
+
if(data is None):
|
|
92
|
+
data = ''
|
|
93
|
+
|
|
94
|
+
headers:Dict[str, str] = { 'Content-Type':'text/plain;charset=UTF-8' }
|
|
95
|
+
|
|
96
|
+
if args and args.get('Authorization'):
|
|
97
|
+
headers['Authorization'] = args.get('Authorization')
|
|
98
|
+
|
|
99
|
+
req:urllib.request.Request = urllib.request.Request(
|
|
100
|
+
f'https://httpstate.com/{uuid}',
|
|
101
|
+
data=data.encode('utf-8'),
|
|
102
|
+
headers=headers,
|
|
103
|
+
method='POST'
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
with urllib.request.urlopen(req) as f:
|
|
108
|
+
return f.status
|
|
109
|
+
except urllib.error.HTTPError as e:
|
|
110
|
+
if e.code == 401:
|
|
111
|
+
raise Exception('401 Unauthorized')
|
|
112
|
+
elif e.code == 404:
|
|
113
|
+
raise Exception('404 Not Found')
|
|
114
|
+
elif e.code == 413:
|
|
115
|
+
raise Exception('413 Content Too Large')
|
|
116
|
+
|
|
117
|
+
return e.code
|
|
118
|
+
except Exception as e:
|
|
119
|
+
print(datetime.datetime.now().isoformat(), 'set.error', e)
|
|
120
|
+
|
|
121
|
+
def write(uuid:str, data:None|str = None, args:None|Dict = None) -> None|int:
|
|
122
|
+
return set(uuid, data, args)
|
|
123
|
+
|
|
124
|
+
# HTTPState
|
|
125
|
+
class HTTPState:
|
|
126
|
+
def __init__(self, uuid:str, args:None|Dict = None) -> None:
|
|
127
|
+
self.authorization:None|str = args.get('Authorization') if args else None
|
|
128
|
+
self.data:None|str = None
|
|
129
|
+
self.el:None|asyncio.AbstractEventLoop = None
|
|
130
|
+
self.et:None|Dict[str, List[Callable[[None|str], None]]] = {}
|
|
131
|
+
self.lock:None|threading.Lock = threading.Lock()
|
|
132
|
+
self.uuid:None|str = uuid
|
|
133
|
+
self.ws:None|websockets.WebSocketClientProtocol = None
|
|
134
|
+
|
|
135
|
+
threading.Thread(
|
|
136
|
+
daemon=True,
|
|
137
|
+
target=self._el
|
|
138
|
+
).start()
|
|
139
|
+
|
|
140
|
+
threading.Thread(
|
|
141
|
+
daemon=True,
|
|
142
|
+
target=lambda : asyncio.run(self._ws())
|
|
143
|
+
).start()
|
|
144
|
+
|
|
145
|
+
def _el(self) -> None:
|
|
146
|
+
self.el:asyncio.AbstractEventLoop = asyncio.new_event_loop()
|
|
147
|
+
|
|
148
|
+
asyncio.set_event_loop(self.el)
|
|
149
|
+
|
|
150
|
+
self.el.call_soon_threadsafe(lambda : self.get())
|
|
151
|
+
|
|
152
|
+
self.el.run_forever()
|
|
153
|
+
|
|
154
|
+
async def _ws(self) -> None:
|
|
155
|
+
self.ws:websockets.WebSocketClientProtocol = await websockets.connect(f"wss://httpstate.com/{self.uuid}")
|
|
156
|
+
|
|
157
|
+
await self.ws.send(json.dumps({ 'open':self.uuid, **({ 'Authorization':self.authorization } if self.authorization is not None else {}) }))
|
|
158
|
+
|
|
159
|
+
self.emit('open')
|
|
160
|
+
|
|
161
|
+
async def data() -> None:
|
|
162
|
+
async for data in self.ws:
|
|
163
|
+
data:None|MessageType = message.unpack(data)
|
|
164
|
+
|
|
165
|
+
if(
|
|
166
|
+
data
|
|
167
|
+
and data.uuid == self.uuid
|
|
168
|
+
and data.type == 1
|
|
169
|
+
):
|
|
170
|
+
with self.lock:
|
|
171
|
+
self.data:None|str = data.value.decode()
|
|
172
|
+
|
|
173
|
+
self.emit('change', self.data)
|
|
174
|
+
|
|
175
|
+
asyncio.create_task(data())
|
|
176
|
+
|
|
177
|
+
async def interval() -> None:
|
|
178
|
+
while True:
|
|
179
|
+
try:
|
|
180
|
+
await self.ws.ping()
|
|
181
|
+
|
|
182
|
+
await asyncio.sleep(30) # 30 SECONDS
|
|
183
|
+
except websockets.ConnectionClosed:
|
|
184
|
+
break
|
|
185
|
+
|
|
186
|
+
asyncio.create_task(interval())
|
|
187
|
+
|
|
188
|
+
await asyncio.Event().wait()
|
|
189
|
+
|
|
190
|
+
def delete(self) -> None:
|
|
191
|
+
if self.el is not None:
|
|
192
|
+
if self.ws is not None:
|
|
193
|
+
asyncio.run_coroutine_threadsafe(self.ws.close(), self.el)
|
|
194
|
+
|
|
195
|
+
self.el.call_soon_threadsafe(self.el.stop)
|
|
196
|
+
|
|
197
|
+
self.authorization = None
|
|
198
|
+
self.data = None
|
|
199
|
+
self.el = None
|
|
200
|
+
self.et = None
|
|
201
|
+
self.lock = None
|
|
202
|
+
self.uuid = None
|
|
203
|
+
self.ws = None
|
|
204
|
+
|
|
205
|
+
def emit(self, type:str, data:None|str = None) -> "HTTPState":
|
|
206
|
+
if self.et is not None:
|
|
207
|
+
for callback in self.et.get(type, []):
|
|
208
|
+
if(data is None):
|
|
209
|
+
callback()
|
|
210
|
+
else:
|
|
211
|
+
callback(data)
|
|
212
|
+
|
|
213
|
+
return self
|
|
214
|
+
|
|
215
|
+
def get(self) -> None|str:
|
|
216
|
+
args:None|Dict = { 'Authorization':self.authorization } if self.authorization is not None else None
|
|
217
|
+
data:None|str = get(self.uuid, args)
|
|
218
|
+
|
|
219
|
+
with self.lock:
|
|
220
|
+
if(data != self.data):
|
|
221
|
+
if self.el is not None:
|
|
222
|
+
self.el.call_soon_threadsafe(lambda : self.emit('change', self.data))
|
|
223
|
+
|
|
224
|
+
self.data = data
|
|
225
|
+
|
|
226
|
+
return self.data
|
|
227
|
+
|
|
228
|
+
def off(self, type:str, callback:Callable[[None|str], None]) -> "HTTPState":
|
|
229
|
+
if self.et is not None and type in self.et:
|
|
230
|
+
try:
|
|
231
|
+
self.et[type].remove(callback)
|
|
232
|
+
except ValueError:
|
|
233
|
+
pass
|
|
234
|
+
|
|
235
|
+
if not self.et[type]:
|
|
236
|
+
del self.et[type]
|
|
237
|
+
|
|
238
|
+
return self
|
|
239
|
+
|
|
240
|
+
def on(self, type:str, callback:Callable[[None|str], None]) -> "HTTPState":
|
|
241
|
+
if self.et is not None:
|
|
242
|
+
if type not in self.et:
|
|
243
|
+
self.et[type] = []
|
|
244
|
+
|
|
245
|
+
self.et[type].append(callback)
|
|
246
|
+
|
|
247
|
+
return self
|
|
248
|
+
|
|
249
|
+
def post(self, data:None|str = None) -> None|int:
|
|
250
|
+
return self.set(data)
|
|
251
|
+
|
|
252
|
+
def put(self, data:None|str = None) -> None|int:
|
|
253
|
+
return self.set(data)
|
|
254
|
+
|
|
255
|
+
def read(self) -> None|str:
|
|
256
|
+
return self.get()
|
|
257
|
+
|
|
258
|
+
def set(self, data:None|str = None) -> None|int:
|
|
259
|
+
args:None|Dict = { 'Authorization':self.authorization } if self.authorization is not None else None
|
|
260
|
+
return set(self.uuid, data, args)
|
|
261
|
+
|
|
262
|
+
def write(self, data:None|str = None) -> None|int:
|
|
263
|
+
return self.set(data)
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
# HTTPState, https://httpstate.com/
|
|
2
|
-
# Copyright (C) Alex Morales, 2026
|
|
3
|
-
|
|
4
|
-
# Unless otherwise stated in particular files or directories, this software is free software.
|
|
5
|
-
# You can redistribute it and/or modify it under the terms of the GNU Affero
|
|
6
|
-
# General Public License as published by the Free Software Foundation, either
|
|
7
|
-
# version 3 of the License, or (at your option) any later version.
|
|
8
|
-
|
|
9
|
-
import asyncio
|
|
10
|
-
import struct
|
|
11
|
-
import threading
|
|
12
|
-
import urllib.error
|
|
13
|
-
import urllib.request
|
|
14
|
-
import websockets
|
|
15
|
-
|
|
16
|
-
from typing import Callable, Dict, List
|
|
17
|
-
|
|
18
|
-
def get(uuid:str) -> None|str:
|
|
19
|
-
try:
|
|
20
|
-
with urllib.request.urlopen(f'https://httpstate.com/{uuid}') as f:
|
|
21
|
-
if f.status == 200:
|
|
22
|
-
return f.read().decode('utf-8', 'replace')
|
|
23
|
-
|
|
24
|
-
return None
|
|
25
|
-
except urllib.error.HTTPError:
|
|
26
|
-
return None
|
|
27
|
-
except Exception:
|
|
28
|
-
return None
|
|
29
|
-
|
|
30
|
-
class MessageType:
|
|
31
|
-
def __init__(self, uuid:str, timestamp:int, type:int, value:bytes) -> None:
|
|
32
|
-
self.uuid:str = uuid
|
|
33
|
-
self.timestamp:int = timestamp
|
|
34
|
-
self.type:int = type
|
|
35
|
-
self.value:bytes = value
|
|
36
|
-
|
|
37
|
-
class Message:
|
|
38
|
-
@staticmethod
|
|
39
|
-
def unpack(b:bytes) -> MessageType:
|
|
40
|
-
length:int = b[0]
|
|
41
|
-
|
|
42
|
-
return MessageType(
|
|
43
|
-
uuid=b[1:1+length].decode('utf-8'),
|
|
44
|
-
timestamp=struct.unpack_from('>Q', b, 1+length)[0],
|
|
45
|
-
type=b[1+length+8],
|
|
46
|
-
value=b[1+length+9:],
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
message:type = Message
|
|
50
|
-
|
|
51
|
-
def post(uuid:str, data:None|str = None) -> None|int:
|
|
52
|
-
return set(uuid, data)
|
|
53
|
-
|
|
54
|
-
def put(uuid:str, data:None|str = None) -> None|int:
|
|
55
|
-
return set(uuid, data)
|
|
56
|
-
|
|
57
|
-
def read(uuid:str) -> None|str:
|
|
58
|
-
return get(uuid)
|
|
59
|
-
|
|
60
|
-
def set(uuid:str, data:None|str = None) -> None|int:
|
|
61
|
-
if(data is None):
|
|
62
|
-
data = ''
|
|
63
|
-
|
|
64
|
-
req:urllib.request.Request = urllib.request.Request(
|
|
65
|
-
f'https://httpstate.com/{uuid}',
|
|
66
|
-
data=data.encode('utf-8'),
|
|
67
|
-
headers={ 'Content-Type':'text/plain;charset=UTF-8' },
|
|
68
|
-
method='POST'
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
with urllib.request.urlopen(req) as f:
|
|
73
|
-
return f.status
|
|
74
|
-
except urllib.error.HTTPError as e:
|
|
75
|
-
return e.code
|
|
76
|
-
except Exception:
|
|
77
|
-
return None
|
|
78
|
-
|
|
79
|
-
def write(uuid:str, data:None|str = None) -> None|int:
|
|
80
|
-
return set(uuid, data)
|
|
81
|
-
|
|
82
|
-
# HTTPState
|
|
83
|
-
class HttpState:
|
|
84
|
-
def __init__(self, uuid:str) -> None:
|
|
85
|
-
self.data:None|str = None
|
|
86
|
-
self.el:None|asyncio.AbstractEventLoop = None
|
|
87
|
-
self.et:Dict[str, List[Callable[[None|str], None]]] = {}
|
|
88
|
-
self.lock:threading.Lock = threading.Lock()
|
|
89
|
-
self.uuid:str = uuid
|
|
90
|
-
self.ws:None|websockets.WebSocketClientProtocol = None
|
|
91
|
-
|
|
92
|
-
threading.Thread(
|
|
93
|
-
daemon=True,
|
|
94
|
-
target=self._el
|
|
95
|
-
).start()
|
|
96
|
-
|
|
97
|
-
threading.Thread(
|
|
98
|
-
daemon=True,
|
|
99
|
-
target=lambda : asyncio.run(self._ws())
|
|
100
|
-
).start()
|
|
101
|
-
|
|
102
|
-
def _el(self) -> None:
|
|
103
|
-
self.el:asyncio.AbstractEventLoop = asyncio.new_event_loop()
|
|
104
|
-
|
|
105
|
-
asyncio.set_event_loop(self.el)
|
|
106
|
-
|
|
107
|
-
self.el.call_soon_threadsafe(lambda : self.get())
|
|
108
|
-
|
|
109
|
-
self.el.run_forever()
|
|
110
|
-
|
|
111
|
-
async def _ws(self) -> None:
|
|
112
|
-
self.ws:websockets.WebSocketClientProtocol = await websockets.connect(f"wss://httpstate.com/{self.uuid}")
|
|
113
|
-
|
|
114
|
-
await self.ws.send(f'{{"open":"{self.uuid}"}}')
|
|
115
|
-
self.emit('open')
|
|
116
|
-
|
|
117
|
-
async def data() -> None:
|
|
118
|
-
async for data in self.ws:
|
|
119
|
-
data:MessageType = message.unpack(data)
|
|
120
|
-
|
|
121
|
-
if(
|
|
122
|
-
data
|
|
123
|
-
and data.uuid == self.uuid
|
|
124
|
-
and data.type == 1
|
|
125
|
-
):
|
|
126
|
-
with self.lock:
|
|
127
|
-
self.data:None|str = data.value.decode()
|
|
128
|
-
|
|
129
|
-
self.emit('change', self.data)
|
|
130
|
-
|
|
131
|
-
asyncio.create_task(data())
|
|
132
|
-
|
|
133
|
-
async def interval() -> None:
|
|
134
|
-
while True:
|
|
135
|
-
try:
|
|
136
|
-
await self.ws.ping()
|
|
137
|
-
|
|
138
|
-
await asyncio.sleep(30) # 30 SECONDS
|
|
139
|
-
except websockets.ConnectionClosed:
|
|
140
|
-
break
|
|
141
|
-
|
|
142
|
-
asyncio.create_task(interval())
|
|
143
|
-
|
|
144
|
-
await asyncio.Event().wait()
|
|
145
|
-
|
|
146
|
-
def delete(self) -> None:
|
|
147
|
-
pass
|
|
148
|
-
|
|
149
|
-
def emit(self, type:str, data:None|str = None) -> "HttpState":
|
|
150
|
-
for callback in self.et.get(type, []):
|
|
151
|
-
if(data is None):
|
|
152
|
-
callback()
|
|
153
|
-
else:
|
|
154
|
-
callback(data)
|
|
155
|
-
|
|
156
|
-
return self
|
|
157
|
-
|
|
158
|
-
def get(self) -> None|str:
|
|
159
|
-
data:None|str = get(self.uuid)
|
|
160
|
-
|
|
161
|
-
with self.lock:
|
|
162
|
-
if(data != self.data):
|
|
163
|
-
if self.el is not None:
|
|
164
|
-
self.el.call_soon_threadsafe(lambda : self.emit('change', self.data))
|
|
165
|
-
|
|
166
|
-
self.data = data
|
|
167
|
-
|
|
168
|
-
return self.data
|
|
169
|
-
|
|
170
|
-
def off(self, type:str, callback:Callable[[None|str], None]) -> "HttpState":
|
|
171
|
-
if type in self.et:
|
|
172
|
-
try:
|
|
173
|
-
self.et[type].remove(callback)
|
|
174
|
-
except ValueError:
|
|
175
|
-
pass
|
|
176
|
-
|
|
177
|
-
if not self.et[type]:
|
|
178
|
-
del self.et[type]
|
|
179
|
-
|
|
180
|
-
return self
|
|
181
|
-
|
|
182
|
-
def on(self, type:str, callback:Callable[[None|str], None]) -> "HttpState":
|
|
183
|
-
if type not in self.et:
|
|
184
|
-
self.et[type] = []
|
|
185
|
-
|
|
186
|
-
self.et[type].append(callback)
|
|
187
|
-
|
|
188
|
-
return self
|
|
189
|
-
|
|
190
|
-
def post(self, data:None|str = None) -> None|int:
|
|
191
|
-
return self.set(data)
|
|
192
|
-
|
|
193
|
-
def put(self, data:None|str = None) -> None|int:
|
|
194
|
-
return self.set(data)
|
|
195
|
-
|
|
196
|
-
def read(self) -> None|str:
|
|
197
|
-
return self.get()
|
|
198
|
-
|
|
199
|
-
def set(self, data:None|str = None) -> None|int:
|
|
200
|
-
return set(self.uuid, data)
|
|
201
|
-
|
|
202
|
-
def write(self, data:None|str = None) -> None|int:
|
|
203
|
-
return self.set(data)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|