PhRegisterImpl.mesa
Copyright Ó 1990, 1992 by Xerox Corporation. All rights reserved.
Vin, September 25, 1990 5:40 pm PDT
Swinehar, October 1, 1992 4:09 pm PDT
DIRECTORY
IO USING [ atom, rope ],
PhSmarts USING [ lock, PhoenixInfo, PhoenixInfoBody, phoenixInfo, pd, SHHH ],
Process USING [ Detach, SecondsToTicks, SetTimeout ],
Rope USING [ Equal, ROPE ],
ThParty,
ThPartySunRPControl USING [ ReportProblem, ReportState, ThrushConnect, ThrushDisconnect, ThrushReportState ],
Thrush,
ThSmartsSunExport USING [ ExportInterface ],
UserProfile USING [ Token ],
VoiceUtils USING [ CurrentRName, CurrentPasskey, OwnNetAddress, Problem, ProblemFR, Report, RopeFromSunAddr ]
;
PhRegisterImpl: CEDAR MONITOR LOCKS PhSmarts.lock
IMPORTS IO, PhSmarts, Process, Rope, ThParty, ThPartySunRPControl, ThSmartsSunExport, UserProfile, VoiceUtils
EXPORTS PhSmarts
~ BEGIN
OPEN PhSmarts;
NB: TYPE = Thrush.NB;
ROPE: TYPE = Rope.ROPE;
uniqueSuffix: CARD ¬ 0;
InitPhoenixSmarts: PUBLIC ENTRY PROC [
thrushInstance: Thrush.ROPE¬NIL
] = {
ENABLE UNWIND => NULL;
problem: ROPE¬NIL; nb: NB¬$serverDown;
prevInfo: PhSmarts.PhoenixInfo ¬ PhSmarts.phoenixInfo;
IF phoenixInfo#NIL AND phoenixInfo.connected THEN UnInitPhoenixSmartsInt[];
phoenixInfo ¬ NEW[PhSmarts.PhoenixInfoBody]; -- Dump any old one!
IF prevInfo#NIL THEN NOTIFY prevInfo.pollCondition;
phoenixInfo.conversations ¬ NIL;
phoenixInfo.connected ¬ FALSE;
thrushInstance ¬ SELECT TRUE FROM
thrushInstance#NIL => thrushInstance,
prevInfo#NIL AND prevInfo.prevThrushInstance#NIL => prevInfo.prevThrushInstance,
ENDCASE=> UserProfile.Token["ThrushSunClientServerInstance", "Growler"];
phoenixInfo.prevThrushInstance ¬ thrushInstance;
uniqueSuffix ¬ ThSmartsSunExport.ExportInterface[port: uniqueSuffix];
phoenixInfo.myName ¬ [
type: "ThSmarts.Lark",
instance: VoiceUtils.RopeFromSunAddr[port: uniqueSuffix]];
phoenixInfo.myRName ¬ VoiceUtils.CurrentRName[];
phoenixInfo.myPassword ¬ VoiceUtils.CurrentPasskey[];
Now connect to server and register with Thrush
phoenixInfo.shh ¬ ThPartySunRPControl.ThrushConnect[
server: thrushInstance, rName: phoenixInfo.myRName, type: $telephone,
interface: phoenixInfo.myName, properties: [role: $voiceTerminal, netAddress: VoiceUtils.OwnNetAddress[]], reportState: ReportStateFromThPartyRPC, reportProblem: ReportProblemFromThPartyRPC];
TRUSTED { Process.Detach[FORK PollWaiter[phoenixInfo]]; };
};
UnInitPhoenixSmarts: PUBLIC ENTRY PROC[disable: BOOL¬TRUE] = {
ENABLE UNWIND=>NULL;
UnInitPhoenixSmartsInt[disable];
};
UnInitPhoenixSmartsInt: INTERNAL PROC[disable: BOOL¬TRUE] = {
shhh: PhSmarts.SHHH ¬ IF phoenixInfo#NIL THEN phoenixInfo.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 phoenixInfo and create a new one, about the possibility that old reports will encounter strange credentials. DCS, September 13, 1990 11:57:37 am PDT
};
PhoenixIsRunning: PUBLIC PROC
RETURNS [phoenixIsEnabled: BOOL¬FALSE, phoenixIsRunning: BOOL¬FALSE] = {
IF phoenixInfo=NIL THEN RETURN;
RETURN[phoenixInfo.enabled, phoenixInfo.connected];
};
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 phoenixInfo.shh#NIL THEN
ThPartySunRPControl.ThrushReportState[phoenixInfo.shh, enabled, connected];
RETURN[RecSS[nb, remark, connected, enabled, voicePath, remoteRemark]];
};
nextSched: INT ¬ pd.pollDefault;
PollWaiter: ENTRY PROC[myInfo: PhSmarts.PhoenixInfo] = {
ENABLE UNWIND => NULL;
nextSched ¬ pd.pollDefault;
WHILE myInfo = phoenixInfo DO
nextSched ¬ MIN[nextSched, pd.pollDefault];
TRUSTED { Process.SetTimeout[@myInfo.pollCondition, Process.SecondsToTicks[nextSched]]; };
WAIT phoenixInfo.pollCondition;
IF myInfo#phoenixInfo THEN RETURN;
IF phoenixInfo.nextScheduledCheck#0 THEN {
nextSched ¬ phoenixInfo.nextScheduledCheck; phoenixInfo.nextScheduledCheck ¬ 0; LOOP; }
ELSE nextSched ¬ nextSched + 30;
Ordinary case: received another CheckIn report before timeout.
IF ~phoenixInfo.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: phoenixInfo.shh, credentials: [
partyID: phoenixInfo.partyID, smartsID: phoenixInfo.smartsID, convID: Thrush.nullConvID]];
ENDLOOP;
};
ReportProblemFromThPartyRPC: --already ENTRY-- ThPartySunRPControl.ReportProblem ~ {
[]¬RecSS[nb: ec, remark: expl];
};
ReportStateFromThPartyRPC: --already ENTRY-- ThPartySunRPControl.ReportState ~ {
IF phoenixInfo#NIL THEN {
phoenixInfo.partyID ¬ myPartyID;
phoenixInfo.smartsID ¬ mySmartsID;
};
[]¬RecSS[connected: registered, enabled: enabled];
};
Poke: PUBLIC ENTRY PROC = {
ENABLE UNWIND => NULL;
IF phoenixInfo#NIL THEN NOTIFY phoenixInfo.pollCondition; };
Polling loop will awaken immediately and if necessary (and not inhibited) try to reconnect.
Generalized reporting utility
RecSS: --may be INTERNAL-- PROC[
nb: NB¬NIL,
remark: Rope.ROPE¬NIL,
connected: BOOL¬phoenixInfo.connected,
enabled: BOOL¬phoenixInfo.enabled,
voicePath: BOOL¬FALSE,
remoteRemark: Rope.ROPE¬NIL
]
RETURNS[echoNB: NB] -- A convenience for callers -- = {
IF nb#NIL OR connected#phoenixInfo.connected OR enabled#phoenixInfo.enabled THEN {
IF nb#NIL THEN NBProblem[remark, nb]
ELSE IF remark#NIL THEN VoiceUtils.Report[remark, $Finch];
};
phoenixInfo.connected ¬ connected;
phoenixInfo.enabled ¬ enabled;
pd.requests.QueueClientAction[ReportSystemStateToFinchClients, NIL];
IF remoteRemark#NIL THEN {
Relate each distinct remote remark exactly once.
IF phoenixInfo=NIL OR ~remoteRemark.Equal[phoenixInfo.lastRemoteRemark]
THEN VoiceUtils.Report[remoteRemark, $Finch];
IF phoenixInfo#NIL THEN phoenixInfo.lastRemoteRemark ¬ remoteRemark;
};
RETURN[nb];
};
NBProblem: PROC[remark: ROPE¬NIL, nb: NB¬NIL] = {
IF nb=NIL THEN VoiceUtils.Problem[remark, $Finch]
ELSE VoiceUtils.ProblemFR["%g, reason: %g", $Finch, NIL, IO.rope[remark], IO.atom[nb]];
};
END.