FinchRegisterImpl.mesa
Copyright Ó 1990 by Xerox Corporation. All rights reserved.
Polle Zellweger (PTZ) August 1, 1990 4:53:55 pm PDT
Swinehart, September 24, 1990 11:34 am PDT
Activities associated with connection, registering, reporting, error management, and the like.
Still some concerns about the locking requirements of the back-reporting stuff!!
DIRECTORY
Atom USING [ GetProp, PutProp ],
Convert USING [ CardFromRope, RopeFromCard ],
FinchSmarts USING [ ConvDesc, EnumerateIncreasing, FinchInfo, FinchInfoBody, info, lock, pd, Problem, ReportProcs, ReportProcsBody, ReportSystemStateProc, ReportConversationStateProc, ReportRequestStateProc, SHHH ],
IO,
MBQueue USING [ QueueClientAction ],
NameDB USING [ GetAttribute ],
Process USING [ Detach, SecondsToTicks, SetTimeout ],
RedBlackTree USING [ Create, Compare, EachNode, GetKey, Insert, LookupNextLarger, LookupNextSmaller, Table ],
Rope USING [ Equal, ROPE ],
RPC USING [ InterfaceName ],
ThParty,
ThPartySunRPControl USING [ ReportProblem, ReportState, ThrushConnect, ThrushDisconnect, ThrushReportState ],
Thrush,
ThSmartsSunExport USING [ ExportInterface ],
ThVersions USING [ FinchVR ],
UserProfile USING [ Token ],
VoiceUtils USING [ CurrentRName, CurrentPasskey, OwnNetAddress, Report ],
VoiceUtilsExtras USING [ RopeFromSunAddr ]
;
FinchRegisterImpl: CEDAR MONITOR LOCKS FinchSmarts.lock
IMPORTS
Atom, Convert, FinchSmarts, MBQueue, Process, RedBlackTree, Rope, ThParty, ThPartySunRPControl, ThSmartsSunExport, ThVersions, UserProfile, VoiceUtils, VoiceUtilsExtras
EXPORTS FinchSmarts
~ BEGIN
OPEN IO, FinchSmarts;
NB: TYPE = Thrush.NB;
uniqueSuffix: CARD ← 0;
High-level registration code, keep-alive code.
InitFinchSmarts: PUBLIC ENTRY PROC [
thrushInstance: Thrush.ROPENIL,
key: ATOM,
s: FinchSmarts.ReportSystemStateProc ← NIL,
c: FinchSmarts.ReportConversationStateProc ← NIL,
r: FinchSmarts.ReportRequestStateProc ← NIL] = {
ENABLE UNWIND => NULL;
problem: ROPENIL; nb: NB←$serverDown;
prevInfo: FinchSmarts.FinchInfo ← info;
IF info#NIL AND info.connected THEN UninitFinchSmartsInt[];
info ← NEW[FinchSmarts.FinchInfoBody]; -- Dump any old one!
IF prevInfo#NIL THEN NOTIFY prevInfo.pollCondition;
info.conversations ← NIL;
info.connected ← FALSE;
RegisterForReportsInt[key: $FinchSmarts, s: ClearInfo, other: $all, before: FALSE];
Must be the very last thing
RegisterForReportsInt[key: key, s: s, c: c, r: r];
thrushInstanceSELECT TRUE FROM
thrushInstance#NIL => thrushInstance,
prevInfo#NIL AND prevInfo.prevThrushInstance#NIL => prevInfo.prevThrushInstance,
ENDCASE=> UserProfile.Token["ThrushSunClientServerInstance", "Growler"];
info.prevThrushInstance ← thrushInstance;
uniqueSuffix ← ThSmartsSunExport.ExportInterface[port: uniqueSuffix];
info.myName ← [
type: "ThSmarts.Lark",
instance: VoiceUtilsExtras.RopeFromSunAddr[port: uniqueSuffix],
version: ThVersions.FinchVR]; -- Sun RPC code doesn't use this version yet
info.myRName ← VoiceUtils.CurrentRName[];
info.myPassword ← VoiceUtils.CurrentPasskey[];
Now connect to server and register with Thrush
info.shh ← ThPartySunRPControl.ThrushConnect[
server: thrushInstance, rName: info.myRName, type: $individual,
interface: info.myName, properties: [$controller, VoiceUtils.OwnNetAddress[]],
reportState: ReportStateFromThPartyRPC, reportProblem: ReportProblemFromThPartyRPC];
TRUSTED { Process.Detach[FORK PollWaiter[info]]; };
};
UninitFinchSmarts: PUBLIC ENTRY PROC[disable: BOOLTRUE] = {
ENABLE UNWIND=>NULL;
UninitFinchSmartsInt[disable];
};
UninitFinchSmartsInt: INTERNAL PROC[disable: BOOLTRUE] = {
shhh: FinchSmarts.SHHHIF info#NIL THEN info.shh ELSE NIL;
IF shhh=NIL THEN RETURN;
ThPartySunRPControl.ThrushDisconnect[shhh, disable];
IF disable THEN ThPartySunRPControl.ReleaseConversation[shhh];
That's just a cleanliness, and I'm worried about not adequately recording the last Progress and Substitution reports as they drag in. Before putting this back, analyze some typical traffic flow and see what's needed. Perhaps the previous stuff should be put on a timer, then destroyed. Worry, if ever we don't destroy info and create a new one, about the possibility that old reports will encounter strange credentials. DCS, September 13, 1990 11:57:37 am PDT
};
FinchIsRunning: PUBLIC PROC
RETURNS [finchIsEnabled: BOOL�LSE, finchIsRunning: BOOL�LSE, voicePath: BOOL�LSE] = {
IF info=NIL THEN RETURN;
RETURN[info.enabled, info.connected, info.voicePath];
};
ClearInfo: ENTRY FinchSmarts.ReportSystemStateProc = {
ENABLE UNWIND => NULL;
IF connected OR info=NIL THEN RETURN;
FOR cs: LIST OF FinchSmarts.ConvDesc ← info.conversations, cs.rest WHILE cs#NIL DO
cs.first.clientData ← NIL;
cs.first.props ← NIL; -- probably unnecessary.
ENDLOOP;
info.conversations ← NIL;
};
Could be made part of ThPartyToThPartySunRPC, sort of.
nextSched: INT ← pd.pollDefault;
PollWaiter: ENTRY PROC[myInfo: FinchSmarts.FinchInfo] = {
ENABLE UNWIND => NULL;
nextSched ← pd.pollDefault;
WHILE myInfo = info DO
nextSched ← MIN[nextSched, pd.pollDefault];
TRUSTED { Process.SetTimeout[@myInfo.pollCondition, Process.SecondsToTicks[nextSched]]; };
WAIT info.pollCondition;
IF myInfo#info THEN RETURN;
IF info.nextScheduledCheck#0 THEN {
nextSched ← info.nextScheduledCheck; info.nextScheduledCheck ← 0; LOOP; }
ELSE nextSched ← nextSched + 30;
Ordinary case: received another CheckIn report before timeout.
IF ~info.enabled OR ~pd.doPollingTimeouts THEN LOOP;
Timeout occurred before next CheckIn report, and either we're disconnected or we've been told to worry if we haven't heard from the server (or it's been quite a while, we've been told not to worry, and we're paranoid. Calling any ThParty function will either succeed or the failure will trigger the best available recovery activities.
[] ← ThParty.CheckIn[shh: info.shh, credentials: [
partyID: info.partyID, smartsID: info.smartsID, convID: Thrush.nullConvID]];
ENDLOOP;
};
State report, error management routines.
ReportSystemStateToFinchClients: PROC [r: REF] ~ {
reportProcsTable: RedBlackTree.Table ← NARROW[Atom.GetProp[$ReportProcs, $rpTable]];
EachRSS: RedBlackTree.EachNode = {
procs: FinchSmarts.ReportProcs ← NARROW[data];
IF procs.reportSystemState#NIL THEN
procs.reportSystemState[info.enabled, info.connected, info.voicePath];
};
IF reportProcsTable#NIL THEN
FinchSmarts.EnumerateIncreasing[reportProcsTable, EachRSS];
};
RecordSystemStateFromSmartsReport: PUBLIC INTERNAL PROC[
nb: NB, remark: Rope.ROPE, connected: BOOL, enabled: BOOL, voicePath: BOOL, remoteRemark: Rope.ROPE ]
RETURNS[echoNB: NB] -- A convenience for callers -- = {
IF info.shh#NIL THEN
ThPartySunRPControl.ThrushReportState[info.shh, enabled, connected];
RETURN[RecSS[nb, remark, connected, enabled, voicePath, remoteRemark]];
};
ReportProblemFromThPartyRPC: --already ENTRY-- ThPartySunRPControl.ReportProblem ~ {
[]←RecSS[nb: ec, remark: expl];
};
ReportStateFromThPartyRPC: --already ENTRY-- ThPartySunRPControl.ReportState ~ {
IF info#NIL THEN {
info.partyID ← myPartyID;
info.smartsID ← mySmartsID;
};
[]←RecSS[connected: registered, enabled: enabled];
};
Generalized reporting utility
RecSS: --may be INTERNAL-- PROC[
nb: NBNIL,
remark: Rope.ROPENIL,
connected: BOOL←info.connected,
enabled: BOOL←info.enabled,
voicePath: BOOL←info.voicePath,
remoteRemark: Rope.ROPENIL
]
RETURNS[echoNB: NB] -- A convenience for callers -- = {
IF nb#NIL OR connected#info.connected OR enabled#info.enabled THEN {
IF nb#NIL THEN FinchSmarts.Problem[remark, nb]
ELSE IF remark#NIL THEN VoiceUtils.Report[remark, $Finch];
};
info.connected ← connected;
info.enabled ← enabled;
info.voicePath ← voicePath;
pd.requests.QueueClientAction[ReportSystemStateToFinchClients, NIL];
IF remoteRemark#NIL THEN {
Relate each distinct remote remark exactly once.
IF info=NIL OR ~remoteRemark.Equal[info.lastRemoteRemark]
THEN VoiceUtils.Report[remoteRemark, $Finch];
IF info#NIL THEN info.lastRemoteRemark ← remoteRemark;
};
RETURN[nb];
};
More state reporting code.
RegisterForReports: PUBLIC ENTRY PROC [key: ATOM, s: FinchSmarts.ReportSystemStateProc ← NIL, c: FinchSmarts.ReportConversationStateProc ← NIL, r: FinchSmarts.ReportRequestStateProc ← NIL, other: ATOMNIL, before: BOOLTRUE] = {
ENABLE UNWIND => NULL;
RegisterForReportsInt[key, s, c, r, other, before]; };
RegisterForReportsInt: INTERNAL PROC [key: ATOM, s: FinchSmarts.ReportSystemStateProc ← NIL, c: FinchSmarts.ReportConversationStateProc ← NIL, r: FinchSmarts.ReportRequestStateProc ← NIL, other: ATOMNIL, before: BOOLTRUE] = {
lowPos: INT ← 0;
highPos: INTLAST[INT]/2;
newPos: INT;
oldPos: INT;
newProcs: FinchSmarts.ReportProcs ←
NEW[FinchSmarts.ReportProcsBody ← [key, 0, s, c, r, TRUE]];
oldProcs: FinchSmarts.ReportProcs ← NARROW[Atom.GetProp[$ReportProcs, key]];
reportProcsTable: RedBlackTree.Table ← NARROW[Atom.GetProp[$ReportProcs, $rpTable]];
IF reportProcsTable=NIL THEN {
reportProcsTable ← RedBlackTree.Create[getKey: RPGetKey, compare: RPCompare];
Atom.PutProp[$ReportProcs, $rpTable, reportProcsTable];
};
IF oldProcs#NIL THEN {
newProcs.position ← oldProcs.position; oldProcs^ ← newProcs^; RETURN; };
IF other=$all THEN newPos ← IF before THEN lowPos ELSE highPos
ELSE {
neighborProcs: FinchSmarts.ReportProcs;
IF other#NIL THEN {
oldProcs ← NARROW[Atom.GetProp[$ReportProcs, other]];
IF oldProcs=NIL THEN ERROR; -- nothing to be before or after
}
ELSE oldProcs ← NARROW[RedBlackTree.LookupNextLarger[reportProcsTable, newProcs]];
oldPos ← IF oldProcs=NIL THEN highPos ELSE oldProcs.position;
newProcs.position ← oldPos;
IF before THEN {
highPos ← oldPos;
neighborProcs ← NARROW[RedBlackTree.LookupNextSmaller[reportProcsTable,newProcs]];
IF neighborProcs#NIL THEN lowPos ← neighborProcs.position;
}
ELSE {
lowPos ← oldPos;
neighborProcs ← NARROW[RedBlackTree.LookupNextLarger[reportProcsTable,newProcs]];
IF neighborProcs#NIL THEN highPos ← neighborProcs.position;
};
newPos ← (lowPos+highPos)/2;
};
newProcs.position ← newPos;
Atom.PutProp[$ReportProcs, key, newProcs];
RedBlackTree.Insert[reportProcsTable, newProcs, newProcs];
};
UnRegisterForReports: PUBLIC ENTRY PROC [key: ATOM] = {
ENABLE UNWIND => NULL;
procs: FinchSmarts.ReportProcs ← NARROW[Atom.GetProp[$ReportProcs, key]];
IF procs#NIL THEN procs.enabled ← FALSE;
};
RPGetKey: RedBlackTree.GetKey = { RETURN[data]; };
RPCompare: RedBlackTree.Compare = {
kv: INTNARROW[k, FinchSmarts.ReportProcs].position;
dv: INTNARROW[data, FinchSmarts.ReportProcs].position;
RETURN[IF kv<dv THEN less ELSE IF kv>dv THEN greater ELSE equal];
};
instanceSuffix: Rope.ROPENARROW[Atom.GetProp[$ReportProcs, $instanceSuffix]];
uniqueSuffix ← IF instanceSuffix=NIL THEN 1 ELSE Convert.CardFromRope[instanceSuffix]+1;
Atom.PutProp[$ReportProcs, $instanceSuffix, Convert.RopeFromCard[uniqueSuffix]];
END.
Polle Zellweger (PTZ) May 18, 1990 9:26:23 pm PDT
changes to: DIRECTORY, FinchRegisterTest, thrushHost, FinchRegister
Polle Zellweger (PTZ) May 18, 1990 9:31:08 pm PDT
changes to: DIRECTORY, FinchRegisterTest, thrushHost, FinchRegister, END
Polle Zellweger (PTZ) May 18, 1990 10:03:06 pm PDT
changes to: FinchRegisterTestImpl, DIRECTORY, thrushHost
Polle Zellweger (PTZ) June 26, 1990 2:27:19 pm PDT
changes to: DIRECTORY, FinchRegisterTestImpl, FinchRegister
Polle Zellweger (PTZ) July 5, 1990 4:23:52 pm PDT
Must use Pup address for $controller property; otherwise server can't find assoc Etherphone.
changes to: FinchRegister
Swinehart, September 8, 1990 6:54:19 pm PDT
Renamed from FinchRegisterTestImpl; simplified; adapted to new error management code in ThPartySunRPControl.
changes to: everything