RemoteFilesImpl:
CEDAR
PROGRAM
IMPORTS AlpineInterimDirectory, AlpFile, AlpTransaction, FileIOAlpine, IO, NewSTP, Stream, UnsafeSTP, UserCredentials
EXPORTS RemoteFiles =
BEGIN
STPStreamDataRef: TYPE = REF STPStreamData;
STPStreamData:
TYPE =
RECORD [
handle: NewSTP.Handle,
stream: Stream.Handle];
OpenSTP:
PUBLIC
PROC [ fileName: Rope.
ROPE, accessOptions: FileIO.AccessOptions ← read, host, connect, directory: Rope.
ROPE ←
NIL ]
RETURNS [ self:
IO.
STREAM, greetings: Rope.
ROPE ] =
BEGIN -- simplified for output to Oliver servers like [vice]
stpHandle: NewSTP.Handle;
streamHandle: Stream.Handle;
SELECT accessOptions
FROM
write -- , read -- => NULL;
ENDCASE => ERROR IO.Error[NotImplementedForThisStream, NIL];
stpHandle ← NewSTP.Create[];
IF host=NIL THEN host ← "indigo";
greetings ← stpHandle.Open[host];
stpHandle.Login[name: UserCredentials.GetUserCredentials[].name,
password: UserCredentials.GetUserCredentials[].password];
IF connect#NIL THEN stpHandle.Connect[name: connect, password: NIL];
IF directory#NIL THEN stpHandle.SetDirectory[directory: directory];
streamHandle ← stpHandle.CreateRemoteStream[
file: fileName,
access: (
SELECT accessOptions
FROM
read => read,
ENDCASE => write),
fileType: binary];
self ←
IO.CreateProcsStream[
streamProcs:
IO.CreateRefStreamProcs[
putChar: SendSTPChar,
unsafePutBlock: SendSTPBlock,
close: CloseSTP],
streamData:
NEW[STPStreamData ← [
handle: stpHandle,
stream: streamHandle]]];
END;
SendSTPChar:
PROC [ self:
IO.
STREAM, char:
CHAR ] =
BEGIN
sd: STPStreamDataRef = NARROW[self.streamData];
TRUSTED {sd.stream.PutChar[char: char]};
END;
SendSTPBlock:
PROC [ self:
IO.
STREAM, block:
IO.UnsafeBlock ] =
BEGIN
sd: STPStreamDataRef = NARROW[self.streamData];
TRUSTED {sd.stream.PutBlock[block: [blockPointer: block.base, startIndex: block.startIndex, stopIndexPlusOne: block.stopIndexPlusOne]]};
END;
CloseSTP:
PROC [ self:
IO.
STREAM, abort:
BOOL ←
FALSE ] =
BEGIN
BEGIN
ENABLE UnsafeSTP.Error =>
IF abort THEN CONTINUE ELSE REJECT;
sd: STPStreamDataRef = NARROW[self.streamData];
TRUSTED {sd.stream.Delete[]};
sd.stream ← NIL;
sd.handle.Close[];
sd.handle ← NIL;
END;
END;
OpenAlpineForWrite:
PUBLIC PROC [ fileName: Rope.
ROPE, expectedLength:
INT ← 6D6 ]
RETURNS [ self:
IO.
STREAM ] =
BEGIN
server: AlpInstance.Handle;
trans: AlpTransaction.Handle;
file: AlpFile.Handle;
refUniversalFile: REF AlpineEnvironment.UniversalFile;
retryCount: INT ← 0;
DO {
ENABLE AlpineInterimDirectory.Error =>
IF retryCount < 2
THEN
LOOP;
retryCount ← retryCount + 1;
[instHandle: server, refUniversalFile: refUniversalFile] ←
AlpineInterimDirectory.Open[fileName: fileName, initialByteAllocation: expectedLength];
trans ← AlpTransaction.Create[server];
file ← AlpFile.Open[
transHandle: trans, universalFile: refUniversalFile^, access: $readWrite,
referencePattern: $sequential].handle;
file.SetSize[expectedLength/512];
file.WriteProperties[
LIST[
[highWaterMark[highWaterMark: 0]]]];
IF trans.Finish[$commit].outcome # $commit THEN LOOP;
trans ← AlpTransaction.Create[server];
file ← AlpFile.Open[
transHandle: trans, universalFile: refUniversalFile^, access: $readWrite,
referencePattern: $sequential, lock: [mode: write, ifConflict: wait]].handle;
self ← FileIOAlpine.StreamFromAlpineOpenFile[
fileHandle: file, fileName: fileName, accessOptions: $write];
EXIT;
} ENDLOOP;
END;
Module START code...
END. -- of RemoteFilesImpl