Files
BeWoPlaner/BeWoChatServer/Server.cs
2016-09-13 11:19:36 +02:00

407 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using BeWo.Data;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BS.Shared;
namespace BeWoChatServer
{
public class Server
{
// Fehlercodes zwischen 1000 und 1499
private static readonly object _Lock = string.Empty;
private static readonly Dictionary<Socket, long> clientList = new Dictionary<Socket, long>();
protected static Socket serverSocket;
private static AsyncCallback asyncCallback;
private static int clientCount;
public static void Main(string[] args)
{
try
{
Console.WriteLine(DateTime.Now + ": Starte Server");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var server = new IPEndPoint(IPAddress.Any, 5000);
serverSocket.Bind(server);
serverSocket.Listen(4);
serverSocket.BeginAccept(OnClientConnected, null);
while (true) { }
}
catch (Exception e)
{
WriteErrorMessageToConsole(e.Message, e.StackTrace);
}
}
public static void OnClientConnected(IAsyncResult asyncResult)
{
try
{
var workerSocket = serverSocket.EndAccept(asyncResult);
Interlocked.Increment(ref clientCount);
clientList.Add(workerSocket, 0);
Console.WriteLine(DateTime.Now + ": Client hinzugefügt");
WaitForClientData(workerSocket, "", 0, 0);
serverSocket.BeginAccept(OnClientConnected, null);
}
catch (SocketException e)
{
WriteErrorMessageToConsole(e.Message, e.StackTrace);
}
}
public static void WaitForClientData(Socket socket, string clientName, long oid, long recipientPersonOid)
{
try
{
if (asyncCallback == null)
{
asyncCallback = OnReceiveData;
}
var packet = new Packet(socket, clientName, oid, recipientPersonOid);
socket.BeginReceive(packet.DataBuffer, 0, packet.DataBuffer.Length, SocketFlags.None, asyncCallback, packet);
}
catch (Exception e)
{
WriteErrorMessageToConsole(e.Message, e.StackTrace);
}
}
public static void OnReceiveData(IAsyncResult asyncResult)
{
var dataPacket = (Packet) asyncResult.AsyncState;
Console.WriteLine(DateTime.Now + ": Empfange Nachricht");
try
{
var responseByteCount = dataPacket.Socket.EndReceive(asyncResult);
var chars = new char[responseByteCount];
var decoder = Encoding.UTF8.GetDecoder();
decoder.GetChars(dataPacket.DataBuffer, 0, responseByteCount, chars, 0);
if(chars.Count(f => f.Equals(';')) >= 4)
{
var message = new string(chars);
dataPacket.GetData(message);
}
switch(dataPacket.DataIdentifier) {
case DataIdentifier.Login:
try
{
Console.WriteLine(DateTime.Now + ": Login von " + dataPacket.ClientName);
Monitor.Enter(_Lock);
var endPoint = dataPacket.Socket.RemoteEndPoint;
var endPointCollection = clientList.Select(s => s.Key.RemoteEndPoint).ToList();
var istEnthalten = endPointCollection.Contains(endPoint);
if(istEnthalten)
{
clientList[dataPacket.Socket] = dataPacket.SenderPersonOid;
}
var notificationPacket = new Packet(dataPacket.Socket, dataPacket.ClientName, dataPacket.SenderPersonOid, 0) {DataIdentifier = DataIdentifier.StatusNotificationLogin, Tenant = dataPacket.Tenant};
Console.WriteLine(DateTime.Now + ": Benachrichtige die anderen angemeldeten Clients");
foreach (var client in clientList.Where(w => !w.Value.Equals(dataPacket.SenderPersonOid)))
{
client.Key.Send(notificationPacket.GetDataStream());
}
// Boradcast
var abc = clientList.Where(w => w.Value != dataPacket.SenderPersonOid && w.Value > 0).Select(s => s.Value).Distinct().ToList();
var msg = "";
foreach(var oid in abc)
{
msg += oid;
if(abc.IndexOf(oid) != abc.Count - 1)
{
msg += ",";
}
}
if(msg.Length > 0)
{
var packet = new Packet {ChatMessage = msg, ClientName = dataPacket.ClientName, DataIdentifier = DataIdentifier.StatusNotificationLoginBroadcast, MessageTimeStamp = DateTime.Now, Tenant = dataPacket.Tenant, SenderPersonOid = dataPacket.SenderPersonOid};
dataPacket.Socket.Send(packet.GetDataStream());
}
}
finally
{
Monitor.Exit(_Lock);
}
break;
case DataIdentifier.Message:
if(responseByteCount == 0)
{
try
{
Console.WriteLine(DateTime.Now + ": Chat-Nachricht ist leer und sorgt dafür, dass der Client ausgeloggt wird");
Monitor.Enter(_Lock);
var notificationPacketLogout2 = new Packet(dataPacket.Socket, dataPacket.ClientName, dataPacket.SenderPersonOid, 0) {DataIdentifier = DataIdentifier.StatusNotificationLogout};
clientList.Remove(dataPacket.Socket);
Console.WriteLine(DateTime.Now + ": Leite Logout an die anderen Clients weiter");
foreach(var client in clientList)
{
client.Key.Send(notificationPacketLogout2.GetDataStream());
}
dataPacket.Socket.Close();
}
finally
{
Monitor.Exit(_Lock);
}
return;
}
else
{
try
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(DateTime.Now + ": Chat-Nachricht erhalten");
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Gray;
Monitor.Enter(_Lock);
DefaultHibernateSessionManager.CurrentTenant = dataPacket.Tenant;
var chatMessage = new ChatMessage
{
SenderPersonOid = dataPacket.SenderPersonOid,
ChatText = System.Text.Encoding.Default.GetBytes(dataPacket.ChatMessage),
EmpfängerPersonOid = dataPacket.RecipientPersonOid,
Uhrzeit = dataPacket.MessageTimeStamp,
InsUser = dataPacket.ClientName
};
Console.WriteLine(DateTime.Now + ": Speichere die Chat-Nachricht in die Datenbank");
DAOFactory.GenericDAO.Insert(chatMessage);
// Testweise die Id einfügen
if(chatMessage.Oid != null)
{
Console.WriteLine(DateTime.Now + ": Chat-Nachricht erfolgreich mit Oid " + chatMessage.Oid.Value + " gespeichert");
dataPacket.ServerseitigeOid = chatMessage.Oid.Value;
}
if(dataPacket.RecipientPersonOid > 0)
{
if (clientList.ContainsValue(dataPacket.RecipientPersonOid))
{
var recipients = clientList.Where(w => w.Value.Equals(dataPacket.RecipientPersonOid));
Console.WriteLine(DateTime.Now + ": Leite die Chat-Nachricht an die Empfänger (Derselbe User angemeldet an verschiedenen Clients) weiter");
foreach(var recipient in recipients)
{
recipient.Key.Send(dataPacket.GetDataStream());
}
}
var packet = new Packet
{
ClientseitigeOid = dataPacket.ClientseitigeOid,
ServerseitigeOid = dataPacket.ServerseitigeOid,
DataIdentifier = DataIdentifier.MessageResponse
};
Console.WriteLine(DateTime.Now + ": Sende Datenbank-Insert-Bestätigung an den Absender, damit die Nachricht später nicht doppelt auf den Client heruntergeladen wird");
dataPacket.Socket.Send(packet.GetDataStream());
}
}
finally
{
Monitor.Exit(_Lock);
}
}
break;
case DataIdentifier.Logout:
clientList.Remove(dataPacket.Socket);
var notificationPacketLogout = new Packet(dataPacket.Socket, dataPacket.ClientName, dataPacket.SenderPersonOid, 0) {DataIdentifier = DataIdentifier.StatusNotificationLogout};
Console.WriteLine(DateTime.Now + ": Sende Logout an alle anderen Clients");
foreach (var client in clientList.Where(w => !w.Value.Equals(dataPacket.SenderPersonOid)))
{
client.Key.Send(notificationPacketLogout.GetDataStream());
}
break;
case DataIdentifier.Team:
try
{
Console.WriteLine(DateTime.Now + ": Team-Nachricht erhalten");
Monitor.Enter(_Lock);
DefaultHibernateSessionManager.CurrentTenant = dataPacket.Tenant;
var chatMessage = new ChatMessage
{
SenderPersonOid = dataPacket.SenderPersonOid,
ChatText = System.Text.Encoding.Default.GetBytes(dataPacket.ChatMessage),
EmpfängerPersonOid = dataPacket.RecipientPersonOid,
Uhrzeit = dataPacket.MessageTimeStamp,
InsUser = dataPacket.ClientName,
TeamOid = dataPacket.RecipientPersonOid
};
var team = DAOFactory.GenericDAO.LoadByID<Team>(dataPacket.RecipientPersonOid);
Console.WriteLine(DateTime.Now + ": Speichere Team-Nachricht in der Datenbank");
DAOFactory.GenericDAO.Insert(chatMessage);
var personOids = team.MemberList.Select(s => s.Person.Oid.Value);
if (chatMessage.Oid != null)
{
Console.WriteLine(DateTime.Now + ": Team-Nachricht erfolgreich mit Oid " + chatMessage.Oid.Value + " gespeichert");
dataPacket.ServerseitigeOid = chatMessage.Oid.Value;
}
Console.WriteLine(DateTime.Now + ": Leite die Team-Nachricht an die Empfänger weiter");
foreach(var recipient in clientList.Where(w => w.Value != dataPacket.SenderPersonOid && personOids.Contains(w.Value)))
{
recipient.Key.Send(dataPacket.GetDataStream());
}
var packet = new Packet
{
ClientseitigeOid = dataPacket.ClientseitigeOid,
ServerseitigeOid = dataPacket.ServerseitigeOid,
DataIdentifier = DataIdentifier.MessageResponse
};
Console.WriteLine(DateTime.Now + ": Sende Datenbank-Insert-Bestätigung an den Absender, damit die Nachricht später nicht doppelt auf den Client heruntergeladen wird");
dataPacket.Socket.Send(packet.GetDataStream());
}
finally
{
Monitor.Exit(_Lock);
}
break;
case DataIdentifier.StatusNotificationBeschäftigt:
SendNotificationPacket(dataPacket, DataIdentifier.StatusNotificationBeschäftigt);
break;
case DataIdentifier.StatusNotificationOnline:
SendNotificationPacket(dataPacket, DataIdentifier.StatusNotificationOnline);
break;
case DataIdentifier.StatusNotificationOffline:
SendNotificationPacket(dataPacket, DataIdentifier.StatusNotificationOffline);
break;
}
WaitForClientData(dataPacket.Socket, dataPacket.ClientName, dataPacket.SenderPersonOid, dataPacket.RecipientPersonOid);
}
catch (Exception e)
{
Console.WriteLine(DateTime.Now + ": Ein Fehler ist aufgetreten oder die App ist abgestürzt. Der Client wird ausgeloggt");
var sender = dataPacket.Socket;
var notificationPacketLogout = new Packet(dataPacket.Socket, dataPacket.ClientName, dataPacket.SenderPersonOid, 0) { DataIdentifier = DataIdentifier.StatusNotificationLogout };
try
{
Monitor.Enter(_Lock);
if(clientList.ContainsKey(sender))
{
clientList.Remove(sender);
Console.WriteLine(DateTime.Now + ": Leite Logout an die anderen Clients weiter");
foreach(var client in clientList)
{
client.Key.Send(notificationPacketLogout.GetDataStream());
}
sender.Close();
}
}
finally
{
Monitor.Exit(_Lock);
}
WriteErrorMessageToConsole(e.Message, e.StackTrace);
}
}
private static void SendNotificationPacket(Packet dataPacket, DataIdentifier dataIdentifier)
{
var notificationPacket = new Packet(dataPacket.Socket, dataPacket.ClientName, dataPacket.SenderPersonOid, 0) { DataIdentifier = DataIdentifier.StatusNotificationLogout };
Console.WriteLine(DateTime.Now + ": Sende Statusänderung(" + dataIdentifier + ") an alle anderen Clients");
foreach (var client in clientList.Where(w => w.Value != dataPacket.SenderPersonOid))
{
client.Key.Send(notificationPacket.GetDataStream());
}
}
private static void WriteErrorMessageToConsole(string message, string stackTrace)
{
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(DateTime.Now + ": " + message);
Console.WriteLine(stackTrace);
Console.BackgroundColor = ConsoleColor.Black;
Console.ForegroundColor = ConsoleColor.Gray;
}
}
}