/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { byte[] requestedHubConfigurationRawData = await connection.DownloadData("/Hub/Configuration.xml").ConfigureAwait(false); //and now do it without using XMLSerializer since that doesn't work in the agent. Configuration = DataConverter.ByteArrayToHubConfigurationXml(requestedHubConfigurationRawData); }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { byte[] requestedSessionsRawData = await connection.DownloadData(string.Format("/Hub/Hosts/{0}/RequestedSessions.xml", ClientId)).ConfigureAwait(false); //even though it's a session list we can't actually deserialize it directly - because we cant use XmlSerializer //since the types will not necessarily be public. RequestedSessions = DataConverter.ByteArrayToSessionsListXml(requestedSessionsRawData); }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { string strRequestUrl = string.Format("/Hub/Hosts/{0}/Sessions/{1}/session.xml", ClientId, SessionHeader.id); Debug.Assert(SessionHeader.sessionDetail.status != SessionStatusXml.running); Debug.Assert(SessionHeader.sessionDetail.status != SessionStatusXml.unknown); //we can't encode using XmlSerializer because it will only work with public types, and we //aren't public if we get ILMerged into something. byte[] encodedXml = DataConverter.SessionXmlToByteArray(SessionHeader); await connection.UploadData(strRequestUrl, HttpMethod.Post, "text/xml", encodedXml).ConfigureAwait(false); }
private void PerformCleanup(IWebChannelConnection connection) { try { //we're going to upload zero bytes as a delete to the right URL. connection.UploadData(GenerateResourceUri(), HttpMethod.Delete, BinaryContentType, new byte[] { }); } catch (Exception ex) { GC.KeepAlive(ex); #if DEBUG Log.RecordException(0, ex, null, RepositoryPublishClient.LogCategory, true); #endif } }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { string strRequestUrl = string.Format("/Hub/Hosts/{0}/Sessions/{1}/session.xml", ClientId, SessionId); SessionXml sessionHeaderXml = new SessionXml(); sessionHeaderXml.id = SessionId.ToString(); sessionHeaderXml.isComplete = true; sessionHeaderXml.isCompleteSpecified = true; //we can't encode using XmlSerializer because it will only work with public types, and we //aren't public if we get ILMerged into something. byte[] encodedXml = DataConverter.SessionXmlToByteArray(sessionHeaderXml); await connection.UploadData(strRequestUrl, HttpMethod.Post, "text/xml", encodedXml).ConfigureAwait(false); }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { string url; if (ClientId.HasValue) { url = string.Format("/Hub/Hosts/{0}/{1}", ClientId, GenerateResourceUri()); } else { url = string.Format("/Hub/{0}", GenerateResourceUri()); } byte[] sessionFilesListRawData = await connection.DownloadData(url).ConfigureAwait(false); //even though it's a session list we can't actually deserialize it directly - because we cant use XmlSerializer //since the types will not necessarily be public. Files = DataConverter.ByteArrayToSessionFilesListXml(sessionFilesListRawData); }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { byte[] requestedRepositoryRawData = await connection.UploadData(GenerateResourceUri(), HttpMethod.Put, XmlContentType, ConvertXmlToByteArray(InputRepository)).ConfigureAwait(false); //now we deserialize the response which is the new state of the document. //now, this is supposed to be a sessions list... using (var inputStream = new MemoryStream(requestedRepositoryRawData)) { XmlSerializerNamespaces xmlNsEmpty = new XmlSerializerNamespaces(); xmlNsEmpty.Add("", "http://www.gibraltarsoftware.com/Gibraltar/Repository.xsd"); //gets rid of the default namespaces we'd otherwise generate var xmlReader = XmlReader.Create(inputStream); XmlSerializer xmlSerializer = new XmlSerializer(typeof(ClientRepositoryXml), "http://www.gibraltarsoftware.com/Gibraltar/Repository.xsd"); ClientRepositoryXml repositoryXml = (ClientRepositoryXml)xmlSerializer.Deserialize(xmlReader); ResponseRepository = repositoryXml; } }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { if (m_Initialized == false) { Initialize(); } if (m_SessionTransportLock == null) { throw new InvalidOperationException("The session is currently being transported by another process."); } //if we might have left a file fragment on the server we need to send a delete call to remove any partial file if (m_PerformCleanup) { m_PerformCleanup = false; //even if we fail, don't try again. PerformCleanup(connection); } var resourceUri = GenerateResourceUri(); var additionalHeaders = new List <NameValuePair <string> >(); if (string.IsNullOrEmpty(m_SessionFileHash) == false) { additionalHeaders.Add(new NameValuePair <string>(HubConnection.SHA1HashHeader, m_SessionFileHash)); } //if it's SMALL we just put the whole thing up as a single action. if (m_SessionFileStream.Length < SinglePassCutoffBytes) { var sessionData = new byte[m_SessionFileStream.Length]; await m_SessionFileStream.ReadAsync(sessionData, 0, sessionData.Length).ConfigureAwait(false); await connection.UploadData(resourceUri, HttpMethod.Put, BinaryContentType, sessionData, additionalHeaders).ConfigureAwait(false); } else { //we need to do a segmented post operation. Note that we may be restarting a request after an error, so don't reset //our bytes written. m_SessionFileStream.Position = m_BytesWritten; var restartCount = 0; var sessionData = new byte[DefaultSegmentSizeBytes]; while (m_BytesWritten < m_SessionFileStream.Length) { //Read the next segment which is either our segment size or the last fragment of the file, exactly sized. if ((m_SessionFileStream.Length - m_SessionFileStream.Position) < sessionData.Length) { //we're at the last block - resize our buffer down. sessionData = new byte[(m_SessionFileStream.Length - m_SessionFileStream.Position)]; } await m_SessionFileStream.ReadAsync(sessionData, 0, sessionData.Length).ConfigureAwait(false); var isComplete = (m_SessionFileStream.Position == m_SessionFileStream.Length); var requestUrl = $"{resourceUri}?Start={m_BytesWritten}&Complete={isComplete}&FileSize={m_SessionFileStream.Length}"; try { await connection.UploadData(requestUrl, HttpMethod.Post, BinaryContentType, sessionData, additionalHeaders).ConfigureAwait(false); //and now that we've written the bytes and not gotten an exception we can mark these bytes as done! m_BytesWritten = (int)m_SessionFileStream.Position; UpdateProgressTrackingFile(); } catch (WebChannelBadRequestException ex) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Error, LogWriteMode.Queued, ex, RepositoryPublishClient.LogCategory, "Server exchange error, we will assume client and server are out of sync.", "The server returned a Bad Request Error (400) which generally means there is either a session-specific transfer problem that may be resolved by restarting the transfer from zero or an internal server problem.\r\nException: {0}", ex); } if (restartCount < 4) { //if we experience this type of Server-level transport error, assume there's some out of sync condition and start again. restartCount++; PerformCleanup(connection); m_SessionFileStream.Position = 0; m_BytesWritten = 0; UpdateProgressTrackingFile(); } else { //we didn't find a reason to restart the transfer, we need to let the exception fly. throw; } } } } //and since we're now good & done... clean up our temp stuff. SafeDeleteTemporaryData(); //finally, if we are supposed to purge a session once we sent we need to give that a shot. if (PurgeSessionOnSuccess) { SafePurgeSession(); } }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected override async Task OnProcessRequest(IWebChannelConnection connection) { if (m_Initialized == false) { Initialize(); } if (m_SessionTransportLock == null) { throw new InvalidOperationException("The session is currently being transported by another process."); } //if we might have left a file fragment on the server we need to send a delete call to remove any partial file if (m_PerformCleanup) { m_PerformCleanup = false; //even if we fail, don't try again. PerformCleanup(connection); } //find the prepared session file using (var sessionStream = Repository.LoadSessionFileStream(SessionId, FileId.Value)) { //calculate our SHA1 Hash... var additionalHeaders = new List <NameValuePair <string> >(); if (sessionStream.CanSeek) { try { using (var csp = SHA1.Create()) { string hash = BitConverter.ToString(csp.ComputeHash(sessionStream)); additionalHeaders.Add(new NameValuePair <string>(HubConnection.SHA1HashHeader, hash)); } //now back up the stream to the beginning so we can send the actual data. sessionStream.Position = 0; } catch (Exception ex) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Error, LogWriteMode.Queued, ex, RepositoryPublishClient.LogCategory, "Unable to calculate hash for session file due to " + ex.GetType() + " exception.", "The upload will proceed but without the hash to check the accuracy of the upload.\r\nException: {0}\r\n{1}\r\n", ex.GetType(), ex.Message); } } } //if it's SMALL we just put the whole thing up as a single action. if (sessionStream.Length < SinglePassCutoffBytes) { byte[] sessionData = new byte[sessionStream.Length]; sessionStream.Read(sessionData, 0, sessionData.Length); await connection.UploadData(GenerateResourceUri(), HttpMethod.Put, BinaryContentType, sessionData, additionalHeaders).ConfigureAwait(false); } else { //we need to do a segmented post operation. Note that we may be restarting a request after an error, so don't reset //our bytes written. sessionStream.Position = m_BytesWritten; int restartCount = 0; byte[] sessionData = new byte[DefaultSegmentSizeBytes]; while (m_BytesWritten < sessionStream.Length) { //Read the next segment which is either our segment size or the last fragment of the file, exactly sized. if ((sessionStream.Length - sessionStream.Position) < sessionData.Length) { //we're at the last block - resize our buffer down. sessionData = new byte[(sessionStream.Length - sessionStream.Position)]; } sessionStream.Read(sessionData, 0, sessionData.Length); bool isComplete = (sessionStream.Position == sessionStream.Length); string requestUrl = string.Format("{0}?Start={1}&Complete={2}&FileSize={3}", GenerateResourceUri(), m_BytesWritten, isComplete, sessionStream.Length); bool restartTransfer = false; try { await connection.UploadData(requestUrl, HttpMethod.Post, BinaryContentType, sessionData, additionalHeaders).ConfigureAwait(false); } catch (WebException ex) { //is this an access denied error? if (ex.Status == WebExceptionStatus.ProtocolError) { //get the inner web response to figure out exactly what the deal is. HttpWebResponse response = (HttpWebResponse)ex.Response; if (response.StatusCode == HttpStatusCode.BadRequest) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Error, LogWriteMode.Queued, ex, RepositoryPublishClient.LogCategory, "Server exchange error, we will assume client and server are out of sync.", "The server returned a Bad Request Error (400) which generally means there is either a session-specific transfer problem that may be resolved by restarting the transfer from zero or an internal server problem.\r\nException: {0}", ex); } if (restartCount < 4) { restartTransfer = true; restartCount++; } } } if (restartTransfer == false) { //we didn't find a reason to restart the transfer, we need to let the exception fly. throw; } } if (restartTransfer) { //if we experience this type of Server-level transport error, assume there's some out of sync condition and start again. PerformCleanup(connection); sessionStream.Position = 0; m_BytesWritten = 0; } else { //and now that we've written the bytes and not gotten an exception we can mark these bytes as done! m_BytesWritten = (int)sessionStream.Position; UpdateProgressTrackingFile(); } } } } //and since we're now good & done... clean up our temp stuff. SafeDeleteTemporaryData(); //finally, if we are supposed to purge a session once we sent we need to give that a shot. if (PurgeSessionOnSuccess) { SafePurgeSession(); } }
/// <summary> /// Implemented by inheritors to perform the request on the provided web client. /// </summary> /// <param name="connection"></param> protected abstract Task OnProcessRequest(IWebChannelConnection connection);
/// <summary> /// Perform the request against the specified web client connection. /// </summary> /// <param name="connection"></param> public async Task ProcessRequest(IWebChannelConnection connection) { await OnProcessRequest(connection).ConfigureAwait(false); }