public abstract class ModelContext<TModel> : IDisposable { #region consts private const int TimeOut = 10000; #endregion #region fields private static object syncObject = new object(); protected TModel model; #endregion #region initialization protected ModelContext(TModel initialModel) { if (!Monitor.TryEnter(syncObject, TimeOut)) throw new InvalidOperationException("model lock timeout"); model = initialModel; } public void Dispose() { model = default(TModel); Monitor.Exit(syncObject); } #endregion } }
public class ServerModel { #region static model private static ServerModel model; /// <summary> /// API /// </summary> public static IServerAPI API { get; private set; } /// <summary> /// /// </summary> public static AsyncServer Server { get; private set; } /// <summary> /// using /// </summary> /// <example>using (var server = SeeverModel.Get()) { ... }</example> /// <returns> .</returns> public static ServerContext Get() { if (Interlocked.CompareExchange(ref model, null, null) == null) throw new ArgumentException("model do not inited yet"); return new ServerContext(model); } #endregion #region consts public const string MainRoomName = "Main room"; #endregion #region properties public Dictionary<string, Room> Rooms { get; private set; } public Dictionary<string, User> Users { get; private set; } #endregion #region constructor public ServerModel() { Users = new Dictionary<string, User>(); Rooms = new Dictionary<string, Room>(); Rooms.Add(MainRoomName, new Room(null, MainRoomName)); } #endregion #region static methods public static bool IsInited { get { return Interlocked.CompareExchange(ref model, null, null) != null; } } public static void Init(IServerAPI api) { if (Interlocked.CompareExchange(ref model, new ServerModel(), null) != null) throw new InvalidOperationException("model already inited"); Server = new AsyncServer("ServerErrors.log"); API = api; } public static void Reset() { if (Interlocked.Exchange(ref model, null) == null) throw new InvalidOperationException("model not yet inited"); if (Server != null) { Server.Dispose(); Server = null; } API = null; } #endregion }
public class DataReceivedEventArgs : EventArgs { public byte[] ReceivedData { get; set; } public Exception Error { get; set; } } public interface IServerAPICommand { void Run(ServerCommandArgs args); } public class ServerCommandArgs { public string ConnectionId { get; set; } public byte[] Message { get; set; } } private void DataReceivedCallBack(object sender, DataReceivedEventArgs e) { try { if (e.Error != null) throw e.Error; if (!isServerRunning) return; IServerAPICommand command = ServerModel.API.GetCommand(e.ReceivedData); ServerCommandArgs args = new ServerCommandArgs { Message = e.ReceivedData, ConnectionId = ((ServerConnection)sender).Id, }; command.Run(args); } catch (Exception exc) { ServerModel.Logger.Write(exc); } }
/// <summary> /// API. /// </summary> public class StandardServerAPI : IServerAPI { /// <summary> /// API. /// </summary> public const string API = "StandartAPI v2.0"; private Dictionary<ushort, IServerAPICommand> commandDictionary = new Dictionary<ushort, IServerAPICommand>(); /// <summary> /// API. /// </summary> /// <param name="host"> API.</param> public StandardServerAPI() { commandDictionary.Add(ServerRegisterCommand.Id, new ServerRegisterCommand()); commandDictionary.Add(ServerUnregisterCommand.Id, new ServerUnregisterCommand()); commandDictionary.Add(ServerSendRoomMessageCommand.Id, new ServerSendRoomMessageCommand()); commandDictionary.Add(ServerSendPrivateMessageCommand.Id, new ServerSendPrivateMessageCommand()); commandDictionary.Add(ServerGetUserOpenKeyCommand.Id, new ServerGetUserOpenKeyCommand()); commandDictionary.Add(ServerCreateRoomCommand.Id, new ServerCreateRoomCommand()); commandDictionary.Add(ServerDeleteRoomCommand.Id, new ServerDeleteRoomCommand()); commandDictionary.Add(ServerInviteUsersCommand.Id, new ServerInviteUsersCommand()); commandDictionary.Add(ServerKickUsersCommand.Id, new ServerKickUsersCommand()); commandDictionary.Add(ServerExitFormRoomCommand.Id, new ServerExitFormRoomCommand()); commandDictionary.Add(ServerRefreshRoomCommand.Id, new ServerRefreshRoomCommand()); commandDictionary.Add(ServerSetRoomAdminCommand.Id, new ServerSetRoomAdminCommand()); commandDictionary.Add(ServerAddFileToRoomCommand.Id, new ServerAddFileToRoomCommand()); commandDictionary.Add(ServerRemoveFileFormRoomCommand.Id, new ServerRemoveFileFormRoomCommand()); commandDictionary.Add(ServerP2PConnectRequestCommand.Id, new ServerP2PConnectRequestCommand()); commandDictionary.Add(ServerP2PReadyAcceptCommand.Id, new ServerP2PReadyAcceptCommand()); commandDictionary.Add(ServerPingRequestCommand.Id, new ServerPingRequestCommand()); } /// <summary> /// API. /// </summary> public string Name { get { return API; } } /// <summary> /// . /// </summary> /// <param name="message"> , .</param> /// <returns> .</returns> public IServerAPICommand GetCommand(byte[] message) { ushort id = BitConverter.ToUInt16(message, 0); IServerAPICommand command; if (commandDictionary.TryGetValue(id, out command)) return command; return ServerEmptyCommand.Empty; } /// <summary> /// . /// </summary> /// <param name="container"></param> public void IntroduceConnections(string senderId, IPEndPoint senderPoint, string requestId, IPEndPoint requestPoint) { using (var context = ServerModel.Get()) { var content = new ClientWaitPeerConnectionCommand.MessageContent { RequestPoint = requestPoint, SenderPoint = senderPoint, RemoteInfo = context.Users[senderId], }; ServerModel.Server.SendMessage(requestId, ClientWaitPeerConnectionCommand.Id, content); } } /// <summary> /// . /// </summary> /// <param name="nick"> .</param> /// <param name="message">.</param> public void SendSystemMessage(string nick, string message) { var sendingContent = new ClientOutSystemMessageCommand.MessageContent { Message = message }; ServerModel.Server.SendMessage(nick, ClientOutSystemMessageCommand.Id, sendingContent); } /// <summary> /// . /// </summary> /// <param name="nick"> , .</param> public void CloseConnection(string nick) { ServerModel.Server.CloseConnection(nick); using (var server = ServerModel.Get()) { foreach (string roomName in server.Rooms.Keys) { Room room = server.Rooms[roomName]; if (!room.Users.Contains(nick)) continue; room.Remove(nick); server.Users.Remove(nick); var sendingContent = new ClientRoomRefreshedCommand.MessageContent { Room = room, Users = room.Users.Select(n => server.Users[n]).ToList() }; foreach (string user in room.Users) { if (user == null) continue; ServerModel.Server.SendMessage(user, ClientRoomRefreshedCommand.Id, sendingContent); } } } } }
public interface IServerAPICommand { void Run(ServerCommandArgs args); } public class ServerCommandArgs { public string ConnectionId { get; set; } public byte[] Message { get; set; } } abstract class BaseCommand { protected static T GetContentFormMessage<T>(byte[] message) { using (MemoryStream messageStream = new MemoryStream(message)) { messageStream.Position = sizeof(ushort); BinaryFormatter formatter = new BinaryFormatter(); T receivedContent = (T)formatter.Deserialize(messageStream); return receivedContent; } } } class ServerAddFileToRoomCommand : BaseServerCommand, IServerAPICommand { public void Run(ServerCommandArgs args) { MessageContent receivedContent = GetContentFormMessage<MessageContent>(args.Message); // . if (receivedContent.File == null) throw new ArgumentNullException("File"); if (string.IsNullOrEmpty(receivedContent.RoomName)) throw new ArgumentException("RoomName"); if (!RoomExists(receivedContent.RoomName, args.ConnectionId)) return; using (var context = ServerModel.Get()) // , { Room room = context.Rooms[receivedContent.RoomName]; if (!room.Users.Contains(args.ConnectionId)) { ServerModel.API.SendSystemMessage(args.ConnectionId, " ."); return; } if (room.Files.FirstOrDefault(file => file.Equals(receivedContent.File)) == null) room.Files.Add(receivedContent.File); var sendingContent = new ClientFilePostedCommand.MessageContent { File = receivedContent.File, RoomName = receivedContent.RoomName }; // // , foreach (string user in room.Users) ServerModel.Server.SendMessage(user, ClientFilePostedCommand.Id, sendingContent); } } [Serializable] public class MessageContent { string roomName; FileDescription file; public string RoomName { get { return roomName; } set { roomName = value; } } public FileDescription File { get { return file; } set { file = value; } } } public const ushort Id = (ushort)ServerCommand.AddFileToRoom; }
Source: https://habr.com/ru/post/228021/
All Articles