untoldwind / KontrolSystem2

Autopilot scripting system for KSP2
Other
54 stars 14 forks source link

Question about processus #155

Closed lefouvert closed 1 week ago

lefouvert commented 2 months ago

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 ^^

untoldwind commented 2 months 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.

lefouvert commented 2 months ago

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.

untoldwind commented 2 months ago

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)

lefouvert commented 2 months ago

Hum... My knowledge about thoses topics are really light, but it smell like 2 things.

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.

untoldwind commented 2 months ago

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" ...

lefouvert commented 2 months ago

GREAT ! Thank you. Can't wait to try this. But have to, busy times :'(.

untoldwind commented 2 months ago

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.

github-actions[bot] commented 3 weeks ago

This issue is stale because it has been open for 60 days with no activity.

github-actions[bot] commented 1 week ago

This issue was closed because it has been inactive for 14 days since being marked as stale.