@scrypted/server 0.123.21 → 0.123.23

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.
@@ -0,0 +1,227 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import base64
5
+ import hashlib
6
+ import os
7
+ from asyncio.events import AbstractEventLoop
8
+ from collections.abc import Mapping
9
+ from typing import Any
10
+
11
+ import rpc
12
+ import rpc_reader
13
+ from typing import TypedDict
14
+
15
+ class ClusterObject(TypedDict):
16
+ id: str
17
+ address: str
18
+ port: int
19
+ proxyId: str
20
+ sourceKey: str
21
+ sha256: str
22
+
23
+ def isClusterAddress(address: str):
24
+ return not address or address == os.environ.get("SCRYPTED_CLUSTER_ADDRESS", None)
25
+
26
+ def getClusterPeerKey(address: str, port: int):
27
+ return f"{address}:{port}"
28
+ class ClusterSetup():
29
+ def __init__(self, loop: AbstractEventLoop, peer: rpc.RpcPeer):
30
+ self.loop = loop
31
+ self.peer = peer
32
+ self.clusterId: str = None
33
+ self.clusterSecret: str = None
34
+ self.clusterAddress: str = None
35
+ self.clusterPort: int = None
36
+ self.SCRYPTED_CLUSTER_ADDRESS: str = None
37
+ self.clusterPeers: Mapping[str, asyncio.Future[rpc.RpcPeer]] = {}
38
+
39
+ async def resolveObject(self, id: str, sourceKey: str):
40
+ sourcePeer: rpc.RpcPeer = (
41
+ self.peer
42
+ if not sourceKey
43
+ else await rpc.maybe_await(self.clusterPeers.get(sourceKey, None))
44
+ )
45
+ if not sourcePeer:
46
+ return
47
+ return sourcePeer.localProxyMap.get(id, None)
48
+
49
+ async def connectClusterObject(self, o: ClusterObject):
50
+ sha256 = self.computeClusterObjectHash(o)
51
+ if sha256 != o["sha256"]:
52
+ raise Exception("secret incorrect")
53
+ return await self.resolveObject(o.get('proxyId', None), o.get('sourceKey', None))
54
+
55
+ def onProxySerialization(self, peer: rpc.RpcPeer, value: Any, sourceKey: str = None):
56
+ properties: dict = rpc.RpcPeer.prepareProxyProperties(value) or {}
57
+ clusterEntry = properties.get("__cluster", None)
58
+ proxyId: str
59
+ existing = peer.localProxied.get(value, None)
60
+ if existing:
61
+ proxyId = existing["id"]
62
+ else:
63
+ proxyId = (
64
+ clusterEntry and clusterEntry.get("proxyId", None)
65
+ ) or rpc.RpcPeer.generateId()
66
+
67
+ if clusterEntry:
68
+ if (
69
+ isClusterAddress(clusterEntry.get("address", None))
70
+ and self.clusterPort == clusterEntry["port"]
71
+ and sourceKey != clusterEntry.get("sourceKey", None)
72
+ ):
73
+ clusterEntry = None
74
+
75
+ if not clusterEntry:
76
+ clusterEntry: ClusterObject = {
77
+ "id": self.clusterId,
78
+ "proxyId": proxyId,
79
+ "address": self.SCRYPTED_CLUSTER_ADDRESS,
80
+ "port": self.clusterPort,
81
+ "sourceKey": sourceKey,
82
+ }
83
+ clusterEntry["sha256"] = self.computeClusterObjectHash(clusterEntry)
84
+ properties["__cluster"] = clusterEntry
85
+
86
+ return proxyId, properties
87
+
88
+ async def initializeCluster(self, options: dict):
89
+ if self.clusterPort:
90
+ return
91
+ self.clusterId = options["clusterId"]
92
+ self.clusterSecret = options["clusterSecret"]
93
+ self.SCRYPTED_CLUSTER_ADDRESS = os.environ.get("SCRYPTED_CLUSTER_ADDRESS", None)
94
+
95
+ async def handleClusterClient(
96
+ reader: asyncio.StreamReader, writer: asyncio.StreamWriter
97
+ ):
98
+ clusterPeerAddress, clusterPeerPort = writer.get_extra_info("peername")
99
+ clusterPeerKey = getClusterPeerKey(clusterPeerAddress, clusterPeerPort)
100
+ rpcTransport = rpc_reader.RpcStreamTransport(reader, writer)
101
+ peer: rpc.RpcPeer
102
+ peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(
103
+ self.loop, rpcTransport
104
+ )
105
+ # set all params from self.peer
106
+ for key, value in self.peer.params.items():
107
+ peer.params[key] = value
108
+ peer.onProxySerialization = lambda value: self.onProxySerialization(
109
+ peer, value, clusterPeerKey
110
+ )
111
+ future: asyncio.Future[rpc.RpcPeer] = asyncio.Future()
112
+ future.set_result(peer)
113
+ self.clusterPeers[clusterPeerKey] = future
114
+ peer.params["connectRPCObject"] = lambda o: self.connectClusterObject(o)
115
+ try:
116
+ await peerReadLoop()
117
+ except:
118
+ pass
119
+ finally:
120
+ self.clusterPeers.pop(clusterPeerKey)
121
+ peer.kill("cluster client killed")
122
+ writer.close()
123
+
124
+ listenAddress = "0.0.0.0" if self.SCRYPTED_CLUSTER_ADDRESS else "127.0.0.1"
125
+ clusterRpcServer = await asyncio.start_server(
126
+ handleClusterClient, listenAddress, 0
127
+ )
128
+ self.clusterPort = clusterRpcServer.sockets[0].getsockname()[1]
129
+ self.peer.onProxySerialization = lambda value: self.onProxySerialization(self.peer, value, None)
130
+ del self.peer.params["initializeCluster"]
131
+
132
+ def computeClusterObjectHash(self, o: ClusterObject) -> str:
133
+ m = hashlib.sha256()
134
+ m.update(
135
+ bytes(
136
+ f"{o['id']}{o.get('address') or ''}{o['port']}{o.get('sourceKey', None) or ''}{o['proxyId']}{self.clusterSecret}",
137
+ "utf8",
138
+ )
139
+ )
140
+ return base64.b64encode(m.digest()).decode("utf-8")
141
+
142
+ def ensureClusterPeer(self, address: str, port: int):
143
+ if isClusterAddress(address):
144
+ address = "127.0.0.1"
145
+ clusterPeerKey = getClusterPeerKey(address, port)
146
+ clusterPeerPromise = self.clusterPeers.get(clusterPeerKey)
147
+ if clusterPeerPromise:
148
+ return clusterPeerPromise
149
+
150
+ async def connectClusterPeer():
151
+ try:
152
+ reader, writer = await asyncio.open_connection(address, port)
153
+ sourceAddress, sourcePort = writer.get_extra_info("sockname")
154
+ if (
155
+ sourceAddress != self.SCRYPTED_CLUSTER_ADDRESS
156
+ and sourceAddress != "127.0.0.1"
157
+ ):
158
+ print("source address mismatch", sourceAddress)
159
+ rpcTransport = rpc_reader.RpcStreamTransport(reader, writer)
160
+ clusterPeer, peerReadLoop = await rpc_reader.prepare_peer_readloop(
161
+ self.loop, rpcTransport
162
+ )
163
+ # set all params from self.peer
164
+ for key, value in self.peer.params.items():
165
+ clusterPeer.params[key] = value
166
+ clusterPeer.onProxySerialization = (
167
+ lambda value: self.clusterSetup.onProxySerialization(
168
+ clusterPeer, value, clusterPeerKey
169
+ )
170
+ )
171
+ except:
172
+ self.clusterPeers.pop(clusterPeerKey)
173
+ raise
174
+
175
+ async def run_loop():
176
+ try:
177
+ await peerReadLoop()
178
+ except:
179
+ pass
180
+ finally:
181
+ self.clusterPeers.pop(clusterPeerKey)
182
+
183
+ asyncio.run_coroutine_threadsafe(run_loop(), self.loop)
184
+ return clusterPeer
185
+
186
+ clusterPeerPromise = self.loop.create_task(connectClusterPeer())
187
+
188
+ self.clusterPeers[clusterPeerKey] = clusterPeerPromise
189
+ return clusterPeerPromise
190
+
191
+ async def connectRPCObject(self, value):
192
+ __cluster = getattr(value, "__cluster")
193
+ if type(__cluster) is not dict:
194
+ return value
195
+
196
+ clusterObject: ClusterObject = __cluster
197
+
198
+ if clusterObject.get("id", None) != self.clusterId:
199
+ return value
200
+
201
+ address = clusterObject.get("address", None)
202
+ port = clusterObject["port"]
203
+ proxyId = clusterObject["proxyId"]
204
+ if port == self.clusterPort:
205
+ return await self.connectRPCObject(clusterObject)
206
+
207
+ clusterPeerPromise = self.ensureClusterPeer(address, port)
208
+
209
+ try:
210
+ clusterPeer = await clusterPeerPromise
211
+ weakref = clusterPeer.remoteWeakProxies.get(proxyId, None)
212
+ existing = weakref() if weakref else None
213
+ if existing:
214
+ return existing
215
+
216
+ peerConnectRPCObject = clusterPeer.tags.get("connectRPCObject")
217
+ if not peerConnectRPCObject:
218
+ peerConnectRPCObject = await clusterPeer.getParam(
219
+ "connectRPCObject"
220
+ )
221
+ clusterPeer.tags["connectRPCObject"] = peerConnectRPCObject
222
+ newValue = await peerConnectRPCObject(clusterObject)
223
+ if not newValue:
224
+ raise Exception("rpc object not found?")
225
+ return newValue
226
+ except Exception as e:
227
+ return value
@@ -1,9 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
- import base64
5
4
  import gc
