public bool TryGetSlot(long slotno, out MemoryStreamSlot mem)
 {
     mem = null;
     if (slotno < 0 || slotno > lastslot)
     {
         return(false);
     }
     TouchSlot(slotno);
     return(slot.TryGetValue(slotno, out mem));
 }
        public void StartDownload(long slotno, ConcurrentDictionary <long, MemoryStreamSlot> slot, BlockingCollection <KeyValuePair <long, MemoryStreamSlot> > SlotBuffer)
        {
            int  timeout = (int)(1000 * (double)AmazonDriveStreamConfig.shortbuflen / (Config.FFmodule_TransferLimit * 1024));
            long start   = slotno * AmazonDriveStreamConfig.slotsize;
            long length  = AmazonDriveStreamConfig.slotsize;

            if (start + length > (targetItem.OrignalLength ?? 0))
            {
                length = (targetItem.OrignalLength ?? 0) - start;
            }
            if (length <= 0)
            {
                return;
            }
            readslot = slotno;
            done     = false;
            CancellationTokenSource cancel_cts = new CancellationTokenSource();
            var cts_1 = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, cancel_cts.Token);

            //Config.Log.LogOut(string.Format("AmazonDriveStream : start to download slot {0} offset {1:#,0} - ", slotno, start));

            Drive.downloadFile(targetItem, start, ct: cts_1.Token)
            .ContinueWith(task =>
            {
                if (!task.Wait(timeout, cts_1.Token))
                {
                    cts_1.Token.ThrowIfCancellationRequested();
                    //Config.Log.LogOut(string.Format("AmazonDriveStream : wait timeout slot {0}", slotno));
                    throw new IOException("transfer timeout0");
                }
                using (var stream = task.Result)
                {
                    while (slotno <= lastslot)
                    {
                        //Config.Log.LogOut(string.Format("AmazonDriveStream : download slot {0}", slotno));
                        cts_1.Token.ThrowIfCancellationRequested();

                        // すでに取得済みかチェック
                        MemoryStreamSlot o;
                        if (slot.TryGetValue(slotno, out o))
                        {
                            cts.Cancel();
                        }

                        readslot      = slotno;
                        byte[] buffer = new byte[(length > AmazonDriveStreamConfig.shortbuflen) ? AmazonDriveStreamConfig.shortbuflen : length];
                        var mem       = new MemoryStream();
                        var stime     = DateTime.Now;
                        int loopdelay = 0;
                        while (length > 0)
                        {
                            cts_1.Token.ThrowIfCancellationRequested();
                            var tret = stream.ReadAsync(buffer, 0, buffer.Length).ContinueWith(task2 =>
                            {
                                if (!task2.Wait(timeout, cts_1.Token))
                                {
                                    cts_1.Token.ThrowIfCancellationRequested();
                                    //Config.Log.LogOut(string.Format("AmazonDriveStream : wait timeout slot {0}", slotno));
                                    throw new IOException("transfer timeout1");
                                }
                                var ret = task2.Result;
                                mem.Write(buffer, 0, ret);
                                length    -= ret;
                                loopdelay += 5;
                                if ((DateTime.Now - stime).TotalMilliseconds > timeout + loopdelay)
                                {
                                    //Config.Log.LogOut(string.Format("AmazonDriveStream : transfer timeout slot {0}", slotno));
                                    throw new IOException("transfer timeout2");
                                }
                                if (buffer.Length > length)
                                {
                                    buffer = new byte[length];
                                }
                            }, cts_1.Token, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default)
                                       .Wait(timeout, cts_1.Token);
                            if (!tret)
                            {
                                //Config.Log.LogOut(string.Format("AmazonDriveStream : wait2 timeout slot {0}", slotno));
                                throw new IOException("transfer timeout3");
                            }
                        }
                        cts_1.Token.ThrowIfCancellationRequested();
                        var newslot = new MemoryStreamSlot(mem, start);
                        if (leadThread)
                        {
                            while (leadThread)
                            {
                                if (SlotBuffer.TryAdd(new KeyValuePair <long, MemoryStreamSlot>(slotno, newslot), 500, cts_1.Token))
                                {
                                    break;
                                }
                            }
                            if (!leadThread)
                            {
                                if (slot.GetOrAdd(slotno, newslot) != newslot)
                                {
                                    cts.Cancel();
                                }
                            }
                        }
                        else
                        {
                            if (slot.GetOrAdd(slotno, newslot) != newslot)
                            {
                                cts.Cancel();
                            }
                        }
                        cts_1.Token.ThrowIfCancellationRequested();

                        start  = ++slotno * AmazonDriveStreamConfig.slotsize;
                        length = AmazonDriveStreamConfig.slotsize;
                        if (start + length > (targetItem.OrignalLength ?? 0))
                        {
                            length = (targetItem.OrignalLength ?? 0) - start;
                        }
                        if (length <= 0)
                        {
                            return;
                        }
                    }
                }
            }, cts_1.Token, TaskContinuationOptions.LongRunning, TaskScheduler.Default)
            .ContinueWith(task =>
            {
                leadThread = false;
                if (task.IsFaulted)
                {
                    var e = task.Exception;
                    e.Flatten().Handle(ex =>
                    {
                        Config.Log.LogOut(string.Format("AmazonDriveStream : ERROR {0}", ex.Message));
                        return(true);
                    });
                    e.Handle(ex =>
                    {
                        return(true);
                    });
                    if (++failcount < 10)
                    {
                        Config.Log.LogOut(string.Format("AmazonDriveStream : ERROR restart to download {0} - ", slotno));
                        cancel_cts.Cancel(true);
                        StartDownload(slotno, slot, SlotBuffer);
                    }
                    else
                    {
                        Config.Log.LogOut(string.Format("AmazonDriveStream : ERROR too much fail stop. {0}", slotno));
                        done = true;
                    }
                }
                else if (task.IsCanceled)
                {
                    //Config.Log.LogOut(string.Format("AmazonDriveStream : cancel to download {0}", slotno));
                    done = true;
                }
                else if (task.IsCompleted)
                {
                    //Config.Log.LogOut(string.Format("AmazonDriveStream : finish download {0}", slotno));
                    done = true;
                }
                cancel_cts.Cancel(true);
            });
        }