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 ], 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; 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: VoiceUtilsExtras.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 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!! 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 Κ ·– "cedar" style•NewlineDelimiter ™Jšœ™šœ<™—Jšžœžœžœžœ˜4J™Οšœ2˜2JšœL˜L—Jšžœ˜—J˜—J˜—™(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š2˜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˜—™J˜š œžœžœžœžœΟr œžœ€ œžœ€ œžœ žœžœ žœžœ˜ζJšžœžœžœ˜Jšœ6˜6J˜—š œžœžœžœ€ œžœ€ œžœ€ œžœ žœžœ žœžœ˜εJšœžœ˜Jšœ žœžœžœ˜Jšœžœ˜ Jšœžœ˜ šœ#˜#Jšžœ1žœ˜;—Jšœ$žœ"˜LJšœ'žœ'˜Tšžœžœžœ˜J˜MJšœ7˜7J˜—šžœ žœžœ˜Jšœ>žœ˜H—Jš žœ žœ žœžœžœ˜>šžœ˜Jšœ'˜'šžœžœžœ˜Jšœ žœ$˜5Jš žœ žœžœžœ£ ˜