Class AgentOutboundFeeds

java.lang.Object
com.ultikits.ultitools.manager.AgentOutboundFeeds

@Internal public final class AgentOutboundFeeds extends Object
The framework's outbound producers on the v2 connection (plan 22-22, D-14, D-20, D-23, S-56); internal, not for module use. Public only because the session wiring lives in utils while the encoders it feeds are package-private here, like RemoteRequestHandlers.

What it feeds. Telemetry: AgentTelemetry sends status and the three snapshots after each welcome, on its cadence, and answers snapshot.request; this class samples TPS and CPU once a second and the server state every five seconds on the main thread through the package-private hooks of ServerMonitorManager, without its v1 sender. Logs: a SystemLogHandler attached to the root logger hands every record to a v2 UltiPanelLogTransmitter, whose single builder redacts it (22-04), and the redacted line goes to AgentLogBatcher; a full batch is flushed at once on the agent thread, the rest every second. Errors: the reports ErrorReportCollector grouped leave as error.report every second (at most 10). Player events: the join, leave and command payloads come only from AgentEventEncoders (playerRefPayload(java.lang.String, java.lang.String), playerCommandPayload(java.lang.String)).

Only while connected. A line logged while no connection is established is dropped, never buffered for the next one (D-14), and a close clears what the batcher still held. The switches are read for every line and every frame, so turning one off stops its frames without a new handshake.

Threads. established(com.ultikits.ultitools.websocket.CloudChannel, java.util.concurrent.Executor, boolean) and closed(com.ultikits.ultitools.websocket.CloudChannel) run on the agent thread; mainThreadSecond() on the Bukkit main thread only; agentSecond() on the agent thread; offerLine(long, java.util.logging.Level, java.lang.String) on any logging thread.

Resolved at first use (22-22 fix). The plugin creates this object before initWebSocketManagers() creates the ServerMonitorManager, so the monitor is never read at construction: telemetryAvailable() and every telemetry path ask the supplier until it yields a monitor, and keep the first one it yields. The error collector is read every second for the same reason. Nothing else this object holds depends on an object the plugin creates later.

