/// <summary> /// Unregister the WmKcd object specified if there are no more references /// to it and it is disconnected. /// </summary> public static void RemoveKcdIfNoRef(WmKcd kcd) { if (kcd.KwsTree.Count == 0 && kcd.ConnStatus == KcdConnStatus.Disconnected) { KcdTree.Remove(kcd.KcdID); } }
/// <summary> /// Process a KCD connection notice. /// </summary> private static void ProcessKcdConnectionNotice(KcdConnectionNotice notice) { Debug.Assert(Wm.KcdTree.ContainsKey(notice.KcdID)); WmKcd kcd = Wm.KcdTree[notice.KcdID]; Debug.Assert(kcd.ConnStatus == KcdConnStatus.Connecting || kcd.ConnStatus == KcdConnStatus.Disconnecting); // We do not want the KCD to be connected anymore. Ignore the // message. if (kcd.ConnStatus == KcdConnStatus.Disconnecting) { return; } // The KCD is now connected. kcd.ConnStatus = KcdConnStatus.Connected; kcd.MinorVersion = notice.MinorVersion; kcd.ClearError(true); // Notify every workspace that the KCD is connected. Stop if the KCD // state changes while notifications are being sent. foreach (Workspace kws in kcd.KwsTree.Values) { if (kcd.ConnStatus != KcdConnStatus.Connected) { break; } kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Connected, null); } }
/// <summary> /// Clear the errors associated to the KCD specified, reset the number /// of failed connection attempts to 0 and request a run of the state /// machine, if required. This can be used to force a KCD to reconnect /// sooner than usual. /// </summary> public static void ResetKcdFailureState(WmKcd kcd) { if (kcd.FailedConnectCount != 0 || kcd.ErrorDate != DateTime.MinValue) { kcd.ClearError(true); RequestRun("cleared KCD error"); } }
public KcdQuery(AnpMsg cmd, KcdQueryDelegate callback, WmKcd kcd, Workspace kws) { Debug.Assert(cmd.ID != 0); Cmd = cmd; Callback = callback; Kcd = kcd; Kws = kws; }
/// <summary> /// Handle non-recoverable KCD errors (aside of disconnection notices). /// This method should be called when a KCD behaves badly. /// </summary> public static void HandleTroublesomeKcd(WmKcd kcd, Exception ex) { // Assign the error to the KCD. AssignErrorToKcd(kcd, false); // Disconnect the KCD. DisconnectKcd(kcd, ex); }
/// <summary> /// Create the WmKcd object specified if it does not exist, and return /// a reference to the WmKcd object specified, if any. /// </summary> public static WmKcd GetOrCreateKcd(KcdIdentifier kcdID) { if (kcdID.Host == "") { return(null); } if (!KcdTree.ContainsKey(kcdID)) { KcdTree[kcdID] = new WmKcd(kcdID); } return(KcdTree[kcdID]); }
/// <summary> /// Process an ANP message received from the KCD. /// </summary> private static void ProcessKcdAnpMsg(KcdAnpMsg m) { KLogging.Log("ProcessKcdAnpMsg() called"); // We're stopping. Bail out. if (StopFlag) { return; } // The KCD specified does not exist. Bail out. if (!Wm.KcdTree.ContainsKey(m.KcdID)) { return; } // The KCD is not connected. Bail out. WmKcd kcd = Wm.KcdTree[m.KcdID]; if (kcd.ConnStatus != KcdConnStatus.Connected) { return; } // Process the message according to its type. try { if (m.Msg.Type == KAnp.KANP_RES_FAIL && m.Msg.Elements[0].UInt32 == KAnp.KANP_RES_FAIL_BACKEND) { throw new Exception("backend error: " + m.Msg.Elements[1].String); } else if (m.IsReply()) { ProcessKcdAnpReply(kcd, m.Msg); } else if (m.IsEvent()) { ProcessKcdAnpEvent(kcd, m.Msg); } else { throw new Exception("received unexpected ANP message type (" + m.Msg.Type + ")"); } } catch (Exception ex) { HandleTroublesomeKcd(kcd, ex); } }
public void Relink(UInt64 internalID, KwsCoreData cd) { InternalID = internalID; Cd = cd; Cd.Relink(); Wm.KwsTree[InternalID] = this; Kcd = Wm.GetOrCreateKcd(Cd.Credentials.KcdID); Kcd.KwsTree[InternalID] = this; Sm.Relink(this); KcdEventHandler.Relink(this); KcdLoginHandler.Relink(this); Chat.Relink(this); Pb.Relink(this); Vnc.Relink(this); Kfs.Relink(this); }
/// <summary> /// Process an ANP event received from the KCD. /// </summary> private static void ProcessKcdAnpEvent(WmKcd kcd, AnpMsg msg) { // Get the external workspace ID referred to by the event. UInt64 externalID = msg.Elements[0].UInt64; // Locate the workspace. Workspace kws = kcd.GetWorkspaceByExternalID(externalID); // No such workspace, bail out. if (kws == null) { return; } // Dispatch the event to its workspace. kws.Sm.HandleKcdEvent(msg); }
/// <summary> /// Disconnect a KCD if it is connecting/connected. /// </summary> private static void DisconnectKcd(WmKcd kcd, Exception ex) { if (kcd.ConnStatus == KcdConnStatus.Disconnecting || kcd.ConnStatus == KcdConnStatus.Disconnected) { return; } // Send a disconnection request to the KCD. kcd.ConnStatus = KcdConnStatus.Disconnecting; Wm.KcdBroker.RequestKcdDisconnect(kcd.KcdID); // Notify the listeners. foreach (Workspace kws in kcd.KwsTree.Values) { kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Disconnecting, ex); } }
/// <summary> /// Remove the workspace object from the workspace manager. Used by the /// WM state machine. /// </summary> public static void RemoveWorkspace(Workspace kws) { try { WmKcd kcd = kws.Kcd; // Make sure the state is valid. Debug.Assert(KwsTree.ContainsKey(kws.InternalID)); if (kcd != null) { Debug.Assert(kcd.KwsTree.ContainsKey(kws.InternalID)); Debug.Assert(!kcd.KwsConnectTree.ContainsKey(kws.InternalID)); } // Unregister the workspace from the workspace manager. KwsTree.Remove(kws.InternalID); if (KwsRemoveTree.ContainsKey(kws.InternalID)) { KwsRemoveTree.Remove(kws.InternalID); } if (kcd != null) { kcd.CancelKwsKcdQuery(kws); kcd.KwsTree.Remove(kws.InternalID); RemoveKcdIfNoRef(kcd); } AdjustPublicKwsID(); // Delete the workspace data. kws.PrepareToRemove(); foreach (KwsApp app in kws.AppTree.Values) { app.PrepareToRemove(); } // The WM state has changed. Wm.OnStateChange(WmStateChange.Permanent); } catch (Exception ex) { KBase.HandleException(ex, true); } }
/// <summary> /// Connect a KCD if it is disconnected. /// </summary> private static void ConnectKcd(WmKcd kcd) { if (kcd.ConnStatus != KcdConnStatus.Disconnected) { return; } // Clear the current error, but not the failed connection count. kcd.ClearError(false); // Send a connection request. kcd.ConnStatus = KcdConnStatus.Connecting; Wm.KcdBroker.RequestKcdConnect(kcd.KcdID); // Notify the listeners. foreach (Workspace kws in kcd.KwsTree.Values) { kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Connecting, null); } }
/// <summary> /// Process an ANP reply received from the KCD. /// </summary> private static void ProcessKcdAnpReply(WmKcd kcd, AnpMsg msg) { // We have no knowledge of the query. Ignore the reply. if (!kcd.QueryMap.ContainsKey(msg.ID)) { return; } // Retrieve and remove the query from the query map. KcdQuery query = kcd.QueryMap[msg.ID]; // Set the reply in the query. query.Res = msg; // We don't have non-workspace-related replies yet. Debug.Assert(query.Kws != null); // Dispatch the message to the workspace. query.Kws.Sm.HandleKcdReply(query); query.Terminate(); }
/// <summary> /// Process a KCD disconnection notice. /// </summary> private static void ProcessKcdDisconnectionNotice(KcdDisconnectionNotice notice) { Debug.Assert(Wm.KcdTree.ContainsKey(notice.KcdID)); WmKcd kcd = Wm.KcdTree[notice.KcdID]; Debug.Assert(kcd.ConnStatus != KcdConnStatus.Disconnected); // The KCD died unexpectedly. if (kcd.ConnStatus != KcdConnStatus.Disconnecting) { // Handle the offense. if (notice.Ex != null) { // Increase the failed connection attempt count if were // connecting. AssignErrorToKcd(kcd, (kcd.ConnStatus == KcdConnStatus.Connecting)); } } // The KCD is now disconnected. kcd.ConnStatus = KcdConnStatus.Disconnected; // Clear the command-reply mappings associated to the KCD. kcd.QueryMap.Clear(); // Notify every workspace that the KCD is disconnected. foreach (Workspace kws in kcd.KwsTree.Values) { kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Disconnected, notice.Ex); } // Remove the KCD if we no longer need it. Wm.RemoveKcdIfNoRef(kcd); // Re-run the state machine, in case we want to reconnect to the KCD // or stop. RequestRun("KCD disconnected"); }
/// <summary> /// Process an ANP reply received from the KCD. /// </summary> private static void ProcessKcdAnpReply(WmKcd kcd, AnpMsg msg) { // We have no knowledge of the query. Ignore the reply. if (!kcd.QueryMap.ContainsKey(msg.ID)) return; // Retrieve and remove the query from the query map. KcdQuery query = kcd.QueryMap[msg.ID]; // Set the reply in the query. query.Res = msg; // We don't have non-workspace-related replies yet. Debug.Assert(query.Kws != null); // Dispatch the message to the workspace. query.Kws.Sm.HandleKcdReply(query); query.Terminate(); }
/// <summary> /// Process an ANP event received from the KCD. /// </summary> private static void ProcessKcdAnpEvent(WmKcd kcd, AnpMsg msg) { // Get the external workspace ID referred to by the event. UInt64 externalID = msg.Elements[0].UInt64; // Locate the workspace. Workspace kws = kcd.GetWorkspaceByExternalID(externalID); // No such workspace, bail out. if (kws == null) return; // Dispatch the event to its workspace. kws.Sm.HandleKcdEvent(msg); }
/// <summary> /// Disconnect a KCD if it is connecting/connected. /// </summary> private static void DisconnectKcd(WmKcd kcd, Exception ex) { if (kcd.ConnStatus == KcdConnStatus.Disconnecting || kcd.ConnStatus == KcdConnStatus.Disconnected) return; // Send a disconnection request to the KCD. kcd.ConnStatus = KcdConnStatus.Disconnecting; Wm.KcdBroker.RequestKcdDisconnect(kcd.KcdID); // Notify the listeners. foreach (Workspace kws in kcd.KwsTree.Values) kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Disconnecting, ex); }
/// <summary> /// Connect a KCD if it is disconnected. /// </summary> private static void ConnectKcd(WmKcd kcd) { if (kcd.ConnStatus != KcdConnStatus.Disconnected) return; // Clear the current error, but not the failed connection count. kcd.ClearError(false); // Send a connection request. kcd.ConnStatus = KcdConnStatus.Connecting; Wm.KcdBroker.RequestKcdConnect(kcd.KcdID); // Notify the listeners. foreach (Workspace kws in kcd.KwsTree.Values) kws.Sm.HandleKcdConnStatusChange(KcdConnStatus.Connecting, null); }
/// <summary> /// Assign an error to a KCD. /// </summary> private static void AssignErrorToKcd(WmKcd kcd, bool connectFailureFlag) { kcd.SetError(DateTime.Now, connectFailureFlag); }
/// <summary> /// Unregister the WmKcd object specified if there are no more references /// to it and it is disconnected. /// </summary> public static void RemoveKcdIfNoRef(WmKcd kcd) { if (kcd.KwsTree.Count == 0 && kcd.ConnStatus == KcdConnStatus.Disconnected) KcdTree.Remove(kcd.KcdID); }
/// <summary> /// Create the WmKcd object specified if it does not exist, and return /// a reference to the WmKcd object specified, if any. /// </summary> public static WmKcd GetOrCreateKcd(KcdIdentifier kcdID) { if (kcdID.Host == "") return null; if (!KcdTree.ContainsKey(kcdID)) KcdTree[kcdID] = new WmKcd(kcdID); return KcdTree[kcdID]; }