wolsocketproxy 0.3.1__tar.gz → 0.4.0__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.
- {wolsocketproxy-0.3.1/src/wolsocketproxy.egg-info → wolsocketproxy-0.4.0}/PKG-INFO +23 -3
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/README.md +21 -2
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/pyproject.toml +2 -1
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/proxy.py +153 -7
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0/src/wolsocketproxy.egg-info}/PKG-INFO +23 -3
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy.egg-info/requires.txt +1 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/LICENSE +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/setup.cfg +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/__init__.py +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/__main__.py +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/common.py +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/keepalive.py +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/monitor.py +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy/utils.py +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy.egg-info/SOURCES.txt +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy.egg-info/dependency_links.txt +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy.egg-info/entry_points.txt +0 -0
- {wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wolsocketproxy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A socket proxy with wake-on-lan feature.
|
|
5
5
|
Author-email: Song Fuchang <song.fc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -14,6 +14,7 @@ Requires-Python: >=3.12
|
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
16
|
Requires-Dist: aiohttp==3.13.5
|
|
17
|
+
Requires-Dist: croniter==6.0.0
|
|
17
18
|
Requires-Dist: dataclass-wizard==0.39.1
|
|
18
19
|
Requires-Dist: icmplib==3.0.4
|
|
19
20
|
Requires-Dist: redfish==3.3.5
|
|
@@ -102,8 +103,14 @@ The `wolsocketproxy.conf` has the following structure:
|
|
|
102
103
|
"ipmi_force_reset_if_power_up_failed": true, // Use IPMI power reset if this machine is not online after timeout, optional, default is false
|
|
103
104
|
"ipmi_max_reset_try_count": 3, // Max IPMI power reset retry count before giving-up, optional, default is 3
|
|
104
105
|
"keep_alive_mode": true, // Indicates whether this machine has a keep-alive daemon, optional, default is false
|
|
105
|
-
|
|
106
|
-
"keep_alive_mode_base_url": "http://192.168.1.124:8080" // Keep-alive daemon provided URL, optional
|
|
106
|
+
// If you enable this, wolsocketproxy will send a request when there is any traffic
|
|
107
|
+
"keep_alive_mode_base_url": "http://192.168.1.124:8080", // Keep-alive daemon provided URL, optional
|
|
108
|
+
"scheduled_power_up_times": [ // Scheduled power-up times, optional
|
|
109
|
+
{
|
|
110
|
+
"cron": "0 7 * * 1-5", // Cron expression for auto power-up
|
|
111
|
+
"keep_alive_time": 7200 // Send keep-alive requests for N seconds after power-up
|
|
112
|
+
}
|
|
113
|
+
]
|
|
107
114
|
},
|
|
108
115
|
// ... more machines ...
|
|
109
116
|
},
|
|
@@ -167,3 +174,16 @@ or the special process will be killed.
|
|
|
167
174
|
You can combine this mode with `circadian`'s `process_block` config to keep it from auto-suspending.
|
|
168
175
|
|
|
169
176
|
If you enable `keep_alive_mode` in proxy mode's config, the proxy will send requests to `/watchdog/feed` of this machine whenever there is any traffic towards this machine through it.
|
|
177
|
+
|
|
178
|
+
### Scheduled power-up
|
|
179
|
+
|
|
180
|
+
You can configure `scheduled_power_up_times` in each machine entry to automatically power up the machine at specified times using
|
|
181
|
+
a cron expression. After the machine comes online, the proxy sends keep-alive requests to the machine's keep-alive daemon
|
|
182
|
+
(for the duration specified by `keep_alive_time`) to prevent it from auto-suspending during the expected usage window.
|
|
183
|
+
|
|
184
|
+
Each entry in `scheduled_power_up_times` contains:
|
|
185
|
+
- `cron`: A standard 5-field cron expression (e.g. `"0 7 * * 1-5"` for weekdays at 7:00)
|
|
186
|
+
- `keep_alive_time`: Duration in seconds to send keep-alive requests after power-up (e.g. `7200` for 2 hours)
|
|
187
|
+
|
|
188
|
+
If multiple entries overlap in time, the keep-alive period is automatically extended to cover the longest window, and no
|
|
189
|
+
duplicate keep-alive requests are sent.
|
|
@@ -71,8 +71,14 @@ The `wolsocketproxy.conf` has the following structure:
|
|
|
71
71
|
"ipmi_force_reset_if_power_up_failed": true, // Use IPMI power reset if this machine is not online after timeout, optional, default is false
|
|
72
72
|
"ipmi_max_reset_try_count": 3, // Max IPMI power reset retry count before giving-up, optional, default is 3
|
|
73
73
|
"keep_alive_mode": true, // Indicates whether this machine has a keep-alive daemon, optional, default is false
|
|
74
|
-
|
|
75
|
-
"keep_alive_mode_base_url": "http://192.168.1.124:8080" // Keep-alive daemon provided URL, optional
|
|
74
|
+
// If you enable this, wolsocketproxy will send a request when there is any traffic
|
|
75
|
+
"keep_alive_mode_base_url": "http://192.168.1.124:8080", // Keep-alive daemon provided URL, optional
|
|
76
|
+
"scheduled_power_up_times": [ // Scheduled power-up times, optional
|
|
77
|
+
{
|
|
78
|
+
"cron": "0 7 * * 1-5", // Cron expression for auto power-up
|
|
79
|
+
"keep_alive_time": 7200 // Send keep-alive requests for N seconds after power-up
|
|
80
|
+
}
|
|
81
|
+
]
|
|
76
82
|
},
|
|
77
83
|
// ... more machines ...
|
|
78
84
|
},
|
|
@@ -136,3 +142,16 @@ or the special process will be killed.
|
|
|
136
142
|
You can combine this mode with `circadian`'s `process_block` config to keep it from auto-suspending.
|
|
137
143
|
|
|
138
144
|
If you enable `keep_alive_mode` in proxy mode's config, the proxy will send requests to `/watchdog/feed` of this machine whenever there is any traffic towards this machine through it.
|
|
145
|
+
|
|
146
|
+
### Scheduled power-up
|
|
147
|
+
|
|
148
|
+
You can configure `scheduled_power_up_times` in each machine entry to automatically power up the machine at specified times using
|
|
149
|
+
a cron expression. After the machine comes online, the proxy sends keep-alive requests to the machine's keep-alive daemon
|
|
150
|
+
(for the duration specified by `keep_alive_time`) to prevent it from auto-suspending during the expected usage window.
|
|
151
|
+
|
|
152
|
+
Each entry in `scheduled_power_up_times` contains:
|
|
153
|
+
- `cron`: A standard 5-field cron expression (e.g. `"0 7 * * 1-5"` for weekdays at 7:00)
|
|
154
|
+
- `keep_alive_time`: Duration in seconds to send keep-alive requests after power-up (e.g. `7200` for 2 hours)
|
|
155
|
+
|
|
156
|
+
If multiple entries overlap in time, the keep-alive period is automatically extended to cover the longest window, and no
|
|
157
|
+
duplicate keep-alive requests are sent.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wolsocketproxy"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "A socket proxy with wake-on-lan feature."
|
|
9
9
|
authors = [
|
|
10
10
|
{name = "Song Fuchang", email = "song.fc@gmail.com"}
|
|
@@ -20,6 +20,7 @@ classifiers = [
|
|
|
20
20
|
requires-python = ">=3.12"
|
|
21
21
|
dependencies = [
|
|
22
22
|
"aiohttp==3.13.5",
|
|
23
|
+
"croniter==6.0.0",
|
|
23
24
|
"dataclass-wizard==0.39.1",
|
|
24
25
|
"icmplib==3.0.4",
|
|
25
26
|
"redfish==3.3.5",
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import contextlib
|
|
3
3
|
import logging
|
|
4
|
+
import time
|
|
5
|
+
from collections.abc import Callable, Coroutine
|
|
4
6
|
from dataclasses import dataclass
|
|
7
|
+
from datetime import datetime
|
|
5
8
|
from logging import Logger
|
|
6
|
-
from threading import Thread
|
|
9
|
+
from threading import Event, Thread
|
|
7
10
|
from typing import Any, Literal, override
|
|
8
11
|
|
|
9
12
|
import aiohttp
|
|
10
13
|
import wakeonlan
|
|
14
|
+
from croniter import croniter
|
|
11
15
|
from redfish.rest.v1 import HttpClient, redfish_client
|
|
12
16
|
|
|
13
17
|
from wolsocketproxy.common import URL_WATCHDOG_FEED
|
|
@@ -15,6 +19,12 @@ from wolsocketproxy.monitor import Monitor, MonitorConfig
|
|
|
15
19
|
from wolsocketproxy.utils import perform_ipmi_action
|
|
16
20
|
|
|
17
21
|
|
|
22
|
+
@dataclass
|
|
23
|
+
class ScheduledPowerUpTime:
|
|
24
|
+
cron: str
|
|
25
|
+
keep_alive_time: int = 0
|
|
26
|
+
|
|
27
|
+
|
|
18
28
|
@dataclass
|
|
19
29
|
class MachineConfig:
|
|
20
30
|
wake_up_method: Literal["ipmi", "wol"] = "wol"
|
|
@@ -36,6 +46,8 @@ class MachineConfig:
|
|
|
36
46
|
keep_alive_mode_base_url: str | None = None
|
|
37
47
|
keep_alive_min_interval: int = 1
|
|
38
48
|
|
|
49
|
+
scheduled_power_up_times: list[ScheduledPowerUpTime] | None = None
|
|
50
|
+
|
|
39
51
|
|
|
40
52
|
@dataclass
|
|
41
53
|
class ProxyRoute:
|
|
@@ -64,10 +76,13 @@ class ProxyConfig:
|
|
|
64
76
|
|
|
65
77
|
|
|
66
78
|
class TargetKeepAliveSender:
|
|
79
|
+
_log: logging.Logger = logging.getLogger(__name__)
|
|
80
|
+
|
|
67
81
|
_target_url: str
|
|
68
82
|
_keep_alive_min_interval: int
|
|
69
83
|
_loop: asyncio.AbstractEventLoop
|
|
70
84
|
_queue: asyncio.Queue
|
|
85
|
+
_stop_event: Event
|
|
71
86
|
|
|
72
87
|
def __init__(self, target_base_url: str, keep_alive_min_interval: int) -> None:
|
|
73
88
|
self._target_url = target_base_url.removesuffix("/") + URL_WATCHDOG_FEED
|
|
@@ -75,21 +90,32 @@ class TargetKeepAliveSender:
|
|
|
75
90
|
|
|
76
91
|
self._loop = asyncio.new_event_loop()
|
|
77
92
|
self._queue = asyncio.Queue(1)
|
|
93
|
+
self._stop_event = Event()
|
|
78
94
|
|
|
79
|
-
def
|
|
95
|
+
def _run_loop() -> None:
|
|
80
96
|
asyncio.set_event_loop(self._loop)
|
|
81
97
|
self._loop.run_until_complete(self._send_worker())
|
|
82
98
|
|
|
83
|
-
Thread(target=
|
|
99
|
+
Thread(target=_run_loop, daemon=True).start()
|
|
84
100
|
|
|
85
101
|
async def _send_worker(self) -> None:
|
|
86
|
-
while
|
|
102
|
+
while not self._stop_event.is_set():
|
|
87
103
|
await self._queue.get()
|
|
104
|
+
if self._stop_event.is_set():
|
|
105
|
+
break
|
|
106
|
+
await self._send()
|
|
107
|
+
await asyncio.sleep(self._keep_alive_min_interval)
|
|
88
108
|
|
|
89
|
-
|
|
109
|
+
async def _send(self) -> None:
|
|
110
|
+
try:
|
|
111
|
+
async with aiohttp.request(
|
|
112
|
+
"GET",
|
|
113
|
+
self._target_url,
|
|
114
|
+
timeout=aiohttp.ClientTimeout(total=5),
|
|
115
|
+
) as resp:
|
|
90
116
|
await resp.json()
|
|
91
|
-
|
|
92
|
-
|
|
117
|
+
except (aiohttp.ClientError, aiohttp.ClientResponseError):
|
|
118
|
+
self._log.warning("Failed to send target keep alive request to %s", self._target_url, exc_info=True)
|
|
93
119
|
|
|
94
120
|
def schedule_send(self) -> None:
|
|
95
121
|
def _no_exception_put() -> None:
|
|
@@ -98,6 +124,118 @@ class TargetKeepAliveSender:
|
|
|
98
124
|
|
|
99
125
|
self._loop.call_soon_threadsafe(_no_exception_put)
|
|
100
126
|
|
|
127
|
+
def stop(self) -> None:
|
|
128
|
+
self._stop_event.set()
|
|
129
|
+
with contextlib.suppress(asyncio.QueueFull):
|
|
130
|
+
self._loop.call_soon_threadsafe(lambda: self._queue.put_nowait(None))
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class ScheduledPowerUpManager:
|
|
134
|
+
_log: Logger = logging.getLogger(__name__)
|
|
135
|
+
|
|
136
|
+
_machines: dict[str, MachineConfig]
|
|
137
|
+
_wake_up_callback: Callable[[str], Coroutine[Any, Any, None]]
|
|
138
|
+
_loop: asyncio.AbstractEventLoop
|
|
139
|
+
_keep_alive_end_times: dict[str, float]
|
|
140
|
+
|
|
141
|
+
def __init__(
|
|
142
|
+
self,
|
|
143
|
+
machines: dict[str, MachineConfig],
|
|
144
|
+
wake_up_callback: Callable[[str], Coroutine[Any, Any, None]],
|
|
145
|
+
) -> None:
|
|
146
|
+
self._machines = machines
|
|
147
|
+
self._wake_up_callback = wake_up_callback
|
|
148
|
+
self._keep_alive_end_times = {}
|
|
149
|
+
|
|
150
|
+
def start(self) -> None:
|
|
151
|
+
self._loop = asyncio.new_event_loop()
|
|
152
|
+
|
|
153
|
+
def _run_loop() -> None:
|
|
154
|
+
asyncio.set_event_loop(self._loop)
|
|
155
|
+
self._loop.run_forever()
|
|
156
|
+
|
|
157
|
+
Thread(target=_run_loop, daemon=True).start()
|
|
158
|
+
|
|
159
|
+
for machine_name, machine in self._machines.items():
|
|
160
|
+
schedules = machine.scheduled_power_up_times
|
|
161
|
+
if not schedules:
|
|
162
|
+
continue
|
|
163
|
+
|
|
164
|
+
if machine.keep_alive_mode_base_url is None:
|
|
165
|
+
self._log.warning(
|
|
166
|
+
"Machine %s has scheduled_power_up_times but no keep_alive_mode_base_url configured, "
|
|
167
|
+
"keep-alive after power-up will be skipped",
|
|
168
|
+
machine_name,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
for schedule in schedules:
|
|
172
|
+
asyncio.run_coroutine_threadsafe(
|
|
173
|
+
self._process_schedule(machine_name, machine, schedule),
|
|
174
|
+
self._loop,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
async def _process_schedule(
|
|
178
|
+
self,
|
|
179
|
+
machine_name: str,
|
|
180
|
+
machine: MachineConfig,
|
|
181
|
+
schedule: ScheduledPowerUpTime,
|
|
182
|
+
) -> None:
|
|
183
|
+
while True:
|
|
184
|
+
now = datetime.now()
|
|
185
|
+
cron = croniter(schedule.cron, now)
|
|
186
|
+
next_time = cron.get_next(datetime)
|
|
187
|
+
|
|
188
|
+
delay = (next_time - datetime.now()).total_seconds()
|
|
189
|
+
if delay > 0:
|
|
190
|
+
await asyncio.sleep(delay)
|
|
191
|
+
|
|
192
|
+
self._log.info(
|
|
193
|
+
"Scheduled power-up triggered for %s (cron: %s)",
|
|
194
|
+
machine_name,
|
|
195
|
+
schedule.cron,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
await self._wake_up_callback(machine_name)
|
|
200
|
+
except ConnectionAbortedError:
|
|
201
|
+
self._log.error(
|
|
202
|
+
"Scheduled power-up failed for %s, will retry at next schedule time",
|
|
203
|
+
machine_name,
|
|
204
|
+
)
|
|
205
|
+
continue
|
|
206
|
+
|
|
207
|
+
if schedule.keep_alive_time > 0 and machine.keep_alive_mode_base_url is not None:
|
|
208
|
+
await self._run_keep_alive(machine_name, machine, schedule.keep_alive_time)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
async def _run_keep_alive(
|
|
212
|
+
self,
|
|
213
|
+
machine_name: str,
|
|
214
|
+
machine: MachineConfig,
|
|
215
|
+
keep_alive_time: int,
|
|
216
|
+
) -> None:
|
|
217
|
+
assert machine.keep_alive_mode_base_url is not None
|
|
218
|
+
new_end = time.monotonic() + keep_alive_time
|
|
219
|
+
current_end = self._keep_alive_end_times.get(machine_name, 0.0)
|
|
220
|
+
|
|
221
|
+
if new_end > current_end:
|
|
222
|
+
self._keep_alive_end_times[machine_name] = new_end
|
|
223
|
+
|
|
224
|
+
if current_end > time.monotonic():
|
|
225
|
+
return
|
|
226
|
+
|
|
227
|
+
sender = TargetKeepAliveSender(
|
|
228
|
+
machine.keep_alive_mode_base_url,
|
|
229
|
+
machine.keep_alive_min_interval,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
try:
|
|
233
|
+
while time.monotonic() < self._keep_alive_end_times.get(machine_name, 0.0):
|
|
234
|
+
sender.schedule_send()
|
|
235
|
+
await asyncio.sleep(machine.keep_alive_min_interval)
|
|
236
|
+
finally:
|
|
237
|
+
sender.stop()
|
|
238
|
+
|
|
101
239
|
|
|
102
240
|
class ProxyUdpProtocol(asyncio.DatagramProtocol):
|
|
103
241
|
_proxy: "Proxy"
|
|
@@ -154,6 +292,7 @@ class Proxy:
|
|
|
154
292
|
_machines: dict[str, MachineConfig]
|
|
155
293
|
_routes: list[ProxyRoute]
|
|
156
294
|
_ipmi_configs: dict[str, IPMIConfig]
|
|
295
|
+
_scheduled_power_up_manager: ScheduledPowerUpManager
|
|
157
296
|
|
|
158
297
|
def __init__(self, config: ProxyConfig) -> None:
|
|
159
298
|
self._config = config
|
|
@@ -193,6 +332,11 @@ class Proxy:
|
|
|
193
332
|
}
|
|
194
333
|
)
|
|
195
334
|
|
|
335
|
+
self._scheduled_power_up_manager = ScheduledPowerUpManager(
|
|
336
|
+
machines=self._machines,
|
|
337
|
+
wake_up_callback=self._wake_up_target,
|
|
338
|
+
)
|
|
339
|
+
|
|
196
340
|
def start(self) -> None:
|
|
197
341
|
self._monitor.start()
|
|
198
342
|
|
|
@@ -201,6 +345,8 @@ class Proxy:
|
|
|
201
345
|
|
|
202
346
|
loop = asyncio.get_event_loop()
|
|
203
347
|
|
|
348
|
+
self._scheduled_power_up_manager.start()
|
|
349
|
+
|
|
204
350
|
self._log.info("Proxy server started.")
|
|
205
351
|
|
|
206
352
|
with contextlib.suppress(KeyboardInterrupt):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wolsocketproxy
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: A socket proxy with wake-on-lan feature.
|
|
5
5
|
Author-email: Song Fuchang <song.fc@gmail.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -14,6 +14,7 @@ Requires-Python: >=3.12
|
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
16
|
Requires-Dist: aiohttp==3.13.5
|
|
17
|
+
Requires-Dist: croniter==6.0.0
|
|
17
18
|
Requires-Dist: dataclass-wizard==0.39.1
|
|
18
19
|
Requires-Dist: icmplib==3.0.4
|
|
19
20
|
Requires-Dist: redfish==3.3.5
|
|
@@ -102,8 +103,14 @@ The `wolsocketproxy.conf` has the following structure:
|
|
|
102
103
|
"ipmi_force_reset_if_power_up_failed": true, // Use IPMI power reset if this machine is not online after timeout, optional, default is false
|
|
103
104
|
"ipmi_max_reset_try_count": 3, // Max IPMI power reset retry count before giving-up, optional, default is 3
|
|
104
105
|
"keep_alive_mode": true, // Indicates whether this machine has a keep-alive daemon, optional, default is false
|
|
105
|
-
|
|
106
|
-
"keep_alive_mode_base_url": "http://192.168.1.124:8080" // Keep-alive daemon provided URL, optional
|
|
106
|
+
// If you enable this, wolsocketproxy will send a request when there is any traffic
|
|
107
|
+
"keep_alive_mode_base_url": "http://192.168.1.124:8080", // Keep-alive daemon provided URL, optional
|
|
108
|
+
"scheduled_power_up_times": [ // Scheduled power-up times, optional
|
|
109
|
+
{
|
|
110
|
+
"cron": "0 7 * * 1-5", // Cron expression for auto power-up
|
|
111
|
+
"keep_alive_time": 7200 // Send keep-alive requests for N seconds after power-up
|
|
112
|
+
}
|
|
113
|
+
]
|
|
107
114
|
},
|
|
108
115
|
// ... more machines ...
|
|
109
116
|
},
|
|
@@ -167,3 +174,16 @@ or the special process will be killed.
|
|
|
167
174
|
You can combine this mode with `circadian`'s `process_block` config to keep it from auto-suspending.
|
|
168
175
|
|
|
169
176
|
If you enable `keep_alive_mode` in proxy mode's config, the proxy will send requests to `/watchdog/feed` of this machine whenever there is any traffic towards this machine through it.
|
|
177
|
+
|
|
178
|
+
### Scheduled power-up
|
|
179
|
+
|
|
180
|
+
You can configure `scheduled_power_up_times` in each machine entry to automatically power up the machine at specified times using
|
|
181
|
+
a cron expression. After the machine comes online, the proxy sends keep-alive requests to the machine's keep-alive daemon
|
|
182
|
+
(for the duration specified by `keep_alive_time`) to prevent it from auto-suspending during the expected usage window.
|
|
183
|
+
|
|
184
|
+
Each entry in `scheduled_power_up_times` contains:
|
|
185
|
+
- `cron`: A standard 5-field cron expression (e.g. `"0 7 * * 1-5"` for weekdays at 7:00)
|
|
186
|
+
- `keep_alive_time`: Duration in seconds to send keep-alive requests after power-up (e.g. `7200` for 2 hours)
|
|
187
|
+
|
|
188
|
+
If multiple entries overlap in time, the keep-alive period is automatically extended to cover the longest window, and no
|
|
189
|
+
duplicate keep-alive requests are sent.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wolsocketproxy-0.3.1 → wolsocketproxy-0.4.0}/src/wolsocketproxy.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|