Closed lefouvert closed 1 week ago
I wanted have something like this to improve communication with background tasks, but then I started to overthink it and the scope became bigger and bigger.
I guess the main problem is to decide on a simple initial implementation that does not prevent further expansion in the future.
When I see all solutions existing, I gess it's an hard topic (Since if it was easy, everybody would have adopt the same easy way). From C with Semaphor, Java with shared memory (Bleh...), to Erlang/OTP with... mail boxes ! If I'm not wrong, Rust use Channel concept, but I have to admit I'm not fully aware about how to implement thoses kind of functionnalities.
In rust there is the mpsc pattern as part of the standard library, which stands for multi-producer single-consumer. Which is nice for coordinating a bunch of worker-threads (or similar), but does not match well with this use-case.
I guess a content-based PubSub pattern might be the best match. I.e. you define a bunch of different message types and have a method to publish a message to everyone who is interested (or the void) and a method to subscribe to a message type (which acts like a mailbox/queue)
Hum... My knowledge about thoses topics are really light, but it smell like 2 things.
while(true)
loop containing if(event == THE_THING_IM_INTERESTING_IN) then blablabla
In anycase, it seems to be a workable workflow. (Is it so obvious I'm not a front-end dev ? ^^) Broadcast/Queue is a scheme I already have experimented and is nice to use and somewhat robust.
Kind of forgot about this, in 0.5.8.0 (https://github.com/untoldwind/KontrolSystem2/releases/tag/v0.5.8.0) there is some basic support for a message bus:
Script 1 "test_send.to2":
use { Vessel } from ksp::vessel
use { CONSOLE } from ksp::console
use { MESSAGE_BUS } from ksp::game
pub struct MyMessage(message: string, a_number: int) {
message: string = message
a_number: int = a_number
}
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
MESSAGE_BUS.publish(MyMessage("Hello", 1234))
}
Script 2 "test_recv.to2":
use { Vessel } from ksp::vessel
use { CONSOLE } from ksp::console
use { MESSAGE_BUS, wait_until, Subscription } from ksp::game
use { MyMessage } from test_send
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
CONSOLE.clear()
const subscription : Subscription<MyMessage> = MESSAGE_BUS.subscribe()
while(true) {
// This is still rather clunky, there should be a proper helper for "wait for message"
wait_until(fn() -> subscription.peek().defined)
// The wait is not really necessary, this can be done in any loop with yield or sleep
if(Some(message) = subscription.recv()) {
CONSOLE.print_line($"Recv message: {message.message} {message.a_number}")
}
}
}
Limitations: Whenever the system is rebooted, the connection between old and new script will be lost. This is actually pretty complicated to fix (because after a reboot that will be two versions of the "MyMessage" type, that do not work well with each other).
This should eventually be extended by a bunch of system messages to subscribe to, like "Script started", "Script crashed", "Vessel changed" ...
GREAT ! Thank you. Can't wait to try this. But have to, busy times :'(.
In 0.5.8.1 (https://github.com/untoldwind/KontrolSystem2/releases/tag/v0.5.8.1) I added basic ProcessStarted and ProcessStopped events. So the receiver can now contain this:
use { Vessel } from ksp::vessel
use { CONSOLE } from ksp::console
use { MESSAGE_BUS, wait_until, Subscription, EventProcessStarted, EventProcessStopped } from ksp::game
use { MyMessage } from test_send
pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
CONSOLE.clear()
const sub_message : Subscription<MyMessage> = MESSAGE_BUS.subscribe()
const sub_started : Subscription<EventProcessStarted> = MESSAGE_BUS.subscribe()
const sub_stopped : Subscription<EventProcessStopped> = MESSAGE_BUS.subscribe()
while(true) {
wait_until(fn() -> sub_message.has_messages || sub_started.has_messages || sub_stopped.has_messages)
// The wait is not really necessary, this can be done in any loop with yield or sleep
if(Some(started) = sub_started.recv()) {
CONSOLE.print_line($"Process started: {started.name} {started.arguments.to_string()}")
}
if(Some(message) = sub_message.recv()) {
CONSOLE.print_line($"Recv message: {message.message} {message.a_number}")
}
if(Some(stopped) = sub_stopped.recv()) {
CONSOLE.print_line($"Process stopped: {stopped.name} {if(stopped.error.defined) stopped.error.value else "success"}")
}
}
}
This should be a workable pattern to listen for multiple events.
This issue is stale because it has been open for 60 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.
version : 0.5.7.6 (Ckan) Gessed tag: Question, Enhancement
Hi, There is anyway to processus to communicate between eachother ? Actualy, the only way I think about with tools available (and I know) is by writting files, but I may miss something. I don't think it's the best way to do it.
Context : I would like to have an independant processus listening for «message» and be able to process them even if main autopilot crash or end. Application : «Black Box logger» «Mid-computing data viewer» And probably many other.
If it not exists, don't worry, I'm not in hurry, it could be only a seed of an idea beded until it grow ^^