public async Task OnCompleted(HttpTransfer transfer) { await this.notifications.Send( "Transfer Complete", $"{transfer.Identifier} complete" ); }
public async Task OnError(HttpTransfer transfer, Exception ex) { await this.notifications.Send( "Transfer Error", $"{transfer.Identifier} errored - SORRY!" ); }
public Task OnCompleted(HttpTransfer transfer) { return(Task.Run(() => { Xamarin.Forms.MessagingCenter.Send(this, "UPLOAD_DONE", transfer); })); }
public async Task <Screenshot> GetAppScreenShotAsync(Guid appGuid, AppScreenshotType appScreenshotType, AppScreenshotSize appScreenshotSize, int screenShotIndex) { return(await HttpTransfer.GetAppScreenshotAsync( appGuid, appScreenshotType, appScreenshotSize, screenShotIndex)); }
public Task OnError(HttpTransfer transfer, Exception ex) { return(Task.Run(() => { System.Diagnostics.Debug.WriteLine(ex.Message); MessagingCenter.Send(this, "UPLOAD_FAILED", ex); })); }
async Task TryUpdate(HttpTransfer transfer) { var result = await repository.Remove <SyncItem>(transfer.Identifier); if (result && this.syncManager.ShowBadgeCount) { this.notificationManager.Badge = this.notificationManager.Badge - 1; } }
static void ToViewModel(HttpTransferViewModel viewModel, HttpTransfer transfer) { // => Math.Round(this.transfer.BytesPerSecond.Bytes().Kilobytes, 2) + " Kb/s"; //public string EstimateMinsRemaining => Math.Round(this.transfer.EstimatedCompletionTime.TotalMinutes, 1) + " min(s)"; //viewModel.EstimateMinsRemaining = viewModel.PercentComplete = transfer.PercentComplete; viewModel.PercentCompleteText = $"{transfer.PercentComplete * 100}%"; viewModel.Status = transfer.Status.ToString(); }
static MetricHolder Get(HttpTransfer transfer, Dictionary <string, MetricHolder> metrics) { if (!metrics.ContainsKey(transfer.Identifier)) { metrics.Add(transfer.Identifier, new MetricHolder(transfer.Identifier) { LastBytesTransferred = transfer.BytesTransferred, LastPing = DateTime.UtcNow }); } return(metrics[transfer.Identifier]); }
static HttpTransferMetric Calculate(HttpTransfer transfer, IDictionary <string, MetricHolder> metrics) { var holder = metrics[transfer.Identifier]; var elapsed = DateTime.UtcNow - holder.LastPing; var totalSeconds = (long)elapsed.TotalSeconds; var xferDiff = transfer.BytesTransferred - holder.LastBytesTransferred; var bytesPerSecond = xferDiff / totalSeconds; var rawEta = (transfer.FileSize - transfer.BytesTransferred) / bytesPerSecond; var metric = new HttpTransferMetric(transfer, bytesPerSecond, TimeSpan.FromSeconds(rawEta)); holder.LastPing = DateTime.UtcNow; holder.LastBytesTransferred = transfer.BytesTransferred; return(metric); }
/// <summary> /// This method is called by <see cref="MediaServerDevice.WebServer_OnPacketReceiveSink"/> /// and handles the HTTP-GET or HTTP-GET message requests and provides /// the appropriate response. In either case, the handler is intended /// to handle requests for resource URIs that have been mapped to local /// files using the <see cref="MediaResource.AUTOMAPFILE"/> convention. /// <para> /// If a resource cannot be mapped to a local file, /// then the method will ask upper-layer application logic /// for a stream object to send in response to the request. /// This is used primarily in scenarios where the application intentionally /// specified a contentUri value for a resource that uses the /// <see cref="MediaResource.AUTOMAPFILE"/> convention but doesn't /// actually map to a local file. This gives the upper application layer /// to provide transcoded stream objects or some specialized file stream /// that is not stored on the local file system. /// </para> /// <para> /// Upper application layers can always opt to leave the stream object /// blank, effectively indicating that the HTTP-GET or head request /// cannot be handled because such a file does not exist. /// </para> /// </summary> /// <param name="msg"></param> /// <param name="session"></param> private void HandleGetOrHeadRequest(HTTPMessage msg, HTTPSession session) { // Format of DirectiveObj will be // "/[res.m_ResourceID]/[item.ID]/[item.Title].[ext]" // We want the bool is404 = true; Exception problem = null; string resourceID = null; string objectID = null; try { DText DirectiveParser = new DText(); DirectiveParser.ATTRMARK = "/"; DirectiveParser[0] = msg.DirectiveObj; resourceID = DirectiveParser[2]; objectID = DirectiveParser[3]; IDvResource res = this.GetResource(objectID, resourceID); if (res == null) { throw new Error_GetRequestError(msg.DirectiveObj, null); } else { // attempt to figure otu the local file path and the mime type string f = MediaResource.AUTOMAPFILE; string fileName = res.ContentUri.Substring(f.Length); string type = res.ProtocolInfo.MimeType; if ((type == null) || (type == "") || (type == "*")) { //content-type not known, programmer //that built content-hierarchy didn't provide one throw new Error_GetRequestError(msg.DirectiveObj, res); } else { // must be a get or head request // check if the file actually exists if (Directory.Exists(fileName)) { throw new Error_GetRequestError(msg.DirectiveObj, res); } FileNotMapped mapping = new FileNotMapped(); mapping.RequestedResource = res; mapping.LocalInterface = session.Source.ToString(); mapping.RedirectedStream = null; if (File.Exists(fileName)) { // the file exists, so go ahead and send it mapping.RedirectedStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); } else { try { // the file doesn't exist but the owner of this // server specified some kind of locally mapped file // so perhaps they may want to route a stream object themselves if (this.OnFileNotMapped != null) { this.OnFileNotMapped (this, mapping); } } catch (Exception ofnm) { mapping.RedirectedStream = null; } } // if the RedirectedStream is blank, then it means // no stream can be sent in response to the request if (mapping.RedirectedStream != null) { lock (session) { // get the intended length, if known long expectedLength = -1; if (mapping.OverrideRedirectedStreamLength) { expectedLength = mapping.ExpectedStreamLength; } else { expectedLength = mapping.RedirectedStream.Length; } if (String.Compare(msg.Directive, "HEAD", true) == 0) { // must be a head request - reply with 200/OK, content type, content length HTTPMessage head = new HTTPMessage(); head.StatusCode = 200; head.StatusData = "OK"; head.ContentType = type; if (expectedLength >= 0) { // if we can calculate the length, // then we provide a content-length and // also indicate that range requests can be // handled. head.OverrideContentLength = true; string rangeStr = msg.GetTag("RANGE"); if ((rangeStr == null) || (rangeStr == "")) { head.AddTag("CONTENT-LENGTH", expectedLength.ToString()); head.AddTag("ACCEPT-RANGES", "bytes"); } else { ArrayList rangeSets = new ArrayList(); head.StatusCode = 206; AddRangeSets(rangeSets, rangeStr.Trim().ToLower(), expectedLength); if (rangeSets.Count == 1) { head.AddTag("Content-Range", "bytes " + ((HTTPSession.Range)(rangeSets[0])).Position.ToString() + "-" + ((int)(((HTTPSession.Range)(rangeSets[0])).Position+((HTTPSession.Range)(rangeSets[0])).Length-1)).ToString() + "/" + expectedLength.ToString()); head.AddTag("Content-Length", ((HTTPSession.Range)(rangeSets[0])).Length.ToString()); } } } else { // can't calculate length => can't do range head.AddTag("ACCEPT-RANGES", "none"); } session.Send(head); is404 = false; } else { ArrayList rangeSets = new ArrayList(); string rangeStr = msg.GetTag("RANGE"); // Only allow range requests for content where we have the // entire length and also only for requests that have // also provided an allowed range. if ((rangeStr == null) || (rangeStr != "")) { if (expectedLength >= 0) { // validate the requested ranges; if invalid range // found, send the entire document... AddRangeSets(rangeSets, rangeStr.Trim().ToLower(), expectedLength); } } // must be a get request // create an outgoing transfer that is not visible to UPNP // GetTransferProgress method, and add the transfer HttpTransfer transferInfo = new HttpTransfer(false, false, session, res, mapping.RedirectedStream, expectedLength); this.AddTransfer(session, transferInfo); if (rangeSets.Count > 0) { session.SendStreamObject(mapping.RedirectedStream, (HTTPSession.Range[])rangeSets.ToArray(typeof(HTTPSession.Range)), type); } else { //start from the beginning mapping.RedirectedStream.Seek(0, SeekOrigin.Begin); if (expectedLength >= 0) { session.SendStreamObject(mapping.RedirectedStream, expectedLength, type); } else { session.SendStreamObject(mapping.RedirectedStream, type); } } is404 = false; } } } } } } catch (Exception error) { problem = error; } if (is404) { StringBuilder sb = new StringBuilder(); sb.Append("File not found."); sb.AppendFormat("\r\n\tRequested: \"{0}\"", msg.DirectiveObj); if (objectID != null) { sb.AppendFormat("\r\n\tObjectID=\"{0}\"", objectID); } if (resourceID != null) { sb.AppendFormat("\r\n\tResourceID=\"{0}\"", resourceID); } Error_GetRequestError getHeadError = problem as Error_GetRequestError; if (getHeadError != null) { sb.Append("\r\n"); IUPnPMedia mobj = this._GetEntry(objectID); if (mobj == null) { sb.AppendFormat("\r\n\tCould not find object with ID=\"{0}\"", objectID); } else { sb.AppendFormat("\r\n\tFound object with ID=\"{0}\"", objectID); sb.Append("\r\n---Metadata---\r\n"); sb.Append(mobj.ToDidl()); } sb.Append("\r\n"); if (getHeadError.Resource == null) { sb.Append("\r\n\tResource is null."); } else { sb.Append("\r\n\tResource is not null."); string uri = getHeadError.Resource.ContentUri; if (uri== null) { sb.Append("\r\n\t\tContentUri of resource is null."); } else if (uri == "") { sb.Append("\r\n\t\tContentUri of resource is empty."); } else { sb.AppendFormat("\r\n\t\tContentUri of resource is \"{0}\"", uri); } } } if (problem != null) { sb.Append("\r\n"); Exception e = problem; sb.Append("\r\n!!! Exception information !!!"); while (e != null) { sb.AppendFormat("\r\nMessage=\"{0}\".\r\nStackTrace=\"{1}\"", e.Message, e.StackTrace); e = e.InnerException; if (e != null) { sb.Append("\r\n---InnerException---"); } } } // file has not been found so return a valid HTTP 404 error message HTTPMessage error = new HTTPMessage(); error.StatusCode = 404; error.StatusData = "File not found"; error.StringBuffer = sb.ToString(); session.Send(error); } }
/// <summary> /// Method executes when a control point invokes the ContentDirectory.ImportResource action. /// The method first checks to see if the local URI actually maps to an automapped file /// and that the remote URI is an HTTP resource. /// The method then asks upper software layers to accept or reject the request to /// import a resource from a remote URI to a local URI. Upper software layers reject the request by throwing an exception, /// preferably a UPnPCustomException. If the request was approved by upper layers, /// then we do a bunch of stuff that results in the file getting transferred over HTTP. /// </summary> /// <param name="SourceURI">the URI where the binary should be obtained</param> /// <param name="DestinationURI">the URI (that can map to a local file) where the binary should be stored</param> /// <param name="TransferID">Returns ID for the file transfer.</param> private void SinkCd_ImportResource(System.Uri SourceURI, System.Uri DestinationURI, out System.UInt32 TransferID) { string objectID, resourceID; // Parse the media and resource IDs from the destination uri. this.GetObjectResourceIDS(DestinationURI, out objectID, out resourceID); if ((objectID == "") || (resourceID == "")) { throw new Error_NoSuchResource(DestinationURI.ToString()); } else { // TODO: Might consider throwing ane xception in the // rare case that stupid ass control point says to // download to a different media server. } // ensure that we're doing http if (SourceURI.Scheme.ToLower().StartsWith("http") == false) { throw new Error_NonHttpImport(DestinationURI.ToString()); } // get the resource object associated with the destination uri IDvResource res = this.GetResource(objectID, resourceID); // request application logic to approve the binary transfer; // Application logic should throw an exception to rject the request. if (this.OnRequestSaveBinary != null) { this.OnRequestSaveBinary(this, res); } else { throw new Error_InvalidServerConfiguration("ImportResource() cannot be supported until the vendor configures the server correctly."); } // // Grab the file through http-get // IPAddress addr = null; IPHostEntry ihe = null; IPEndPoint dest = null; // Attempt to get a routeable IP address for the request try { if(SourceURI.HostNameType == UriHostNameType.Dns) { ihe = Dns.GetHostByName(SourceURI.Host); addr = new IPAddress(ihe.AddressList[0].Address); } else { addr = IPAddress.Parse(SourceURI.Host); } } catch { throw new Error_ConnectionProblem("Could parse or resolve the SourceURI IP address represented by" +SourceURI.ToString()); } dest = new IPEndPoint(addr, SourceURI.Port); // Open a socket and connect to the remote IP address and port System.Net.Sockets.Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { s.Connect(dest); } catch { throw new Error_ConnectionProblem("Could not connect to the remote URI " + DestinationURI.ToString()); } // Do a check to make sure we're not dumping to a directory. string filename = res.ContentUri.Substring(MediaResource.AUTOMAPFILE.Length); if (Directory.Exists(filename)) { throw new Error_ImportError("System error. Resource has been mapped incorrectly. Cannot overwrite a directory with a binary."); } // Create an HTTP session for this socket. // Set things up so that the HTTP-GET will automatically dump // the body of the message into a binary file that has // been automatically mapped. HTTPSession session = new HTTPSession(s, null, null); this.SetupSessionForTransfer(session); session.OnHeader += new HTTPSession.ReceiveHeaderHandler(this.GetRequest_OnHeaderReceiveSink); try { session.UserStream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); } catch { throw new Error_ImportError("System busy. Could not open file from local system for writing."); } if (session.UserStream == null) { throw new Error_ImportError("System error. Cannot write to a null stream."); } SessionData sd = (SessionData) session.StateObject; sd.HttpVer1_1 = false; // Create the HTTP message that will request the binary. HTTPMessage msg = new HTTPMessage(); msg.Directive = "GET"; msg.DirectiveObj = HTTPMessage.UnEscapeString(SourceURI.PathAndQuery); msg.AddTag("HOST", dest.ToString()); msg.Version = "1.0"; // Create an HttpTransfer object that will represent the progress // of this file transfer and add it to the media server's current // transfers list. long expectedLength = 0; HttpTransfer transferInfo = new HttpTransfer(true, true, session, res, session.UserStream, expectedLength); this.AddTransfer(session, transferInfo); TransferID = transferInfo.m_TransferId; // Go make the request for the file. session.Send(msg); this.m_Stats.ImportResource++; this.FireStatsChange(); }
public async Task <BitmapImage> GetAppBackgroundImageAsync(Guid appGuid) { return(await HttpTransfer.GetAppBackgroundImageAsync(appGuid)); }
async Task <HttpTransfer> Download(HttpTransferStore request, CancellationToken ct) { HttpTransfer lastTransfer = default; var status = HttpTransferState.Pending; var file = new FileInfo(request.LocalFile); var message = this.Build(request); var fileSize = 0L; var bytesTransferred = file.Exists ? file.Length : 0; var fileMode = file.Exists ? FileMode.Append : FileMode.Create; Exception? exception = null; using (var fs = file.Open(fileMode, FileAccess.Write, FileShare.Write)) { while (!status.IsCompleted() && !ct.IsCancellationRequested) { try { if (fs.Length > 0) { var resumeOffset = fs.Length + 1; message.Headers.Range = new RangeHeaderValue(resumeOffset, null); } var buffer = new byte[65535]; var response = await this.httpClient .SendAsync( message, HttpCompletionOption.ResponseHeadersRead, ct ) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); var inputStream = await response .Content .ReadAsStreamAsync() .ConfigureAwait(false); var read = inputStream.Read(buffer, 0, buffer.Length); // status code 206 means restart if (response.Headers.AcceptRanges == null && fs.Length > 0) { // resume not supported, starting over fs.SetLength(0); fs.Flush(); bytesTransferred = 0; } var i = 0; while (read > 0 && !ct.IsCancellationRequested) { fileSize = response.Content?.Headers?.ContentRange?.Length ?? response.Content?.Headers?.ContentLength ?? 0; //this.RemoteFileName = response.Content?.Headers?.ContentDisposition?.FileName ?? String.Empty; ////pr.FileSize = response.Content?.Headers?.ContentLength ?? 0; // this will change on resume bytesTransferred += read; fs.Write(buffer, 0, read); fs.Flush(); i++; if (i % 4 == 0) { lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, false, request.UseMeteredConnection, null, fileSize, bytesTransferred, HttpTransferState.InProgress ); this.messageBus.Publish(lastTransfer); } read = inputStream.Read(buffer, 0, buffer.Length); } status = HttpTransferState.Completed; } catch (TaskCanceledException) { status = ct.IsCancellationRequested ? HttpTransferState.Canceled : HttpTransferState.Retrying; } catch (IOException ex) { if (ex.InnerException is WebException) { status = HttpTransferState.Retrying; } else { exception = ex; status = HttpTransferState.Error; } } catch (Exception ex) { exception = ex; status = HttpTransferState.Error; } lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, true, request.UseMeteredConnection, exception, fileSize, bytesTransferred, status ); this.messageBus.Publish(lastTransfer); } } return(lastTransfer); }
public void OnError(HttpTransfer transfer, Exception ex) { }
/// <summary> /// Lock the set of existing transfers for the entire server. /// Add the new transfer to the session's state object, for future reference. /// Obtain a unique transfer ID /// Add the new transfer to the set of existing transfers for the entire server. /// Unlock the set of existing transfers. /// </summary> /// <param name="session"></param> /// <param name="transferInfo"></param> private void AddTransfer(HTTPSession session, HttpTransfer transferInfo) { this.m_LockHttpTransfers.AcquireWriterLock(-1); SessionData sd = (SessionData) session.StateObject; sd.Transfers.Enqueue(transferInfo); sd.Requested++; // obtain unique transfer id UInt32 id = (uint) session.GetHashCode(); while (this.m_HttpTransfers.ContainsKey(id)) { id++; } this.m_HttpTransfers.Add(id, transferInfo); transferInfo.m_TransferId = id; this.m_LockHttpTransfers.ReleaseWriterLock(); this.FireHttpTransfersChange(); }
public Task OnCompleted(HttpTransfer transfer) => this.TryUpdate(transfer);
public Task OnError(HttpTransfer transfer, Exception ex) { // TODO: file error with delegate? return(this.TryUpdate(transfer)); }
public void OnCompleted(HttpTransfer transfer) { }
/// <summary> /// Handles the code for when a client attempts to post a binary /// to the server. The method attempts to find a resource object /// that maps to the specified uri and will then ask upper application /// logic for permission to save the binary. Application logic /// can reject the request by throwing an exception. /// <para> /// As an aside, piplelining is really easy for POST messages /// because the bodies of POST messages will contain the actual /// binary that's getting transfered to the server. Standard pipelining /// rules dictate that the next POST message must follow an already /// complete HTTP message. Regardless of whether the request was /// GET, POST, or HEAD - setting the WebSession's UserSTream property /// should always work. /// </para> /// </summary> /// <param name="msg"></param> /// <param name="WebSession"></param> private void HandlePostedFileToServer(HTTPMessage msg, HTTPSession WebSession) { // Format of DirectiveObj will be // "/[res.m_ResourceID]/[res.m_Owner.ID]/" // DText DirectiveParser = new DText(); DirectiveParser.ATTRMARK = "/"; DirectiveParser[0] = msg.DirectiveObj; string resourceID = DirectiveParser[2]; string objectID = DirectiveParser[3]; IDvResource res = this.GetResource(objectID, resourceID); WebSession.UserStream = null; if (res != null) { // only receive files that are allow overwriting if (res.AllowImport) { if (this.OnRequestSaveBinary != null) { // If application has not requested notifications for // when something post data, tnen automatically approve // the POST. } else { // Allow the application to approve or reject the POST. // If the application logic throws an exception, // then the WebSession.UserStream field remains null. // The message of the exception is used in the HTTP // error response to the POST-sender. this.OnRequestSaveBinary(this, res); } // Set the session to write to the following local file. // string path = res.ContentUri.Substring(MediaResource.AUTOMAPFILE.Length); // attempt to figure out the intended file extension by // examining the sender's post request for a content-type. // if so, append the extension as appropriately. string mime = msg.ContentType; string ext = MimeTypes.MimeToExtension(mime); if (path.EndsWith(ext) == false) { path += ext; } // attempt to figure ot the intended file's length by // examining the sender's post request long expectedLength = 0; try { expectedLength = this.ExtractContentLength(msg); } catch { } // Create a stream for the file incoming data, // wire up session to dump the incoming data to the stream, // create a transfer info block indicating information about // the transfer, and formally add the transfer. FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 4*1024); WebSession.UserStream = fs; HttpTransfer transferInfo = new HttpTransfer(true, true, WebSession, res, WebSession.UserStream, expectedLength); this.AddTransfer(WebSession, transferInfo); } } }
async Task <HttpTransfer> Upload(HttpTransferStore request, CancellationToken ct) { var file = new FileInfo(request.LocalFile); var status = HttpTransferState.Pending; var bytesTransferred = 0L; Exception? exception = null; HttpTransfer lastTransfer = default; // and not cancelled or error while (!status.IsCompleted() && !ct.IsCancellationRequested) { try { var content = new MultipartFormDataContent(); if (!request.PostData.IsEmpty()) { content.Add(new StringContent(request.PostData)); } content.Add( new ProgressStreamContent( file.OpenRead(), 8192, sent => { status = HttpTransferState.InProgress; bytesTransferred += sent; lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, true, request.UseMeteredConnection, null, file.Length, bytesTransferred, status ); this.messageBus.Publish(lastTransfer); } ), "blob", file.Name ); var message = this.Build(request); message.Content = content; var response = await this.httpClient .SendAsync(message, ct) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); status = HttpTransferState.Completed; } catch (TimeoutException) { status = HttpTransferState.Retrying; } catch (IOException ex) { if (ex.InnerException is WebException) { status = HttpTransferState.Retrying; } else { exception = ex; status = HttpTransferState.Error; } } catch (WebException ex) { switch (ex.Status) { case WebExceptionStatus.ConnectFailure: case WebExceptionStatus.Timeout: status = HttpTransferState.Retrying; break; default: status = HttpTransferState.Error; exception = ex; break; } } catch (TaskCanceledException) { status = ct.IsCancellationRequested ? HttpTransferState.Canceled : HttpTransferState.Retrying; } catch (Exception ex) { exception = ex; status = HttpTransferState.Error; } lastTransfer = new HttpTransfer( request.Id, request.Uri, request.LocalFile, true, request.UseMeteredConnection, exception, file.Length, bytesTransferred, status ); this.messageBus.Publish(lastTransfer); } return(lastTransfer); }
/// <summary> /// Method actually removes an <see cref="HttpTransfer"/> /// object from the mediaserver's list of active transfers. /// The method is executed after the LifeTimeMonitor /// notes that the prerequisite 30 seconds has passed since /// the actual transfer was completed. /// Method is called by <see cref="MediaServerDevice.Sink_OnExpired"/>. /// </summary> /// <param name="transferInfo"></param> private void RemoveTransfer(HttpTransfer transferInfo) { UInt32 id = transferInfo.m_TransferId; this.m_LockHttpTransfers.AcquireWriterLock(-1); bool error = false; if (this.m_HttpTransfers.ContainsKey(id)) { HttpTransfer transferInfo2 = (HttpTransfer) this.m_HttpTransfers[id]; if (transferInfo2 == transferInfo) { this.m_HttpTransfers.Remove(id); } else { error = true; } } else { error = true; } this.m_LockHttpTransfers.ReleaseWriterLock(); if (error) { throw new Error_TransferProblem(id, transferInfo); } this.FireHttpTransfersChange(); }
static void ToViewModel(HttpTransferViewModel viewModel, HttpTransfer transfer) { viewModel.PercentComplete = transfer.PercentComplete; viewModel.PercentCompleteText = $"{transfer.PercentComplete * 100}%"; viewModel.Status = transfer.Status.ToString(); }
/// <summary> /// Method executes when a control point invokes the ContentDirectory.ExportResource action. /// This method effectively causes the MediaServer to send a local binary to /// an URI that expects an HTTP-POST method of transfer. The method will report /// error messages if the specified local URI does not map to a URI that is /// automapped using <see cref="MediaResource.AUTOMAPFILE"/>. /// </summary> /// <param name="SourceURI"></param> /// <param name="DestinationURI"></param> /// <param name="TransferID"></param> private void SinkCd_ExportResource(System.Uri SourceURI, System.Uri DestinationURI, out System.UInt32 TransferID) { TransferID = 0; Uri dest = DestinationURI; string resourceID, objectID; // find media and resource IDs given a URI that should map to something // served on this server this.GetObjectResourceIDS(SourceURI, out objectID, out resourceID); if ((objectID == "") || (resourceID == "")) { throw new Error_NoSuchResource(SourceURI.ToString()); } IDvResource res = this.GetResource(objectID, resourceID); if (res != null) { //TODO: Might actually want to throw an exception here if the IP address //of the requested resource doesn't match an IP address of the server. //This may be more trouble than its worth though,a s it means //we have to figure out all of the IP addresses that apply to this //object and do a match, etc. What happens if the IP address //of the server changes spontaneously? Ignore the problem for now. // // create a socket that will connect to remote host // Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint remoteIPE = null; if (dest.HostNameType == System.UriHostNameType.Dns) { remoteIPE = new IPEndPoint(Dns.GetHostByName(dest.Host).AddressList[0], dest.Port); } else { remoteIPE = new IPEndPoint(IPAddress.Parse(dest.Host), dest.Port); } if (remoteIPE != null) { // check if the file actually exists string fileName = res.ContentUri.Substring(MediaResource.AUTOMAPFILE.Length); if (Directory.Exists(fileName)) { throw new Error_NoSuchResource("The binary could not be found on the system."); } FileNotMapped mapping = new FileNotMapped(); StringBuilder li = new StringBuilder(); li.AppendFormat("{0}:{1}", SourceURI.Host, SourceURI.Port); mapping.LocalInterface = li.ToString(); mapping.RequestedResource = res; mapping.RedirectedStream = null; if (File.Exists(fileName)) { // the file exists, so go ahead and send it mapping.RedirectedStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); } else { try { if (this.OnFileNotMapped != null) { this.OnFileNotMapped(this, mapping); } } catch (Exception ofnme) { mapping.RedirectedStream = null; } } if (mapping.RedirectedStream == null) { throw new Error_NoSuchResource("The binary could not be found on the system."); } else { try { s.Connect(remoteIPE); } catch { throw new UPnPCustomException(800, "Could not connect to the remote address of " +remoteIPE.ToString()+":"+remoteIPE.Port.ToString()); } // Create a session that will post the file HTTPSession session = null; SessionData sd; this.SetupSessionForTransfer(session); sd = (SessionData) session.StateObject; sd.HttpVer1_1 = true; HttpTransfer transferInfo = new HttpTransfer(false, true, session, res, mapping.RedirectedStream, mapping.RedirectedStream.Length); this.AddTransfer(session, transferInfo); session.PostStreamObject(mapping.RedirectedStream, dest.PathAndQuery, res.ProtocolInfo.MimeType); TransferID = transferInfo.m_TransferId; } } else { throw new UPnPCustomException(800, "Could not connect to the socket."); } } else { throw new Error_NoSuchResource(""); } this.m_Stats.ExportResource++; this.FireStatsChange(); }