httpstate 0.0.12__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: httpstate
3
- Version: 0.0.12
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://www.uuidgenerator.net/version4).
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 real-time updates
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
- - `read(uuid)`
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>.read()`
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 real-time updates.
93
- - `<HttpState>.on(type, callback)`
94
- Subscribe to real-time updates (type = `change`).
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://www.uuidgenerator.net/version4).
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 real-time updates
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
- - `read(uuid)`
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>.read()`
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 real-time updates.
79
- - `<HttpState>.on(type, callback)`
80
- Subscribe to real-time updates (type = `change`).
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
 
@@ -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.12"
19
+ version = "0.0.14"
20
20
 
21
21
  [project.url]
22
22
  Homepage = "https://httpstate.com"
@@ -8,6 +8,9 @@
8
8
 
9
9
  from .httpstate import(
10
10
  get,
11
+ message,
12
+ post,
13
+ put,
11
14
  read,
12
15
  set,
13
16
  write,
@@ -16,6 +19,9 @@ from .httpstate import(
16
19
 
17
20
  __all__ = [
18
21
  'get',
22
+ 'message',
23
+ 'post',
24
+ 'put',
19
25
  'read',
20
26
  'set',
21
27
  'write',
@@ -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,23 +79,54 @@ 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
84
+ self.el:None|asyncio.AbstractEventLoop = None
55
85
  self.et:Dict[str, List[Callable[[None|str], None]]] = {}
56
86
  self.uuid:str = uuid
57
87
  self.ws:None|websockets.WebSocketClientProtocol = None
58
88
 
89
+ threading.Thread(
90
+ daemon=True,
91
+ target=self._el
92
+ ).start()
93
+
59
94
  threading.Thread(
60
95
  daemon=True,
61
96
  target=lambda : asyncio.run(self._ws())
62
97
  ).start()
98
+
99
+ def _el(self) -> None:
100
+ self.el:asyncio.AbstractEventLoop = asyncio.new_event_loop()
101
+
102
+ asyncio.set_event_loop(self.el)
103
+
104
+ self.el.call_soon_threadsafe(lambda : self.get())
105
+
106
+ self.el.run_forever()
63
107
 
64
- async def _ws(self):
65
- 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}")
66
110
 
67
111
  await self.ws.send(f'{{"open":"{self.uuid}"}}')
112
+ self.emit('open')
113
+
114
+ async def data() -> None:
115
+ async for data in self.ws:
116
+ data:MessageType = message.unpack(data)
117
+
118
+ if(
119
+ data
120
+ and data.uuid == self.uuid
121
+ and data.type == 1
122
+ ):
123
+ self.data:None|str = data.value.decode()
124
+
125
+ self.emit('change', self.data)
126
+
127
+ asyncio.create_task(data())
68
128
 
69
- async def interval():
129
+ async def interval() -> None:
70
130
  while True:
71
131
  try:
72
132
  await self.ws.ping()
@@ -76,28 +136,32 @@ class HttpState:
76
136
  break
77
137
 
78
138
  asyncio.create_task(interval())
139
+
140
+ await asyncio.Event().wait()
141
+
142
+ def delete(self) -> None:
143
+ pass
79
144
 
80
- async for data in self.ws:
81
- self.data = data.decode()
82
-
83
- if(
84
- self.data
85
- and len(self.data) > 32
86
- and self.data[:32] == self.uuid
87
- and self.data[45] == '1'
88
- ):
89
- self.emit('change', self.data[46:])
90
-
91
- def emit(self, type:str, data:None|str) -> None:
145
+ def emit(self, type:str, data:None|str = None) -> "HttpState":
92
146
  for callback in self.et.get(type, []):
93
- callback(data)
147
+ if(data is None):
148
+ callback()
149
+ else:
150
+ callback(data)
94
151
 
95
152
  return self
96
153
 
97
154
  def get(self) -> None|str:
98
- return get(self.uuid)
155
+ data:None|str = get(self.uuid)
156
+
157
+ if(data != self.data):
158
+ self.el.call_soon_threadsafe(lambda : self.emit('change', self.data))
159
+
160
+ self.data = data
161
+
162
+ return self.data
99
163
 
100
- def off(self, type:str, callback:Callable[[None|str], None]):
164
+ def off(self, type:str, callback:Callable[[None|str], None]) -> "HttpState":
101
165
  if type in self.et:
102
166
  try:
103
167
  self.et[type].remove(callback)
@@ -109,19 +173,25 @@ class HttpState:
109
173
 
110
174
  return self
111
175
 
112
- def on(self, type:str, callback:Callable[[None|str], None]) -> None:
176
+ def on(self, type:str, callback:Callable[[None|str], None]) -> "HttpState":
113
177
  if type not in self.et:
114
178
  self.et[type] = []
115
179
 
116
180
  self.et[type].append(callback)
117
181
 
118
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)
119
189
 
120
190
  def read(self) -> None|str:
121
- return read(self.uuid)
191
+ return self.get()
122
192
 
123
193
  def set(self, data:str) -> None|int:
124
194
  return set(self.uuid, data)
125
195
 
126
196
  def write(self, data:str) -> None|int:
127
- return write(self.uuid, data)
197
+ return self.set(data)
File without changes
File without changes