22 January 2002
14 August 2011
This is a discussion of the architecture of flow. The primary classes are those of the Correspondent hierarchy:
Correspondent Client IncomingClient IncomingHTTPClient IncomingIdentificationClient IncomingMIDIClient IncomingVISCAClient IncomingX10Client IncomingTelnetClient OutgoingClient OutgoingHTTPClient OutgoingIdentificationClient OutgoingIRCClient OutgoingMIDIClient OutgoingNNTPClient OutgoingPOPClient OutgoingSMTPClient OutgoingTimeClient OutgoingVISCAClient OutgoingX10Client ServerThese classes do the recurring bookkeeping involved in writing clients and servers. For example, a Server keeps track of the clients connected to it, and has simple default behavior for servicing and disconnecting them. Transport details are encapsulated by NetStreams (described below). Correspondent authors can focus on protocol details, with a streamy message interface, instead of transport details.
When both client and server systems are using Flow, an OutgoingClient uses its stream to connect to a Server, then communicates with a remote IncomingClient that the Server creates for the conversation. Likewise, the IncomingClient uses its stream, created by the Server, to communicate with the remote OutgoingClient. The Server uses its stream only to listen for connection requests from remote OutgoingClients, and to create IncomingClients for servicing them.
With this arrangement one can model the different sides of a conversation independently, including protocols with many-way interactions.
Of course, when a participant system is not using Flow, the required behavior is provided by some other piece of software. For example, in the hierarchy above, "OutgoingTelnetClient" isn't listed because I have no need to make my own outgoing telnet client; I just use the one that comes with the host operating system. I did implement IncomingTelnetClient, because it's part of customized telnet behavior I wanted for Quoth, another project of mine. In fact, it was that project which pointed out the need to model incoming and outgoing client behavior separately.
It's straightforward to combine multiple correspondents in an "application". For example, a mailer would probably use multiple OutgoingPOPClients and OutgoingSMTPClients.
I rewrote the Stream hierarchy:
Stream PositionableStream WritableStream DiscardingStream ExternalStream FileStream AppendingFileStream AppendingFileStreamWriter RemoteFileStream NetStream Conversation (used for speech recognition/synthesis) HardwareStream 1394Stream AudioStream MIDIStream ParallelPortStream SerialPortStream SocketStream TCPStream UDPStream NetMessage HTTPMessage HTTPMethod GET LOCK MOVE OPTIONS PROPFIND PROPPATCH PUT MailMessage NewsMessage RingBuffer InfiniteRingBuffer TextStream RandomNumberStreamI was originally motivated by the need to get a filesystem working on custom hardware. The Squeak filesystem support at the time (including the Stream hierarchy) was cumbersome, with a lot of unreachable and redundant code and an overly-complicated class factoring. The new factoring is much simpler, unifies all "external" resources with the ExternalStream hierarchy, and has smarter buffering.
The NetMessage hierarchy extends stream protocol to the creation of HTTP, mail, and news messages, minimizing copying.
External resources are named by Universal Resource Locators (URLs):
UniformResourceLocator AuthenticatingLocator HierarchicalLocator FileLocator Filename HypertextLocator MIDILocator TelnetSession MailAddress MessageLocator MailMessageLocator NewsMessageLocatorAll low-level access to the outside world is factored into one hierarchy:
ExternalResource File MakeControllerKit (with OSC support defined separately) Peer HardwarePort AudioPort IEEE1394Port InfraredPort MIDIPort ParallelPort SerialPort USBPort Socket TCPSocket ClientTCPSocket IncomingClientTCPSocket OutgoingClientTCPSocket ServerTCPSocket UDPSocket PhidgetInterfaceKit SocketAddressResolver SpeechRelay
Each ExternalResource has a "handle" instance variable, an opaque identifier which is known to the virtual machine (there is no need to model resource handles separately at the object level). All external resources support an interface which makes them suitable for use as collections for NetStreams. File will probably have subclasses to account for host platform differences.
Exception handling is used in many places by the classes above, usually for "ensured behavior". For example, one may open a file stream and write to it, ensuring that the file will be closed despite interruptions.