Repository navigation
Conversation
|
|
This pull request will eliminate the need for systemd socket activation and will output the content immediately, without delays. I’m using this for my website to show that everything is fine (I’m too lazy to log in via SSH). |
|
Mmmm 😒 i don't like ai-made pr but i will reply anyways...
No. This is too much for the use case. Synchronously is enough.
I don't understand this very well, but seems off-topic. Just need to move command handler to a variable and trigger it via a posted task.
Off-topic
Factually false. CLaJ has indeed no default monitoring thing like that, but stop you from creating one. The server is moddable. Changes, Configuration, Examples, Checklist: I don't care of this bullshit. Well... To summarize, this is too much for a simple thing... No need to make a book for that. I know, I love optimization and low level things, but for what you want to do, is it worst it to do all of this? Just making the implementation, telling me it's working is enough. |
|
Okay, well, thank you, then I'll close this request, I hope in the Future someone will write it easier, unfortunately, I don't like sending and receiving data via systemd sockets, although it's a good option. |
|
No need to close it so soon. You can try to make a better implementation. Your idea is great But the execution is not good. |
I’m not very good at writing in Java, and I can only make minor adjustments to already existing code, study something, or do some testing — nothing more… |
|
So you can try to improve yourself. I'm not judging your skills, I'm judging the excessive use of external help without understanding what your doing. Try to make an implementation by yourself and inspiring you from what anuken or internet done. Your here to learn too. I'm sure you can do better, take few days to search, code, test an implementation, and suggest your changes. I'll help you with how to implement it properly. As I said, this kind of thing is usually short to make, as java already does most the job. More over by reading the CLaJ and Arc codebase, you will learn how to implement it by following the "mood". E.g. for getting the console output, there is a simple way than replacing stdout... |



Notes for reviewer
The listener is intentionally synchronous (one client at a time), same as Mindustry's ServerControl. If concurrent access is ever needed, it's a small change to spawn a handle() thread per connection — but the current model is deliberate: it matches upstream and keeps System.out mirroring deterministic.
CommandHandler is not thread-safe upstream. We synchronize on it locally. Console input arrives via Core.app.post(), which serializes on the main thread; in practice the two paths never actually race because command registration happens once at startup.
The hooked flag exists so that init() can be called multiple times without chaining stdout wrappers. disposed exists so a late-arriving listen() cannot resurrect a shut-down listener. Both are edge cases, but cheap insurance.
Summary
Adds a TCP socket interface for remote command execution, mirroring Mindustry's socketInput. Enables automation, remote management, and status polling without relying on stdin / journald.
Three new config parameters, managed through the existing config command, with live reload for port/address. The listener duplicates System.out into the socket so clients receive the exact same output the console does.
Motivation
CLaJ has no programmatic interface for external tools. Web dashboards, monitoring scripts, and automation currently have to parse journald — fragile, slow, and platform-dependent. Mindustry solved this years ago with socketInput; this PR ports the same model to CLaJ.
Primary use cases:
Changes
Four files touched:
Configuration
Three new fields registered through the existing ClajConfig mechanism, exposed via the standard config command:
Changes to socket-input-port and socket-input-address take effect immediately — no restart required — via Field.changed(Cons) callbacks.
Example:
Behavior
Compatibility
Mindustry-style: same UX, same defaults (localhost binding, one client, port near 6859), same command semantics.
CLaJ-style: uses existing ClajConfig.Field, Field.changed, Threads.daemon, Log, and ApplicationListener — no new patterns introduced.
No breaking changes: socket-input defaults to true but listens only on localhost. Operators who do not want the listener can set config socket-input false.
Testing
Extensive stress testing was performed; the full transcript is attached separately. Highlights:
Correctness — status, help, config produce identical output to the console.
Latency — 50-sample distribution, avg < 1 ms, p99 < 3 ms.
Throughput — 500 / 1000 / 2000 batched commands, all ≥ 95 % delivered.
Concurrency — 25 simultaneous clients, zero errors.
Memory — RSS stable across the entire test suite.
Resilience — oversized payload (2 MB), 20 partial sends, 50 idle connections, 75 rapid connect/disconnect cycles — CLaJ stays alive in all cases.
Live config — port and address changed at runtime, listener restarts cleanly.
Log hygiene — no timeout spam, no unexpected stack traces, no stray [E] lines.
Runtime invariants — exactly one Socket Input thread, 10 s idle timeout, clean heap after GC.
Checklist
Code compiles cleanly (gradlew clean release)
☑ No new warnings introduced by this change
☑ Runs on Linux (Debian 13, Java 25)
☑ Tested on Windows (build) and Linux (runtime)
☑ Follows existing code style and license headers
☑ Uses existing CLaJ mechanisms (config, threads, logging)
☑ No breaking changes to existing APIs
☑ Listener bound to localhost by default
☑ Documentation added in the code (JavaDoc on key methods)
Happy to split into smaller commits if preferred, or adjust naming/placement to match project conventions.