6
- import hashlib
7
5
  import inspect
8
6
  import multiprocessing
9
7
  import multiprocessing.connection
@@ -19,39 +17,27 @@ from asyncio.futures import Future
19
17
  from asyncio.streams import StreamReader, StreamWriter
20
18
  from collections.abc import Mapping
21
19
  from io import StringIO
22
- from typing import Any, Optional, Set, Tuple, TypedDict, Callable, Coroutine
20
+ from typing import Any, Callable, Coroutine, Optional, Set, Tuple, TypedDict
23
21
 
24
22
  import plugin_volume as pv
25
23
  import rpc
26
24
  import rpc_reader
27
25
  import scrypted_python.scrypted_sdk.types
26
+ from cluster_setup import ClusterSetup
28
27
  from plugin_pip import install_with_pip, need_requirements, remove_pip_dirs
29
28
  from scrypted_python.scrypted_sdk import PluginFork, ScryptedStatic
30
- from scrypted_python.scrypted_sdk.types import (
31
- Device,
32
- DeviceManifest,
33
- EventDetails,
34
- ScryptedInterface,
35
- ScryptedInterfaceMethods,
36
- ScryptedInterfaceProperty,
37
- Storage,
38
- )
29
+ from scrypted_python.scrypted_sdk.types import (Device, DeviceManifest,
30
+ EventDetails,
31
+ ScryptedInterface,
32
+ ScryptedInterfaceMethods,
33
+ ScryptedInterfaceProperty,
34
+ Storage)
39
35
 