Since:
6.3.1
  • Field Details

    • SNAPSHOT_REQUEST

      public static final String SNAPSHOT_REQUEST
      The request type snapshotRequests() answers.
      See Also:
    • STATE_SAMPLE_PERIOD_SECONDS

      static final int STATE_SAMPLE_PERIOD_SECONDS
      The server state is sampled on every fifth once-a-second run, as v1's 100-tick state task did.
      See Also:
    • ERRORS_PER_SECOND

      static final int ERRORS_PER_SECOND
      The most error reports sent in one second (the collector's own per-batch cap still applies).
      See Also:
    • ERROR_REPORT

      private static final String ERROR_REPORT
      See Also:
    • monitorSource

      private final Supplier<ServerMonitorManager> monitorSource
    • telemetryEnabled

      private final BooleanSupplier telemetryEnabled
    • clock

      private final LongSupplier clock
    • mainThread

      private final Executor mainThread
    • telemetryLock

      private final Object telemetryLock
    • monitor

      private volatile ServerMonitorManager monitor
      The first monitor the supplier yielded, or null before. Written under telemetryLock.
    • telemetry

      private volatile AgentTelemetry telemetry
      The telemetry over monitor, or null before a monitor exists. Same guard.
    • logs

      private final AgentLogBatcher logs
    • logsEnabled

      private final BooleanSupplier logsEnabled
    • errorsEnabled

      private final BooleanSupplier errorsEnabled
    • errors

      private final Supplier<ErrorReportCollector> errors
    • transmitter

      private final UltiPanelLogTransmitter transmitter
    • flushQueued

      private final AtomicBoolean flushQueued
    • live

      private volatile CloudChannel live
      The live channel between a welcome and its close, or null.
    • agentThread

      private volatile Executor agentThread
      The agent thread of the live connection, for an immediate flush of a full batch.
    • logsAccepted

      private volatile boolean logsAccepted
      Whether the gateway accepted logs on the live connection; false while none is live.
    • capture

      private SystemLogHandler capture
      The handler this object attached to the root logger, or null. Guarded by this.
    • secondsSampled

      private int secondsSampled
      Main thread only.
    • tpsClockPrimed

      private boolean tpsClockPrimed
      Whether the monitor's TPS clock was started by the first run. Main thread only.
  • Constructor Details

    • AgentOutboundFeeds

      public AgentOutboundFeeds(Supplier<ServerMonitorManager> monitor, BooleanSupplier telemetryEnabled, BooleanSupplier logsEnabled, BooleanSupplier errorsEnabled, Supplier<ErrorReportCollector> errors, LongSupplier clock, Executor mainThread)
      Parameters:
      monitor - supplies the server sampler, read at first use and then kept; null, or a supplier of null, means no telemetry (yet)
      telemetryEnabled - the telemetry switch, read for every frame
      logsEnabled - the logs switch, read for every line
      errorsEnabled - the errors switch, read every second
      errors - the error-report collector, or a supplier of null for no error reports
      clock - epoch milliseconds for the cadence and the log rate bucket
      mainThread - runs Bukkit work on the main thread, in order; null for no telemetry
  • Method Details

    • snapshotRequests

      public CloudRequestHandler snapshotRequests()
      Returns:
      the snapshot.request handler, or null while there is no telemetry
    • telemetryAvailable

      public boolean telemetryAvailable()
      Whether the telemetry can run now: a monitor exists and the main thread is bound. The hello declares telemetry only when this is true, so the hello and the router agree.
      Returns:
      true once a monitor was obtained
    • telemetry

      private AgentTelemetry telemetry()
      The telemetry, built over the first monitor the supplier yields; null while it yields none.
    • established

      public void established(CloudChannel channel, Executor agentThread, boolean logsAccepted)
      A connection was established: its channel becomes the live one, the telemetry sends its opening snapshots, and the log capture is attached when the logs switch is on (again, if a logout detached it).

      When the gateway did not accept logs, the line stream is inert for this connection (22-22 fix): no line is built, batched or flushed, so a refused log.lines never turns every following line into a flush attempt. The handler itself may stay attached, because it also feeds the error collector.

      Parameters:
      channel - the connection's live channel
      agentThread - the connection's agent thread
      logsAccepted - whether the welcome accepted logs
    • closed

      public void closed(CloudChannel channel)
      A connection closed: nothing is sent until the next welcome, and the lines not yet sent are dropped (D-14).
      Parameters:
      channel - the closed connection's channel; a close of an older connection does not clear a newer one
    • mainThreadSecond

      public void mainThreadSecond()
      The once-a-second main-thread run: one TPS and CPU sample (the first run only starts the TPS clock), a state sample every 5 seconds, then the telemetry cadence. Bukkit main thread only; scheduled every 20 ticks so the TPS sample measures ticks, not wall-clock hops.
    • agentSecond

      public void agentSecond()
      The once-a-second agent-thread run: sends the buffered log lines and the pending error reports. Never throws.
    • shutdown

      public void shutdown()
      Detaches the log capture and forgets the live connection; at plugin disable. Never waits for a thread.
    • sendErrorReports

      private void sendErrorReports(CloudChannel channel)
      Sends what the collector grouped since the last second, while the errors switch is on. While it is off or no connection is established the reports stay in the collector's bounded queue.
    • playerRefPayload

      public static com.google.gson.JsonObject playerRefPayload(String uuid, String name)
      Parameters:
      uuid - the player's UUID string
      name - the player's name as the server reports it
      Returns:
      the player.join / player.leave payload { playerUuid, playerName }, or null when the contract cannot carry this player
    • playerCommandPayload

      public static com.google.gson.JsonObject playerCommandPayload(String commandLine)
      Parameters:
      commandLine - the command line as the player typed it
      Returns:
      the player.command payload carrying only the normalised command name (D-20), or null when the name does not fit the contract
    • offerLine

      void offerLine(long timestamp, Level level, String message)
      One redacted line from the transmitter; dropped while offline, with the logs switch off, or when the gateway did not accept logs on this connection.
    • linesWanted

      private boolean linesWanted()
      Returns:
      whether a line would be sent: a connection is live, accepted logs, and the switch is on
    • requestFlush

      private void requestFlush()
      A full batch leaves at once, on the agent thread, never inline on the logging thread (22-13).
    • ensureLogCapture

      private void ensureLogCapture()
      Attaches the log handler to the root logger unless it is still attached (a logout's v1 log teardown detaches every SystemLogHandler); the start-up records the early capture kept are replayed through it first.
    • logBatcher

      AgentLogBatcher logBatcher()
      Returns:
      the batcher, for tests