| Server IP : 62.60.133.156 / Your IP : 216.73.217.51 Web Server : LiteSpeed System : Linux linux24.centraldnserver.com 4.18.0-553.141.2.lve.el8.x86_64 #1 SMP Wed Jul 8 16:10:02 UTC 2026 x86_64 User : mimradmin ( 1166) PHP Version : 7.4.33 Disable Function : show_source, system, shell_exec, passthru, exec, popen, proc_open MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /proc/thread-self/root/opt/imunify360/venv/lib64/python3.11/site-packages/im360/ |
Upload File : |
import contextlib
import logging
from typing import Generator
from defence360agent.api.server import send_message, NATSSendMessageException
from defence360agent.contracts.plugins import MessageSink
from defence360agent.plugins.client import SendToServerClient
from defence360agent.utils import Scope
logger = logging.getLogger(__name__)
class SendToServerNATS(SendToServerClient, MessageSink):
SCOPE = Scope.IM360
SHUTDOWN_PRIORITY = 900 # Shutdown late, after Accumulate has flushed
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._nats_api = None
@contextlib.contextmanager
def _get_api(
self,
) -> Generator[send_message.NATSGatewayAPI, None, None]:
# Reuse the same API instance to keep the NATS connection alive
if self._nats_api is None:
self._nats_api = send_message.NATSGatewayAPI()
yield self._nats_api
async def _send_pending_messages(self) -> None:
if self._pending.empty():
return None
if self._shutting_down.is_set():
logger.warning("Shutdown signal received, skipping NATS send")
return None
messages = self._pending.pop_all()
logger.info("Sending %s messages via NATS", len(messages))
with self._get_api() as api:
try:
await api.send_messages(messages)
if self._pending.qsize() > 0:
logger.info(
"Still need to send %s messages",
self._pending.qsize(),
)
except NATSSendMessageException as e:
unsent = messages[e.published :]
if unsent:
self._pending.put_many(unsent)
logger.warning(
"Failed to send messages via NATS: "
"%d published, %d re-queued: %s",
e.published,
len(unsent),
e,
)
except BaseException:
# CancelledError (BaseException in 3.9+) or other fatal
# errors — re-queue all messages to avoid data loss.
self._pending.put_many(messages)
raise
async def shutdown(self) -> None:
await super().shutdown()
if self._nats_api is not None:
await self._nats_api.close()
logger.info("NATS connection closed")