From 1d052590ef1102f0eb562b5f44e5ac10c05573f4 Mon Sep 17 00:00:00 2001 From: shijy-naruto Date: Mon, 20 May 2013 20:33:09 +0800 Subject: [PATCH 1/3] v5 ok init --- Demo/Demo.cs | 269 +++++------------- QBox/Auth/AuthToken.cs | 26 +- QBox/Auth/{DownloadPolicy.cs => GetPolicy.cs} | 81 +++--- QBox/Auth/{AuthPolicy.cs => PutPolicy.cs} | 117 ++++---- ...{DigestAuthClient.cs => QBoxAuthClient.cs} | 86 +++--- QBox/{RS => Conf}/Config.cs | 32 +-- QBox/FileOp/Exif.cs | 18 ++ QBox/FileOp/FileOpClient.cs | 4 +- QBox/FileOp/ImageInfo.cs | 19 ++ QBox/FileOp/ImageInfoRet.cs | 2 +- .../{ImageMogrifySpec.cs => ImageMogrify.cs} | 70 ++--- QBox/FileOp/ImageOp.cs | 29 -- .../FileOp/{ImageViewSpec.cs => ImageView.cs} | 57 ++-- QBox/{RS => IO}/FileParameter.cs | 35 +-- QBox/IO/IOClient.cs | 55 ++++ .../MultiPart.cs} | 254 +++++++++-------- QBox/IO/PutExtra.cs | 29 ++ QBox/{RS/PutFileRet.cs => IO/PutRet.cs} | 68 ++--- QBox/{RS => IO}/ResumablePut.cs | 194 ++++++------- .../ResumablePutRet.cs} | 76 ++--- QBox/QBox.csproj | 35 +-- QBox/RPC/Client.cs | 2 +- QBox/RS/{StatRet.cs => Entry.cs} | 99 +++---- QBox/RS/GetRet.cs | 45 --- QBox/RS/PutAuthRet.cs | 36 --- QBox/RS/RSClient.cs | 90 ++---- QBox/RS/RSService.cs | 127 --------- QBox/Util/Base64UrlSafe.cs | 2 +- QBox/Util/{StreamUtil.cs => IO.cs} | 92 +++--- 29 files changed, 881 insertions(+), 1168 deletions(-) rename QBox/Auth/{DownloadPolicy.cs => GetPolicy.cs} (67%) rename QBox/Auth/{AuthPolicy.cs => PutPolicy.cs} (62%) rename QBox/Auth/{DigestAuthClient.cs => QBoxAuthClient.cs} (77%) rename QBox/{RS => Conf}/Config.cs (57%) create mode 100644 QBox/FileOp/Exif.cs create mode 100644 QBox/FileOp/ImageInfo.cs rename QBox/FileOp/{ImageMogrifySpec.cs => ImageMogrify.cs} (87%) delete mode 100644 QBox/FileOp/ImageOp.cs rename QBox/FileOp/{ImageViewSpec.cs => ImageView.cs} (69%) rename QBox/{RS => IO}/FileParameter.cs (70%) create mode 100644 QBox/IO/IOClient.cs rename QBox/{RS/MultiPartFormDataPost.cs => IO/MultiPart.cs} (82%) create mode 100644 QBox/IO/PutExtra.cs rename QBox/{RS/PutFileRet.cs => IO/PutRet.cs} (83%) rename QBox/{RS => IO}/ResumablePut.cs (76%) rename QBox/{RS/ResumablePutFileRet.cs => IO/ResumablePutRet.cs} (84%) rename QBox/RS/{StatRet.cs => Entry.cs} (81%) delete mode 100644 QBox/RS/GetRet.cs delete mode 100644 QBox/RS/PutAuthRet.cs delete mode 100644 QBox/RS/RSService.cs rename QBox/Util/{StreamUtil.cs => IO.cs} (86%) diff --git a/Demo/Demo.cs b/Demo/Demo.cs index 3513a186..c9e311b8 100644 --- a/Demo/Demo.cs +++ b/Demo/Demo.cs @@ -1,9 +1,11 @@ using System; +using QBox.Conf; using QBox.Auth; -using QBox.RS; using QBox.FileOp; using QBox.RPC; using QBox.Util; +using QBox.IO; +using QBox.RS; namespace QBox.Demo { @@ -12,11 +14,7 @@ public class Demo public static string bucketName; public static string key; public static string localFile; - public static string bigkey; - public static string bigFile; public static string DEMO_DOMAIN; - public static Client conn; - public static RSService rs; public static void Main() { @@ -27,142 +25,71 @@ public static void Main() DEMO_DOMAIN = bucketName + ".qiniudn.com"; key = "gogopher.jpg"; localFile = "Resource/gogopher.jpg"; - bigkey = key; - bigFile = localFile; - conn = new DigestAuthClient(); - rs = new RSService(conn, bucketName); - - MkBucket(); - RSClientPutFile(); - RSClientPutFileWithCRC32(); - Get(key); + PutFile(); + Stat(); + Delete(); ResumablePutFile(); - Stat(bigkey); - Delete(key); - Drop(); - - MkBucket(); + MakeGetToken(); ImageOps(); - MakeDownloadToken(); - Console.ReadLine(); } - public static void MkBucket() - { - Console.WriteLine("\n===> RSService.MkBucket"); - CallRet callRet = rs.MkBucket(); - PrintRet(callRet); - } - - public static void RSClientPutFile() + public static void PutFile() { - Console.WriteLine("\n===> RSClient Generate UpToken"); - var authPolicy = new AuthPolicy(bucketName, 3600); - string upToken = authPolicy.MakeAuthTokenString(); + Console.WriteLine("\n===>PutFile: Generate UpToken"); + var policy = new PutPolicy(bucketName, 3600); + string upToken = policy.Token(); Console.WriteLine("upToken: " + upToken); - Console.WriteLine("\n===> RSClient.PutFileWithUpToken"); - PutFileRet putFileRet = RSClient.PutFileWithUpToken(upToken, bucketName, key, null, localFile, null, "key="); - PrintRet(putFileRet); - if (putFileRet.OK) + Console.WriteLine("\n===> PutFile"); + PutExtra extra = new PutExtra { Bucket = bucketName, MimeType = "image/jpeg" }; + PutRet ret = IOClient.PutFile(upToken, key, localFile, extra); + PrintRet(ret); + if (ret.OK) { - Console.WriteLine("Hash: " + putFileRet.Hash); + Console.WriteLine("Hash: " + ret.Hash); } else { - Console.WriteLine("Failed to RSClient.PutFileWithUpToken"); - } - } - - public static void RSClientPutFileWithCRC32() - { - Console.WriteLine("\n===> RSClientPutFileWithCRC32 Generate CRC32"); - UInt32 crc = CRC32.CheckSumFile(localFile); - Console.WriteLine("CRC32: " + crc.ToString()); - - Console.WriteLine("\n===> RSClientPutFileWithCRC32 Generate UpToken"); - var authPolicy = new AuthPolicy(bucketName, 3600); - string upToken = authPolicy.MakeAuthTokenString(); - Console.WriteLine("upToken: " + upToken); - - Console.WriteLine("\n===> RSClient.PutFileWithUpToken(CRC32)"); - PutFileRet putFileRet = RSClient.PutFileWithUpToken(upToken, bucketName, key, null, localFile, null, "key=", crc); - PrintRet(putFileRet); - if (putFileRet.OK) - { - Console.WriteLine("Hash: " + putFileRet.Hash); - } - else - { - Console.WriteLine("Failed to RSClient.PutFileWithUpToken(CRC32)"); + Console.WriteLine("Failed to PutFile"); } } public static void ResumablePutFile() { - Console.WriteLine("\n===> ResumablePut.PutFile"); - var authPolicy = new AuthPolicy(bucketName, 3600); - string upToken = authPolicy.MakeAuthTokenString(); - PutAuthClient client = new PutAuthClient(upToken); - PutFileRet putFileRet = ResumablePut.PutFile(client, bucketName, bigkey, null, bigFile, null, "key="); - PrintRet(putFileRet); - if (putFileRet.OK) - { - Console.WriteLine("Hash: " + putFileRet.Hash); - } - else - { - Console.WriteLine("Failed to ResumablePut.PutFile"); - } - } - - public static void Get(string key) - { - Console.WriteLine("\n===> RSService.Get"); - GetRet getRet = rs.Get(key, "attName"); - PrintRet(getRet); - if (getRet.OK) - { - Console.WriteLine("Hash: " + getRet.Hash); - Console.WriteLine("FileSize: " + getRet.FileSize); - Console.WriteLine("MimeType: " + getRet.MimeType); - Console.WriteLine("Url: " + getRet.Url); - } - else - { - Console.WriteLine("Failed to Get"); - } + Console.WriteLine("\n===> ResumablePutFile: Generate UpToken"); + var policy = new PutPolicy(bucketName, 3600); + string upToken = policy.Token(); + Console.WriteLine("upToken: " + upToken); - Console.WriteLine("\n===> RSService.GetIfNotModified"); - getRet = rs.GetIfNotModified(key, "attName", getRet.Hash); - PrintRet(getRet); - if (getRet.OK) + PutExtra extra = new PutExtra { Bucket = bucketName, MimeType = "image/jpeg" }; + PutRet ret = IOClient.ResumablePutFile(upToken, key, localFile, extra); + PrintRet(ret); + if (ret.OK) { - Console.WriteLine("Hash: " + getRet.Hash); - Console.WriteLine("FileSize: " + getRet.FileSize); - Console.WriteLine("MimeType: " + getRet.MimeType); - Console.WriteLine("Url: " + getRet.Url); + Console.WriteLine("Hash: " + ret.Hash); } else { - Console.WriteLine("Failed to GetIfNotModified"); + Console.WriteLine("Failed to ResumablePutFile"); } } - public static void Stat(string key) + public static void Stat() { - Console.WriteLine("\n===> RSService.Stat"); - StatRet statRet = rs.Stat(key); - PrintRet(statRet); - if (statRet.OK) - { - Console.WriteLine("Hash: " + statRet.Hash); - Console.WriteLine("FileSize: " + statRet.FileSize); - Console.WriteLine("PutTime: " + statRet.PutTime); - Console.WriteLine("MimeType: " + statRet.MimeType); + Console.WriteLine("\n===> Stat"); + RSClient client = new RSClient(); + Entry entry = client.Stat(bucketName, key); + PrintRet(entry); + if (entry.OK) + { + Console.WriteLine("Hash: " + entry.Hash); + Console.WriteLine("Fsize: " + entry.Fsize); + Console.WriteLine("PutTime: " + entry.PutTime); + Console.WriteLine("MimeType: " + entry.MimeType); + Console.WriteLine("Customer: " + entry.Customer); } else { @@ -170,41 +97,34 @@ public static void Stat(string key) } } - public static void Delete(string key) + public static void Delete() { - Console.WriteLine("\n===> RSService.Delete"); - CallRet deleteRet = rs.Delete(key); - PrintRet(deleteRet); - if (!deleteRet.OK) + Console.WriteLine("\n===> Delete"); + RSClient client = new RSClient(); + CallRet ret = client.Delete(bucketName, key); + PrintRet(ret); + if (!ret.OK) { Console.WriteLine("Failed to Delete"); } } - public static void Drop() - { - Console.WriteLine("\n===> RSService.Drop"); - CallRet dropRet = rs.Drop(); - PrintRet(dropRet); - if (!dropRet.OK) - { - Console.WriteLine("Failed to Drop"); - } - } - - public static void MakeDownloadToken() + public static void MakeGetToken() { - Console.WriteLine("\n===> Auth.MakeDownloadToken"); + Console.WriteLine("\n===> GetPolicy Token"); string pattern = "*/*"; - var downloadPolicy = new DownloadPolicy(pattern, 3600); - string dnToken = downloadPolicy.MakeAuthTokenString(); - Console.WriteLine("dnToken: " + dnToken); + var policy = new GetPolicy(pattern, 3600); + string getToken = policy.Token(); + Console.WriteLine("GetToken: " + getToken); } public static void ImageOps() { + string host = "http://" + DEMO_DOMAIN + "/" + key; + Console.WriteLine("\n===> FileOp.ImageInfo"); - ImageInfoRet infoRet = ImageOp.ImageInfo("http://" + DEMO_DOMAIN + "/" + key); + string imageInfoURL = ImageInfo.MakeRequest(host); + ImageInfoRet infoRet = ImageInfo.Call(imageInfoURL); PrintRet(infoRet); if (infoRet.OK) { @@ -218,75 +138,32 @@ public static void ImageOps() Console.WriteLine("Failed to ImageInfo"); } - Console.WriteLine("\n===> FileOp.ImageExif"); - CallRet exifRet = ImageOp.ImageExif("http://" + DEMO_DOMAIN + "/" + key); + Console.WriteLine("\n===> FileOp.Exif"); + string exifURL = Exif.MakeRequest(host); + CallRet exifRet = Exif.Call(exifURL); PrintRet(exifRet); if (!exifRet.OK) { Console.WriteLine("Failed to ImageExif"); } - Console.WriteLine("\n===> FileOp.ImageViewUrl"); - ImageViewSpec viewSpec = new ImageViewSpec{Mode = 0, Width = 200, Height= 200}; - string viewUrl = ImageOp.ImageViewUrl("http://" + DEMO_DOMAIN + "/" + key, viewSpec); - Console.WriteLine("ImageViewUrl 1:" + viewUrl); - viewSpec.Quality = 1; - viewSpec.Format = "gif"; - viewUrl = ImageOp.ImageViewUrl("http://" + DEMO_DOMAIN + "/" + key, viewSpec); - Console.WriteLine("ImageViewUrl 2:" + viewUrl); - viewSpec.Quality = 90; - viewSpec.Sharpen = 10; - viewSpec.Format = "png"; - viewUrl = ImageOp.ImageViewUrl("http://" + DEMO_DOMAIN + "/" + key, viewSpec); - Console.WriteLine("ImageViewUrl 3:" + viewUrl); + Console.WriteLine("\n===> FileOp.ImageView"); + ImageView imageView = new ImageView { Mode = 0, Width = 200, Height = 200, Quality = 90, Format = "gif" }; + string viewUrl = imageView.MakeRequest(host); + Console.WriteLine("ImageViewURL:" + viewUrl); - Console.WriteLine("\n===> FileOp.ImageMogrifyUrl"); - ImageMogrifySpec mogrSpec = new ImageMogrifySpec { - Thumbnail = "!50x50r", Gravity = "center", Rotate = 90, - Crop = "!50x50", Quality = 80, AutoOrient = true - }; - string mogrUrl = ImageOp.ImageMogrifyUrl("http://" + DEMO_DOMAIN + "/" + key, mogrSpec); - Console.WriteLine("ImageMogrifyUrl:" + mogrUrl); - - Console.WriteLine("\n===> Get"); - GetRet getRet = rs.Get(key, "save-as"); - PrintRet(getRet); - if (getRet.OK) - { - Console.WriteLine("Hash: " + getRet.Hash); - Console.WriteLine("FileSize: " + getRet.FileSize); - Console.WriteLine("MimeType: " + getRet.MimeType); - Console.WriteLine("Url: " + getRet.Url); - } - else - { - Console.WriteLine("Failed to Get"); - } - Console.WriteLine("\n===> FileOp.ImageMogrifySaveAs"); - PutFileRet saveAsRet = rs.ImageMogrifySaveAs(getRet.Url, mogrSpec, key + ".mogr-save-as"); - PrintRet(saveAsRet); - if (saveAsRet.OK) - { - Console.WriteLine("Hash: " + saveAsRet.Hash); - } - else + Console.WriteLine("\n===> FileOp.ImageMogrify"); + ImageMogrify imageMogr = new ImageMogrify { - Console.WriteLine("Failed to ImageMogrifySaveAs"); - } - Console.WriteLine("\n===> Get"); - getRet = rs.Get(key + ".mogr-save-as", "mogr-save-as.jpg"); - PrintRet(getRet); - if (getRet.OK) - { - Console.WriteLine("Hash: " + getRet.Hash); - Console.WriteLine("FileSize: " + getRet.FileSize); - Console.WriteLine("MimeType: " + getRet.MimeType); - Console.WriteLine("Url: " + getRet.Url); - } - else - { - Console.WriteLine("Failed to Get"); - } + Thumbnail = "!50x50r", + Gravity = "center", + Rotate = 90, + Crop = "!50x50", + Quality = 80, + AutoOrient = true + }; + string mogrUrl = imageMogr.MakeRequest(host); + Console.WriteLine("ImageMogrifyURL:" + mogrUrl); } public static void PrintRet(CallRet callRet) diff --git a/QBox/Auth/AuthToken.cs b/QBox/Auth/AuthToken.cs index ecc02b75..dde06335 100644 --- a/QBox/Auth/AuthToken.cs +++ b/QBox/Auth/AuthToken.cs @@ -2,7 +2,7 @@ using System.Text; using System.IO; using System.Security.Cryptography; -using QBox.RS; +using QBox.Conf; using QBox.Util; namespace QBox.Auth @@ -11,35 +11,33 @@ public static class AuthToken { public static byte[] Make(string scope) { - Encoding encoding = Encoding.ASCII; - byte[] accessKey = encoding.GetBytes(Config.ACCESS_KEY); - byte[] secretKey = encoding.GetBytes(Config.SECRET_KEY); - byte[] upToken = null; + byte[] accessKey = Config.Encoding.GetBytes(Config.ACCESS_KEY); + byte[] secretKey = Config.Encoding.GetBytes(Config.SECRET_KEY); + byte[] token = null; try { - byte[] policyBase64 = encoding.GetBytes(Base64UrlSafe.Encode(scope)); - byte[] digestBase64 = null; + byte[] encodedScope = Config.Encoding.GetBytes(Base64URLSafe.Encode(scope)); + byte[] digestScope = null; using (HMACSHA1 hmac = new HMACSHA1(secretKey)) { - byte[] digest = hmac.ComputeHash(policyBase64); - digestBase64 = encoding.GetBytes(Base64UrlSafe.Encode(digest)); + byte[] digest = hmac.ComputeHash(encodedScope); + digestScope = Config.Encoding.GetBytes(Base64URLSafe.Encode(digest)); } using (MemoryStream buffer = new MemoryStream()) { buffer.Write(accessKey, 0, accessKey.Length); buffer.WriteByte((byte)':'); - buffer.Write(digestBase64, 0, digestBase64.Length); + buffer.Write(digestScope, 0, digestScope.Length); buffer.WriteByte((byte)':'); - buffer.Write(policyBase64, 0, policyBase64.Length); - upToken = buffer.ToArray(); + buffer.Write(encodedScope, 0, encodedScope.Length); + token = buffer.ToArray(); } } catch (Exception e) { Console.WriteLine(e.ToString()); } - return upToken; + return token; } - } } diff --git a/QBox/Auth/DownloadPolicy.cs b/QBox/Auth/GetPolicy.cs similarity index 67% rename from QBox/Auth/DownloadPolicy.cs rename to QBox/Auth/GetPolicy.cs index 219a152a..d2d80369 100644 --- a/QBox/Auth/DownloadPolicy.cs +++ b/QBox/Auth/GetPolicy.cs @@ -1,43 +1,38 @@ -using System; -using System.Text; -using System.IO; -using System.Security.Cryptography; -using LitJson; -using QBox.RS; -using QBox.Util; - -namespace QBox.Auth -{ - public class DownloadPolicy - { - public string Pattern { get; set; } - public long Deadline { get; set; } - - public DownloadPolicy(string pattern, long expires) - { - Pattern = pattern; - DateTime begin = new DateTime(1970, 1, 1); - DateTime now = DateTime.Now; - TimeSpan interval = new TimeSpan(now.Ticks - begin.Ticks); - Deadline = (long)interval.TotalSeconds + expires; - } - - public string Marshal() - { - JsonData data = new JsonData(); - data["S"] = Pattern; - data["E"] = Deadline; - return data.ToJson(); - } - - public byte[] MakeAuthToken() - { - return AuthToken.Make(Marshal()); - } - - public string MakeAuthTokenString() - { - return Encoding.ASCII.GetString(MakeAuthToken()); - } - } -} +using System; +using System.Text; +using System.IO; +using System.Security.Cryptography; +using LitJson; +using QBox.Util; +using QBox.Conf; + +namespace QBox.Auth +{ + public class GetPolicy + { + public string Pattern { get; set; } + public long Deadline { get; set; } + + public GetPolicy(string pattern, long expires) + { + Pattern = pattern; + DateTime begin = new DateTime(1970, 1, 1); + DateTime now = DateTime.Now; + TimeSpan interval = new TimeSpan(now.Ticks - begin.Ticks); + Deadline = (long)interval.TotalSeconds + expires; + } + + public string Marshal() + { + JsonData data = new JsonData(); + data["S"] = Pattern; + data["E"] = Deadline; + return data.ToJson(); + } + + public string Token() + { + return Config.Encoding.GetString(AuthToken.Make(Marshal())); + } + } +} diff --git a/QBox/Auth/AuthPolicy.cs b/QBox/Auth/PutPolicy.cs similarity index 62% rename from QBox/Auth/AuthPolicy.cs rename to QBox/Auth/PutPolicy.cs index 1bd4a9c6..a28c4e51 100644 --- a/QBox/Auth/AuthPolicy.cs +++ b/QBox/Auth/PutPolicy.cs @@ -1,58 +1,59 @@ -using System; -using System.Text; -using System.IO; -using LitJson; -using System.Security.Cryptography; -using QBox.RS; -using QBox.Util; - -namespace QBox.Auth -{ - public class AuthPolicy - { - public string Scope { get; set; } - public long Deadline { get; set; } - public string CallbackUrl { get; set; } - public string CallbackBodyType { get; set; } - public bool Escape { get; set; } - public string AsyncOps { get; set; } - public string ReturnBody { get; set; } - - public AuthPolicy(string scope, long expires) - { - Scope = scope; - DateTime begin = new DateTime(1970, 1, 1); - DateTime now = DateTime.Now; - TimeSpan interval = new TimeSpan(now.Ticks - begin.Ticks); - Deadline = (long)interval.TotalSeconds + expires; - } - - public string Marshal() - { - JsonData data = new JsonData(); - data["scope"] = Scope; - data["deadline"] = Deadline; - if (!String.IsNullOrEmpty(CallbackUrl)) - data["callbackUrl"] = CallbackUrl; - if (!String.IsNullOrEmpty(CallbackBodyType)) - data["callbackBodyType"] = CallbackBodyType; - if (Escape) - data["escape"] = 1; - if (!String.IsNullOrEmpty(AsyncOps)) - data["asyncOps"] = AsyncOps; - if (!String.IsNullOrEmpty(ReturnBody)) - data["returnBody"] = ReturnBody; - return data.ToJson(); - } - - public byte[] MakeAuthToken() - { - return AuthToken.Make(Marshal()); - } - - public string MakeAuthTokenString() - { - return Encoding.ASCII.GetString(MakeAuthToken()); - } - } -} +using System; +using System.Text; +using System.IO; +using LitJson; +using System.Security.Cryptography; +using QBox.Util; +using QBox.Conf; + +namespace QBox.Auth +{ + public class PutPolicy + { + public string Scope { get; set; } + public string CallbackUrl { get; set; } + public string CallbackBodyType { get; set; } + public string Customer { get; set; } + public string AsyncOps { get; set; } + public string ReturnBody { get; set; } + public UInt32 Expires { get; set; } + public UInt16 Escape { get; set; } + public UInt16 DetectMime { get; set; } + + public PutPolicy(string scope, UInt32 expires) + { + Scope = scope; + DateTime begin = new DateTime(1970, 1, 1); + DateTime now = DateTime.Now; + TimeSpan interval = new TimeSpan(now.Ticks - begin.Ticks); + Expires = (UInt32)interval.TotalSeconds + expires; + } + + public string Marshal() + { + JsonData data = new JsonData(); + data["scope"] = Scope; + data["deadline"] = Expires; + if (!String.IsNullOrEmpty(CallbackUrl)) + data["callbackUrl"] = CallbackUrl; + if (!String.IsNullOrEmpty(CallbackBodyType)) + data["callbackBodyType"] = CallbackBodyType; + if (!String.IsNullOrEmpty(AsyncOps)) + data["asyncOps"] = AsyncOps; + if (!String.IsNullOrEmpty(ReturnBody)) + data["returnBody"] = ReturnBody; + if (!String.IsNullOrEmpty(Customer)) + data["customer"] = Customer; + if (Escape != 0) + data["escape"] = Escape; + if (DetectMime != 0) + data["detectMime"] = DetectMime; + return data.ToJson(); + } + + public string Token() + { + return Config.Encoding.GetString(AuthToken.Make(Marshal())); + } + } +} diff --git a/QBox/Auth/DigestAuthClient.cs b/QBox/Auth/QBoxAuthClient.cs similarity index 77% rename from QBox/Auth/DigestAuthClient.cs rename to QBox/Auth/QBoxAuthClient.cs index e156c270..eaba7c2f 100644 --- a/QBox/Auth/DigestAuthClient.cs +++ b/QBox/Auth/QBoxAuthClient.cs @@ -1,43 +1,43 @@ -using System; -using System.Text; -using System.Net; -using System.IO; -using System.Security.Cryptography; -using QBox.Util; -using QBox.RPC; -using QBox.RS; - -namespace QBox.Auth -{ - public class DigestAuthClient : Client - { - public override void SetAuth(HttpWebRequest request, Stream body) - { - byte[] secretKey = Encoding.ASCII.GetBytes(Config.SECRET_KEY); - using (HMACSHA1 hmac = new HMACSHA1(secretKey)) - { - string pathAndQuery = request.Address.PathAndQuery; - byte[] pathAndQueryBytes = Encoding.ASCII.GetBytes(pathAndQuery); - using (MemoryStream buffer = new MemoryStream()) - { - buffer.Write(pathAndQueryBytes, 0, pathAndQueryBytes.Length); - buffer.WriteByte((byte)'\n'); - if (request.ContentType == "application/x-www-form-urlencoded" && body != null) - { - if (!body.CanSeek) - { - throw new Exception("stream can not seek"); - } - StreamUtil.Copy(body, buffer); - body.Seek(0, SeekOrigin.Begin); - } - byte[] digest = hmac.ComputeHash(buffer.ToArray()); - string digestBase64 = Base64UrlSafe.Encode(digest); - - string authHead = "QBox " + Config.ACCESS_KEY + ":" + digestBase64; - request.Headers.Add("Authorization", authHead); - } - } - } - } -} +using System; +using System.Text; +using System.Net; +using System.IO; +using System.Security.Cryptography; +using QBox.Util; +using QBox.RPC; +using QBox.Conf; + +namespace QBox.Auth +{ + public class QBoxAuthClient : Client + { + public override void SetAuth(HttpWebRequest request, Stream body) + { + byte[] secretKey = Config.Encoding.GetBytes(Config.SECRET_KEY); + using (HMACSHA1 hmac = new HMACSHA1(secretKey)) + { + string pathAndQuery = request.Address.PathAndQuery; + byte[] pathAndQueryBytes = Config.Encoding.GetBytes(pathAndQuery); + using (MemoryStream buffer = new MemoryStream()) + { + buffer.Write(pathAndQueryBytes, 0, pathAndQueryBytes.Length); + buffer.WriteByte((byte)'\n'); + if (request.ContentType == "application/x-www-form-urlencoded" && body != null) + { + if (!body.CanSeek) + { + throw new Exception("stream can not seek"); + } + Util.IO.Copy(body, buffer); + body.Seek(0, SeekOrigin.Begin); + } + byte[] digest = hmac.ComputeHash(buffer.ToArray()); + string digestBase64 = Base64URLSafe.Encode(digest); + + string authHead = "QBox " + Config.ACCESS_KEY + ":" + digestBase64; + request.Headers.Add("Authorization", authHead); + } + } + } + } +} diff --git a/QBox/RS/Config.cs b/QBox/Conf/Config.cs similarity index 57% rename from QBox/RS/Config.cs rename to QBox/Conf/Config.cs index f40d7fd3..6c53f8b1 100644 --- a/QBox/RS/Config.cs +++ b/QBox/Conf/Config.cs @@ -1,16 +1,16 @@ -using System; - -namespace QBox.RS -{ - public class Config - { - public static string ACCESS_KEY = ""; - public static string SECRET_KEY = ""; - - public static string IO_HOST = "http://iovip.qbox.me"; - public static string RS_HOST = "http://rs.qbox.me:10100"; - public static string UP_HOST = "http://up.qbox.me"; - - public static int PUT_RETRY_TIMES = 3; - } -} +using System; +using System.Text; + +namespace QBox.Conf +{ + public class Config + { + public static string ACCESS_KEY = ""; + public static string SECRET_KEY = ""; + + public static string RS_HOST = "http://rs.qbox.me"; + public static string UP_HOST = "http://up.qbox.me"; + + public static Encoding Encoding = Encoding.UTF8; + } +} diff --git a/QBox/FileOp/Exif.cs b/QBox/FileOp/Exif.cs new file mode 100644 index 00000000..403a2262 --- /dev/null +++ b/QBox/FileOp/Exif.cs @@ -0,0 +1,18 @@ +using System; +using QBox.RPC; + +namespace QBox.FileOp +{ + public static class Exif + { + public static string MakeRequest(string url) + { + return url + "?exif"; + } + + public static CallRet Call(string url) + { + return FileOpClient.Get(url); + } + } +} diff --git a/QBox/FileOp/FileOpClient.cs b/QBox/FileOp/FileOpClient.cs index 55fc1c5c..4353d2ea 100644 --- a/QBox/FileOp/FileOpClient.cs +++ b/QBox/FileOp/FileOpClient.cs @@ -5,11 +5,11 @@ namespace QBox.FileOp { - public static class FileOpClient + static class FileOpClient { public static CallRet Get(string url) { - Console.WriteLine("Client.Get ==> URL: " + url); + Console.WriteLine("FopClient.Get ==> URL: " + url); try { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); diff --git a/QBox/FileOp/ImageInfo.cs b/QBox/FileOp/ImageInfo.cs new file mode 100644 index 00000000..ff9250cd --- /dev/null +++ b/QBox/FileOp/ImageInfo.cs @@ -0,0 +1,19 @@ +using System; +using QBox.RPC; + +namespace QBox.FileOp +{ + public static class ImageInfo + { + public static string MakeRequest(string url) + { + return url + "?imageInfo"; + } + + public static ImageInfoRet Call(string url) + { + CallRet callRet = FileOpClient.Get(url); + return new ImageInfoRet(callRet); + } + } +} diff --git a/QBox/FileOp/ImageInfoRet.cs b/QBox/FileOp/ImageInfoRet.cs index d83afee5..e7bae506 100644 --- a/QBox/FileOp/ImageInfoRet.cs +++ b/QBox/FileOp/ImageInfoRet.cs @@ -6,9 +6,9 @@ namespace QBox.FileOp { public class ImageInfoRet : CallRet { - public string Format { get; private set; } public int Width { get; private set; } public int Height { get; private set; } + public string Format { get; private set; } public string ColorModel { get; private set; } public ImageInfoRet(CallRet ret) diff --git a/QBox/FileOp/ImageMogrifySpec.cs b/QBox/FileOp/ImageMogrify.cs similarity index 87% rename from QBox/FileOp/ImageMogrifySpec.cs rename to QBox/FileOp/ImageMogrify.cs index 338f26e7..042ac749 100644 --- a/QBox/FileOp/ImageMogrifySpec.cs +++ b/QBox/FileOp/ImageMogrify.cs @@ -1,35 +1,35 @@ -using System; - -namespace QBox.FileOp -{ - public class ImageMogrifySpec - { - public string Thumbnail { get; set; } - public string Gravity { get; set; } - public string Crop { get; set; } - public int Quality { get; set; } - public int Rotate { get; set; } - public string Format { get; set; } - public bool AutoOrient { get; set; } - - public string MakeSpecString() - { - string spec = "?imageMogr"; - if (!String.IsNullOrEmpty(Thumbnail)) - spec += "/thumbnail/" + Thumbnail; - if (!String.IsNullOrEmpty(Gravity)) - spec += "/gravity/" + Gravity; - if (!String.IsNullOrEmpty(Crop)) - spec += "/crop/" + Crop; - if (Quality != 0) - spec += "/quality/" + Quality.ToString(); - if (Rotate != 0) - spec += "/rotate/" + Rotate.ToString(); - if (!String.IsNullOrEmpty(Format)) - spec += "/format/" + Format; - if (AutoOrient) - spec += "/auto-orient"; - return spec; - } - } -} +using System; + +namespace QBox.FileOp +{ + public class ImageMogrify + { + public string Thumbnail { get; set; } + public string Gravity { get; set; } + public string Crop { get; set; } + public int Quality { get; set; } + public int Rotate { get; set; } + public string Format { get; set; } + public bool AutoOrient { get; set; } + + public string MakeRequest(string url) + { + string spec = url + "?imageMogr"; + if (AutoOrient) + spec += "/auto-orient"; + if (!String.IsNullOrEmpty(Thumbnail)) + spec += "/thumbnail/" + Thumbnail; + if (!String.IsNullOrEmpty(Gravity)) + spec += "/gravity/" + Gravity; + if (!String.IsNullOrEmpty(Crop)) + spec += "/crop/" + Crop; + if (Quality != 0) + spec += "/quality/" + Quality.ToString(); + if (Rotate != 0) + spec += "/rotate/" + Rotate.ToString(); + if (!String.IsNullOrEmpty(Format)) + spec += "/format/" + Format; + return spec; + } + } +} diff --git a/QBox/FileOp/ImageOp.cs b/QBox/FileOp/ImageOp.cs deleted file mode 100644 index 7fccb45f..00000000 --- a/QBox/FileOp/ImageOp.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using QBox.RPC; - -namespace QBox.FileOp -{ - public static class ImageOp - { - public static ImageInfoRet ImageInfo(string url) - { - CallRet callRet = FileOpClient.Get(url + "?imageInfo"); - return new ImageInfoRet(callRet); - } - - public static CallRet ImageExif(string url) - { - return FileOpClient.Get(url + "?exif"); - } - - public static string ImageViewUrl(string url, ImageViewSpec spec) - { - return url + spec.MakeSpecString(); - } - - public static string ImageMogrifyUrl(string url, ImageMogrifySpec spec) - { - return url + spec.MakeSpecString(); - } - } -} diff --git a/QBox/FileOp/ImageViewSpec.cs b/QBox/FileOp/ImageView.cs similarity index 69% rename from QBox/FileOp/ImageViewSpec.cs rename to QBox/FileOp/ImageView.cs index df05bd28..8b63e283 100644 --- a/QBox/FileOp/ImageViewSpec.cs +++ b/QBox/FileOp/ImageView.cs @@ -1,30 +1,27 @@ -using System; - -namespace QBox.FileOp -{ - public class ImageViewSpec - { - public int Mode { get; set; } - public int Width { get; set; } - public int Height { get; set; } - public int Quality { get; set; } - public string Format { get; set; } - public int Sharpen { get; set; } - - public string MakeSpecString() - { - string spec = "?imageView/" + Mode.ToString(); - if (Width != 0) - spec += "/w/" + Width.ToString(); - if (Height != 0) - spec += "/h/" + Height.ToString(); - if (Quality != 0) - spec += "/q/" + Quality.ToString(); - if (!String.IsNullOrEmpty(Format)) - spec += "/format/" + Format; - if (Sharpen != 0) - spec += "/sharpen/" + Sharpen; - return spec; - } - } -} +using System; + +namespace QBox.FileOp +{ + public class ImageView + { + public int Mode { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public int Quality { get; set; } + public string Format { get; set; } + + public string MakeRequest(string url) + { + string spec = url + "?imageView/" + Mode.ToString(); + if (Width != 0) + spec += "/w/" + Width.ToString(); + if (Height != 0) + spec += "/h/" + Height.ToString(); + if (Quality != 0) + spec += "/q/" + Quality.ToString(); + if (!String.IsNullOrEmpty(Format)) + spec += "/format/" + Format; + return spec; + } + } +} diff --git a/QBox/RS/FileParameter.cs b/QBox/IO/FileParameter.cs similarity index 70% rename from QBox/RS/FileParameter.cs rename to QBox/IO/FileParameter.cs index 5de705ce..893bfa2e 100644 --- a/QBox/RS/FileParameter.cs +++ b/QBox/IO/FileParameter.cs @@ -1,16 +1,19 @@ -using System; - -namespace QBox.RS -{ - public class FileParameter - { - public string FileName { get; set; } - public string MimeType { get; set; } - - public FileParameter(string fname, string mimeType) - { - FileName = fname; - MimeType = mimeType; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace QBox.IO +{ + class FileParameter + { + public string FileName { get; set; } + public string MimeType { get; set; } + + public FileParameter(string fname, string mimeType) + { + FileName = fname; + MimeType = mimeType; + } + } +} diff --git a/QBox/IO/IOClient.cs b/QBox/IO/IOClient.cs new file mode 100644 index 00000000..4c19a746 --- /dev/null +++ b/QBox/IO/IOClient.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Net; +using QBox.Conf; +using QBox.Auth; +using QBox.RPC; +using QBox.Util; + +namespace QBox.IO +{ + public class IOClient + { + public static PutRet PutFile(string upToken, string key, string localFile, PutExtra extra) + { + string entryURI = extra.Bucket + ":" + key; + string action = "/rs-put/" + Base64URLSafe.Encode(entryURI); + if (!String.IsNullOrEmpty(extra.MimeType)) + { + action += "/mimeType/" + Base64URLSafe.Encode(extra.MimeType); + } + if (!String.IsNullOrEmpty(extra.CustomMeta)) + { + action += "/meta/" + Base64URLSafe.Encode(extra.CustomMeta); + } + if (extra.Crc32 >= 0) + { + action += "/crc32/" + extra.Crc32.ToString(); + } + + try + { + var postParams = new Dictionary(); + postParams["auth"] = upToken; + postParams["action"] = action; + postParams["file"] = new FileParameter(localFile, extra.MimeType); + if (!String.IsNullOrEmpty(extra.CallbackParams)) + postParams["params"] = extra.CallbackParams; + CallRet callRet = MultiPart.Post(Config.UP_HOST + "/upload", postParams); + return new PutRet(callRet); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + return new PutRet(new CallRet(HttpStatusCode.BadRequest, e)); + } + } + + public static PutRet ResumablePutFile(string upToken, string key, string localFile, PutExtra extra) + { + PutAuthClient client = new PutAuthClient(upToken); + return ResumablePut.PutFile(client, extra.Bucket, key, extra.MimeType, localFile, + extra.CustomMeta, extra.CallbackParams); + } + } +} diff --git a/QBox/RS/MultiPartFormDataPost.cs b/QBox/IO/MultiPart.cs similarity index 82% rename from QBox/RS/MultiPartFormDataPost.cs rename to QBox/IO/MultiPart.cs index 400f2c95..57083440 100644 --- a/QBox/RS/MultiPartFormDataPost.cs +++ b/QBox/IO/MultiPart.cs @@ -1,122 +1,132 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.IO; -using System.Net; -using QBox.Util; -using QBox.RPC; - -namespace QBox.RS -{ - public static class MultiPartFormDataPost - { - public static Encoding encoding = Encoding.ASCII; - - private static long GetContentLength(Dictionary postParams, string boundary) - { - long length = 0; - bool needsCLRF = false; - foreach (var param in postParams) - { - if (needsCLRF) - length += encoding.GetByteCount("\r\n"); - - needsCLRF = true; - - if (param.Value is FileParameter) - { - FileParameter fileToUpload = (FileParameter)param.Value; - - string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n"; - string header = string.Format(headfmt, boundary, param.Key, - fileToUpload.FileName ?? param.Key, - fileToUpload.MimeType ?? "application/octet-stream"); - - length += encoding.GetByteCount(header); - using (FileStream fs = File.OpenRead(fileToUpload.FileName)) - { - length += fs.Length; - } - } - else - { - string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}"; - string partData = string.Format(headfmt, boundary, param.Key, param.Value); - length += encoding.GetByteCount(partData); - } - } - - string footer = "\r\n--" + boundary + "--\r\n"; - length += encoding.GetByteCount(footer); - return length; - } - - private static void WriteBody(Dictionary postParams, string boundary, Stream body) - { - bool needsCLRF = false; - foreach (var param in postParams) - { - if (needsCLRF) - body.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); - - needsCLRF = true; - - if (param.Value is FileParameter) - { - FileParameter fileToUpload = (FileParameter)param.Value; - - string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n"; - string header = string.Format(headfmt, boundary, param.Key, - fileToUpload.FileName ?? param.Key, - fileToUpload.MimeType ?? "application/octet-stream"); - - body.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); - using (FileStream fs = File.OpenRead(fileToUpload.FileName)) - { - StreamUtil.Copy(fs, body); - } - } - else - { - string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}"; - string partData = string.Format(headfmt, boundary, param.Key, param.Value); - body.Write(encoding.GetBytes(partData), 0, encoding.GetByteCount(partData)); - } - } - - string footer = "\r\n--" + boundary + "--\r\n"; - body.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); - } - - public static CallRet Post(string url, Dictionary postParams) - { - Console.WriteLine("URL: " + url); - string boundary = String.Format("----------{0:N}", Guid.NewGuid()); - string contentType = "multipart/form-data; boundary=" + boundary; - - Stream requestStream = null; - HttpWebResponse response = null; - try - { - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); - request.Method = "POST"; - request.ContentType = contentType; - request.ContentLength = GetContentLength(postParams, boundary); - requestStream = request.GetRequestStream(); - WriteBody(postParams, boundary, requestStream); - response = request.GetResponse() as HttpWebResponse; - return Client.HandleResult(response); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - return new CallRet(HttpStatusCode.BadRequest, e); - } - finally - { - requestStream.Close(); - response.Close(); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Text; +using System.IO; +using System.Net; +using QBox.RPC; +using QBox.Conf; + +namespace QBox.IO +{ + static class MultiPart + { + public static Encoding encoding = Config.Encoding; + + public static string RandomBoundary() + { + return String.Format("----------{0:N}", Guid.NewGuid()); + } + + public static string FormDataContentType(string boundary) + { + return "multipart/form-data; boundary=" + boundary; + } + + public static long ContentLength(Dictionary postParams, string boundary) + { + long length = 0; + bool needsCLRF = false; + foreach (var param in postParams) + { + if (needsCLRF) + length += encoding.GetByteCount("\r\n"); + + needsCLRF = true; + + if (param.Value is FileParameter) + { + FileParameter fileToUpload = (FileParameter)param.Value; + + string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n"; + string header = string.Format(headfmt, boundary, param.Key, + fileToUpload.FileName ?? param.Key, + fileToUpload.MimeType ?? "application/octet-stream"); + + length += encoding.GetByteCount(header); + using (FileStream fs = File.OpenRead(fileToUpload.FileName)) + { + length += fs.Length; + } + } + else + { + string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}"; + string partData = string.Format(headfmt, boundary, param.Key, param.Value); + length += encoding.GetByteCount(partData); + } + } + + string footer = "\r\n--" + boundary + "--\r\n"; + length += encoding.GetByteCount(footer); + return length; + } + + public static void WriteBody(Dictionary postParams, string boundary, Stream body) + { + bool needsCLRF = false; + foreach (var param in postParams) + { + if (needsCLRF) + body.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n")); + + needsCLRF = true; + + if (param.Value is FileParameter) + { + FileParameter fileToUpload = (FileParameter)param.Value; + + string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\";\r\nContent-Type: {3}\r\n\r\n"; + string header = string.Format(headfmt, boundary, param.Key, + fileToUpload.FileName ?? param.Key, + fileToUpload.MimeType ?? "application/octet-stream"); + + body.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header)); + using (FileStream fs = File.OpenRead(fileToUpload.FileName)) + { + fs.CopyTo(body); + } + } + else + { + string headfmt = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}"; + string partData = string.Format(headfmt, boundary, param.Key, param.Value); + body.Write(encoding.GetBytes(partData), 0, encoding.GetByteCount(partData)); + } + } + + string footer = "\r\n--" + boundary + "--\r\n"; + body.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer)); + } + + public static CallRet Post(string url, Dictionary postParams) + { + Console.WriteLine("URL: " + url); + string boundary = RandomBoundary(); + string contentType = FormDataContentType(boundary); + + Stream requestStream = null; + HttpWebResponse response = null; + try + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = "POST"; + request.ContentType = contentType; + request.ContentLength = ContentLength(postParams, boundary); + requestStream = request.GetRequestStream(); + WriteBody(postParams, boundary, requestStream); + response = request.GetResponse() as HttpWebResponse; + return RPC.Client.HandleResult(response); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + return new CallRet(HttpStatusCode.BadRequest, e); + } + finally + { + requestStream.Close(); + response.Close(); + } + } + } +} diff --git a/QBox/IO/PutExtra.cs b/QBox/IO/PutExtra.cs new file mode 100644 index 00000000..4898cef9 --- /dev/null +++ b/QBox/IO/PutExtra.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace QBox.IO +{ + public class PutExtra + { + public string CallbackParams { get; set; } + public string Bucket { get; set; } + public string CustomMeta { get; set; } + public string MimeType { get; set; } + public Int64 Crc32 { get; set; } + + public PutExtra() + { + Crc32 = -1; + } + + public PutExtra(string bucket, string mimeType, string callbackParams) + { + Bucket = bucket; + MimeType = mimeType; + CallbackParams = callbackParams; + Crc32 = -1; + } + } +} diff --git a/QBox/RS/PutFileRet.cs b/QBox/IO/PutRet.cs similarity index 83% rename from QBox/RS/PutFileRet.cs rename to QBox/IO/PutRet.cs index eaba1389..ee831eb6 100644 --- a/QBox/RS/PutFileRet.cs +++ b/QBox/IO/PutRet.cs @@ -1,34 +1,34 @@ -using System; -using LitJson; -using QBox.RPC; - -namespace QBox.RS -{ - public class PutFileRet : CallRet - { - public string Hash { get; private set; } - - public PutFileRet(CallRet ret) - : base(ret) - { - if (!String.IsNullOrEmpty(Response)) - { - try - { - Unmarshal(Response); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - this.Exception = e; - } - } - } - - private void Unmarshal(string json) - { - JsonData data = JsonMapper.ToObject(json); - Hash = (string)data["hash"]; - } - } -} +using System; +using LitJson; +using QBox.RPC; + +namespace QBox.IO +{ + public class PutRet : CallRet + { + public string Hash { get; private set; } + + public PutRet(CallRet ret) + : base(ret) + { + if (!String.IsNullOrEmpty(Response)) + { + try + { + Unmarshal(Response); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + this.Exception = e; + } + } + } + + private void Unmarshal(string json) + { + JsonData data = JsonMapper.ToObject(json); + Hash = (string)data["hash"]; + } + } +} diff --git a/QBox/RS/ResumablePut.cs b/QBox/IO/ResumablePut.cs similarity index 76% rename from QBox/RS/ResumablePut.cs rename to QBox/IO/ResumablePut.cs index a74bfaa6..4b78c2e8 100644 --- a/QBox/RS/ResumablePut.cs +++ b/QBox/IO/ResumablePut.cs @@ -1,96 +1,98 @@ -using System; -using System.IO; -using System.Text; -using QBox.Util; -using QBox.RPC; - -namespace QBox.RS -{ - public static class ResumablePut - { - private static int ChunkBits = 22; - private static long ChunkSize = 1 << ChunkBits; - - public static ResumablePutFileRet Mkblock(string host, Client client, Stream body, long length) - { - string url = host + "/mkblk/" + Convert.ToString(length); - CallRet callRet = client.CallWithBinary(url, "application/octet-stream", body, length); - return new ResumablePutFileRet(callRet); - } - - public static PutFileRet Mkfile(string host, Client client, string entryURI, long fsize, - string customMeta, string callbackParam, string[] ctxs) - { - string url = host + "/rs-mkfile/" + Base64UrlSafe.Encode(entryURI) + - "/fsize/" + Convert.ToString(fsize); - if (!String.IsNullOrEmpty(callbackParam)) - { - url += "/params/" + Base64UrlSafe.Encode(callbackParam); - } - if (!String.IsNullOrEmpty(customMeta)) - { - url += "/meta/" + Base64UrlSafe.Encode(customMeta); - } - - using (Stream body = new MemoryStream()) - { - for (int i = 0; i < ctxs.Length; i++) - { - byte[] bctx = Encoding.ASCII.GetBytes(ctxs[i]); - body.Write(bctx, 0, bctx.Length); - if (i != ctxs.Length-1) - { - body.WriteByte((byte)','); - } - } - body.Seek(0, SeekOrigin.Begin); - CallRet ret= client.CallWithBinary(url, "text/plain", body, body.Length); - return new PutFileRet(ret); - } - } - - public static PutFileRet PutFile( - Client client, string tableName, string key, string mimeType, - string localFile, string customMeta, string callbackParam) - { - long fsize = 0; - string[] ctxs = null; - string host = Config.UP_HOST; - using (FileStream fs = File.OpenRead(localFile)) - { - fsize = fs.Length; - int chunkCnt = (int)((fsize + (ChunkSize - 1)) >> ChunkBits); - long chunkSize = ChunkSize; - ctxs = new string[chunkCnt]; - Console.WriteLine("ResumablePut ==> fsize: {0}, chunkCnt: {1}", fsize, chunkCnt); - for (int i = 0; i < chunkCnt; i++) - { - if (i == chunkCnt - 1) - { - chunkSize = fsize - (i << ChunkBits); - } - ResumablePutFileRet ret = null; - for (int retry = 0; retry < Config.PUT_RETRY_TIMES; retry++) - { - fs.Seek(i * ChunkSize, SeekOrigin.Begin); - ret = Mkblock(host, client, fs, chunkSize); - if (ret.OK) - { - ctxs[i] = ret.Ctx; - host = ret.Host; - break; - } - } - if (!ret.OK) - { - Console.WriteLine(ret.Exception.ToString()); - return new PutFileRet(new CallRet(ret)); - } - } - } - - string entryURI = tableName + ":" + key; - return Mkfile(host, client, entryURI, fsize, customMeta, callbackParam, ctxs); - } - } -} +using System; +using System.IO; +using System.Text; +using QBox.Conf; +using QBox.Util; +using QBox.RPC; + +namespace QBox.IO +{ + static class ResumablePut + { + private static int ChunkBits = 22; + private static long ChunkSize = 1 << ChunkBits; + private static int PutRetryTimes = 3; + + public static ResumablePutRet Mkblock(string host, Client client, Stream body, long length) + { + string url = host + "/mkblk/" + Convert.ToString(length); + CallRet callRet = client.CallWithBinary(url, "application/octet-stream", body, length); + return new ResumablePutRet(callRet); + } + + public static PutRet Mkfile(string host, Client client, string entryURI, long fsize, + string customMeta, string callbackParam, string[] ctxs) + { + string url = host + "/rs-mkfile/" + Base64URLSafe.Encode(entryURI) + + "/fsize/" + Convert.ToString(fsize); + if (!String.IsNullOrEmpty(callbackParam)) + { + url += "/params/" + Base64URLSafe.Encode(callbackParam); + } + if (!String.IsNullOrEmpty(customMeta)) + { + url += "/meta/" + Base64URLSafe.Encode(customMeta); + } + + using (Stream body = new MemoryStream()) + { + for (int i = 0; i < ctxs.Length; i++) + { + byte[] bctx = Encoding.ASCII.GetBytes(ctxs[i]); + body.Write(bctx, 0, bctx.Length); + if (i != ctxs.Length-1) + { + body.WriteByte((byte)','); + } + } + body.Seek(0, SeekOrigin.Begin); + CallRet ret= client.CallWithBinary(url, "text/plain", body, body.Length); + return new PutRet(ret); + } + } + + public static PutRet PutFile( + Client client, string tableName, string key, string mimeType, + string localFile, string customMeta, string callbackParam) + { + long fsize = 0; + string[] ctxs = null; + string host = Config.UP_HOST; + using (FileStream fs = File.OpenRead(localFile)) + { + fsize = fs.Length; + int chunkCnt = (int)((fsize + (ChunkSize - 1)) >> ChunkBits); + long chunkSize = ChunkSize; + ctxs = new string[chunkCnt]; + Console.WriteLine("ResumablePut ==> fsize: {0}, chunkCnt: {1}", fsize, chunkCnt); + for (int i = 0; i < chunkCnt; i++) + { + if (i == chunkCnt - 1) + { + chunkSize = fsize - (i << ChunkBits); + } + ResumablePutRet ret = null; + for (int retry = 0; retry < PutRetryTimes; retry++) + { + fs.Seek(i * ChunkSize, SeekOrigin.Begin); + ret = Mkblock(host, client, fs, chunkSize); + if (ret.OK) + { + ctxs[i] = ret.Ctx; + host = ret.Host; + break; + } + } + if (!ret.OK) + { + Console.WriteLine(ret.Exception.ToString()); + return new PutRet(new CallRet(ret)); + } + } + } + + string entryURI = tableName + ":" + key; + return Mkfile(host, client, entryURI, fsize, customMeta, callbackParam, ctxs); + } + } +} diff --git a/QBox/RS/ResumablePutFileRet.cs b/QBox/IO/ResumablePutRet.cs similarity index 84% rename from QBox/RS/ResumablePutFileRet.cs rename to QBox/IO/ResumablePutRet.cs index 5140712a..bce5125e 100644 --- a/QBox/RS/ResumablePutFileRet.cs +++ b/QBox/IO/ResumablePutRet.cs @@ -1,38 +1,38 @@ -using System; -using LitJson; -using QBox.RPC; - -namespace QBox.RS -{ - public class ResumablePutFileRet : CallRet - { - public string Ctx { get; private set; } - public string Checksum { get; private set; } - public string Host { get; private set; } - - public ResumablePutFileRet(CallRet ret) - : base(ret) - { - if (!String.IsNullOrEmpty(Response)) - { - try - { - Unmarshal(Response); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - this.Exception = e; - } - } - } - - private void Unmarshal(string json) - { - JsonData data = JsonMapper.ToObject(json); - Ctx = (string)data["ctx"]; - Checksum = (string)data["checksum"]; - Host = (string)data["host"]; - } - } -} +using System; +using LitJson; +using QBox.RPC; + +namespace QBox.IO +{ + class ResumablePutRet : CallRet + { + public string Ctx { get; private set; } + public string Checksum { get; private set; } + public string Host { get; private set; } + + public ResumablePutRet(CallRet ret) + : base(ret) + { + if (!String.IsNullOrEmpty(Response)) + { + try + { + Unmarshal(Response); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + this.Exception = e; + } + } + } + + private void Unmarshal(string json) + { + JsonData data = JsonMapper.ToObject(json); + Ctx = (string)data["ctx"]; + Checksum = (string)data["checksum"]; + Host = (string)data["host"]; + } + } +} diff --git a/QBox/QBox.csproj b/QBox/QBox.csproj index 8f48cd55..1e277d0f 100644 --- a/QBox/QBox.csproj +++ b/QBox/QBox.csproj @@ -39,11 +39,17 @@ - + + - - + + + + + + + @@ -52,27 +58,21 @@ - - + + - + + - - - - - - - - + + + - - - + @@ -81,6 +81,7 @@ +