DIRECTORY Process USING [ Detach, EnableAborts, SecondsToTicks, SetTimeout ], Log USING [ ProblemBool, SLOG ], RPC USING [ CallFailed ], SafeStorage USING [ GetCanonicalType, Type ], ThParty USING [ Deregister ], ThPartyMonitorImpl, ThPartyPrivate USING [ CFRef, ConversationBody, ConversationData, DestroyConversation, Distribute, DistributionProc, GetEvent, PartyBody, PartyData, recordingRAtom, Verify ], Thrush USING [ ConversationHandle, ConvEvent, Credentials, Disposition, EventSequence, EventSequenceBody, H, HandleFault, KillHandle, MakeUnique, NB, Priorities, SHHH, StateID, ThHandle ], Triples USING [ Any, Erase, Foreach, ForeachProc, Select ] ; ThPartySupervisorImpl: CEDAR MONITOR LOCKS root IMPORTS Log, Process, root: ThPartyMonitorImpl, RPC, SafeStorage, --SpyLog,-- Thrush, ThParty, ThPartyPrivate, Triples EXPORTS ThPartyPrivate SHARES ThPartyMonitorImpl = { CFRef: TYPE = ThPartyPrivate.CFRef; ConversationData: TYPE = ThPartyPrivate.ConversationData; RTConvType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[ThPartyPrivate.ConversationBody]]; ConvEvent: TYPE = Thrush.ConvEvent; Credentials: TYPE = Thrush.Credentials; H: PROC[r: REF] RETURNS [Thrush.ThHandle] = INLINE { RETURN[LOOPHOLE[Thrush.H[r]]]; }; NB: TYPE = Thrush.NB; PartyData: TYPE = ThPartyPrivate.PartyData; RTPartyType: SafeStorage.Type = SafeStorage.GetCanonicalType[CODE[ThPartyPrivate.PartyBody]]; StateID: TYPE = Thrush.StateID; maxSpvrInterval: NAT _ 10; Supervisor: PUBLIC PROC[ party: PartyData ] = { event: ConvEvent; toDo, failing, latest: BOOL_FALSE; informationOnly: BOOLEAN_FALSE; Inform: ThPartyPrivate.DistributionProc = { ENABLE RPC.CallFailed => { smarts.canProgress_FALSE; ThParty.Deregister[smartsID: H[smarts]]; RETRY; }; yourParty: BOOL = event.credentials.partyID=H[party]; d_pass; IF ~smarts.canProgress THEN RETURN; IF event.keyTable=NIL AND event.intervalSpec=NIL AND (NOT yourParty) AND (event.state#initiating) THEN RETURN; -- don't report uninteresting events SELECT (d _ smarts.interface.Progress[shh: smarts.shh, smartsID: H[smarts], informationOnly: informationOnly, yourParty: yourParty, event: event, latestEvent: latest ]) FROM actedAndPass => informationOnly_TRUE; willAlwaysPassThisRequest => smarts.canProgress_FALSE; ENDCASE; }; TRUSTED { Process.EnableAborts[@party.actionNeeded]; Process.SetTimeout[@party.actionNeeded, Process.SecondsToTicks[maxSpvrInterval]]; }; DO ENABLE ABORTED => { party.partyFailed _ TRUE; CONTINUE; }; [ event, toDo, latest ] _ ScanPostOrWait[party]; informationOnly _ FALSE; IF toDo THEN []_ThPartyPrivate.Distribute[party: party, proc: Inform] ELSE IF failing THEN EXIT ELSE IF party.partyFailed THEN failing_TRUE -- one more pass to clean up! ELSE IF party.supervisor=NIL THEN RETURN; -- vanish to keep local frames to minimum. ENDLOOP; EndParty[party]; }; Supervise: PUBLIC INTERNAL PROC[party: PartyData] = TRUSTED { IF party.supervisor=NIL THEN Process.Detach[party.supervisor _ FORK Supervisor[party]]; NOTIFY party.actionNeeded; -- Spurious if process just spawned? }; ScanPostOrWait: ENTRY PROC[ party: PartyData ] RETURNS [ event: ConvEvent, toDo: BOOL_FALSE, latest: BOOL ] = { ENABLE UNWIND => NULL; Scanner: INTERNAL Triples.ForeachProc = TRUSTED { conv: ConversationData; WITH trip.att SELECT FROM r: CFRef => { cfRef: CFRef_NIL; conv _ NARROW[trip.obj]; IF r.lastNotedID RETURN[FALSE]; actedAndPass, pass, willAlwaysPassThisRequest => RETURN[TRUE]; ENDCASE=> RETURN[Log.ProblemBool[ remark: "Invalid distribute return code", where: $System, bool: TRUE]]; }; Triples.Foreach[priority, party, Triples.Any, DistOne]; IF d=actedAndStop THEN RETURN; ENDLOOP; ENDLOOP; }; Dissolve: INTERNAL PROC[cfRef: CFRef, conv: ConversationData, party: PartyData] = { IF cfRef.event.state#idle THEN RETURN; Triples.Erase[cfRef, conv, party]; conv.numParties _ conv.numParties-1; party.numConvs _ party.numConvs-1; IF conv.numParties=0 THEN ThPartyPrivate.DestroyConversation[conv]; TRUSTED { WITH p: party SELECT FROM trunk => { p.outgoing _ NIL; Triples.Erase[$RnameForTrunk, party, Triples.Any]; }; recording => Thrush.MakeUnique[$RnameForParty, party, ThPartyPrivate.recordingRAtom]; ENDCASE; }; }; EndParty: ENTRY PROC[party: PartyData] = { Thrush.KillHandle[H[party], RTPartyType!Thrush.HandleFault=>CONTINUE]; Triples.Erase[Triples.Any, party, Triples.Any]; party.supervisor _ NIL; }; GetHistory: PUBLIC ENTRY PROC[ shhh: Thrush.SHHH, credentials: Credentials, firstState: StateID, lastState: StateID -- default: get latest ] RETURNS [ nb: Thrush.NB, events: Thrush.EventSequence_NIL ] = { ENABLE UNWIND => NULL; conv: ConversationData; numStates: NAT; [conv, , , nb] _ ThPartyPrivate.Verify[credentials]; IF nb#success OR conv=NIL OR conv.currentStateID=0 THEN RETURN; IF lastState=0 OR lastState>conv.currentStateID THEN lastState_conv.currentStateID; SELECT firstState FROM <1 => firstState_1; >conv.currentStateID => RETURN; ENDCASE; IF lastState> Perform distribution in order of this Party's priorities <> Distribute to all Smarts at this priority level. If Post generates new work to do, stop and do it, then cycle again. Post is probably the wrong word for this activity, now. But the work needs doing. When a trunk party leaves a conversation, it loses its identity (<< something wrong here? >>) When a recording party leaves, it reverts to available. �ÊܘJšœ™Jšœ8™8J˜šÏk ˜ Jšœ�œ6˜CJšœ�œ�œ˜ Jš�œ�œ˜J˜-Jšœ�œ˜Jšœ˜šœ�œ˜Jšœ—˜——Jš œ�œ^�œ'�œ�œ˜¼Jšœ�œ-˜:J˜J˜—šœ� œ�œ˜/š�˜J˜Jšœ˜J˜Jš�œ˜J˜ JšÏc ˜ Jšœ˜J˜Jšœ˜Jšœ˜—Jš�œ˜Jš�œ˜J˜—J™™Jšœ�œ˜#šœ�œ#˜9Jšœ<�œ#˜c—Jšœ �œ˜#Jšœ �œ˜'Jšœ�œ�œ�œ�œ�œ�œ�œ ˜VJš�œ�œ �œ˜šœ �œ˜+Jšœ=�œ˜]—J˜J˜—™J™Jšœ�œ˜J˜—™'J™šÏn œ� œ˜/Jšœ˜Jšœ� œ˜"Jšœ�œ�œ˜J˜šŸœ%˜+Jš�œ�œ™<š�œ�œ˜Jšœ�œ˜Jšœ�œ ˜(Jš�œ˜ —Jšœ �œ�œ˜5J˜Jš�œ�œ�œ˜$š �œ�œ�œ�œ�˜4Jš œ�œ �œ�œ�œž%˜_—š�œE˜KJšœ7˜7šœ%�˜)Jšœ!�œ˜&Jšœ1�œ˜7Jš�œ˜ ——Jšœ˜J˜—š�œ˜ J˜*J˜QJ˜—š�˜Jš�œ�œ�œ˜:Jšœ0˜0J™¬Jšœ�œ˜Jš�œ�œ9˜EJš�œ�œ �œ�˜Jš �œ�œ�œ �œž˜IJš �œ�œ�œ�œ�œž*˜TJš�œ˜—J˜J˜—J˜š Ÿ œ�œ�œ�œ�œ˜>š�œ�œ�˜Jšœ"�œ˜:—Jš�œž$˜?J˜J˜—šŸœ�œ�œ˜.Jš�œ�œ�œ �œ˜@Jš�œ�œ�œ˜šœ �œ�œ˜1Jš�œ�œ � ™6J˜š�œ �œ�˜šœ ˜ Jšœ �œ˜Jšœ�œ ˜Jš�œ#�œ ˜3Jš�œ�œ�œ˜9š�œ�œ�œ˜Jšœ(˜(Jšœ�œ˜ šœ˜Jšœ(�œ(˜R—Jšœ9˜9Jšœ�œ˜ Jš�œ�œ˜Jšœ˜—Jšœ˜—Jš�œ˜—Jšœ˜—Jšœ:˜:š�œ�œ�˜$Jš �œ�œ�œ�œ�œ˜K—Jšœ˜J˜—šœH™HšŸ œ�œ�œ;˜RJš�œ#˜*J˜Jš�œ �œ�œ�œ˜!Jšœ �œ$žœ˜KJšœ8™8š �œ!�œ$žœ�œ �œ�˜‡J™(š �œ$�œ'�œ�œ�˜nJšœ �œ�œ˜-šŸœ˜ Jšœ�œ ˜#š�œ�˜ Jšœ�œ˜Jšœ1� œ˜>š�œ�œ˜!Jšœ@�œ˜G——Jšœ˜—Jšœ0™0Jšœ7˜7Jš �œ�œ�œ�œ�œ˜3——J˜—J˜—šŸœ�œ�œ<˜SJ™CJ™RJš�œ�œ�œ˜&J˜"J˜$J˜"Jš�œ�œ*˜CJ™]J™7š�œ�œ �œ�˜#Jšœ�œ7˜RJ˜UJš�œ˜J˜—Jšœ˜—J˜šŸœ�œ�œ˜*Jšœ�œ)�œ˜FJ˜/Jšœ�œ˜Jšœ˜J˜—šŸ œ�œ�œ�œ˜Jšœ �œ˜Jšœ˜J˜Jšœž˜)Jšœ�œ�œ�œ˜AJš�œ�œ�œ˜J˜Jšœ �œ˜Jšœ4˜4Jš �œ �œ�œ�œ�œ�œ˜?Jš�œ �œ�œ˜Sš�œ �˜J˜Jšœ�œ˜Jš�œ˜—Jš�œ�œ�œ˜$J˜#Jšœ�œ&˜0Jš �œ�œ�œ�œ%�œ˜O—J˜—J˜—…—°$^