"The interface and abstract framework on which all external interaction libraries depend." prototypes addPrototype: #ExternalResource derivedFrom: {Cloneable}. "Abstract object for representing resources used by the system but maintained outside of it, such as external storage and network resources." ExternalResource addSlot: #handle. "An ID number perhaps for the struct or the actual low-level object itself." ExternalResource addSlot: #readStream. "What object has read-capabilities for this resource." ExternalResource addSlot: #writeStream. "What object has write-capabilities for this resource." ExternalResource addSlot: #locator. "An identifying locator for the connection so that it may be closed and re-opened with persistent identity." r@(ExternalResource traits) resetStreams "Resets all the stream connections to and from the resource." [ r readStream ifNotNilDo: [| :s | s resource: Nil]. r writeStream ifNotNilDo: [| :s | s resource: Nil]. r readStream: (r writeStream: Nil). ]. r@(ExternalResource traits) enable "Creates the external resource represented and assigns the handle." [overrideThis]. r@(ExternalResource traits) open "Resets/removes any stale I/O objects and then sets up the resource anew." [ r resetStreams. r enable. r ]. r@(ExternalResource traits) close "Close the resource connection. Override this and resend for derived objects." [ r handle: Nil ]. r@(ExternalResource traits) commit "Commit all pending write-out information to the resource." [r]. r@(ExternalResource traits) isOpen "Whether there is considered to be a working connection with the peer." [ r handle isNotNil ]. r@(ExternalResource traits) isActive "Whether both the system and the peer agree that the connection is working." [ r isOpen ]. r@(ExternalResource traits) sessionDo: block "Calls the block with the resource object as input, opening and closing it transparently in an error-tolerant way. The return value of the block is answered if it completes without error." [ [r open. block applyWith: r] ensure: [r isOpen ifTrue: [r commit. r close]] ]. r@(ExternalResource traits) restart "Restart the resource if already active." [ r isActive ifTrue: [r open] ]. r@(ExternalResource traits) defaultBufferSize "The size that a Stream should use for an interaction buffer." [overrideThis]. r@(ExternalResource traits) read: n from: handle startingAt: start into: array "The primitive for external input: read N bytes from the resource's handle at the given start position, placing them in the array (starting at 0)." [overrideThis]. r@(ExternalResource traits) read: n startingAt: start into: array [r read: n from: r handle startingAt: start into: array]. r@(ExternalResource traits) write: n to: handle startingAt: start from: array "The primitive for external output: write N bytes to the resource's handle at the given start position, taking them from the array (starting at 0)." [overrideThis]. r@(ExternalResource traits) write: n startingAt: start from: array [r write: n to: r handle startingAt: start from: array]. ExternalResource traits addPrototype: #Stream derivedFrom: {Stream}. "A Stream used on an ExternalResource." ExternalResource Stream addSlot: #resource valued: ExternalResource clone. ExternalResource Stream addSlot: #isBinary valued: True. ExternalResource Stream addSlot: #indexOfLastDirtyElement valued: 0. r@(ExternalResource traits) reader "This defers access control to the one object that has been handed original access." [ r readStream ifNil: [r readStream: (r ReadStream newOn: r)] ]. r@(ExternalResource traits) writer "This defers access control to the one object that has been handed original access." [ r writeStream ifNil: [r writeStream: (r WriteStream newOn: r)] ]. r@(ExternalResource traits) interactor "Provides a ReadWriteStream for working with the resource. It can't be an iterator since those provide synchronized (ie the reading and writing modify the same contents) access. This also defers access control to the one object that has been handed original access." [ r readStream: (r writeStream: (r ReadWriteStream newOn: r)) ]. r@(ExternalResource traits) iterator "This defers access control to the one object that has been handed original access." [ r readStream: (r writeStream: (r ReadWriteStream newOn: r)) ]. s@(ExternalResource Stream traits) newOn: r [| newS | newS: s clone. newS on: r. newS ]. s@(ExternalResource Stream traits) on: r [ s isBinary: False. s resource: r. s indexOfLastDirtyElement: 0. ]. s@(ExternalResource Stream traits) elementType "ExternalResources generally will only be able to work with characters or (byte-sized?) integers." [ s isBinary ifTrue: [Integer] ifFalse: [Character] ]. s@(ExternalResource Stream traits) arrayType [ s isBinary ifTrue: [ByteArray] ifFalse: [String] ]. s@(ExternalResource Stream traits) open [ s resource open ]. s@(ExternalResource Stream traits) isDirty "Whether the Stream's writing buffer has elements which should be committed." [ s indexOfLastDirtyElement > 0 ]. s@(ExternalResource Stream traits) flush "Flushes any unwritten elements." [ s isDirty ifTrue: [s resource isActive ifFalse: [s open]. s flushWriteBuffer. s indexOfLastDirtyElement: 0]. s ]. s@(ExternalResource Stream traits) commit "Commit differs from flush in that the latter can make use of implicit buffering in the low-level implementation, while commit ensures that the data is actually sent to the peer." [ s flush. s resource commit. s ]. s@(ExternalResource Stream traits) close [ s resource isOpen ifTrue: [s resource close] ]. ExternalResource traits addPrototype: #ReadStream derivedFrom: {ExternalResource Stream. ReadStream}. s@(ExternalResource ReadStream traits) next [ (s next: 1) first as: s elementType ]. s@(ExternalResource ReadStream traits) next: n putInto: seq startingAt: start [| bytes | bytes: (ByteArray newSize: n). s next: n putInto: bytes startingAt: 0. bytes doWithIndex: [| :byte :index | seq at: start + index put: (byte as: s elementType)]. n ]. s@(ExternalResource ReadStream traits) next: n putInto: seq@(ByteArray traits) startingAt: start [ s resource read: n startingAt: start into: seq. n ]. ExternalResource traits addPrototype: #WriteStream derivedFrom: {ExternalResource Stream. WriteStream}. s@(ExternalResource WriteStream traits) nextPut: obj [s nextPutAll: {obj}]. _@(ExternalResource WriteStream traits) nextPut: _@(String traits) [ error: 'Strings cannot be single elements for ExternalResource streams.' ]. s@(ExternalResource WriteStream traits) next: n putAll: seq startingAt: start [| bytes | bytes: (ByteArray newSize: n). 0 below: n do: [| :index | bytes at: index put: ((seq at: start + index) as: Integer)]. s next: n putAll: bytes startingAt: 0 ]. s@(ExternalResource WriteStream traits) next: n putAll: seq@(ByteArray traits) startingAt: start [s resource write: n startingAt: start from: seq]. ExternalResource traits addPrototype: #ReadWriteStream derivedFrom: {ExternalResource ReadStream. ExternalResource WriteStream}. s@(ExternalResource ReadWriteStream traits) flush [ s resource readStream flush. s resource writeStream flush. ]. Console addSlotsFrom: ExternalResource. Console atSlotNamed: #traits put: ExternalResource traits. "The Console as an ExternalResource object." co@Console ; seq "A convenience method for the Console as a Stream resource; do NOT repeat this pattern without determining that ; can have no other meaning for the resource." [co writer ; seq]. "A kluge to make the EchoStream prototype initialized properly." Stream EchoStream dribble: Console writer. co@(Console writer) skip: n [ n isPositive ifTrue: [n timesRepeat: (co nextPut: $\s)]. n isNegative ifTrue: [n timesRepeat: [co nextPut: $\b]]. co ]. _@Console isOpen [True]. _@(Console writer) elementType [Character]. _@(Console writer) arrayType [String]. _@(Console reader) elementType [Character]. _@(Console reader) arrayType [String]. _@(Console reader) isAtEnd [False]. _@(Console writer) isAtEnd [False]. c@(Console reader) flush []. c@(Console writer) flush [c resource flushOutput]. Console addImmutableSlot: #interactor valued: ReadWriteStream clone. "A singleton which delegates to ConsoleInput and ConsoleOutput in order to provide ReadWriteStream access for the Console." _@(Console interactor) elementType [Character]. _@(Console interactor) arrayType [String]. _@(Console interactor) next [Console reader next]. _@(Console interactor) next: n [Console reader next: n]. _@(Console interactor) nextPut: obj [Console writer nextPut: obj]. _@(Console interactor) nextPutAll: c [Console writer nextPutAll: c]. _@(Console interactor) flush [Console reader flush. Console writer flush]. ExternalResource traits addPrototype: #ConnectionFailed derivedFrom: {SeriousCondition}. ExternalResource ConnectionFailed addSlot: #resource. "A condition where a connection attempt fails." r@(ExternalResource traits) connectionFailure [| newC | newC: r ConnectionFailed new. newC resource: r. newC signal ]. r@(ExternalResource traits) describe [ DebugConsole ; 'Could not connect to ' ; (r resource locator as: String) ]. ExternalResource traits addPrototype: #Locator derivedFrom: {Cloneable}. "An empty abstract type of object for filenames and other resource-locating structures."