/HatenaPhotLife/HatenaPhotLifeClient.cs
C# | 124 lines | 106 code | 18 blank | 0 comment | 3 complexity | cea1659afb418bd4466a8f69bcda1f26 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Reactive;
- using System.Reactive.Linq;
- using System.Security.Cryptography;
- using System.Net;
- using System.IO;
- using System.Xml.Linq;
- using System.Xml;
-
-
- namespace HatenaPhotLife
- {
- public class HatenaPhotLifeClient
- {
- private string _userId;
- private string _password;
-
- public HatenaPhotLifeClient(string userId, string password)
- {
- _userId = userId;
- _password = password;
- }
-
- public IObservable<string> UploadAsObservable(string imageFilePath,string folder)
- {
- XNamespace ns = "http://purl.org/atom/ns#";
-
- return Observable.Defer(() =>
- {
- var request = (HttpWebRequest)HttpWebRequest.Create("http://f.hatena.ne.jp/atom");
- request.Headers.Add("X-WSSE", GetWSSEHeader(_userId, _password));
- request.ContentType = "application/x.atom+xml";
- return Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)();
- })
- .GetResponseAsXElement()
- .Select(responseXElement =>
- (string)responseXElement.Descendants(ns + "link")
- .Where(element => (string)element.Attribute("rel") == "service.post")
- .First()
- .Attribute("href"))
- .SelectMany(url => Observable.Defer(() =>
- {
- var request = (HttpWebRequest)HttpWebRequest.Create(url);
- request.Method = "POST";
- request.Headers.Add("X-WSSE", GetWSSEHeader(_userId, _password));
- request.ContentType = "application/x.atom+xml";
- using (var requestStream = request.GetRequestStream())
- using (var writer = new XmlTextWriter(requestStream, Encoding.UTF8))
- {
- GenerateXml(imageFilePath,folder).WriteTo(writer);
- }
- return Observable.FromAsyncPattern<WebResponse>(request.BeginGetResponse, request.EndGetResponse)();
- }))
- .GetResponseAsXElement()
- .Select(responseXElement => responseXElement.Descendants(ns + "link").Where(element => (string)element.Attribute("rel") == "alternate"))
- .Select(elements => (string)elements.First().Attribute("href"));
- }
-
- private static string GetWSSEHeader(string userid, string password)
- {
- var createdAtTime = DateTime.Now.ToUniversalTime().ToString("s");
- var nonce = new byte[40];
- new Random().NextBytes(nonce);
- string passwordDigest;
-
- var digestSource = nonce.Concat(createdAtTime.GetUTF8Bytes()).Concat(password.GetUTF8Bytes());
-
- using (SHA1Managed sha = new SHA1Managed())
- {
- passwordDigest = Convert.ToBase64String(sha.ComputeHash(digestSource.ToArray()));
- }
-
- return string.Format(@"UsernameToken Username=""{0}"", PasswordDigest=""{1}"", Nonce=""{2}"", Created=""{3}""",
- userid,
- passwordDigest,
- Convert.ToBase64String(nonce),
- createdAtTime
- );
- }
-
- private static XElement GenerateXml(string imageFilePath,string folderName)
- {
- XNamespace ns = "http://purl.org/atom/ns#";
- XNamespace dc = "http://purl.org/dc/elements/1.1/";
-
- var root = new XElement(ns + "entry", new XAttribute(XNamespace.Xmlns + "dc", dc));
-
- var contentElement = new XElement("content", Convert.ToBase64String(File.ReadAllBytes(imageFilePath)));
- contentElement.SetAttributeValue("mode", "Base64");
- contentElement.SetAttributeValue("type", "image/png");
- root.Add(contentElement);
-
- if (!string.IsNullOrEmpty(folderName))
- {
- var folderElement = new XElement(dc + "subject", folderName);
- root.Add(folderElement);
- }
-
- var toolElement = new XElement("generator", "InstantImageUploader");
- root.Add(toolElement);
-
- return root;
- }
- }
-
- public static class CommonExtension
- {
- public static byte[] GetUTF8Bytes(this string source)
- {
- return Encoding.UTF8.GetBytes(source);
- }
-
- public static IObservable<XElement> GetResponseAsXElement(this IObservable<WebResponse> source)
- {
- return source.Select(response => response.GetResponseStream())
- .Select(stream => new StreamReader(stream).ReadToEnd())
- .Select(responseText => XElement.Parse(responseText));
- }
- }
-
- }