2016-07-18 06:14:17 +02:00
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 ;
2016-07-25 09:23:22 +02:00
2016-07-18 06:14:17 +02:00
using BeWo.Data ;
using BeWo.Data.Access ;
using BeWo.Data.Entities ;
using BS.Shared ;
2016-07-29 13:08:32 +02:00
2016-07-18 06:14:17 +02:00
namespace BeWoChatServer
{
public class Server
{
2016-07-25 09:23:22 +02:00
// Fehlercodes zwischen 1000 und 1499
private static readonly object _Lock = string . Empty ;
2016-07-18 06:14:17 +02:00
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
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Starte Server" ) ;
2016-07-18 06:14:17 +02:00
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 )
{
2016-08-26 12:28:57 +02:00
WriteErrorMessageToConsole ( e . Message , e . StackTrace ) ;
2016-07-18 06:14:17 +02:00
}
}
public static void OnClientConnected ( IAsyncResult asyncResult )
{
try
{
var workerSocket = serverSocket . EndAccept ( asyncResult ) ;
Interlocked . Increment ( ref clientCount ) ;
clientList . Add ( workerSocket , 0 ) ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Client hinzugefügt" ) ;
2016-07-25 09:23:22 +02:00
WaitForClientData ( workerSocket , "" , 0 , 0 ) ;
2016-07-18 06:14:17 +02:00
serverSocket . BeginAccept ( OnClientConnected , null ) ;
}
catch ( SocketException e )
{
2016-08-26 12:28:57 +02:00
WriteErrorMessageToConsole ( e . Message , e . StackTrace ) ;
2016-07-18 06:14:17 +02:00
}
}
2016-07-25 09:23:22 +02:00
public static void WaitForClientData ( Socket socket , string clientName , long oid , long recipientPersonOid )
2016-07-18 06:14:17 +02:00
{
try
{
if ( asyncCallback = = null )
{
asyncCallback = OnReceiveData ;
}
2016-07-25 09:23:22 +02:00
var packet = new Packet ( socket , clientName , oid , recipientPersonOid ) ;
2016-07-18 06:14:17 +02:00
socket . BeginReceive ( packet . DataBuffer , 0 , packet . DataBuffer . Length , SocketFlags . None , asyncCallback , packet ) ;
}
catch ( Exception e )
{
2016-08-26 12:28:57 +02:00
WriteErrorMessageToConsole ( e . Message , e . StackTrace ) ;
2016-07-18 06:14:17 +02:00
}
}
public static void OnReceiveData ( IAsyncResult asyncResult )
{
var dataPacket = ( Packet ) asyncResult . AsyncState ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Empfange Nachricht" ) ;
2016-07-18 06:14:17 +02:00
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 ) ;
}
2016-07-18 11:50:51 +02:00
switch ( dataPacket . DataIdentifier ) {
case DataIdentifier . Login :
2016-08-17 12:20:27 +02:00
try
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Login von " + dataPacket . ClientName ) ;
2016-08-17 12:20:27 +02:00
Monitor . Enter ( _Lock ) ;
2016-07-18 06:14:17 +02:00
2016-08-17 12:20:27 +02:00
var endPoint = dataPacket . Socket . RemoteEndPoint ;
2016-07-18 06:14:17 +02:00
2016-08-17 12:20:27 +02:00
var endPointCollection = clientList . Select ( s = > s . Key . RemoteEndPoint ) . ToList ( ) ;
2016-07-25 09:23:22 +02:00
2016-08-17 12:20:27 +02:00
var istEnthalten = endPointCollection . Contains ( endPoint ) ;
if ( istEnthalten )
{
clientList [ dataPacket . Socket ] = dataPacket . SenderPersonOid ;
}
2016-07-25 14:48:35 +02:00
2016-08-17 12:20:27 +02:00
var notificationPacket = new Packet ( dataPacket . Socket , dataPacket . ClientName , dataPacket . SenderPersonOid , 0 ) { DataIdentifier = DataIdentifier . StatusNotificationLogin , Tenant = dataPacket . Tenant } ;
2016-07-25 09:23:22 +02:00
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Benachrichtige die anderen angemeldeten Clients" ) ;
2016-08-17 12:20:27 +02:00
foreach ( var client in clientList . Where ( w = > ! w . Value . Equals ( dataPacket . SenderPersonOid ) ) )
{
client . Key . Send ( notificationPacket . GetDataStream ( ) ) ;
}
2016-07-26 15:51:30 +02:00
2016-08-17 12:20:27 +02:00
// Boradcast
var abc = clientList . Where ( w = > w . Value ! = dataPacket . SenderPersonOid & & w . Value > 0 ) . Select ( s = > s . Value ) . Distinct ( ) . ToList ( ) ;
var msg = "" ;
2016-07-26 15:51:30 +02:00
2016-08-17 12:20:27 +02:00
foreach ( var oid in abc )
2016-07-29 13:08:32 +02:00
{
2016-08-17 12:20:27 +02:00
msg + = oid ;
if ( abc . IndexOf ( oid ) ! = abc . Count - 1 )
{
msg + = "," ;
}
2016-07-29 13:08:32 +02:00
}
2016-08-17 12:20:27 +02:00
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 } ;
2016-07-29 13:08:32 +02:00
2016-08-17 12:20:27 +02:00
dataPacket . Socket . Send ( packet . GetDataStream ( ) ) ;
}
}
finally
{
Monitor . Exit ( _Lock ) ;
2016-08-03 11:50:16 +02:00
}
2016-07-26 15:51:30 +02:00
2016-07-18 06:14:17 +02:00
break ;
case DataIdentifier . Message :
if ( responseByteCount = = 0 )
{
2016-08-17 12:20:27 +02:00
try
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Chat-Nachricht ist leer und sorgt dafür, dass der Client ausgeloggt wird" ) ;
2016-08-17 12:20:27 +02:00
Monitor . Enter ( _Lock ) ;
2016-07-29 13:08:32 +02:00
2016-08-17 12:20:27 +02:00
var notificationPacketLogout2 = new Packet ( dataPacket . Socket , dataPacket . ClientName , dataPacket . SenderPersonOid , 0 ) { DataIdentifier = DataIdentifier . StatusNotificationLogout } ;
clientList . Remove ( dataPacket . Socket ) ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Leite Logout an die anderen Clients weiter" ) ;
2016-08-17 12:20:27 +02:00
foreach ( var client in clientList )
{
client . Key . Send ( notificationPacketLogout2 . GetDataStream ( ) ) ;
}
dataPacket . Socket . Close ( ) ;
}
finally
2016-07-29 13:08:32 +02:00
{
2016-08-17 12:20:27 +02:00
Monitor . Exit ( _Lock ) ;
2016-07-29 13:08:32 +02:00
}
2016-07-18 06:14:17 +02:00
return ;
}
else
{
try
{
2016-08-26 12:28:57 +02:00
Console . BackgroundColor = ConsoleColor . Black ;
Console . ForegroundColor = ConsoleColor . Red ;
Console . WriteLine ( DateTime . Now + ": Chat-Nachricht erhalten" ) ;
Console . BackgroundColor = ConsoleColor . Black ;
Console . ForegroundColor = ConsoleColor . Gray ;
2016-07-18 06:14:17 +02:00
Monitor . Enter ( _Lock ) ;
2016-07-25 09:23:22 +02:00
DefaultHibernateSessionManager . CurrentTenant = dataPacket . Tenant ;
2016-07-18 06:14:17 +02:00
2016-07-25 09:23:22 +02:00
var chatMessage = new ChatMessage
{
SenderPersonOid = dataPacket . SenderPersonOid ,
ChatText = dataPacket . ChatMessage ,
EmpfängerPersonOid = dataPacket . RecipientPersonOid ,
Uhrzeit = dataPacket . MessageTimeStamp ,
InsUser = dataPacket . ClientName
} ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Speichere die Chat-Nachricht in die Datenbank" ) ;
2016-07-25 09:23:22 +02:00
DAOFactory . GenericDAO . Insert ( chatMessage ) ;
2016-07-29 13:08:32 +02:00
// Testweise die Id einfügen
if ( chatMessage . Oid ! = null )
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Chat-Nachricht erfolgreich mit Oid " + chatMessage . Oid . Value + " gespeichert" ) ;
2016-07-29 13:08:32 +02:00
dataPacket . ServerseitigeOid = chatMessage . Oid . Value ;
}
2016-08-17 12:20:27 +02:00
if ( dataPacket . RecipientPersonOid > 0 )
2016-07-25 09:23:22 +02:00
{
2016-08-17 12:20:27 +02:00
if ( clientList . ContainsValue ( dataPacket . RecipientPersonOid ) )
2016-07-25 09:23:22 +02:00
{
2016-08-17 12:20:27 +02:00
var recipients = clientList . Where ( w = > w . Value . Equals ( dataPacket . RecipientPersonOid ) ) ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Leite die Chat-Nachricht an die Empfänger (Derselbe User angemeldet an verschiedenen Clients) weiter" ) ;
2016-08-17 12:20:27 +02:00
foreach ( var recipient in recipients )
{
recipient . Key . Send ( dataPacket . GetDataStream ( ) ) ;
}
2016-07-25 09:23:22 +02:00
}
2016-08-05 16:23:58 +02:00
2016-08-17 12:20:27 +02:00
var packet = new Packet
{
ClientseitigeOid = dataPacket . ClientseitigeOid ,
ServerseitigeOid = dataPacket . ServerseitigeOid ,
DataIdentifier = DataIdentifier . MessageResponse
} ;
2016-08-08 09:00:44 +02:00
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Sende Datenbank-Insert-Bestätigung an den Absender, damit die Nachricht später nicht doppelt auf den Client heruntergeladen wird" ) ;
2016-08-08 09:00:44 +02:00
dataPacket . Socket . Send ( packet . GetDataStream ( ) ) ;
2016-07-25 09:23:22 +02:00
}
2016-07-18 06:14:17 +02:00
}
finally
{
Monitor . Exit ( _Lock ) ;
}
}
break ;
case DataIdentifier . Logout :
2016-07-25 14:48:35 +02:00
2016-07-26 15:51:30 +02:00
clientList . Remove ( dataPacket . Socket ) ;
2016-07-25 14:48:35 +02:00
var notificationPacketLogout = new Packet ( dataPacket . Socket , dataPacket . ClientName , dataPacket . SenderPersonOid , 0 ) { DataIdentifier = DataIdentifier . StatusNotificationLogout } ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Sende Logout an alle anderen Clients" ) ;
2016-07-25 14:48:35 +02:00
foreach ( var client in clientList . Where ( w = > ! w . Value . Equals ( dataPacket . SenderPersonOid ) ) )
{
client . Key . Send ( notificationPacketLogout . GetDataStream ( ) ) ;
}
2016-07-29 13:08:32 +02:00
break ;
2016-08-17 12:20:27 +02:00
case DataIdentifier . Team :
try
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Team-Nachricht erhalten" ) ;
2016-08-17 12:20:27 +02:00
Monitor . Enter ( _Lock ) ;
DefaultHibernateSessionManager . CurrentTenant = dataPacket . Tenant ;
var chatMessage = new ChatMessage
{
SenderPersonOid = dataPacket . SenderPersonOid ,
ChatText = dataPacket . ChatMessage ,
EmpfängerPersonOid = dataPacket . RecipientPersonOid ,
Uhrzeit = dataPacket . MessageTimeStamp ,
InsUser = dataPacket . ClientName ,
TeamOid = dataPacket . RecipientPersonOid
} ;
var team = DAOFactory . GenericDAO . LoadByID < Team > ( dataPacket . RecipientPersonOid ) ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Speichere Team-Nachricht in der Datenbank" ) ;
2016-08-17 12:20:27 +02:00
DAOFactory . GenericDAO . Insert ( chatMessage ) ;
var personOids = team . MemberList . Select ( s = > s . Person . Oid . Value ) ;
if ( chatMessage . Oid ! = null )
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Team-Nachricht erfolgreich mit Oid " + chatMessage . Oid . Value + " gespeichert" ) ;
2016-08-17 12:20:27 +02:00
dataPacket . ServerseitigeOid = chatMessage . Oid . Value ;
}
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Leite die Team-Nachricht an die Empfänger weiter" ) ;
2016-08-17 12:20:27 +02:00
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
} ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Sende Datenbank-Insert-Bestätigung an den Absender, damit die Nachricht später nicht doppelt auf den Client heruntergeladen wird" ) ;
2016-08-17 12:20:27 +02:00
dataPacket . Socket . Send ( packet . GetDataStream ( ) ) ;
}
finally
{
Monitor . Exit ( _Lock ) ;
}
2016-07-29 13:08:32 +02:00
2016-08-26 12:28:57 +02:00
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 ) ;
2016-07-18 06:14:17 +02:00
break ;
}
2016-07-25 09:23:22 +02:00
WaitForClientData ( dataPacket . Socket , dataPacket . ClientName , dataPacket . SenderPersonOid , dataPacket . RecipientPersonOid ) ;
2016-07-18 06:14:17 +02:00
}
catch ( Exception e )
{
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Ein Fehler ist aufgetreten oder die App ist abgestürzt. Der Client wird ausgeloggt" ) ;
2016-07-25 09:23:22 +02:00
var sender = dataPacket . Socket ;
2016-07-29 13:08:32 +02:00
var notificationPacketLogout = new Packet ( dataPacket . Socket , dataPacket . ClientName , dataPacket . SenderPersonOid , 0 ) { DataIdentifier = DataIdentifier . StatusNotificationLogout } ;
2016-08-17 12:20:27 +02:00
try
2016-07-25 09:23:22 +02:00
{
2016-08-17 12:20:27 +02:00
Monitor . Enter ( _Lock ) ;
2016-07-29 13:08:32 +02:00
2016-08-17 12:20:27 +02:00
if ( clientList . ContainsKey ( sender ) )
2016-07-29 13:08:32 +02:00
{
2016-08-17 12:20:27 +02:00
clientList . Remove ( sender ) ;
2016-08-26 12:28:57 +02:00
Console . WriteLine ( DateTime . Now + ": Leite Logout an die anderen Clients weiter" ) ;
2016-08-17 12:20:27 +02:00
foreach ( var client in clientList )
{
client . Key . Send ( notificationPacketLogout . GetDataStream ( ) ) ;
}
2016-07-29 13:08:32 +02:00
2016-08-17 12:20:27 +02:00
sender . Close ( ) ;
}
}
finally
{
Monitor . Exit ( _Lock ) ;
2016-07-25 09:23:22 +02:00
}
2016-08-26 12:28:57 +02:00
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 ( ) ) ;
2016-07-18 06:14:17 +02:00
}
}
2016-08-26 12:28:57 +02:00
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 ;
}
2016-07-18 06:14:17 +02:00
}
}