Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions plugins/platforms/whatsapp/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
from gateway.platforms._shared import (
apply_yaml_bridge as _apply_yaml_bridge, extra_or_secret as _extra_or_secret, get_scoped_secret, send_error
)
from hermes_cli._subprocess_compat import windows_detach_popen_kwargs
from hermes_cli._subprocess_compat import (
windows_detach_flags_without_breakaway,
windows_detach_popen_kwargs,
)
from hermes_constants import (find_node_executable, get_hermes_dir, with_hermes_node_path)

_IS_WINDOWS = platform.system() == "Windows"
Expand Down Expand Up @@ -534,9 +537,22 @@ async def connect(self, *, is_reconnect: bool = False) -> bool:
node = find_node_executable("node")
if node is None:
raise RuntimeError("Node.js is no longer available; run `hermes pm install`")
self._bridge_process = subprocess.Popen(
[node, str(bridge_path), "--port", str(self._bridge_port), "--session", str(self._session_path),
"--mode", _wenv("WHATSAPP_MODE", "self-chat")], stdout=bridge_log_fh, stderr=bridge_log_fh, env=self._bridge_env(), **windows_detach_popen_kwargs())
bridge_argv = [node, str(bridge_path), "--port", str(self._bridge_port), "--session", str(self._session_path),
"--mode", _wenv("WHATSAPP_MODE", "self-chat")]
try:
self._bridge_process = subprocess.Popen(
bridge_argv, stdout=bridge_log_fh, stderr=bridge_log_fh, env=self._bridge_env(), **windows_detach_popen_kwargs())
except PermissionError:
# CREATE_BREAKAWAY_FROM_JOB is rejected with ERROR_ACCESS_DENIED unless the parent's job
# sets JOB_OBJECT_LIMIT_BREAKAWAY_OK. Electron (Hermes Desktop) and Task Scheduler both
# wrap children in jobs that forbid it, so the default detach flags can never spawn the
# bridge there and WhatsApp stays permanently "Disconnected". Retry inside the parent's
# job — the documented fallback in windows_detach_flags_without_breakaway. Tradeoff: the
# bridge then dies with the gateway instead of outliving it.
logger.warning("[%s] Bridge spawn denied by parent job (breakaway forbidden); retrying without CREATE_BREAKAWAY_FROM_JOB", self.name)
self._bridge_process = subprocess.Popen(
bridge_argv, stdout=bridge_log_fh, stderr=bridge_log_fh, env=self._bridge_env(),
creationflags=windows_detach_flags_without_breakaway())
_write_bridge_pidfile(self._session_path, self._bridge_process.pid)
if not await self._wait_for_bridge():
return False
Expand Down