FingerSimpleOpsImpl.mesa
Carl Hauser, January 9, 1987 11:16:18 am PST
DIRECTORY
BasicTime USING [GMT, Now],
Booting,
FingerLog,
FingerOps,
FingerSimpleOps,
Idle USING [IdleReason, IdleHandler, RegisterIdleHandler],
Process USING [Detach],
RemoteFingerOps,
RemoteFingerOpsRpcControl,
Rope USING [ROPE],
RPC,
RPCLupineExtras,
ThisMachine USING [Address, Name],
UserCredentials USING [Get],
UserProfile;
FingerSimpleOpsImpl: CEDAR MONITOR
IMPORTS
BasicTime, Booting, FingerLog, Idle, Process, RemoteFingerOps, RemoteFingerOpsRpcControl, RPC, ThisMachine, UserCredentials, UserProfile
EXPORTS
FingerOps, FingerSimpleOps =
BEGIN
OPEN FingerOps, FingerLog;
idle: BOOLFALSE;
is the machine in the idle state; if so, don't bother connecting to the database to save any log entries made (just collect them and replay them when you come out of idle)
The name of the machine currently running Finger
thisMachine: Rope.ROPE ← ThisMachine.Name[$Pup];
The name of the machine to look for a Finger server on
serverMachine: Rope.ROPE;
stateLog: LIST OF LogEntry ← NIL;
bound: BOOLFALSE;
ImportPlayProc: PROC [host: Rope.ROPENIL] ~ {
success: BOOLTRUE;
being careful not to make bound TRUE until it really is true.
RemoteFingerOpsRpcControl.ImportInterface[interfaceName: [instance: IF host = NIL THEN serverMachine ELSE host]
! RPC.ImportFailed => { success ← FALSE; CONTINUE }];
bound ← success;
};
PlayLog: INTERNAL PROC[] ~ { 
IF (stateLog # NIL) THEN {
IF NOT bound THEN ImportPlayProc[];
IF bound THEN {
ENABLE RPC.CallFailed => {bound ← FALSE; CONTINUE}; 
IF RemoteFingerOps.PlayLog[stateLog] THEN {
if this succeeds, then the contents of the log file can be thrown away, since they have all been played to the database
stateLog ← NIL;
FingerLog.FlushLog[]
};
};
};
};
AttemptToPlayLog: PUBLIC ENTRY PROC[] = {
ENABLE UNWIND => NULL;
PlayLog[] };
RegisterLoginOrLogout: ENTRY Idle.IdleHandler =
TRUSTED BEGIN
ENABLE UNWIND => NULL;
idle ← reason = becomingIdle;
InternalPutStateChange[IF idle THEN $logout ELSE $login, BasicTime.Now[]];
Process.Detach[FORK AttemptToPlayLog[]]
END;
PutStateChange: PUBLIC ENTRY PROC [change: FingerOps.StateChange, time: BasicTime.GMT] ~ {
record that the current user has logged off of this machine (entries are changed for both the user and the machine)
ENABLE UNWIND => NULL;
InternalPutStateChange[change, time];
IF NOT idle THEN PlayLog[] };
InternalPutStateChange: INTERNAL PROC [change: FingerOps.StateChange, time: BasicTime.GMT] ~ {
name: Rope.ROPE = UserCredentials.Get[].name;
DoLog[logEntry: NEW[StateChange LogEntryObject ← [StateChange[event: change, user: name, time: time, machine: thisMachine]]]];
};
DoLog: INTERNAL PROC[ logEntry: LogEntry ] = TRUSTED {
Write the entry on the log file and also on the internal log list
FingerLog.Log[ logEntry ];
IF stateLog = NIL THEN stateLog ← LIST[logEntry]
ELSE {
log: LIST OF LogEntry ← stateLog;
WHILE log.rest # NIL DO log ← log.rest ENDLOOP;
log.rest ← LIST[logEntry]
}
};
Log: PUBLIC ENTRY PROC [logEntry: LogEntry] ~ {
DoLog[logEntry];
};
ParseLog: INTERNAL PROC[] ~ { stateLog ← FingerLog.ParseLog[] };
GetLogAndLoginUser: ENTRY PROC[] ~ {
ENABLE UNWIND => NULL;
ParseLog[];
InternalPutStateChange[$login, BasicTime.Now[]];
TRUSTED { Process.Detach[FORK AttemptToPlayLog[]] }
};
OpenUp: Booting.RollbackProc = TRUSTED {
bound ← FALSE;
Process.Detach[FORK GetLogAndLoginUser[]]
};
ProfileChanged: UserProfile.ProfileChangedProc = {
serverMachine ← UserProfile.Token["Finger.RemoteHost", "Ebbetts"];
};
IF thisMachine = NIL THEN thisMachine ← ThisMachine.Address[$Pup];
IF thisMachine = NIL THEN thisMachine ← "Unknown";
UserProfile.CallWhenProfileChanges[proc: ProfileChanged];
ImportPlayProc[];
Booting.RegisterProcs[r: OpenUp];
GetLogAndLoginUser[];
[] ← Idle.RegisterIdleHandler[handler: RegisterLoginOrLogout]
END.