/* * bool DownloadPage(DownloadMessage msg) * { * var origmsg = msg; * var tcs = new TaskCompletionSource<GotContentMessage>(); * var gotMsg = new GotContentMessage(msg); * Client.GetAsync(msg.DownloadUri,HttpCompletionOption.ResponseContentRead) * .ContinueWith((response, origmsg2) => { response.Result.Content.ReadAsStringAsync(); * return tcs.Task; * }) * .ContinueWith(t2=> DoResponse(t2)) * .PipeTo(Self); * return true; // show ActorSystem we handled message [expect next one immediately!] * } */ /// <summary> /// process incoming DownloadMessage /// </summary> /// <param name="msg">incoming msg<see cref="DownloadMessage"/></param> /// <returns>true to state that message has been accepted</returns> internal bool DownloadPage(DownloadMessage msg) { var uri = msg.DownloadUri; SysDiag.Debug.Assert(uri.IsAbsoluteUri, $"DownloadActor.DownloadPage({uri}) called with non-absolute Url"); var fs = msg.TargetPath; var fi = new FileInfo(fs); var dn = fi.DirectoryName; // string representing the directory's full path if (Directory.Exists(dn)) { if (msg.EnumDisposition == DownloadMessage.E_FileDisposition.LeaveIfExists && File.Exists(fs)) { var failmsg = new DownloadedMessage(msg, fs, HttpStatusCode.NotModified); Sender.Tell(failmsg); } } else { _Log.Info("DownloadPage creating directory {0} for {1}.{2}", dn, fi.Name, fi.Extension); Directory.CreateDirectory(dn); } // preserve volatile state now (before t1 that starts hot) for use by subsequent completion var ctx1 = new Context1(Sender, msg); var t1 = Client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); // returns Task<HttpResponseMessage> var t2A = t1.ContinueWith((req, state) => { var ctx1A = state as Context1; // recover entry context var dlmsg = ctx1A.DownloadMessage; var status = req.Result.StatusCode; if (req.IsFaulted) { var s = ""; Console.WriteLine(); PostBack(dlmsg, ctx1A, status, req.Exception); } else { var hrm = req.Result; try { hrm.EnsureSuccessStatusCode(); // throw if !IsSuccessStatusCode // TODO: refine the destination filename.extn from the response // TODO: decide if file already exists and if overwrite/transform #pragma warning disable GCop302 // Since '{0}' implements IDisposable, wrap it in a using() statement var outfs = new FileStream(fs, FileMode.Create); // open stream to write file. Disposed later ! #pragma warning restore GCop302 // Since '{0}' implements IDisposable, wrap it in a using() statement _Log.Info($"DownloadActor.DownloadPage({msg.Url} => {fs}) started"); } catch (Exception excp1) { PostBack(dlmsg, ctx1A, status, excp1); } } }, ctx1); var t2 = t1.ContinueWith(GetStuff, ctx1, TaskContinuationOptions.OnlyOnRanToCompletion); // happy path (no cancel/fault) var t2F = t1.ContinueWith((req2, state) => { var ctx1f = (Context1)state; }, TaskContinuationOptions.NotOnRanToCompletion); var t3 = t2.ContinueWith(t_gotContent) .PipeTo(Self); // Task return(true); // show ActorSystem we handled message [expect next one immediately!] }
/// <summary> /// The PostBack /// </summary> /// <param name="dlmsg">The dlmsg<see cref="DownloadMessage"/></param> /// <param name="ctx1A">The ctx1A<see cref="Context1"/></param> /// <param name="status">The status<see cref="HttpStatusCode"/></param> /// <param name="excp1">The excp1<see cref="Exception"/></param> private static void PostBack(DownloadMessage dlmsg, Context1 ctx1A, HttpStatusCode status, Exception excp1) { var failmsg = new DownloadedMessage(dlmsg, ctx1A.DownloadMessage.TargetPath, status, excp1); ctx1A.OrigSender.Tell(failmsg); }