@scrypted/server 0.7.13 → 0.7.15

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.

Potentially problematic release.


This version of @scrypted/server might be problematic. Click here for more details.

package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrypted/server",
3
- "version": "0.7.13",
3
+ "version": "0.7.15",
4
4
  "description": "",
5
5
  "dependencies": {
6
6
  "@mapbox/node-pre-gyp": "^1.0.10",
@@ -67,8 +67,11 @@
67
67
  "prebuild": "rimraf dist",
68
68
  "build": "tsc --outDir dist",
69
69
  "postbuild": "node test/check-build-output.js",
70
- "prepublishOnly": "npm version patch && git add package.json && npm run build && git commit -m prepublish",
71
- "postpublish": "git tag v$npm_package_version && git push origin v$npm_package_version",
70
+ "prebeta": "npm version patch && git add package.json && npm run build && git commit -m prebeta",
71
+ "beta": "npm publish --tag beta",
72
+ "release": "npm publish",
73
+ "prerelease": "npm version patch && git add package.json && npm run build && git commit -m prerelease",
74
+ "postrelease": "git tag v$npm_package_version && git push origin v$npm_package_version",
72
75
  "docker": "scripts/github-workflow-publish-docker.sh"
73
76
  },
74
77
  "author": "",
@@ -35,25 +35,6 @@ class SystemDeviceState(TypedDict):
35
35
  stateTime: int
36
36
  value: any
37
37
 
38
-
39
- class StreamPipeReader:
40
- def __init__(self, conn: multiprocessing.connection.Connection) -> None:
41
- self.conn = conn
42
- self.executor = concurrent.futures.ThreadPoolExecutor()
43
-
44
- def readBlocking(self, n):
45
- b = bytes(0)
46
- while len(b) < n:
47
- self.conn.poll(None)
48
- add = os.read(self.conn.fileno(), n - len(b))
49
- if not len(add):
50
- raise Exception('unable to read requested bytes')
51
- b += add
52
- return b
53
-
54
- async def read(self, n):
55
- return await asyncio.get_event_loop().run_in_executor(self.executor, lambda: self.readBlocking(n))
56
-
57
38
  class SystemManager(scrypted_python.scrypted_sdk.types.SystemManager):
58
39
  def __init__(self, api: Any, systemState: Mapping[str, Mapping[str, SystemDeviceState]]) -> None:
59
40
  super().__init__()
@@ -288,8 +269,9 @@ class PluginRemote:
288
269
  clusterSecret = options['clusterSecret']
289
270
 
