|
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
Server
These 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
RandomNumberStream
I 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
NewsMessageLocator
All 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. |