internal void MergeFromJSON(FileState state, IDictionary <string, object> jsonData)
 {
     lock (this.mutex)
     {
         string url = jsonData["url"] as string;
         state.Url      = new Uri(url, UriKind.Absolute);
         state.bucketId = FetchBucketId(url);
         state.token    = jsonData["token"] as string;
         state.bucket   = jsonData["bucket"] as string;
         state.ObjectId = jsonData["objectId"] as string;
     }
 }
        public Task <FileState> SaveAsync(FileState state,
                                          Stream dataStream,
                                          String sessionToken,
                                          IProgress <AVUploadProgressEventArgs> progress,
                                          CancellationToken cancellationToken = default(CancellationToken))
        {
            if (state.Url != null)
            {
                // !isDirty
                return(Task <FileState> .FromResult(state));
            }

            if (cancellationToken.IsCancellationRequested)
            {
                var tcs = new TaskCompletionSource <FileState>();
                tcs.TrySetCanceled();
                return(tcs.Task);
            }

            var oldPosition = dataStream.Position;
            var command     = new AVCommand("/files/" + state.Name,
                                            method: "POST",
                                            sessionToken: sessionToken,
                                            contentType: state.MimeType,
                                            stream: dataStream);

            return(commandRunner.RunCommandAsync(command,
                                                 uploadProgress: progress,
                                                 cancellationToken: cancellationToken).OnSuccess(uploadTask =>
            {
                var result = uploadTask.Result;
                var jsonData = result.Item2;
                cancellationToken.ThrowIfCancellationRequested();

                return new FileState
                {
                    Name = jsonData["name"] as string,
                    Url = new Uri(jsonData["url"] as string, UriKind.Absolute),
                    MimeType = state.MimeType
                };
            }).ContinueWith(t =>
            {
                // Rewind the stream on failure or cancellation (if possible)
                if ((t.IsFaulted || t.IsCanceled) && dataStream.CanSeek)
                {
                    dataStream.Seek(oldPosition, SeekOrigin.Begin);
                }
                return t;
            }).Unwrap());
        }
        internal Task <Tuple <HttpStatusCode, string> > QiniuMakeFile(FileState state, Stream dataStream, string upToken, string key, long fsize, string[] ctxes, CancellationToken cancellationToken)
        {
            StringBuilder urlBuilder = new StringBuilder();

            urlBuilder.AppendFormat("{0}/mkfile/{1}", UP_HOST, fsize);
            if (key != null)
            {
                urlBuilder.AppendFormat("/key/{0}", ToBase64URLSafe(key));
            }
            var metaData = GetMetaData(state, dataStream);

            StringBuilder sb = new StringBuilder();

            foreach (string _key in metaData.Keys)
            {
                sb.AppendFormat("/{0}/{1}", _key, ToBase64URLSafe(metaData[_key].ToString()));
            }
            urlBuilder.Append(sb.ToString());

            IList <KeyValuePair <string, string> > headers = new List <KeyValuePair <string, string> >();
            //makeBlockDic.Add("Content-Type", "application/octet-stream");

            string authHead = "UpToken " + upToken;

            headers.Add(new KeyValuePair <string, string>("Authorization", authHead));
            int    proCount = ctxes.Length;
            Stream body     = new MemoryStream();

            for (int i = 0; i < proCount; i++)
            {
                byte[] bctx = StringToAscii(ctxes[i]);
                body.Write(bctx, 0, bctx.Length);
                if (i != proCount - 1)
                {
                    body.WriteByte((byte)',');
                }
            }
            body.Seek(0, SeekOrigin.Begin);

            var rtn = AVClient.RequestAsync(new Uri(urlBuilder.ToString()), "POST", headers, body, "text/plain", cancellationToken).OnSuccess(_ =>
            {
                var dic = AVClient.ReponseResolve(_.Result, CancellationToken.None);
                return(_.Result);
            });

            return(rtn);
        }
 public Task <FileState> SaveAsync(FileState state,
                                   Stream dataStream,
                                   String sessionToken,
                                   IProgress <AVUploadProgressEventArgs> progress,
                                   CancellationToken cancellationToken)
 {
     if (state.Url != null)
     {
         return(Task <FileState> .FromResult(state));
     }
     state.frozenData = dataStream;
     state.CloudName  = GetUniqueName(state);
     return(GetQiniuToken(state, CancellationToken.None).ContinueWith(t =>
     {
         MergeFromJSON(state, t.Result.Item2);
         return UploadNextChunk(state, dataStream, string.Empty, 0, progress);
     }).Unwrap().OnSuccess <FileState>(s =>
     {
         return state;
     }));
 }
        public Task <FileState> SaveAsync(FileState state,
                                          Stream dataStream,
                                          string sessionToken,
                                          IProgress <AVUploadProgressEventArgs> progress,
                                          CancellationToken cancellationToken)
        {
            if (state.Url != null)
            {
                return(Task <FileState> .FromResult(state));
            }
            fileState = state;
            data      = dataStream;
            return(AVFileController.GetFileToken(fileState, cancellationToken).OnSuccess(_ =>
            {
                var fileToken = _.Result.Item2;
                uploadUrl = fileToken["upload_url"].ToString();
                token = fileToken["token"].ToString();
                fileState.ObjectId = fileToken["objectId"].ToString();
                bucket = fileToken["bucket"].ToString();

                return FileSlice(cancellationToken).OnSuccess(t =>
                {
                    if (done)
                    {
                        return Task <FileState> .FromResult(state);
                    }
                    var response = t.Result.Item2;
                    var resumeData = response["data"] as IDictionary <string, object>;
                    if (resumeData.ContainsKey("access_url"))
                    {
                        return Task <FileState> .FromResult(state);
                    }
                    var sliceSession = resumeData["session"].ToString();
                    var sliceOffset = long.Parse(resumeData["offset"].ToString());
                    return UploadSlice(sliceSession, sliceOffset, dataStream, progress, cancellationToken);
                }).Unwrap();
            }).Unwrap());
        }
        internal static Task <Tuple <HttpStatusCode, IDictionary <string, object> > > GetFileToken(FileState fileState, CancellationToken cancellationToken)
        {
            Task <Tuple <HttpStatusCode, IDictionary <string, object> > > rtn;
            string currentSessionToken = AVUser.CurrentSessionToken;
            string str = fileState.Name;
            IDictionary <string, object> parameters = new Dictionary <string, object>();

            parameters.Add("name", str);
            parameters.Add("key", GetUniqueName(fileState));
            parameters.Add("__type", "File");
            parameters.Add("mime_type", AVFile.GetMIMEType(str));
            parameters.Add("metaData", fileState.MetaData);

            rtn = AVClient.RequestAsync("POST", new Uri("/fileTokens", UriKind.Relative), currentSessionToken, parameters, cancellationToken);

            return(rtn);
        }
        Task UploadNextChunk(FileState state, Stream dataStream, string context, long offset, IProgress <AVUploadProgressEventArgs> progress)
        {
            if (AVClient.fileUploaderDebugLog)
            {
                AVClient.LogTracker(state.counter + "|completed=" + state.completed + "|total=" + dataStream.Length + "|");
            }
            var totalSize     = dataStream.Length;
            var remainingSize = totalSize - state.completed;

            if (progress != null)
            {
                lock (mutex)
                {
                    progress.Report(new AVUploadProgressEventArgs()
                    {
                        Progress = AVFileController.CalcProgress(state.completed, totalSize)
                    });
                }
            }
            if (state.completed == totalSize)
            {
                return(QiniuMakeFile(state, state.frozenData, state.token, state.CloudName, totalSize, state.block_ctxes.ToArray(), CancellationToken.None));
            }
            else if (state.completed % BLOCKSIZE == 0)
            {
                var firstChunkBinary = GetChunkBinary(state.completed, dataStream);

                var blockSize = remainingSize > BLOCKSIZE ? BLOCKSIZE : remainingSize;
                return(MakeBlock(state, firstChunkBinary, blockSize).ContinueWith(t =>
                {
                    var dic = AVClient.ReponseResolve(t.Result, CancellationToken.None);
                    var ctx = dic.Item2["ctx"].ToString();

                    offset = long.Parse(dic.Item2["offset"].ToString());
                    var host = dic.Item2["host"].ToString();

                    state.completed += firstChunkBinary.Length;
                    if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize)
                    {
                        state.block_ctxes.Add(ctx);
                    }
                    //if (AVClient.fileUploaderDebugLog)
                    //{
                    //    AVClient.LogTracker(AVFile.objectCounter + "|completed=" + state.completed + "stream:position=" + dataStream.Position + "|");
                    //}

                    return UploadNextChunk(state, dataStream, ctx, offset, progress);
                }).Unwrap());
            }
            else
            {
                var chunkBinary = GetChunkBinary(state.completed, dataStream);
                return(PutChunk(state, chunkBinary, context, offset).ContinueWith(t =>
                {
                    var dic = AVClient.ReponseResolve(t.Result, CancellationToken.None);
                    var ctx = dic.Item2["ctx"].ToString();

                    offset = long.Parse(dic.Item2["offset"].ToString());
                    var host = dic.Item2["host"].ToString();
                    state.completed += chunkBinary.Length;
                    if (state.completed % BLOCKSIZE == 0 || state.completed == totalSize)
                    {
                        state.block_ctxes.Add(ctx);
                    }
                    //if (AVClient.fileUploaderDebugLog)
                    //{
                    //    AVClient.LogTracker(state.counter + "|completed=" + state.completed + "stream:position=" + dataStream.Position + "|");
                    //}

                    return UploadNextChunk(state, dataStream, ctx, offset, progress);
                }).Unwrap());
            }
        }
        Task <Tuple <HttpStatusCode, string> > MakeBlock(FileState state, byte[] firstChunkBinary, long blcokSize = 4194304)
        {
            MemoryStream firstChunkData = new MemoryStream(firstChunkBinary, 0, firstChunkBinary.Length);

            return(AVClient.RequestAsync(new Uri(new Uri(UP_HOST) + string.Format("mkblk/{0}", blcokSize)), "POST", GetQiniuRequestHeaders(state), firstChunkData, "application/octet-stream", CancellationToken.None));
        }
        internal Task <Tuple <HttpStatusCode, IDictionary <string, object> > > GetQiniuToken(FileState state, CancellationToken cancellationToken)
        {
            Task <Tuple <HttpStatusCode, IDictionary <string, object> > > rtn;
            string currentSessionToken = AVUser.CurrentSessionToken;
            string str = state.Name;

            IDictionary <string, object> parameters = new Dictionary <string, object>();

            parameters.Add("name", str);
            parameters.Add("key", state.CloudName);
            parameters.Add("__type", "File");
            parameters.Add("mime_type", AVFile.GetMIMEType(str));

            state.MetaData = GetMetaData(state, state.frozenData);

            parameters.Add("metaData", state.MetaData);

            rtn = AVClient.RequestAsync("POST", new Uri("/qiniu", UriKind.Relative), currentSessionToken, parameters, cancellationToken);

            return(rtn);
        }