40
36
  SCRYPTED_REQUIREMENTS = """
41
37
  ptpython
42
38
  wheel
43
39
  """.strip()
44
40
 
45
-
46
- class ClusterObject(TypedDict):
47
- id: str
48
- address: str
49
- port: int
50
- proxyId: str
51
- sourceKey: str
52
- sha256: str
53
-
54
-
55
41
  class SystemDeviceState(TypedDict):
56
42
  lastEventTime: int
57
43
  stateTime: int
@@ -553,214 +539,6 @@ class DeviceManager(scrypted_python.scrypted_sdk.types.DeviceManager):
553
539
  def getDeviceStorage(self, nativeId: str = None) -> Storage:
554
540
  return self.nativeIds.get(nativeId, None)
555
541
 
556
-
557
- def isClusterAddress(address: str):
558
- return not address or address == os.environ.get("SCRYPTED_CLUSTER_ADDRESS", None)
559
-
560
- def getClusterPeerKey(address: str, port: int):
561
- return f"{address}:{port}"
562
-
563
- class ClusterSetup():
564
- def __init__(self, loop: AbstractEventLoop, peer: rpc.RpcPeer):
565
- self.loop = loop
566
- self.peer = peer
567
- self.clusterId: str = None
568
- self.clusterSecret: str = None
569
- self.clusterAddress: str = None
570
- self.clusterPort: int = None
571
- self.SCRYPTED_CLUSTER_ADDRESS: str = None
572
- self.clusterPeers: Mapping[str, asyncio.Future[rpc.RpcPeer]] = {}
573
-
574
- async def resolveObject(self, id: str, sourceKey: str):
575
- sourcePeer: rpc.RpcPeer = (
576
- self.peer
577
- if not sourceKey
578
- else await rpc.maybe_await(self.clusterPeers.get(sourceKey, None))
579
- )
580
- if not sourcePeer:
581
- return
582
- return sourcePeer.localProxyMap.get(id, None)
583
-
584
- async def connectClusterObject(self, o: ClusterObject):
585
- sha256 = self.computeClusterObjectHash(o)
586
- if sha256 != o["sha256"]:
587
- raise Exception("secret incorrect")
588
- return await self.resolveObject(o.get('proxyId', None), o.get('sourceKey', None))
589
-
590
- def onProxySerialization(self, peer: rpc.RpcPeer, value: Any, sourceKey: str = None):
591
- properties: dict = rpc.RpcPeer.prepareProxyProperties(value) or {}
592
- clusterEntry = properties.get("__cluster", None)
593
- proxyId: str
594
- existing = peer.localProxied.get(value, None)
595
- if existing:
596
- proxyId = existing["id"]
597
- else:
598
- proxyId = (
599
- clusterEntry and clusterEntry.get("proxyId", None)
600
- ) or rpc.RpcPeer.generateId()
601
-
602
- if clusterEntry:
603
- if (
604
- isClusterAddress(clusterEntry.get("address", None))
605
- and self.clusterPort == clusterEntry["port"]
606
- and sourceKey != clusterEntry.get("sourceKey", None)
607
- ):
608
- clusterEntry = None
609
-
610
- if not clusterEntry:
611
- clusterEntry: ClusterObject = {
612
- "id": self.clusterId,
613
- "proxyId": proxyId,
614
- "address": self.SCRYPTED_CLUSTER_ADDRESS,
615
- "port": self.clusterPort,
616
- "sourceKey": sourceKey,
617
- }
618
- clusterEntry["sha256"] = self.computeClusterObjectHash(clusterEntry)
619
- properties["__cluster"] = clusterEntry
620
-
621
- return proxyId, properties
622
-
623
- async def initializeCluster(self, options: dict):
624
- if self.clusterPort:
625
- return
626
- self.clusterId = options["clusterId"]
627
- self.clusterSecret = options["clusterSecret"]
628
- self.SCRYPTED_CLUSTER_ADDRESS = os.environ.get("SCRYPTED_CLUSTER_ADDRESS", None)
629
-
630
- async def handleClusterClient(
631
- reader: asyncio.StreamReader, writer: asyncio.StreamWriter
632
- ):
633
- clusterPeerAddress, clusterPeerPort = writer.get_extra_info("peername")
634
- clusterPeerKey = getClusterPeerKey(clusterPeerAddress, clusterPeerPort)
635
- rpcTransport = rpc_reader.RpcStreamTransport(reader, writer)
636
- peer: rpc.RpcPeer
637
- peer, peerReadLoop = await rpc_reader.prepare_peer_readloop(
638
- self.loop, rpcTransport
639
- )
640
- # set all params from self.peer
641
- for key, value in self.peer.params.items():
642
- peer.params[key] = value
643
- peer.onProxySerialization = lambda value: self.onProxySerialization(
644
- peer, value, clusterPeerKey
645
- )
646
- future: asyncio.Future[rpc.RpcPeer] = asyncio.Future()
647
- future.set_result(peer)
648
- self.clusterPeers[clusterPeerKey] = future
649
- peer.params["connectRPCObject"] = lambda o: self.connectClusterObject(o)
650
- try:
651
- await peerReadLoop()
652
- except:
653
- pass
654
- finally:
655
- self.clusterPeers.pop(clusterPeerKey)
656
- peer.kill("cluster client killed")
657
- writer.close()
658
-
659
- listenAddress = "0.0.0.0" if self.SCRYPTED_CLUSTER_ADDRESS else "127.0.0.1"
660
- clusterRpcServer = await asyncio.start_server(
661
- handleClusterClient, listenAddress, 0
662
- )
663
- self.clusterPort = clusterRpcServer.sockets[0].getsockname()[1]
664
- self.peer.onProxySerialization = lambda value: self.onProxySerialization(self.peer, value, None)
665
- del self.peer.params["initializeCluster"]
666
-
667
- def computeClusterObjectHash(self, o: ClusterObject) -> str:
668
- m = hashlib.sha256()
669
- m.update(
670
- bytes(
671
- f"{o['id']}{o.get('address') or ''}{o['port']}{o.get('sourceKey', None) or ''}{o['proxyId']}{self.clusterSecret}",
672
- "utf8",
673
- )
674
- )
675
- return base64.b64encode(m.digest()).decode("utf-8")
676
-
677
- def ensureClusterPeer(self, address: str, port: int):
678
- if isClusterAddress(address):
679
- address = "127.0.0.1"
680
- clusterPeerKey = getClusterPeerKey(address, port)
681
- clusterPeerPromise = self.clusterPeers.get(clusterPeerKey)
682
- if clusterPeerPromise:
683
- return clusterPeerPromise
684
-
685
- async def connectClusterPeer():
686
- try:
687
- reader, writer = await asyncio.open_connection(address, port)
688
- sourceAddress, sourcePort = writer.get_extra_info("sockname")
689
- if (
690
- sourceAddress != self.SCRYPTED_CLUSTER_ADDRESS
691
- and sourceAddress != "127.0.0.1"
692
- ):
693
- print("source address mismatch", sourceAddress)
694
- rpcTransport = rpc_reader.RpcStreamTransport(reader, writer)
695
- clusterPeer, peerReadLoop = await rpc_reader.prepare_peer_readloop(
696
- self.loop, rpcTransport
697
- )
698
- # set all params from self.peer
699
- for key, value in self.peer.params.items():
700
- clusterPeer.params[key] = value
701
- clusterPeer.onProxySerialization = (
702
- lambda value: self.clusterSetup.onProxySerialization(
703
- clusterPeer, value, clusterPeerKey
704
- )
705
- )
706
- except:
707
- self.clusterPeers.pop(clusterPeerKey)
708
- raise
709
-
710
- async def run_loop():
711
- try:
712
- await peerReadLoop()
713
- except:
714
- pass
715
- finally:
716
- self.clusterPeers.pop(clusterPeerKey)
717
-
718
- asyncio.run_coroutine_threadsafe(run_loop(), self.loop)
719
- return clusterPeer
720
-
721
- clusterPeerPromise = self.loop.create_task(connectClusterPeer())
722
-
723
- self.clusterPeers[clusterPeerKey] = clusterPeerPromise
724
- return clusterPeerPromise
725
-
726
- async def connectRPCObject(self, value):
727
- __cluster = getattr(value, "__cluster")
728
- if type(__cluster) is not dict:
729
- return value
730
-
731
- clusterObject: ClusterObject = __cluster
732
-
733
- if clusterObject.get("id", None) != self.clusterId:
734
- return value
735
-
736
- address = clusterObject.get("address", None)
737
- port = clusterObject["port"]
738
- proxyId = clusterObject["proxyId"]
739
- if port == self.clusterPort:
740
- return await self.connectRPCObject(clusterObject)
741
-
742
- clusterPeerPromise = self.ensureClusterPeer(address, port)
743
-
744
- try:
745
- clusterPeer = await clusterPeerPromise
746
- weakref = clusterPeer.remoteWeakProxies.get(proxyId, None)
747
- existing = weakref() if weakref else None
748
- if existing:
749
- return existing
750
-
751
- peerConnectRPCObject = clusterPeer.tags.get("connectRPCObject")
752
- if not peerConnectRPCObject:
753
- peerConnectRPCObject = await clusterPeer.getParam(
754
- "connectRPCObject"
755
- )
756
- clusterPeer.tags["connectRPCObject"] = peerConnectRPCObject
757
- newValue = await peerConnectRPCObject(clusterObject)
758
- if not newValue:
759
- raise Exception("rpc object not found?")
760
- return newValue
761
- except Exception as e:
762
- return value
763
-
764
542
  class PluginRemote:
