using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HeuristicLab.Hive.Contracts.BusinessObjects;
using HeuristicLab.Hive.Contracts.Interfaces;
using HeuristicLab.Hive.Contracts;
using HeuristicLab.Core;
using HeuristicLab.Hive.Server.Core.InternalInterfaces.DataAccess;
using System.Resources;
using System.Reflection;
using HeuristicLab.Hive.JobBase;
using System.Runtime.CompilerServices;
namespace HeuristicLab.Hive.Server.Core {
///
/// The ClientCommunicator manages the whole communication with the client
///
public class ClientCommunicator: IClientCommunicator {
int nrOfJobs = 0;
Dictionary lastHeartbeats =
new Dictionary();
IClientAdapter clientAdapter;
IJobAdapter jobAdapter;
IJobResultsAdapter jobResultAdapter;
ILifecycleManager lifecycleManager;
public ClientCommunicator() {
clientAdapter = ServiceLocator.GetClientAdapter();
jobAdapter = ServiceLocator.GetJobAdapter();
jobResultAdapter = ServiceLocator.GetJobResultsAdapter();
lifecycleManager = ServiceLocator.GetLifecycleManager();
lifecycleManager.OnServerHeartbeat +=
new EventHandler(lifecycleManager_OnServerHeartbeat);
for (int i = 0; i < nrOfJobs; i++) {
Job job = new Job();
job.Id = i;
job.State = State.offline;
jobAdapter.Update(job);
}
lastHeartbeats = new Dictionary();
}
[MethodImpl(MethodImplOptions.Synchronized)]
void lifecycleManager_OnServerHeartbeat(object sender, EventArgs e) {
List allClients = new List(clientAdapter.GetAll());
List allJobs = new List(jobAdapter.GetAll());
foreach (ClientInfo client in allClients) {
if (client.State != State.offline && client.State != State.nullState) {
if (!lastHeartbeats.ContainsKey(client.ClientId)) {
client.State = State.offline;
clientAdapter.Update(client);
} else {
DateTime lastHbOfClient = lastHeartbeats[client.ClientId];
TimeSpan dif = DateTime.Now.Subtract(lastHbOfClient);
// check if time between last hearbeat and now is greather than HEARTBEAT_MAX_DIF
if (dif.Seconds > ApplicationConstants.HEARTBEAT_MAX_DIF) {
// if client calculated jobs, the job must be reset
if (client.State == State.calculating) {
// check wich job the client was calculating and reset it
foreach (Job job in allJobs) {
if (job.Client.ClientId == client.ClientId) {
// TODO check for job results
job.Client = null;
job.Percentage = 0;
job.State = State.idle;
}
}
}
// client must be set offline
client.State = State.offline;
clientAdapter.Update(client);
lastHeartbeats.Remove(client.ClientId);
}
}
} else {
if (lastHeartbeats.ContainsKey(client.ClientId))
lastHeartbeats.Remove(client.ClientId);
}
}
}
#region IClientCommunicator Members
[MethodImpl(MethodImplOptions.Synchronized)]
public Response Login(ClientInfo clientInfo) {
Response response = new Response();
if (lastHeartbeats.ContainsKey(clientInfo.ClientId)) {
lastHeartbeats[clientInfo.ClientId] = DateTime.Now;
} else {
lastHeartbeats.Add(clientInfo.ClientId, DateTime.Now);
}
ICollection allClients = clientAdapter.GetAll();
ClientInfo client = clientAdapter.GetById(clientInfo.ClientId);
if (client != null && client.State != State.offline && client.State != State.nullState) {
response.Success = false;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_LOGIN_USER_ALLREADY_ONLINE;
return response;
}
clientInfo.State = State.idle;
clientAdapter.Update(clientInfo);
response.Success = true;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_LOGIN_SUCCESS;
return response;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public ResponseHB SendHeartBeat(HeartBeatData hbData) {
ResponseHB response = new ResponseHB();
response.ActionRequest = new List();
if (clientAdapter.GetById(hbData.ClientId).State == State.offline ||
clientAdapter.GetById(hbData.ClientId).State == State.nullState) {
response.Success = false;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_USER_NOT_LOGGED_IN;
response.ActionRequest.Add(new MessageContainer(MessageContainer.MessageType.NoMessage));
return response;
}
if (lastHeartbeats.ContainsKey(hbData.ClientId)) {
lastHeartbeats[hbData.ClientId] = DateTime.Now;
} else {
lastHeartbeats.Add(hbData.ClientId, DateTime.Now);
}
response.Success = true;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_HARDBEAT_RECEIVED;
List allOfflineJobs = new List(jobAdapter.GetJobsByState(State.offline));
if (allOfflineJobs.Count > 0 && hbData.freeCores > 0)
response.ActionRequest.Add(new MessageContainer(MessageContainer.MessageType.FetchJob));
else
response.ActionRequest.Add(new MessageContainer(MessageContainer.MessageType.NoMessage));
return response;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public ResponseJob PullJob(Guid clientId) {
ResponseJob response = new ResponseJob();
lock (this) {
LinkedList allOfflineJobs = new LinkedList(jobAdapter.GetJobsByState(State.offline));
if (allOfflineJobs != null && allOfflineJobs.Count > 0) {
Job job2Calculate = allOfflineJobs.First.Value;
job2Calculate.State = State.calculating;
response.Job = job2Calculate;
jobAdapter.Update(job2Calculate);
response.Success = true;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_JOB_PULLED;
return response;
}
}
response.Success = true;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_NO_JOBS_LEFT;
return response;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public ResponseResultReceived SendJobResult(Guid clientId,
long jobId,
byte[] result,
Exception exception,
bool finished) {
ResponseResultReceived response = new ResponseResultReceived();
ClientInfo client =
clientAdapter.GetById(clientId);
Job job =
jobAdapter.GetById(jobId);
if (job == null) {
response.Success = false;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_NO_JO_WITH_THIS_ID;
return response;
}
if (job.State != State.calculating) {
response.Success = false;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_WRONG_JOB_STATE;
return response;
}
if (finished) {
job.State = State.finished;
jobAdapter.Update(job);
List jobResults = new List(jobResultAdapter.GetResultsOf(job));
foreach (JobResult currentResult in jobResults)
jobResultAdapter.Delete(currentResult);
}
JobResult jobResult =
new JobResult();
jobResult.Client = client;
jobResult.Job = job;
jobResult.Result = result;
jobResult.Exception = exception;
jobResultAdapter.Update(jobResult);
response.Success = true;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_JOBRESULT_RECEIVED;
response.JobId = jobId;
return response;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public Response Logout(Guid clientId) {
Response response = new Response();
if (lastHeartbeats.ContainsKey(clientId))
lastHeartbeats.Remove(clientId);
ClientInfo client = clientAdapter.GetById(clientId);
if (client == null) {
response.Success = false;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_LOGOUT_CLIENT_NOT_REGISTERED;
return response;
}
client.State = State.offline;
clientAdapter.Update(client);
response.Success = true;
response.StatusMessage = ApplicationConstants.RESPONSE_COMMUNICATOR_LOGOUT_SUCCESS;
return response;
}
#endregion
}
}