Pipes, or text streams, are a foundational element of the ARES design. They allow transport of text between programs, which enables a wide variety of applications that are completely beyond the reach of any software environment that lacks them. Text processing pipelines were a 'killer feature' of UNIX, and the ARES implementation is similar in its purpose and flexibility, albeit with some simplifications.

In a normal script, text output is accomplished using llRegionSayTo(target, 0, text). This works as follows:

script calls llRegionSayTo()
→
simulator delivers message to target

In an ARES program, text output uses the print(stream, user, text) macro, where stream and user are both UUIDs. This does the following:

script calls print()
→
message is appended to LSD:p:stream

script tells io daemon that user added a message to stream
→
io daemon checks pipe table
→
if no next pipe is defined:
llRegionSayTo(stream, 0, text)
→
if a next pipe exists:
forwards message

In the base case, if the stream UUID isn't currently assigned to a pipe it is assumed to refer to an object, and the text is sent to it. The result is similar to using llRegionSayTo(stream, 0, text) directly, although the io daemon will perform some collation (very long messages will be split.)

However, the power of text pipes comes from combining them in less trivial arrangements. By registering a pipe object with the io daemon, the programmer can create automated chat listeners from existing tools, forward messages through multiple filters in interesting ways, scrape output to process with devices, and even implement complete communications terminals that allow ARES to interface with systems outside of Second Life, often with little to no modification of existing LSL code.

Pipes are used in ARES for a wide variety of applications, most notably implementation of the chat filter (vox) system. However they are also the intermediary format for most userspace scripts that communicate via private chat channels, such as the input handler itself and the ARES Xanadu software client. Most of the development documentation pertains to the pipe system to some extent, as this routing was vital (in earlier versions of ARES) to minimizing the number of scripts that had to be kept running at all times.

Managing pipes

To see a list of currently-extant pipes on the system, use the command @input debug:

· 00000000-0000-0000-0000-000000000010 · 0 · 2 · · · 00000000-0000-0000-0000-000000000020 · 0 · 2 · · · 00000000-0000-0000-0000-000000000100 · 0 · 2 · · · 000369b6-0003-69b6-0003-69b6000369b6 · 9 · 1 · nav · 00000000-0000-0000-0000-000000000000 · 50495045-0000-0000-0000-000000000000 · 0 · 3 · pipet · 00000000-0000-0000-0000-000000000000 · 00000000-0000-0000-0000-000000000001 · 10 · 1 · _input · d69ca06e-aa22-49e4-86e1-42677e26f3f5 · 43524553-5841-4e41-4455-48414e444c45 · 11 · 1 · _parc · 00000000-0000-0000-0000-000000000000 · 00000000-0000-0000-0000-000000000a01 · 0 · 3 · filter lisp 50 · 00000000-0000-0000-0000-000000000a02 · 00000000-0000-0000-0000-000000000a02 · 0 · 4 · _input output · d69ca06e-aa22-49e4-86e1-42677e26f3f5 io Memory: 228 bytes deallocated; 21594 free

This provides output from the _io daemon, which cannot be accessed via the usual @service ... syntax.

The output may be interpreted as a table, labeled like so:

IDlistenertypecommandnext pipe ID
00000000-0000-0000-0000-00000000001002
00000000-0000-0000-0000-00000000002002
00000000-0000-0000-0000-00000000010002
000369b6-0003-69b6-0003-69b6000369b691nav00000000-0000-0000-0000-000000000000
50495045-0000-0000-0000-00000000000003pipet00000000-0000-0000-0000-000000000000
00000000-0000-0000-0000-000000000001101_inputd69ca06e-aa22-49e4-86e1-42677e26f3f5
43524553-5841-4e41-4455-48414e444c45111_parc00000000-0000-0000-0000-000000000000
00000000-0000-0000-0000-000000000a0103filter lisp 5000000000-0000-0000-0000-000000000a02
00000000-0000-0000-0000-000000000a0204_input outputd69ca06e-aa22-49e4-86e1-42677e26f3f5

These columns have the following definitions:

  • ID: A UUID indicating the pipe ID. When a message is received by _io on a UUID that is present in this column, then the message is stored for subsequent processing rather than immediately being sent to an object as a chat message.
  • listener: If the pipe is of the input pipe type (type 1), then it receives chat messages from an llListen() handler. This will then be forwarded on to the rest of the chain, if one exists. If the pipe is of type 2 (output), then this field instead holds the output channel.
  • type: A numeric indicator of the pipe's type:
    1. Input
    2. Output
    3. Invoke
    4. Notify
    5. File
    6. Invoke (volatile)
    7. Notify (volatile)
    8. Transport
    9. Transport (volatile)
  • command: If the pipe is not of types 2, 8, or 9, then this string will be called with the appropriate system signal. If the pipe is of type 2 (output), then the command is interpreted as the recipient UUID.
  • next pipe ID: The value to provide as the output stream (outs) during invocation.

To reset the _io daemon, use the command @input debug restart. The normal syntax, @service io restart, will not work due to the _io daemon's stream-oriented design.