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 ], 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, RopeFromSunAddr ] ; FinchRegisterImpl: CEDAR MONITOR LOCKS FinchSmarts.lock IMPORTS Atom, Convert, FinchSmarts, MBQueue, Process, RedBlackTree, Rope, ThParty, ThPartySunRPControl, ThSmartsSunExport, ThVersions, UserProfile, VoiceUtils EXPORTS FinchSmarts ~ BEGIN OPEN IO, FinchSmarts; NB: TYPE = Thrush.NB; uniqueSuffix: CARD ¬ 0; InitFinchSmarts: PUBLIC ENTRY PROC [ thrushInstance: Thrush.ROPE¬NIL, key: ATOM, s: FinchSmarts.ReportSystemStateProc ¬ NIL, c: FinchSmarts.ReportConversationStateProc ¬ NIL, r: FinchSmarts.ReportRequestStateProc ¬ NIL] = { ENABLE UNWIND => NULL; problem: ROPE¬NIL; 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]; RegisterForReportsInt[key: key, s: s, c: c, r: r]; thrushInstance ¬ SELECT 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: VoiceUtils.RopeFromSunAddr[port: uniqueSuffix], version: ThVersions.FinchVR]; -- Sun RPC code doesn't use this version yet info.myRName ¬ VoiceUtils.CurrentRName[]; info.myPassword ¬ VoiceUtils.CurrentPasskey[]; 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: BOOL¬TRUE] = { ENABLE UNWIND=>NULL; UninitFinchSmartsInt[disable]; }; UninitFinchSmartsInt: INTERNAL PROC[disable: BOOL¬TRUE] = { shhh: FinchSmarts.SHHH ¬ IF info#NIL THEN info.shh ELSE NIL; IF shhh=NIL THEN RETURN; ThPartySunRPControl.ThrushDisconnect[shhh, disable]; }; FinchIsRunning: PUBLIC PROC RETURNS [finchIsEnabled: BOOL¬FALSE, finchIsRunning: BOOL¬FALSE, voicePath: BOOL¬FALSE] = { 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; }; 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; IF ~info.enabled OR ~pd.doPollingTimeouts THEN LOOP; [] ¬ ThParty.CheckIn[shh: info.shh, credentials: [ partyID: info.partyID, smartsID: info.smartsID, convID: Thrush.nullConvID]]; ENDLOOP; }; 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]; }; RecSS: --may be INTERNAL-- PROC[ nb: NB¬NIL, remark: Rope.ROPE¬NIL, connected: BOOL¬info.connected, enabled: BOOL¬info.enabled, voicePath: BOOL¬info.voicePath, remoteRemark: Rope.ROPE¬NIL ] 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 { IF info=NIL OR ~remoteRemark.Equal[info.lastRemoteRemark] THEN VoiceUtils.Report[remoteRemark, $Finch]; IF info#NIL THEN info.lastRemoteRemark ¬ remoteRemark; }; RETURN[nb]; }; RegisterForReports: PUBLIC ENTRY PROC [key: ATOM, s: FinchSmarts.ReportSystemStateProc ¬ NIL, c: FinchSmarts.ReportConversationStateProc ¬ NIL, r: FinchSmarts.ReportRequestStateProc ¬ NIL, other: ATOM¬NIL, before: BOOL ¬ TRUE] = { 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: ATOM¬NIL, before: BOOL ¬ TRUE] = { lowPos: INT ¬ 0; highPos: INT ¬ LAST[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: INT ¬ NARROW[k, FinchSmarts.ReportProcs].position; dv: INT ¬ NARROW[data, FinchSmarts.ReportProcs].position; RETURN[IF kvdv THEN greater ELSE equal]; }; instanceSuffix: Rope.ROPE ¬ NARROW[Atom.GetProp[$ReportProcs, $instanceSuffix]]; uniqueSuffix ¬ IF instanceSuffix=NIL THEN 1 ELSE Convert.CardFromRope[instanceSuffix]+1; Atom.PutProp[$ReportProcs, $instanceSuffix, Convert.RopeFromCard[uniqueSuffix]]; END. ˜ FinchRegisterImpl.mesa Copyright Σ 1990, 1992 by Xerox Corporation. All rights reserved. Polle Zellweger (PTZ) August 1, 1990 4:53:55 pm PDT Swinehart, June 4, 1992 9:44 pm PDT Activities associated with connection, registering, reporting, error management, and the like. Still some concerns about the locking requirements of the back-reporting stuff!! NameDB USING [ GetAttribute ], High-level registration code, keep-alive code. Must be the very last thing Now connect to server and register with Thrush 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 Could be made part of ThPartyToThPartySunRPC, sort of. Ordinary case: received another CheckIn report before timeout. 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. State report, error management routines. Generalized reporting utility Relate each distinct remote remark exactly once. More state reporting code. 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 Κ ͺ•NewlineDelimiter –(cedarcode) style™šœ™Jšœ Οeœ7™BIcode™3K™#K™K™^K™KšΟtœPž™R—K˜šΟk ˜ KšœŸœ˜ KšœŸœ ˜-Kšœ ŸœΖ˜ΧKšŸœ˜KšœŸœ˜$JšœŸœ™KšœŸœ(˜5Kšœ Ÿœ[˜mKšœŸœ Ÿœ˜KšŸœŸœ˜K˜KšœŸœT˜mKšœ˜KšœŸœ˜,Kšœ Ÿœ ˜Kšœ Ÿœ ˜Kšœ ŸœI˜YK˜K˜—šΠlnœŸœŸœŸœ˜7šŸ˜K˜–—KšŸœ ˜KšœŸ˜KšŸœŸœ˜K˜KšŸœŸœ Ÿœ˜KšœŸœ˜—K˜™.K˜šΟnœŸœŸœŸœ˜$KšΡbosœ ŸœŸœ˜ Kš’œŸœ˜ Kš’œ&Ÿœ˜+Kš’œ,Ÿœ˜1Kš’œ'Ÿœ˜0KšŸœŸœŸœ˜Kšœ ŸœŸœŸœ ˜&K˜'K˜KšŸœŸœŸœŸœ˜;KšΠboœŸœΟc˜;KšŸœ ŸœŸœŸœ˜3KšœŸœ˜K˜Kšœ£ œœŸœ˜šœ)£œ"Ÿœ˜SJ™—Kšœ £œ£œ£œ˜2K˜š£œŸœŸœŸ˜!KšœŸœŸœ˜%Kšœ ŸœŸœŸœ ˜PKšŸœA˜H—Kšœ£œ˜)K˜Ešœ£œ˜K˜K˜9Kšœ€,˜K—Kšœ£œ˜)Kšœ£ œ˜.K˜™.šœ£œ$˜-Kšœ?˜?KšœN˜NKšœT˜T——K˜KšŸœŸœ˜3K˜K˜—š ‘œŸœŸœŸœ ŸœŸœ˜—KšŸœŸœŸœŸœ˜4J™Ο˜2KšœL˜L—KšŸœ˜—K˜—K˜—™(K˜š‘œŸœŸœ˜2Kšœ'Ÿœ'˜Tš‘œ˜"Kšœ!Ÿœ˜.šŸœŸœŸ˜#KšœF˜F—K˜—šŸœŸœŸ˜Kšœ;˜;—K˜K˜—š‘!œŸœŸœŸœ˜8Kš œŸœŸœ Ÿœ Ÿœ ŸœŸœ˜eKšŸœ Ÿœ€œ˜7šŸœ ŸœŸ˜KšœD˜D—KšŸœA˜GK˜K˜—š‘œŸœ&˜TKšžœž˜K˜K˜—š‘œŸœ$˜PšŸœŸœŸœ˜K˜K˜K˜—Kšžœž/˜2K˜K˜—K™š‘œ€œŸœ˜ KšœŸœŸœ˜ Kšœ ŸœŸœ˜Kšœ Ÿœ˜Kšœ Ÿœ˜Kšœ Ÿœ˜KšœŸœŸ˜Kšœ˜KšŸœ Ÿœ€œ˜7š ŸœŸœŸœŸœŸœ˜DKšŸœŸœŸœ ˜.KšŸœŸœŸœŸœ#˜:K˜—K˜K˜K˜Kšœ?Ÿœ˜DšŸœŸœŸœ˜K™0šŸœŸœŸœ+˜9KšŸœ)˜-—KšŸœŸœŸœ&˜6K˜—KšŸœ˜ K˜—K˜—™K˜š‘œŸœŸœŸœŸœΟr œŸœ₯ œŸœ₯ œŸœ ŸœŸœ ŸœŸœ˜ζKšŸœŸœŸœ˜Kšœ6˜6K˜—š‘œŸœŸœŸœ₯ œŸœ₯ œŸœ₯ œŸœ ŸœŸœ ŸœŸœ˜εKšœŸœ˜Kšœ ŸœŸœŸœ˜KšœŸœ˜ KšœŸœ˜ ˜#KšŸœ1Ÿœ˜;—Kšœ$Ÿœ"˜LKšœ'Ÿœ'˜TšŸœŸœŸœ˜K˜MKšœ7˜7K˜—šŸœ ŸœŸœ˜Kšœ>Ÿœ˜H—Kš Ÿœ Ÿœ ŸœŸœŸœ˜>šŸœ˜Kšœ'˜'šŸœŸœŸœ˜Kšœ Ÿœ$˜5Kš Ÿœ ŸœŸœŸœ€ ˜