// On the server disconnecting private static void Disconnected(Connection Sender, DisconnectMessage Message) { // Unhook handlers Server.MessageReceived -= MessageReceived; Server.Disconnect -= Disconnected; // Reset the signals InitialisedEvent.Dispose(); InitialisedEvent = null; UserEvent.Dispose(); UserEvent = null; }
// Handler for when the server receives a message private static void MessageReceived(Connection Sender, Message Msg) { bool Locked = true; Monitor.Enter(Lock); // Don't echo changes back to the server - changes made in this // function have been sent to us by the server ReportModelChanges = false; if (Msg is InitialiseMessage) { // Initialisation of the client - load in the data LoadSnapshot((Msg as InitialiseMessage).Snapshot, false); // Signal that we've received the initial data InitialisedEvent.Set(); } else if (Msg is UserInformationMessage) { // Information on the User and their Room UserInformationMessage m = (Msg as UserInformationMessage); User User = m.User; Room Room = m.Room; if (User == null) { throw new ArgumentNullException("Received a null user."); } if (Room == null) { throw new ArgumentNullException("Received a null room."); } // Acquire references to the actual user/room DataSnapshot Frame = TakeSnapshot(false); CurrentUser = Frame.Users.SingleOrDefault(u => u.Id == User.Id); CurrentRoom = Frame.Rooms.SingleOrDefault(r => r.Id == Room.Id); // Signal that we've received the user data UserEvent.Set(); } else if (Msg is DataMessage) { DataMessage Data = (DataMessage)Msg; // Get references to linked objects using (DataRepository Repo = new DataRepository(false)) Data.Item.Expand(Repo); // If we're not deleting it, set references to this item if (!Data.Delete) { Data.Item.Attach(); } else // Otherwise remove references { Data.Item.Detach(); } // Store the type of the received data Type t = Data.Item.GetType(); // Get the right table from the dictionary (match received type to key) IList Table = Tables.Single(p => t == p.Key || t.IsSubclassOf(p.Key)).Value; // Find the index of the item in the table int Index = -1; for (int x = 0; x < Table.Count; x++) { if (((DataModel)Table[x]).Id == Data.Item.Id) { Index = x; break; } } if (!Data.Delete) { if (Index < 0) // Doesn't already exist, add it { Table.Add(Data.Item); } else // Already exists, update it { ((DataModel)Table[Index]).Update(Data.Item); } } else // Delete it { Table.RemoveAt(Index); } // Release the lock Monitor.Exit(Lock); // Note that we've already released it Locked = false; // Fire the change of data handler DataChanged(Data.Item.GetType()); } ReportModelChanges = true; // Continue reporting changes if (Locked) // Release the lock if we haven't already { Monitor.Exit(Lock); } }
// Initialise the database model from the server public static Tuple <User, Room> Initialise(Connection Server, ConnectMessage Msg) { try { // Thread safe Monitor.Enter(Lock); // Reset the signal that's set when the data's received if (InitialisedEvent == null) { InitialisedEvent = new ManualResetEvent(false); } InitialisedEvent.Reset(); // Reset the signal that's set when the user information's received if (UserEvent == null) { UserEvent = new ManualResetEvent(false); } UserEvent.Reset(); // Set the current server DataRepository.Server = Server; // Hook up network events Server.MessageReceived += MessageReceived; Server.Disconnect += Disconnected; // Hook up data changed events _Bookings.CollectionChanged += Data_CollectionChanged; _Departments.CollectionChanged += Data_CollectionChanged; _Rooms.CollectionChanged += Data_CollectionChanged; _Users.CollectionChanged += Data_CollectionChanged; _Subjects.CollectionChanged += Data_CollectionChanged; _Periods.CollectionChanged += Data_CollectionChanged; _Classes.CollectionChanged += Data_CollectionChanged; // Send the connection message Server.Send(Msg); } catch { return(null); } finally { // Release the lock Monitor.Exit(Lock); } try { // Wait for both signals to fire, signalling completion InitialisedEvent.WaitOne(); UserEvent.WaitOne(); } catch { // Disconnected during initialise return(null); } // Return the User and their Room (grouped together for easy return value) return(new Tuple <User, Room>(CurrentUser, CurrentRoom)); }