IMPORTS
BasicTime, Booting, FingerLog, Idle, Process, RemoteFingerOps, RemoteFingerOpsRpcControl, RPC, ThisMachine, UserCredentials, UserProfile
BEGIN
OPEN FingerOps, FingerLog;
idle: BOOL ← FALSE;
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: BOOL ← FALSE;
ImportPlayProc:
PROC [host: Rope.
ROPE ←
NIL] ~ {
success: BOOL ← TRUE;
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]