765
543
  def __init__(
766
544
  self, clusterSetup: ClusterSetup, api, pluginId: str, hostInfo, loop: AbstractEventLoop
@@ -769,8 +547,6 @@ class PluginRemote:
769
547
  self.nativeIds: Mapping[str, DeviceStorage] = {}
770
548
  self.mediaManager: MediaManager
771
549
  self.consoles: Mapping[str, Future[Tuple[StreamReader, StreamWriter]]] = {}
772
- self.ptimeSum = 0
773
- self.allMemoryStats = {}
774
550
  self.peer = clusterSetup.peer
775
551
  self.clusterSetup = clusterSetup
776
552
  self.api = api
@@ -977,8 +753,6 @@ class PluginRemote:
977
753
  self.deviceManager = DeviceManager(self.nativeIds, self.systemManager)
978
754
  self.mediaManager = MediaManager(await self.api.getMediaManager())
979
755
 
980
- await self.start_stats_runner(zipAPI.updateStats)
981
-
982
756
  try:
983
757
  from scrypted_sdk import sdk_init2 # type: ignore
984
758
 
@@ -1023,7 +797,6 @@ class PluginRemote:
1023
797
  # traceback.print_exc()
1024
798
  print("fork read loop exited")
1025
799
  finally:
1026
- self.allMemoryStats.pop(forkPeer)
1027
800
  parent_conn.close()
1028
801
  rpcTransport.executor.shutdown()
1029
802
  pluginFork.worker.kill()
@@ -1041,10 +814,7 @@ class PluginRemote:
1041
814
  forkOptions["debug"] = debug
1042
815
 
1043
816
  class PluginZipAPI:
1044
- async def updateStats(stats):
1045
- self.ptimeSum += stats["cpu"]["user"]
1046
- self.allMemoryStats[forkPeer] = stats
1047
-
817
+
1048
818
  async def getZip(self):
1049
819
  return await zipAPI.getZip()
1050
820
 
@@ -1140,39 +910,6 @@ class PluginRemote:
1140
910
  return [self.replPort, os.getenv("SCRYPTED_CLUSTER_ADDRESS", None)]
1141
911
  raise Exception(f"unknown service {name}")
1142
912
 
1143
- async def start_stats_runner(self, update_stats):
1144
- def stats_runner():
1145
- ptime = round(time.process_time() * 1000000) + self.ptimeSum
1146
- try:
1147
- import psutil
1148
-
1149
- process = psutil.Process(os.getpid())
1150
- heapTotal = process.memory_info().rss
1151
- except:
1152
- try:
1153
- import resource
1154
-
1155
- heapTotal = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
1156
- except:
1157
- heapTotal = 0
1158
-
1159
- for _, stats in self.allMemoryStats.items():
1160
- heapTotal += stats["memoryUsage"]["heapTotal"]
1161
-
1162
- stats = {
1163
- "cpu": {
1164
- "user": ptime,
1165
- "system": 0,
1166
- },
1167
- "memoryUsage": {
1168
- "heapTotal": heapTotal,
1169
- },
1170
- }
1171
- asyncio.run_coroutine_threadsafe(update_stats(stats), self.loop)
1172
- self.loop.call_later(10, stats_runner)
1173
-
1174
- stats_runner()
1175
-
1176
913
 
1177
914
  async def plugin_async_main(
1178
915
  loop: AbstractEventLoop, rpcTransport: rpc_reader.RpcTransport
@@ -1,6 +1,5 @@
1
1
  import type { Device, DeviceManifest, EventDetails, EventListenerOptions, EventListenerRegister, MediaManager, MediaObject, ScryptedDevice, ScryptedInterfaceDescriptor, ScryptedInterfaceProperty, ScryptedNativeId, SystemDeviceState } from '@scrypted/types';
2
2
  import type { AccessControls } from './acl';
3
- import type { PluginStats } from './plugin-remote-stats';
4
3
 
5
4
  export interface PluginLogger {
6
5
  log(level: string, message: string): Promise<void>;
@@ -170,8 +169,8 @@ export interface PluginRemoteLoadZipOptions {
170
169
 
171
170
  export class PluginZipAPI {
172
171
  constructor(
173
- public getZip: () => Promise<Buffer>,
174
- public updateStats: (stats: PluginStats) => Promise<void>) {
172
+ public getZip: () => Promise<Buffer>
173
+ ) {
175
174
  }
176
175
  }
177
176
 
@@ -4,13 +4,13 @@ import * as io from 'engine.io';
4
4
  import fs from 'fs';
5
5
  import os from 'os';
6
6
  import WebSocket from 'ws';
7
+ import { setupCluster } from '../cluster/cluster-setup';
7
8
  import { Plugin } from '../db-types';
8
9
  import { IOServer, IOServerSocket } from '../io';
9
10
  import { Logger } from '../logger';
10
11
  import { RpcPeer, RPCResultError } from '../rpc';
11
12
  import { createRpcSerializer } from '../rpc-serializer';
12
13
  import { ScryptedRuntime } from '../runtime';
13
- import { setupCluster } from '../cluster/cluster-setup';
14
14
  import { sleep } from '../sleep';
15
15
  import { AccessControls } from './acl';
16
16
  import { MediaManagerHostImpl } from './media';
@@ -20,7 +20,6 @@ import { PluginDebug } from './plugin-debug';
20
20
  import { PluginHostAPI } from './plugin-host-api';
21
21
  import { LazyRemote } from './plugin-lazy-remote';
22
22
  import { setupPluginRemote } from './plugin-remote';
23
- import { PluginStats } from './plugin-remote-stats';
24
23
  import { WebSocketConnection } from './plugin-remote-websocket';
25
24
  import { ensurePluginVolume, getScryptedVolume } from './plugin-volume';
26
25
  import { createClusterForkWorker, needsClusterForkWorker } from './runtime/cluster-fork.worker';
@@ -60,8 +59,6 @@ export class PluginHost {
60
59
  api: PluginHostAPI;
61
60
  pluginName: string;
62
61
  packageJson: any;
63
- lastStats: number;
64
- stats: PluginStats;
65
62
  killed = false;
66
63
  consoleServer: Promise<ConsoleServer>;
67
64
  zipHash: string;
@@ -259,12 +256,7 @@ export class PluginHost {
259
256
  // original implementation sent the zipBuffer, sending the zipFile name now.
260
257
  // can switch back for non-local plugins.
261
258
  const modulePromise = remote.loadZip(this.packageJson,
262
- // the plugin is expected to send process stats every 10 seconds.
263
- // this can be used as a check for liveness.
264
- new PluginZipAPI(async () => fs.promises.readFile(this.zipFile), async (stats: PluginStats) => {
265
- this.lastStats = Date.now();
266
- this.stats = stats;
267
- }),
259
+ new PluginZipAPI(async () => fs.promises.readFile(this.zipFile)),
268
260
  loadZipOptions);
269
261
  // allow garbage collection of the zip buffer
270
262
  const module = await modulePromise;
@@ -414,7 +406,7 @@ export class PluginHost {
414
406
  const now = Date.now();
415
407
  // plugin may take a while to install, so wait 10 minutes.
416
408
  // after that, require 1 minute checkins.
417
- if (!this.lastStats || !lastPong) {
409
+ if (!lastPong) {
418
410
  if (now - startupTime > 10 * 60 * 1000) {
419
411
  const logger = await this.api.getLogger(undefined);
420
412
  logger.log('e', 'plugin failed to start in a timely manner. restarting.');
@@ -422,11 +414,6 @@ export class PluginHost {
422
414
  }
423
415
  return;
424
416
  }
425
- if (!pluginDebug && (this.lastStats + 60000 < now)) {
426
- const logger = await this.api.getLogger(undefined);
427
- logger.log('e', 'plugin is not reporting stats. restarting.');
428
- this.api.requestRestart();
429
- }
430
417
  if (!pluginDebug && (lastPong + 60000 < now)) {
431
418
  const logger = await this.api.getLogger(undefined);
432
419
  logger.log('e', 'plugin is not responding to ping. restarting.');