290
271
  async def handleClusterClient(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
272
+ rpcTransport = rpc_reader.RpcStreamTransport(reader, writer)
291
273
  peer: rpc.RpcPeer
292
- peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(self.loop, reader = reader, writer = writer)
274
+ peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(self.loop, rpcTransport)
293
275
  async def connectRPCObject(id: str, secret: str):
294
276
  m = hashlib.sha256()
295
277
  m.update(bytes('%s%s' % (clusterPort, clusterSecret), 'utf8'))
@@ -324,7 +306,8 @@ class PluginRemote:
324
306
  async def connectClusterPeer():
325
307
  reader, writer = await asyncio.open_connection(
326
308
  '127.0.0.1', port)
327
- peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(self.loop, reader = reader, writer = writer)
309
+ rpcTransport = rpc_reader.RpcStreamTransport(reader, writer)
310
+ peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(self.loop, rpcTransport)
328
311
  async def run_loop():
329
312
  try:
330
313
  await peerReadLoop()
@@ -485,8 +468,8 @@ class PluginRemote:
485
468
  schedule_exit_check()
486
469
 
487
470
  async def getFork():
488
- reader = StreamPipeReader(parent_conn)
489
- forkPeer, readLoop = await rpc_reader.prepare_peer_readloop(self.loop, reader = reader, writeFd = parent_conn.fileno())
471
+ rpcTransport = rpc_reader.RpcConnectionTransport(parent_conn)
472
+ forkPeer, readLoop = await rpc_reader.prepare_peer_readloop(self.loop, rpcTransport)
490
473
  forkPeer.peerName = 'thread'
491
474
 
492
475
  async def updateStats(stats):
@@ -502,7 +485,7 @@ class PluginRemote:
502
485
  finally:
503
486
  allMemoryStats.pop(forkPeer)
504
487
  parent_conn.close()
505
- reader.executor.shutdown()
488
+ rpcTransport.executor.shutdown()
506
489
  asyncio.run_coroutine_threadsafe(forkReadLoop(), loop=self.loop)
507
490
  getRemote = await forkPeer.getParam('getRemote')
508
491
  remote: PluginRemote = await getRemote(self.api, self.pluginId, self.hostInfo)
@@ -594,8 +577,8 @@ class PluginRemote:
594
577
 
595
578
  allMemoryStats = {}
596
579
 
597
- async def plugin_async_main(loop: AbstractEventLoop, readFd: int = None, writeFd: int = None, reader: asyncio.StreamReader = None, writer: asyncio.StreamWriter = None):
598
- peer, readLoop = await rpc_reader.prepare_peer_readloop(loop, readFd=readFd, writeFd=writeFd, reader=reader, writer=writer)
580
+ async def plugin_async_main(loop: AbstractEventLoop, rpcTransport: rpc_reader.RpcTransport):
581
+ peer, readLoop = await rpc_reader.prepare_peer_readloop(loop, rpcTransport)
599
582
  peer.params['print'] = print
600
583
  peer.params['getRemote'] = lambda api, pluginId, hostInfo: PluginRemote(peer, api, pluginId, hostInfo, loop)
601
584
 
@@ -642,11 +625,11 @@ async def plugin_async_main(loop: AbstractEventLoop, readFd: int = None, writeFd
642
625
  try:
643
626
  await readLoop()
644
627
  finally:
645
- if reader and hasattr(reader, 'executor'):
646
- r: StreamPipeReader = reader
628
+ if type(rpcTransport) == rpc_reader.RpcConnectionTransport:
629
+ r: rpc_reader.RpcConnectionTransport = rpcTransport
647
630
  r.executor.shutdown()
648
631
 
649
- def main(readFd: int = None, writeFd: int = None, reader: asyncio.StreamReader = None, writer: asyncio.StreamWriter = None):
632
+ def main(rpcTransport: rpc_reader.RpcTransport):
650
633
  loop = asyncio.new_event_loop()
651
634
 
652
635
  def gc_runner():
@@ -654,10 +637,10 @@ def main(readFd: int = None, writeFd: int = None, reader: asyncio.StreamReader =
654
637
  loop.call_later(10, gc_runner)
655
638
  gc_runner()
656
639
 
657
- loop.run_until_complete(plugin_async_main(loop, readFd=readFd, writeFd=writeFd, reader=reader, writer=writer))
640
+ loop.run_until_complete(plugin_async_main(loop, rpcTransport))
658
641
  loop.close()
659
642
 
660
- def plugin_main(readFd: int = None, writeFd: int = None, reader: asyncio.StreamReader = None, writer: asyncio.StreamWriter = None):
643
+ def plugin_main(rpcTransport: rpc_reader.RpcTransport):
661
644
  try:
662
645
  import gi
663
646
  gi.require_version('Gst', '1.0')
@@ -666,18 +649,16 @@ def plugin_main(readFd: int = None, writeFd: int = None, reader: asyncio.StreamR
666
649
 
667
650
  loop = GLib.MainLoop()
668
651
 
669
- worker = threading.Thread(target=main, args=(readFd, writeFd, reader, writer), name="asyncio-main")
652
+ worker = threading.Thread(target=main, args=(rpcTransport,), name="asyncio-main")
670
653
  worker.start()
671
654
 
672
655
  loop.run()
673
656
  except:
674
- main(readFd=readFd, writeFd=writeFd, reader=reader, writer=writer)
657
+ main(rpcTransport)
675
658
 
676
659
 
677
660
  def plugin_fork(conn: multiprocessing.connection.Connection):
678
- fd = os.dup(conn.fileno())
679
- reader = StreamPipeReader(conn)
680
- plugin_main(reader=reader, writeFd=fd)
661
+ plugin_main(rpc_reader.RpcConnectionTransport(conn))
681
662
 
682
663
  if __name__ == "__main__":
683
- plugin_main(3, 4)
664
+ plugin_main(rpc_reader.RpcFileTransport(3, 4))
@@ -4,14 +4,14 @@ import asyncio
4
4
  import base64
5
5
  import json
6
6
  import os
7
- import sys
8
7
  import threading
9
8
  from asyncio.events import AbstractEventLoop
10
- from os import sys
11
- from typing import List
12
-
9
+ from typing import List, Any
10
+ import multiprocessing.connection
13
11
  import aiofiles
14
12
  import rpc
13
+ import concurrent.futures
14
+ import json
15
15
 
16
16
 
17
17
  class BufferSerializer(rpc.RpcSerializer):
@@ -36,31 +36,131 @@ class SidebandBufferSerializer(rpc.RpcSerializer):
36
36
  buffer = buffers.pop()
37
37
  return buffer
38
38
 
39
- async def readLoop(loop, peer: rpc.RpcPeer, reader: asyncio.StreamReader):
40
- deserializationContext = {
41
- 'buffers': []
42
- }
43
39
 
44
- if isinstance(reader, asyncio.StreamReader):
45
- async def read(n):
46
- return await reader.readexactly(n)
47
- else:
48
- async def read(n):
49
- return await reader.read(n)
40
+ class RpcTransport:
41
+ async def prepare(self):
42
+ pass
50
43
 
44
+ async def read(self):
45
+ pass
51
46
 
52
- while True:
53
- lengthBytes = await read(4)
54
- typeBytes = await read(1)
47
+ def writeBuffer(self, buffer, reject):
48
+ pass
49
+
50
+ def writeJSON(self, json, reject):
51
+ pass
52
+
53
+
54
+ class RpcFileTransport(RpcTransport):
55
+ reader: asyncio.StreamReader
56
+
57
+ def __init__(self, readFd: int, writeFd: int) -> None:
58
+ super().__init__()
59
+ self.readFd = readFd
60
+ self.writeFd = writeFd
61
+ self.reader = None
62
+
63
+ async def prepare(self):
64
+ await super().prepare()
65
+ self.reader = await aiofiles.open(self.readFd, mode='rb')
66
+
67
+ async def read(self):
68
+ lengthBytes = await self.reader.read(4)
69
+ typeBytes = await self.reader.read(1)
55
70
  type = typeBytes[0]
56
71
  length = int.from_bytes(lengthBytes, 'big')
57
- data = await read(length - 1)
72
+ data = await self.reader.read(length - 1)
73
+ if type == 1:
74
+ return data
75
+ message = json.loads(data)
76
+ return message
77
+
78
+ def writeMessage(self, type: int, buffer, reject):
79
+ length = len(buffer) + 1
80
+ lb = length.to_bytes(4, 'big')
81
+ try:
82
+ for b in [lb, bytes([type]), buffer]:
83
+ os.write(self.writeFd, b)
84
+ except Exception as e:
85
+ if reject:
86
+ reject(e)
87
+
88
+ def writeJSON(self, j, reject):
89
+ return self.writeMessage(0, bytes(json.dumps(j), 'utf8'), reject)
90
+
91
+ def writeBuffer(self, buffer, reject):
92
+ return self.writeMessage(1, buffer, reject)
58
93
 
94
+
95
+ class RpcStreamTransport(RpcTransport):
96
+ def __init__(self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
97
+ super().__init__()
98
+ self.reader = reader
99
+ self.writer = writer
100
+
101
+ async def read(self):
102
+ lengthBytes = await self.reader.readexactly(4)
103
+ typeBytes = await self.reader.readexactly(1)
104
+ type = typeBytes[0]
105
+ length = int.from_bytes(lengthBytes, 'big')
106
+ data = await self.reader.readexactly(length - 1)
59
107
  if type == 1:
60
- deserializationContext['buffers'].append(data)
108
+ return data
109
+ message = json.loads(data)
110
+ return message
111
+
112
+ def writeMessage(self, type: int, buffer, reject):
113
+ length = len(buffer) + 1
114
+ lb = length.to_bytes(4, 'big')
115
+ try:
116
+ for b in [lb, bytes([type]), buffer]:
117
+ self.writer.write(b)
118
+ except Exception as e:
119
+ if reject:
120
+ reject(e)
121
+
122
+ def writeJSON(self, j, reject):
123
+ return self.writeMessage(0, bytes(json.dumps(j), 'utf8'), reject)
124
+
125
+ def writeBuffer(self, buffer, reject):
126
+ return self.writeMessage(1, buffer, reject)
127
+
128
+
129
+ class RpcConnectionTransport(RpcTransport):
130
+ def __init__(self, connection: multiprocessing.connection.Connection) -> None:
131
+ super().__init__()
132
+ self.connection = connection
133
+ self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
134
+
135
+ async def read(self):
136
+ return await asyncio.get_event_loop().run_in_executor(self.executor, lambda: self.connection.recv())
137
+
138
+ def writeMessage(self, json, reject):
139
+ try:
140
+ self.connection.send(json)
141
+ except Exception as e:
142
+ if reject:
143
+ reject(e)
144
+
145
+ def writeJSON(self, json, reject):
146
+ return self.writeMessage(json, reject)
147
+
148
+ def writeBuffer(self, buffer, reject):
149
+ return self.writeMessage(bytes(buffer), reject)
150
+
151
+
152
+ async def readLoop(loop, peer: rpc.RpcPeer, rpcTransport: RpcTransport):
153
+ deserializationContext = {
154
+ 'buffers': []
155
+ }
156
+
157
+ while True:
158
+ message = await rpcTransport.read()
159
+
160
+ if type(message) != dict:
161
+ deserializationContext['buffers'].append(message)
61
162
  continue
62
163
 
63
- message = json.loads(data)
64
164
  asyncio.run_coroutine_threadsafe(
65
165
  peer.handleMessage(message, deserializationContext), loop)
66
166
 
@@ -68,28 +168,11 @@ async def readLoop(loop, peer: rpc.RpcPeer, reader: asyncio.StreamReader):
68
168
  'buffers': []
69
169
  }
70
170
 
71
- async def prepare_peer_readloop(loop: AbstractEventLoop, readFd: int = None, writeFd: int = None, reader: asyncio.StreamReader = None, writer: asyncio.StreamWriter = None):
72
- reader = reader or await aiofiles.open(readFd, mode='rb')
73
171
 
74
- mutex = threading.Lock()
172
+ async def prepare_peer_readloop(loop: AbstractEventLoop, rpcTransport: RpcTransport):
173
+ await rpcTransport.prepare()
75
174
 
76
- if writer:
77
- def write(buffers, reject):
78
- try:
79
- for b in buffers:
80
- writer.write(b)
81
- except Exception as e:
82
- if reject:
83
- reject(e)
84
- return None
85
- else:
86
- def write(buffers, reject):
87
- try:
88
- for b in buffers:
89
- os.write(writeFd, b)
90
- except Exception as e:
91
- if reject:
92
- reject(e)
175
+ mutex = threading.Lock()
93
176
 
94
177
  def send(message, reject=None, serializationContext=None):
95
178
  with mutex:
@@ -97,17 +180,9 @@ async def prepare_peer_readloop(loop: AbstractEventLoop, readFd: int = None, wri
97
180
  buffers = serializationContext.get('buffers', None)
98
181
  if buffers:
99
182
  for buffer in buffers:
100
- length = len(buffer) + 1
101
- lb = length.to_bytes(4, 'big')
102
- type = 1
103
- write([lb, bytes([type]), buffer], reject)
104
-
105
- jsonString = json.dumps(message)
106
- b = bytes(jsonString, 'utf8')
107
- length = len(b) + 1
108
- lb = length.to_bytes(4, 'big')
109
- type = 0
110
- write([lb, bytes([type]), b], reject)
183
+ rpcTransport.writeBuffer(buffer, reject)
184
+
185
+ rpcTransport.writeJSON(message, reject)
111
186
 
112
187
  peer = rpc.RpcPeer(send)
113
188
  peer.nameDeserializerMap['Buffer'] = SidebandBufferSerializer()
@@ -117,7 +192,7 @@ async def prepare_peer_readloop(loop: AbstractEventLoop, readFd: int = None, wri
117
192
 
118
193
  async def peerReadLoop():
119
194
  try:
120
- await readLoop(loop, peer, reader)
195
+ await readLoop(loop, peer, rpcTransport)
121
196
  except:
122
197
  peer.kill()
123
198
  raise