> This is true, thanks. Now let's say I wanted to write to the client's > console before reading anything from their console. > > With no other changes, this Pipeline setting doesn't work: > Pipeline( > MyComponent(), > ConsoleReader(), > ).run() > > but I am expecting it to work. What am I missing?
"Pipeline" isn't about saying what order to run things in - its more like expressing how to plug things together: The declaration above is saying: """ Make two components - an instance of MyComponent and an instance of ConsoleReader; now plug them together so that the "outbox" of "MyComponent" is joined to the "inbox" of "ConsoleReader" """ You could think of this as being like wiring your video recorder (MyComponent) up to your television set (ConsoleReader). Both are turned on and run at the same time. It just so happens that one sends stuff to the other. In the Kamaelia system, the MyComponent places data into its "outbox" outbox. Because it is in this pipeline, that data is automatically put straight into the "inbox" inbox of the ConsoleReader, ready to be collected. This is all about the flow of data. The order in which things happen is defined by the behaviour of each component. So going back to your original aim: > This is true, thanks. Now let's say I wanted to write to the client's > console before reading anything from their console. So you want a program where the flow of data is as follows: input from console ---> MyComponent ----> output to console I'm guessing there are two possibilities for what you're after achieving. One is easier than the other :-) In the simplest case, you want a pipeline like this: Pipeline( ConsoleReader(), MyComponent(), ConsoleEchoer() ).run() What is actually being wired up here? These two diagrams from http://www.kamaelia.org/Cookbook/Pipelines may help. The first shows the 'intention' you express when you write a Pipeline. The second shows the detail of what inboxes and outboxes actually get wired up. http://www.kamaelia.org/images/pipeline1_intention.gif http://www.kamaelia.org/images/pipeline1_inside.gif Now the main() generator in MyComponent is where we can control the actual behaviour, so we'll do something like this: def main(self): self.send("Initial message for the console", "outbox") while not self.doShutdown(): if self.dataReady("inbox"): data = self.recv("inbox") # let's echo what we received... self.send(data, 'outbox') if not self.anyReady(): self.pause() yield 1 Thats the simple version. Now a little more complexity! ... The above code won't guarantee is whether the "initial message for the console" is displayed before the prompt that is displayed by the ConsoleReader. Why is this? Because the Pipeline declaration effectively says "make all these and start them all at teh same time". If you want explicit behaviour where a component isn't created or activated, or wired up until a later point in the execution (ie. you want to control the order things happen in) then you need to express it explicitly. Here's *a* way to do it: We can use the Carousel component do delay the creation and wiring up of the ConsoleReader component until MyComponent sends a message telling it to do so. There's some explanation of Carousel here: http://www.kamaelia.org/Cookbook/Carousels if it helps. In short, Carousel is designed to contain another component. When it receives a message, it calls a helper function (that you supply) to create a component. It then takes that component and wires it up so that its "outbox" and "inbox" are mapped to the "outbox" and "inbox" of the Carousel component itself. We'll declare this helper globally for now: def makeConsoleReader(message): # we ignore the parameter return ConsoleReader() So that MyComponent can send a message to the Carousel, we'll need to add an extra outbox to MyComponent, and get it to send that signal: Class MyComponent(component): Outboxes = {"outbox" : "some data out", "signal" : "Shutdown signal", "ready" : "Sends a message when initialisation is complete", } ... def main(self): self.send("Initial message for the console", "outbox") yield 1 self.send("OK", "ready") while not self.doShutdown(): if self.dataReady("inbox"): data = self.recv("inbox") # let's echo what we received... self.send(data, 'outbox') if not self.anyReady(): self.pause() yield 1 Note the 'yield' statements - which give other components a chance to run - giving the ConsoleEchoer a chance to display that initial message. Remember that we don't control the precise order in which components execute: if we sent the initial message and the ready message without a yield in between, we might be unlucky, and the Carousel might get executed first! We cannot use a simple pipeline now, since we need to also wire up the "ready" outbox of MyComponent to the Carousel's "next" inbox. A Pipeline only wires up the standard "inbox" and "control" inboxes and "outbox" and "signal" outboxes. So we'll use a Graphline instead, where we specify each linkage explicitly: from Kamaelia.Chassis.Carousel import Carousel from Kamaelia.Chassis.Graphline import Graphline .... Graphline( READER = Carousel(makeConsoleReader), MYCOMP = MyComponent(), OUTPUT = ConsoleEchoer(), linkages = { # main flow of data: ("READER", "outbox") : ("MYCOMP", "inbox"), ("MYCOMP", "outbox") : ("OUTPUT", "inbox"), # the 'ready' message: ("MYCOMP", "ready") : ("READER", "next"), # the 'signal' and 'control' boxes used for shutdown: ("READER", "signal") : ("MYCOMP", "control"), ("MYCOMP", "signal") : ("OUTPUT", "control"), } ).run() So what should happen when this runs? 1) The components are created and wired up as shown above. 2) They all start executing. 2a) The Carousel and ConsoleEchoer only do stuff in response to messages they receive, so they sit there waiting. Only MyComponent really starts doing anything significant 3) MyComponent sends out its "initial message" out of its "outbox". The ConsoleEchoer receives this and displays the message on the console 4) MyComponent sends a message out of its "ready" outbox, and it is received at the "next" inbox of the Carousel. 4a) The Carousel uses the makeConsoleReader() function we wrote to create a ConsoleReader component. It gets wired up so that it uses the outboxes and inboxes of the Carousel. 4b) The ConsoleReader component also gets activated, and so its main() method starts running. It therefore displays its prompt for user input 5) When the user enters input, the ConsoleReader sends out of its "outbox" to the "inbox" of MyComponent. Hmm, more long winded than I originally hoped this would be. Hope it helps though. Matt -- | Matt Hammond | Research Engineer, FM&T, BBC, Kingswood Warren, Tadworth, Surrey, UK | http://www.bbc.co.uk/rd/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "kamaelia" group. To post to this group, send email to kamaelia@googlegroups.com To unsubscribe from this group, send email to kamaelia+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/kamaelia?hl=en -~----------~----~----~----~------~----~------~--~---