/// <summary> /// /// </summary> /// <param name="client">The client that sent messages.</param> /// <param name="type">The message type</param> /// <param name="payload"></param> private void SendOnReceived(Socket client, SQLiteMessage type, byte[] payload) { // are we a 'send and wait type'? // if we are then send... and wait for a response. // if no respinse is sent... send one. if (type == SQLiteMessage.SendAndWaitRequest) { var packet = new PacketResponse(payload); OnReceived( packet.Packet, (p) => { // send whatever response the client wants us to. // but we need to send it back as a response. var response = new PacketResponse(SQLiteMessage.SendAndWaitResponse, p.Packed, packet.Guid); SendToClient(client, response.Packed); } ); return; } OnReceived( new Packet(type, payload), (p) => { // send whatever response the client wants us to. SendToClient(client, p.Packed); } ); }
/// <summary> /// Get a value from the server by index. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="requestType"></param> /// <param name="index"></param> /// <returns></returns> private async Task <T> GetIndexedValueAsync <T>(SQLiteMessage requestType, int index) { ThrowIfNoCommand(); var getValue = new GuidAndIndexRequest() { Guid = _parentCommand.Guid, Index = index }; var fields = Fields.Fields.SerializeObject(getValue); var response = await _controller.SendAndWaitAsync(requestType, fields.Pack(), _queryTimeouts).ConfigureAwait(false); switch (response.Message) { case SQLiteMessage.SendAndWaitTimeOut: throw new TimeoutException("There was a timeout error executing the read request from the reader."); case SQLiteMessage.ExecuteRequestResponse: return(response.Get <T>()); case SQLiteMessage.ExecuteReaderException: var error = response.Get <string>(); throw new SQLiteServerException(error); default: throw new InvalidOperationException($"Unknown response {response.Message} from the server."); } }
/// <summary> /// Get the result of a requres.t /// </summary> /// <param name="requestType"></param> /// <returns></returns> private async Task <T> GetGuiOnlyValueAsync <T>(SQLiteMessage requestType) { ThrowIfNoCommand(); var response = await _controller.SendAndWaitAsync(requestType, Encoding.ASCII.GetBytes(_parentCommand.Guid), _queryTimeouts).ConfigureAwait(false); switch (response.Message) { case SQLiteMessage.SendAndWaitTimeOut: throw new TimeoutException("There was a timeout error executing the read request from the reader."); case SQLiteMessage.ExecuteReaderReadResponse: case SQLiteMessage.ExecuteReaderGetRowResponse: var fields = Fields.Fields.Unpack(response.Payload); return(Fields.Fields.DeserializeObject <T>(fields)); case SQLiteMessage.ExecuteRequestResponse: return(response.Get <T>()); case SQLiteMessage.ExecuteReaderException: var error = response.Get <string>(); throw new SQLiteServerException(error); default: throw new InvalidOperationException($"Unknown response {response.Message} from the server."); } }
public async Task <Packet> SendAndWaitAsync(SQLiteMessage type, byte[] data, int timeout) { // create the packer var packer = new ResponsePacketHandler(this, WaitForResponseSleepTime); // send and wait for the response. return(await packer.SendAndWaitAsync(type, data, timeout).ConfigureAwait(false)); }
/// <summary> /// Send a message to the clients or to the master. /// @todo we need to fix this function as it is not a good use case. /// </summary> /// <param name="type"></param> /// <param name="data"></param> public void Send(SQLiteMessage type, byte[] data) { if (Server) { SendToClients(type, data); } else { SendToServer(type, data); } }
private long GetBusyTimeoutInMs(SQLiteMessage packetMessage) { switch (packetMessage) { case SQLiteMessage.CreateCommandException: case SQLiteMessage.ExecuteNonQueryRequest: case SQLiteMessage.ExecuteCommandNonQueryRequest: case SQLiteMessage.ExecuteCommandReaderRequest: case SQLiteMessage.ExecuteReaderRequest: return(CommandTimeout == 0 ? DefaultBusyTimeout : Convert.ToInt64((CommandTimeout * 1000) * 0.10)); default: return(DefaultBusyTimeout); } }
public PacketResponse(SQLiteMessage type, byte[] payload, string guid) { // make sure that the guid is the len we want it to be // anything other than that and we have issues. if (guid == null) { throw new ArgumentNullException(nameof(guid), "The given Guid cannot be null."); } if (guid.Length != GuidLen) { throw new Exception($"The length of our guid ({guid}), has changed from the expected len({GuidLen}."); } Guid = guid; Type = type; Payload = payload; }
/// <summary> /// Repack the type/data/guid so we can send it all in one go. /// </summary> private static byte[] Pack(SQLiteMessage type, byte[] payload, string guid) { // get the final size. // [int] payload len // [uint] type // [37] guid payload. var totalSize = sizeof(uint) + sizeof(int) + (payload?.Length ?? 0) + GuidLen; var bytes = new byte[totalSize]; var bLen = BitConverter.GetBytes((payload?.Length ?? 0) + GuidLen); var bType = BitConverter.GetBytes((uint)type); var bGuid = Encoding.ASCII.GetBytes(guid); // add the len var dstOffset = 0; Buffer.BlockCopy(bLen, 0, bytes, dstOffset, sizeof(int)); dstOffset += sizeof(int); Buffer.BlockCopy(bType, 0, bytes, dstOffset, sizeof(uint)); dstOffset += sizeof(uint); if (payload != null && payload.Length > 0) { Buffer.BlockCopy(payload, 0, bytes, dstOffset, payload.Length); dstOffset += payload.Length; } // finally the guid Buffer.BlockCopy(bGuid, 0, bytes, dstOffset, bGuid.Length); dstOffset += bGuid.Length; // sanity check if (dstOffset != totalSize) { throw new Exception("There was an issue re-creating the response packet."); } // we can now return the payload. return(bytes); }
/// <summary> /// Send a request to the server and wait for a response. /// </summary> /// <param name="type"></param> /// <param name="data"></param> /// <param name="timeout">The max number of ms we will be waitng.</param> /// <returns>The response packet</returns> public async Task <Packet> SendAndWaitAsync(SQLiteMessage type, byte[] data, int timeout) { // listen for new messages. Packet response = null; var watch = System.Diagnostics.Stopwatch.StartNew(); var received = new ConnectionsController.DelegateOnReceived((p, r) => { lock (_lock) { try { // is it the response we might be waiting for? if (p.Message != SQLiteMessage.SendAndWaitResponse) { // it is not a response, so we are not really interested. return; } // it looks like a posible match // so we will try and unpack it and see if it is the actual response. var packetResponse = new PacketResponse(p.Packed); if (packetResponse.Guid != _guid) { // not the response packet we were looking for. return; } // we cannot use the payload of packet.Payload as it is // it is the payload of "Types.SendAndWaitResponse" var r2 = new Packet(packetResponse.Payload); if (r2.Message == SQLiteMessage.SendAndWaitBusy) { watch.Restart(); return; } response = r2; } catch { response = null; } } }); // start listenting _connection.OnReceived += received; // try and send. try { // the packet handler. var packet = new PacketResponse(type, data); // save the guid we are looking for. _guid = packet.Guid; // send the data and wait for a response. _connection.Send(SQLiteMessage.SendAndWaitRequest, packet.Packed); await Task.Run(async() => { watch.Restart(); while (response == null) { // delay a little to give other thread a chance. if (_waitForResponseSleepTime > 0) { await Task.Delay(_waitForResponseSleepTime).ConfigureAwait(false); } else { await Task.Yield(); } // check for delay if (timeout > 0 && watch.ElapsedMilliseconds >= timeout * 1000) { // we timed out. break; } } watch.Stop(); }).ConfigureAwait(false); } finally { // whatever happens, we are no longer listening _connection.OnReceived -= received; } // return what we found. return(response ?? new Packet(SQLiteMessage.SendAndWaitTimeOut, 1)); }
/// <summary> /// Send a single message to the master. /// </summary> /// <param name="type"></param> /// <param name="data"></param> private void SendToServer(SQLiteMessage type, byte[] data) { SendToServer(new Packet(type, data)); }
/// <summary> /// Send a message to all the listening clients. /// </summary> /// <param name="type"></param> /// <param name="data"></param> private void SendToClients(SQLiteMessage type, byte[] data) { SendToClients(new Packet(type, data)); }
public PacketResponse(SQLiteMessage type, byte[] payload) : this(type, payload, System.Guid.NewGuid().ToString()) { }
/// <summary> /// Constructor with a string /// </summary> /// <param name="message"></param> /// <param name="payload"></param> public Packet(SQLiteMessage message, string payload) { Payload = payload == null ? null : Encoding.ASCII.GetBytes(payload); Message = message; }
/// <summary> /// Constructor with a byte array /// </summary> /// <param name="message"></param> /// <param name="payload"></param> public Packet(SQLiteMessage message, byte[] payload) { Payload = payload; Message = message; }
/// <summary> /// Constructor with an int. /// </summary> /// <param name="message"></param> /// <param name="payload"></param> public Packet(SQLiteMessage message, long payload) { Payload = BitConverter.GetBytes(payload); Message = message; }