Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial Commit

  • Loading branch information...
commit 82c5db6113b0c2b9be1bac9d38179cd649c99daf 1 parent 336c669
@AndyCross AndyCross authored
View
22 .gitattributes
@@ -0,0 +1,22 @@
+# Auto detect text files and perform LF normalization
+* text=auto
+
+# Custom for Visual Studio
+*.cs diff=csharp
+*.sln merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc diff=astextplain
+*.DOC diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot diff=astextplain
+*.DOT diff=astextplain
+*.pdf diff=astextplain
+*.PDF diff=astextplain
+*.rtf diff=astextplain
+*.RTF diff=astextplain
View
108 .gitignore
@@ -1,108 +0,0 @@
-# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
-[Bb]in/
-[Oo]bj/
-
-# mstest test results
-TestResults
-
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.sln.docstates
-
-# Build results
-[Dd]ebug/
-[Rr]elease/
-x64/
-*_i.c
-*_p.c
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.log
-*.vspscc
-*.vssscc
-.builds
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opensdf
-*.sdf
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*
-
-# NCrunch
-*.ncrunch*
-.*crunch*.local.xml
-
-# Installshield output folder
-[Ee]xpress
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish
-
-# Publish Web Output
-*.Publish.xml
-
-# NuGet Packages Directory
-packages
-
-# Windows Azure Build Output
-csx
-*.build.csdef
-
-# Windows Store app package directory
-AppPackages/
-
-# Others
-[Bb]in
-[Oo]bj
-sql
-TestResults
-[Tt]est[Rr]esult*
-*.Cache
-ClientBin
-[Ss]tyle[Cc]op.*
-~$*
-*.dbmdl
-Generated_Code #added for RIA/Silverlight projects
-
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
View
22 Elastacloud.AzureBlobDemo.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastacloud.AzureBlobDemo", "Elastacloud.AzureBlobDemo\Elastacloud.AzureBlobDemo.csproj", "{1662719F-BF15-4E0A-B4FA-86F29D4B078D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {1662719F-BF15-4E0A-B4FA-86F29D4B078D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1662719F-BF15-4E0A-B4FA-86F29D4B078D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1662719F-BF15-4E0A-B4FA-86F29D4B078D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
+ {1662719F-BF15-4E0A-B4FA-86F29D4B078D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1662719F-BF15-4E0A-B4FA-86F29D4B078D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1662719F-BF15-4E0A-B4FA-86F29D4B078D}.Release|Any CPU.Deploy.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
View
182 Elastacloud.AzureBlobDemo/Blob/BlobClient.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Net;
+using System.Text;
+using ElzeKool;
+using Microsoft.SPOT;
+using NetMf.CommonExtensions;
+
+namespace Elastacloud.AzureBlobDemo.Blob
+{
+ internal class BlobClient
+ {
+ private string _accountName;
+ private string _accountKey;
+
+ internal BlobClient(string accountName, string accountKey)
+ {
+ HttpVerb = "PUT";
+ DateHeader = DateTime.Now.ToString("R");
+ _accountName = accountName;
+ _accountKey = accountKey;
+ }
+
+ internal bool PutBlob(string containerName, string blobName, string fileNamePath)
+ {
+ try
+ {
+ string deploymentPath =
+ StringUtility.Format("http://{0}.blob.core.windows.net/{1}/{2}", _accountName, containerName,
+ blobName);
+ int contentLength;
+ byte[] ms = GetPackageFileBytesAndLength(fileNamePath, out contentLength);
+
+ string canResource = StringUtility.Format("/{0}/{1}/{2}", _accountName, containerName, blobName);
+
+ string authHeader = CreateAuthorizationHeader(canResource, "\nx-ms-blob-type:BlockBlob", contentLength);
+
+ try
+ {
+ var success = SendWebRequest(deploymentPath, authHeader, ms, contentLength);
+ if (!success)
+ {
+ Debug.Print("Deployment Path was " + deploymentPath);
+ Debug.Print("Auth Header was " + authHeader);
+ Debug.Print("Ms was " + ms.Length);
+ Debug.Print("Length was " + contentLength);
+ }
+ else
+ {
+ Debug.Print("Success");
+ Debug.Print("Auth Header was " + authHeader);
+ }
+
+ return success;
+ }
+ catch (WebException wex)
+ {
+ Debug.Print(wex.ToString());
+ return false;
+ }
+ }
+ catch(IOException ex)
+ {
+ Debug.Print(ex.ToString());
+ return false;
+ }
+ catch(Exception ex)
+ {
+ Debug.Print(ex.ToString());
+ return false;
+ }
+
+ return true;
+ }
+
+ protected byte[] GetPackageFileBytesAndLength(string fileName, out int contentLength)
+ {
+ byte[] ms = null;
+ contentLength = 0;
+ if (fileName != null)
+ {
+ using (StreamReader sr = new StreamReader(File.Open(fileName, FileMode.Open)))
+ {
+ string data = sr.ReadToEnd();
+ ms = Encoding.UTF8.GetBytes(data);
+ contentLength = ms.Length;
+ }
+ }
+ return ms;
+ }
+
+ private HttpWebRequest PrepareRequest(string url, string authHeader, byte[] fileBytes = null,
+ int contentLength = 0)
+ {
+ var uri = new Uri(url);
+ var request = (HttpWebRequest)WebRequest.Create(uri);
+ request.Method = HttpVerb;
+ request.ContentLength = contentLength;
+ request.Headers.Add("x-ms-date", DateHeader);
+ request.Headers.Add("x-ms-version", VersionHeader);
+ request.Headers.Add("Authorization", authHeader);
+ request.Expect = "100-continue";
+
+ if (contentLength != 0)
+ {
+ request.Headers.Add("x-ms-blob-type", "BlockBlob");
+ request.GetRequestStream().Write(fileBytes, 0, fileBytes.Length);
+ }
+ return request;
+ }
+
+ protected bool SendWebRequest(string url, string authHeader, byte[] fileBytes = null, int contentLength = 0)
+ {
+ HttpWebRequest request = PrepareRequest(url, authHeader, fileBytes, contentLength);
+ try
+ {
+ HttpWebResponse response;
+ using (response = (HttpWebResponse)request.GetResponse())
+ {
+ if (response.StatusCode == HttpStatusCode.Created)
+ {
+ Debug.Print("Container or blob has been created! " + url);
+ return true;
+ }
+ else if (response.StatusCode == HttpStatusCode.Accepted)
+ {
+ Debug.Print("Container or blob action has been completed");
+ return true;
+ }//this code smell results from the slight difference in throwing between netmf and .net
+ else if (response.StatusCode == HttpStatusCode.Forbidden)
+ {
+ throw new WebException("Forbidden", (WebExceptionStatus) HttpStatusCode.Forbidden);
+ }
+ else
+ {
+ var responseBody = "";
+ using (StreamReader sr = new StreamReader(response.GetResponseStream()))
+ {
+ responseBody = sr.ReadToEnd();
+ }
+
+ Debug.Print("Error Status " + response.StatusCode);
+ Debug.Print(responseBody);
+ return false;
+ }
+ }
+ }
+ catch (WebException ex)
+ {
+ if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Conflict)
+ {
+ Debug.Print("container or blob already exists!");
+ }
+ if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Forbidden)
+ {
+ Debug.Print("problem with signature!");
+ }
+ return false;
+ }
+ }
+
+ protected string CreateAuthorizationHeader(String canResource, string options = "", int contentLength = 0)
+ {
+ string toSign = StringUtility.Format("{0}\n\n\n{1}\n\n\n\n\n\n\n\n{5}\nx-ms-date:{2}\nx-ms-version:{3}\n{4}",
+ HttpVerb, contentLength, DateHeader, VersionHeader, canResource, options);
+
+ string signature;
+
+ var hmacBytes = SHA.computeHMAC_SHA256(Convert.FromBase64String(_accountKey), Encoding.UTF8.GetBytes(toSign));
+ signature = Convert.ToBase64String(hmacBytes).Replace("!", "+").Replace("*", "/");;
+
+ return "SharedKey " + _accountName + ":" + signature;
+ }
+
+ internal const string VersionHeader = "2011-08-18";
+
+ protected string DateHeader { get; set; }
+
+ public string HttpVerb { get; set; }
+ }
+}
View
58 Elastacloud.AzureBlobDemo/Elastacloud.AzureBlobDemo.csproj
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <AssemblyName>Elastacloud.AzureBlobDemo</AssemblyName>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>Elastacloud.AzureBlobDemo</RootNamespace>
+ <ProjectTypeGuids>{b69e3092-b931-443c-abe7-7e7b65f2a37f};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{1662719F-BF15-4E0A-B4FA-86F29D4B078D}</ProjectGuid>
+ <TargetFrameworkVersion>v4.2</TargetFrameworkVersion>
+ <NetMfTargetsBaseDir Condition="'$(NetMfTargetsBaseDir)'==''">$(MSBuildExtensionsPath32)\Microsoft\.NET Micro Framework\</NetMfTargetsBaseDir>
+ <DeployDevice>NetduinoPlus</DeployDevice>
+ <DeployTransport>USB</DeployTransport>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <Import Project="$(NetMfTargetsBaseDir)$(TargetFrameworkVersion)\CSharp.Targets" />
+ <ItemGroup>
+ <Compile Include="Blob\BlobClient.cs" />
+ <Compile Include="HMAC\SHA.cs" />
+ <Compile Include="NTP\NtpClient.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="StringUtilities\ExtensionAttribute.cs" />
+ <Compile Include="StringUtilities\FormatException.cs" />
+ <Compile Include="StringUtilities\Parse.cs" />
+ <Compile Include="StringUtilities\StringBuilder.cs" />
+ <Compile Include="StringUtilities\StringExtensions.cs" />
+ <Compile Include="StringUtilities\StringUtility.cs" />
+ <Compile Include="Table\TableClient.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.SPOT.Hardware" />
+ <Reference Include="Microsoft.SPOT.Native" />
+ <Reference Include="Microsoft.SPOT.Net" />
+ <Reference Include="SecretLabs.NETMF.Hardware, Version=4.2.0.0, Culture=neutral, processorArchitecture=MSIL" />
+ <Reference Include="SecretLabs.NETMF.Hardware.NetduinoPlus, Version=4.2.0.1, Culture=neutral, processorArchitecture=MSIL" />
+ <Reference Include="System" />
+ <Reference Include="System.Http" />
+ <Reference Include="System.IO" />
+ </ItemGroup>
+</Project>
View
213 Elastacloud.AzureBlobDemo/HMAC/SHA.cs
@@ -0,0 +1,213 @@
+// Adapted from http://www.microframework.nl/2009/09/05/shahmac-digest-class/
+// removed algorithms other than HMAC SHA-256 for size
+
+using System;
+using Microsoft.SPOT;
+
+namespace ElzeKool
+{
+ /// <summary>
+ /// Static class providing Secure Hashing Algorithm (SHA-1, SHA-224, SHA-256)
+ /// </summary>
+ public static class SHA
+ {
+ // Number used in SHA256 hash function
+ static readonly uint[] sha256_k = new uint[]
+ {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+ };
+
+
+ // Rotate bits right
+ static uint rotateright(uint x, int n)
+ {
+ return ((x >> n) | (x << (32 - n)));
+ }
+
+ // Convert 4 bytes to big endian uint32
+ static uint big_endian_from_bytes(byte[] input, uint start)
+ {
+ uint r = 0;
+ r |= (((uint)input[start]) << 24);
+ r |= (((uint)input[start + 1]) << 16);
+ r |= (((uint)input[start + 2]) << 8);
+ r |= (((uint)input[start + 3]));
+ return r;
+ }
+
+ // Convert big endian uint32 to bytes
+ static void bytes_from_big_endian(uint input, ref byte[] output, int start)
+ {
+ output[start] = (byte)((input & 0xFF000000) >> 24);
+ output[start + 1] = (byte)((input & 0x00FF0000) >> 16);
+ output[start + 2] = (byte)((input & 0x0000FF00) >> 8);
+ output[start + 3] = (byte)((input & 0x000000FF));
+ }
+
+ // SHA-224/SHA-256 choice function
+ static uint choice(uint x, uint y, uint z)
+ {
+ return ((x & y) ^ (~x & z));
+ }
+
+ // SHA-224/SHA-256 majority function
+ static uint majority(uint x, uint y, uint z)
+ {
+ return ((x & y) ^ (x & z) ^ (y & z));
+ }
+
+ /// <summary>
+ /// Compute HMAC SHA-256
+ /// </summary>
+ /// <param name="secret">Secret</param>
+ /// <param name="value">Password</param>
+ /// <returns>32 byte HMAC_SHA256</returns>
+ public static byte[] computeHMAC_SHA256(byte[] secret, byte[] value)
+ {
+ // Create two arrays, bi and bo
+ byte[] bi = new byte[64 + value.Length];
+ byte[] bo = new byte[64 + 32];
+
+ // Copy secret to both arrays
+ Array.Copy(secret, bi, secret.Length);
+ Array.Copy(secret, bo, secret.Length);
+
+ for (int i = 0; i < 64; i++)
+ {
+ // Xor bi with 0x36
+ bi[i] = (byte)(bi[i] ^ 0x36);
+
+ // Xor bo with 0x5c
+ bo[i] = (byte)(bo[i] ^ 0x5c);
+ }
+
+ // Append value to bi
+ Array.Copy(value, 0, bi, 64, value.Length);
+
+ // Append SHA256(bi) to bo
+ byte[] sha_bi = computeSHA256(bi);
+ Array.Copy(sha_bi, 0, bo, 64, 32);
+
+ // Return SHA256(bo)
+ return computeSHA256(bo);
+ }
+
+ /// <summary>
+ /// Compute SHA-256 digest
+ /// </summary>
+ /// <param name="input">Input array</param>
+ public static byte[] computeSHA256(byte[] input)
+ {
+ // Initialize working parameters
+ uint a, b, c, d, e, f, g, h, i, s0, s1, t1, t2;
+ uint h0 = 0x6a09e667;
+ uint h1 = 0xbb67ae85;
+ uint h2 = 0x3c6ef372;
+ uint h3 = 0xa54ff53a;
+ uint h4 = 0x510e527f;
+ uint h5 = 0x9b05688c;
+ uint h6 = 0x1f83d9ab;
+ uint h7 = 0x5be0cd19;
+ uint blockstart = 0;
+
+ // Calculate how long the padded message should be
+ int newinputlength = input.Length + 1;
+ while ((newinputlength % 64) != 56) // length mod 512bits = 448bits
+ {
+ newinputlength++;
+ }
+
+ // Create array for padded data
+ byte[] processed = new byte[newinputlength + 8];
+ Array.Copy(input, processed, input.Length);
+
+ // Pad data with an 1
+ processed[input.Length] = 0x80;
+
+ // Pad data with big endian 64bit length of message
+ // We do only 32 bits becouse input.length is 32 bit
+ processed[processed.Length - 4] = (byte)(((input.Length * 8) & 0xFF000000) >> 24);
+ processed[processed.Length - 3] = (byte)(((input.Length * 8) & 0x00FF0000) >> 16);
+ processed[processed.Length - 2] = (byte)(((input.Length * 8) & 0x0000FF00) >> 8);
+ processed[processed.Length - 1] = (byte)(((input.Length * 8) & 0x000000FF));
+
+ // Block of 32 bits values used in calculations
+ uint[] wordblock = new uint[64];
+
+ // Now process each 512 bit block
+ while (blockstart < processed.Length)
+ {
+ // break chunk into sixteen 32-bit big-endian words
+ for (i = 0; i < 16; i++)
+ wordblock[i] = big_endian_from_bytes(processed, blockstart + (i * 4));
+
+ // Extend the sixteen 32-bit words into sixty-four 32-bit words:
+ for (i = 16; i < 64; i++)
+ {
+ s0 = rotateright(wordblock[i - 15], 7) ^ rotateright(wordblock[i - 15], 18) ^ (wordblock[i - 15] >> 3);
+ s1 = rotateright(wordblock[i - 2], 17) ^ rotateright(wordblock[i - 2], 19) ^ (wordblock[i - 2] >> 10);
+ wordblock[i] = wordblock[i - 16] + s0 + wordblock[i - 7] + s1;
+ }
+
+ // Initialize hash value for this chunk:
+ a = h0;
+ b = h1;
+ c = h2;
+ d = h3;
+ e = h4;
+ f = h5;
+ g = h6;
+ h = h7;
+
+ // Main loop
+ for (i = 0; i < 64; i++)
+ {
+ t1 = h + (rotateright(e, 6) ^ rotateright(e, 11) ^ rotateright(e, 25)) + choice(e, f, g) + sha256_k[i] + wordblock[i];
+ t2 = (rotateright(a, 2) ^ rotateright(a, 13) ^ rotateright(a, 22)) + majority(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + t1;
+ d = c;
+ c = b;
+ b = a;
+ a = t1 + t2;
+ }
+
+ // Add this chunk's hash to result so far
+ h0 += a;
+ h1 += b;
+ h2 += c;
+ h3 += d;
+ h4 += e;
+ h5 += f;
+ h6 += g;
+ h7 += h;
+
+ // Process next 512bit block
+ blockstart += 64;
+ }
+
+ // Prepare output
+ byte[] output = new byte[32];
+ bytes_from_big_endian(h0, ref output, 0);
+ bytes_from_big_endian(h1, ref output, 4);
+ bytes_from_big_endian(h2, ref output, 8);
+ bytes_from_big_endian(h3, ref output, 12);
+ bytes_from_big_endian(h4, ref output, 16);
+ bytes_from_big_endian(h5, ref output, 20);
+ bytes_from_big_endian(h6, ref output, 24);
+ bytes_from_big_endian(h7, ref output, 28);
+
+ return output;
+ }
+
+ }
+}
View
113 Elastacloud.AzureBlobDemo/NTP/NtpClient.cs
@@ -0,0 +1,113 @@
+/*
+ * NtpClient.cs
+ *
+ * Copyright (c) 2009, Michael Schwarz (http://www.schwarz-interactive.de)
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * MS 09-02-16 added NtpClient
+ *
+ *
+ */
+
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using Microsoft.SPOT;
+
+namespace Elastacloud.AzureBlobDemo.NTP
+{
+
+ /// <summary>
+ /// Static class to receive the time from a NTP server.
+ /// </summary>
+ public class NtpClient
+ {
+ /// <summary>
+ /// Gets the current DateTime from time-a.nist.gov.
+ /// </summary>
+ /// <returns>A DateTime containing the current time.</returns>
+ public static DateTime GetNetworkTime()
+ {
+ return GetNetworkTime("time.windows.com");
+ }
+
+ /// <summary>
+ /// Gets the current DateTime from <paramref name="ntpServer"/>.
+ /// </summary>
+ /// <param name="ntpServer">The hostname of the NTP server.</param>
+ /// <returns>A DateTime containing the current time.</returns>
+ public static DateTime GetNetworkTime(string ntpServer)
+ {
+ IPAddress[] address = Dns.GetHostEntry(ntpServer).AddressList;
+
+ if (address == null || address.Length == 0)
+ throw new ArgumentException("Could not resolve ip address from '" + ntpServer + "'.", "ntpServer");
+
+ var ep = new IPEndPoint(address[0], 123);
+ return GetNetworkTime(ep);
+ }
+
+ /// <summary>
+ /// Gets the current DateTime form <paramref name="ep"/> IPEndPoint.
+ /// </summary>
+ /// <param name="ep">The IPEndPoint to connect to.</param>
+ /// <returns>A DateTime containing the current time.</returns>
+ public static DateTime GetNetworkTime(IPEndPoint ep)
+ {
+ byte[] ntpData = new byte[48]; // RFC 2030
+ ntpData[0] = 0x1B;
+
+ using (var s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
+ {
+ s.ReceiveTimeout = 2000;
+ s.Connect(ep);
+ s.Send(ntpData);
+
+ while (s.Available < 48)
+ {
+ Thread.Sleep(100);
+ Debug.Print("Potentially blocked");
+ }
+
+ s.Receive(ntpData);
+ s.Close();
+ }
+
+ const byte offsetTransmitTime = 40;
+ ulong intpart = 0;
+ ulong fractpart = 0;
+
+ for (int i = 0; i <= 3; i++)
+ intpart = 256 * intpart + ntpData[offsetTransmitTime + i];
+
+ for (int i = 4; i <= 7; i++)
+ fractpart = 256 * fractpart + ntpData[offsetTransmitTime + i];
+
+ ulong milliseconds = (intpart * 1000 + (fractpart * 1000) / 0x100000000L);
+ var timeSpan = TimeSpan.FromTicks((long)milliseconds * TimeSpan.TicksPerMillisecond);
+ var dateTime = new DateTime(1900, 1, 1);
+ dateTime += timeSpan;
+ return dateTime;
+
+ }
+ }
+}
View
139 Elastacloud.AzureBlobDemo/Program.cs
@@ -0,0 +1,139 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Threading;
+using Elastacloud.AzureBlobDemo.Blob;
+using Elastacloud.AzureBlobDemo.NTP;
+using Elastacloud.AzureBlobDemo.Table;
+using Microsoft.SPOT;
+using Microsoft.SPOT.Hardware;
+using Microsoft.SPOT.Net.NetworkInformation;
+using NetMf.CommonExtensions;
+using SecretLabs.NETMF.Hardware.NetduinoPlus;
+
+namespace Elastacloud.AzureBlobDemo
+{
+ public class Program
+ {
+ private const string AccountName = "netmf";
+ private const string AccountKey = "UstPuYqYwj1EEIc815wcVxV6oItRmrvRVByl7A152XoVeDJMr7vn1cahO5xXg0q8z5rSjd6SmQRWJliGQH9j0Q==";
+ private static BlobClient _blobClient;
+ private static TableClient _tableClient;
+ private static InterruptPort _onBoardButton;
+ private static string _macAddress;
+ private static object Padlock = new object();
+ private static AnalogInput _analogInput;
+
+ public static void Main()
+ {
+ //tidy up
+ File.Delete("\\SD\\Data.csv");
+
+ try
+ {
+ //retrive and set device time via NTP
+ var networkTime = NtpClient.GetNetworkTime();
+ Utility.SetLocalTime(networkTime);
+
+ _macAddress = GetMAC();
+ _blobClient = new BlobClient(AccountName, AccountKey);
+ _tableClient = new TableClient(AccountName, AccountKey);
+ _tableClient.CreateTable("netmfdata");
+
+ _onBoardButton = new InterruptPort(Pins.ONBOARD_SW1, true,
+ Port.ResistorMode.Disabled,
+ Port.InterruptMode.InterruptEdgeHigh);
+ _onBoardButton.OnInterrupt += onBoardButton_OnInterrupt;
+
+ _analogInput = new AnalogInput(AnalogChannels.ANALOG_PIN_A0);
+
+ }
+ catch(Exception ex)
+ {
+ Debug.Print("Error setting up Device: " + ex.ToString());
+ }
+
+ int counter = 0;
+ while (true)
+ {
+ counter++;
+ var data = _analogInput.Read() * 40D;
+ _tableClient.AddTableEntityForTemperature("netmfdata", _macAddress, counter.ToString(), DateTime.Now, data, "UK");
+
+ lock (Padlock)
+ {
+ using (FileStream fs = File.Open("\\SD\\Data.csv", FileMode.Append, FileAccess.Write))
+ {
+ Debug.Print(data.ToString());
+ var dataBytes = Encoding.UTF8.GetBytes(
+ StringUtility.Format("{0}, {1}, {2}\r\n",
+ _macAddress, DateTime.Now.ToString(),
+ data)
+ );
+
+ fs.Write(dataBytes, 0, dataBytes.Length);
+ fs.Flush();
+ }
+ }
+
+ Thread.Sleep(1000);
+ Debug.Print("Working");
+ }
+ }
+
+ private static string GetMAC()
+ {
+ NetworkInterface[] netIF = NetworkInterface.GetAllNetworkInterfaces();
+
+ string macAddress = "";
+
+ // Create a character array for hexidecimal conversion.
+ const string hexChars = "0123456789ABCDEF";
+
+ // Loop through the bytes.
+ for (int b = 0; b < 6; b++)
+ {
+ // Grab the top 4 bits and append the hex equivalent to the return string.
+ macAddress += hexChars[netIF[0].PhysicalAddress[b] >> 4];
+
+ // Mask off the upper 4 bits to get the rest of it.
+ macAddress += hexChars[netIF[0].PhysicalAddress[b] & 0x0F];
+
+ // Add the dash only if the MAC address is not finished.
+ if (b < 5) macAddress += "-";
+ }
+
+ return macAddress;
+ }
+
+ static void onBoardButton_OnInterrupt(uint data1, uint data2, DateTime time)
+ {
+ try
+ {
+ lock (Padlock)
+ {
+ var filename = StringUtility.Format("{0}.csv", time.ToString("yyyyMMddhhmmss"));
+ Debug.Print(filename);
+ var success = _blobClient.PutBlob("demo",
+ filename,
+ "\\SD\\Data.csv");
+
+ if (success)
+ {
+ Debug.Print("Files uploaded to netmf.blob.core.windows.net");
+ }
+ else
+ {
+ Debug.Print("There was an error, check debug output");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.Print("Critical error: " + ex);
+ }
+ }
+
+ }
+}
View
25 Elastacloud.AzureBlobDemo/Properties/AssemblyInfo.cs
@@ -0,0 +1,25 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Elastacloud.AzureBlobDemo")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Elastacloud.AzureBlobDemo")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
13 Elastacloud.AzureBlobDemo/StringUtilities/ExtensionAttribute.cs
@@ -0,0 +1,13 @@
+using System;
+using Microsoft.SPOT;
+
+// Required for NETMF to recognized extension methods
+namespace System.Runtime.CompilerServices
+{
+ /// <summary>
+ /// Attribute required for extension methods.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)]
+ public sealed class ExtensionAttribute : Attribute { }
+}
+
View
54 Elastacloud.AzureBlobDemo/StringUtilities/FormatException.cs
@@ -0,0 +1,54 @@
+#region License
+// Copyright (c) 2010 Ross McDermott
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using Microsoft.SPOT;
+
+namespace NetMf.CommonExtensions
+{
+ /// <summary>
+ /// The exception that is thrown when the format of an argument does not meet the parameter specifications of the invoked method.
+ /// </summary>
+ public class FormatException : Exception
+ {
+ internal static string ERROR_MESSAGE = "Format string is not valid.";
+
+ /// <summary>
+ /// Initializes a new instance of the FormatException class.
+ /// </summary>
+ public FormatException() : base()
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the FormatException class with a specified error message.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ public FormatException(string message)
+ : base(message)
+ {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the FormatException class with a specified error message and a reference to the inner exception that is the cause of this exception.
+ /// </summary>
+ /// <param name="message">The error message that explains the reason for the exception.</param>
+ /// <param name="ex">The exception that is the cause of the current exception. If the innerException parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. </param>
+ public FormatException(string message, Exception ex) : base(message, ex)
+ {
+ }
+
+ }
+}
View
204 Elastacloud.AzureBlobDemo/StringUtilities/Parse.cs
@@ -0,0 +1,204 @@
+#region License
+// Copyright (c) 2010 Ross McDermott
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using Microsoft.SPOT;
+
+namespace NetMf.CommonExtensions
+{
+ /// <summary>
+ /// Provides additional parsing operations
+ /// </summary>
+ public abstract class Parse
+ {
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseInt(string s, out int i)
+ {
+ i = 0;
+ try
+ {
+ i = int.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseShort(string s, out short i)
+ {
+ i = 0;
+ try
+ {
+ i = short.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseLong(string s, out long i)
+ {
+ i = 0;
+ try
+ {
+ i = long.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseDouble(string s, out double i)
+ {
+ i = 0;
+ try
+ {
+ i = double.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="val">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseBool(string s, out bool val)
+ {
+ val = false;
+ try
+ {
+ if (s == "1" || s.ToUpper() == bool.TrueString.ToUpper())
+ {
+ val = true;
+
+ return true;
+ }
+ else if (s == "0" || s.ToUpper() == bool.FalseString.ToUpper())
+ {
+ val = false;
+
+ return true;
+ }
+
+ return false;
+
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseUInt(string s, out uint i)
+ {
+ i = 0;
+ try
+ {
+ i = uint.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseUShort(string s, out ushort i)
+ {
+ i = 0;
+ try
+ {
+ i = ushort.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Attempt to parse the provided string value.
+ /// </summary>
+ /// <param name="s">String value to be parsed</param>
+ /// <param name="i">Variable to set successfully parsed value to</param>
+ /// <returns>True if parsing was successful</returns>
+ public static bool TryParseULong(string s, out ulong i)
+ {
+ i = 0;
+ try
+ {
+ i = ulong.Parse(s);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+
+
+ }
+
+}
View
139 Elastacloud.AzureBlobDemo/StringUtilities/StringBuilder.cs
@@ -0,0 +1,139 @@
+#region License
+// Copyright (c) 2010 Ross McDermott
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+
+using System;
+using Microsoft.SPOT;
+
+namespace NetMf.CommonExtensions
+{
+ /// <summary>
+ /// Construct a larger string by appending strings together.
+ /// </summary>
+ public class StringBuilder
+ {
+ private const int INITIAL_SIZE = 16;
+ private const int MIN_GROWTH_SIZE = 64;
+
+ private char[] _content = null;
+ private int _currentLength = 0;
+
+ /// <summary>
+ /// Public constructor
+ /// </summary>
+ public StringBuilder() : this(INITIAL_SIZE)
+ {
+ }
+
+ /// <summary>
+ /// Public constructor
+ /// </summary>
+ /// <param name="capacity">Set initial builder capacity</param>
+ public StringBuilder(int capacity)
+ {
+ this._content = new char[capacity];
+ }
+
+ /// <summary>
+ /// Public constructor
+ /// </summary>
+ /// <param name="initital">The initial content of the string builder</param>
+ public StringBuilder(string initital)
+ {
+ this._content = initital.ToCharArray();
+ this._currentLength = _content.Length;
+ }
+
+ /// <summary>
+ /// Append a character to the current string builder
+ /// </summary>
+ /// <param name="c"></param>
+ public void Append(char c)
+ {
+ this.Append(new string(new char[] { c }));
+ }
+
+ /// <summary>
+ /// Append a string to the current string builder
+ /// </summary>
+ /// <param name="toAppend">String to be appended.</param>
+ public void Append(string toAppend)
+ {
+ int additionalSpaceRequired = (toAppend.Length + _currentLength) - _content.Length;
+
+ if (additionalSpaceRequired > 0)
+ {
+ // ensure at least minimum growth size is done to minimise future copying / manipulation
+ if (additionalSpaceRequired < MIN_GROWTH_SIZE)
+ {
+ additionalSpaceRequired = MIN_GROWTH_SIZE;
+ }
+
+ char[] tmp = new char[_content.Length + additionalSpaceRequired];
+
+ // copy content to new array
+ Array.Copy(_content, tmp, _currentLength);
+
+ // replace the content array.
+ _content = tmp;
+ }
+
+ // copy the new content to the holding array
+ Array.Copy(toAppend.ToCharArray(), 0, _content, _currentLength, toAppend.Length);
+ _currentLength += toAppend.Length;
+ }
+
+
+ /// <summary>
+ /// Append the provided line along with a new line.
+ /// </summary>
+ /// <param name="str"></param>
+ public void AppendLine(string str)
+ {
+ this.Append(str);
+ this.Append("\r\n");
+ }
+
+ /// <summary>
+ /// Append to the string builder using format string and placeholder arguments
+ /// </summary>
+ /// <param name="format">String to be formatted</param>
+ /// <param name="args">Arguments to be placed into the formatted string</param>
+ public void AppendFormat(string format, params object[] args)
+ {
+ this.Append(StringUtility.Format(format, args));
+ }
+
+ /// <summary>
+ /// Clear the current string builder back to an empty string.
+ /// </summary>
+ public void Clear()
+ {
+ _currentLength = 0;
+ }
+
+ /// <summary>
+ /// Get the final built string.
+ /// </summary>
+ /// <returns></returns>
+ public override string ToString()
+ {
+ return new string(_content, 0, _currentLength);
+ }
+
+
+
+ }
+}
View
61 Elastacloud.AzureBlobDemo/StringUtilities/StringExtensions.cs
@@ -0,0 +1,61 @@
+#region License
+// Copyright (c) 2010 Ross McDermott
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using Microsoft.SPOT;
+
+namespace NetMf.CommonExtensions
+{
+ /// <summary>
+ /// General string extensions
+ /// </summary>
+ public static class StringExtensions
+ {
+
+ /// <summary>
+ /// Replace all occurances of the 'find' string with the 'replace' string.
+ /// </summary>
+ /// <param name="content">Original string to operate on</param>
+ /// <param name="find">String to find within the original string</param>
+ /// <param name="replace">String to be used in place of the find string</param>
+ /// <returns>Final string after all instances have been replaced.</returns>
+ public static string Replace(this string content, string find, string replace)
+ {
+ int startFrom = 0;
+ int findItemLength = find.Length;
+
+ int firstFound = content.IndexOf(find, startFrom);
+ StringBuilder returning = new StringBuilder();
+
+ string workingString = content;
+
+ while ((firstFound = workingString.IndexOf(find, startFrom)) >= 0)
+ {
+ returning.Append(workingString.Substring(0, firstFound));
+ returning.Append(replace);
+
+ // the remaining part of the string.
+ workingString = workingString.Substring(firstFound + findItemLength, workingString.Length - (firstFound + findItemLength));
+ }
+
+ returning.Append(workingString);
+
+ return returning.ToString();
+
+ }
+
+
+ }
+}
View
289 Elastacloud.AzureBlobDemo/StringUtilities/StringUtility.cs
@@ -0,0 +1,289 @@
+#region License
+// Copyright (c) 2010 Ross McDermott
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#endregion
+
+using System;
+using Microsoft.SPOT;
+using System.Collections;
+
+namespace NetMf.CommonExtensions
+{
+ /// <summary>
+ /// Provides additional standard string operations
+ /// </summary>
+ public abstract class StringUtility
+ {
+ /// <summary>
+ /// Check if the provided string is either null or empty
+ /// </summary>
+ /// <param name="str">String to validate</param>
+ /// <returns>True if the string is null or empty</returns>
+ public static bool IsNullOrEmpty(string str)
+ {
+ if (str == null || str == string.Empty)
+ return true;
+
+ return false;
+ }
+
+
+ /// <summary>
+ /// Replaces one or more format items in a specified string with the string representation of a specified object.
+ /// </summary>
+ /// <param name="format">A composite format string.</param>
+ /// <param name="arg">The object to format.</param>
+ /// <returns>A copy of format in which any format items are replaced by the string representation of arg0.</returns>
+ /// <exception cref="NetMf.CommonExtensions.FormatException">format is invalid, or the index of a format item is less than zero, or greater than or equal to the length of the args array.</exception>
+ /// <exception cref="System.ArgumentNullException">format or args is null</exception>
+ public static string Format(string format, object arg)
+ {
+ return Format(format, new object[] { arg });
+ }
+
+ /// <summary>
+ /// Format the given string using the provided collection of objects.
+ /// </summary>
+ /// <param name="format">A composite format string.</param>
+ /// <param name="args">An object array that contains zero or more objects to format.</param>
+ /// <returns>A copy of format in which the format items have been replaced by the string representation of the corresponding objects in args.</returns>
+ /// <exception cref="NetMf.CommonExtensions.FormatException">format is invalid, or the index of a format item is less than zero, or greater than or equal to the length of the args array.</exception>
+ /// <exception cref="System.ArgumentNullException">format or args is null</exception>
+ /// <example>
+ /// x = StringUtility.Format("Quick brown {0}","fox");
+ /// </example>
+ public static string Format(string format, params object[] args)
+ {
+ if (format == null)
+ throw new ArgumentNullException("format");
+
+ if (args == null)
+ throw new ArgumentNullException("args");
+
+ // Validate the structure of the format string.
+ ValidateFormatString(format);
+
+ StringBuilder bld = new StringBuilder();
+
+ int endOfLastMatch = 0;
+ int starting = 0;
+
+ while (starting >= 0)
+ {
+ starting = format.IndexOf('{', starting);
+
+ if (starting >= 0)
+ {
+ if (starting != format.Length - 1)
+ {
+ if (format[starting + 1] == '{')
+ {
+ // escaped starting bracket.
+ starting = starting + 2;
+ continue;
+ }
+ else
+ {
+ bool found = false;
+ int endsearch = format.IndexOf('}', starting);
+
+ while(endsearch > starting)
+ {
+ if (endsearch != (format.Length - 1) && format[endsearch + 1] == '}')
+ {
+ // escaped ending bracket
+ endsearch = endsearch + 2;
+ }
+ else
+ {
+ if(starting != endOfLastMatch)
+ {
+ string t = format.Substring(endOfLastMatch, starting - endOfLastMatch);
+ t = t.Replace("{{", "{"); // get rid of the escaped brace
+ t = t.Replace("}}", "}"); // get rid of the escaped brace
+ bld.Append(t);
+ }
+
+ // we have a winner
+ string fmt = format.Substring(starting, endsearch-starting + 1);
+
+ if (fmt.Length >= 3)
+ {
+ fmt = fmt.Substring(1, fmt.Length - 2);
+
+ string[] indexFormat = fmt.Split(new char[] { ':' });
+
+ string formatString = string.Empty;
+
+ if (indexFormat.Length == 2)
+ {
+ formatString = indexFormat[1];
+ }
+
+ int index = 0;
+
+ // no format, just number
+ if (Parse.TryParseInt(indexFormat[0], out index))
+ {
+ bld.Append(FormatParameter(args[index], formatString));
+ }
+ else
+ {
+ throw new FormatException(FormatException.ERROR_MESSAGE);
+ }
+ }
+
+ endOfLastMatch = endsearch + 1;
+
+ found = true;
+ starting = endsearch + 1;
+ break;
+ }
+
+
+ endsearch = format.IndexOf('}', endsearch);
+ }
+ // need to find the ending point
+
+ if(!found)
+ {
+ throw new FormatException(FormatException.ERROR_MESSAGE);
+ }
+ }
+ }
+ else
+ {
+ // invalid
+ throw new FormatException(FormatException.ERROR_MESSAGE);
+ }
+
+ }
+
+ }
+
+ // copy any additional remaining part of the format string.
+ if (endOfLastMatch != format.Length)
+ {
+ bld.Append(format.Substring(endOfLastMatch, format.Length - endOfLastMatch));
+ }
+
+ return bld.ToString();
+ }
+
+ private static void ValidateFormatString(string format)
+ {
+ char expected = '{';
+
+ int i = 0;
+
+ while ((i = format.IndexOfAny(new char[] { '{', '}' }, i)) >= 0)
+ {
+ if (i < (format.Length - 1) && format[i] == format[i + 1])
+ {
+ // escaped brace. continue looking.
+ i = i + 2;
+ continue;
+ }
+ else if (format[i] != expected)
+ {
+ // badly formed string.
+ throw new FormatException(FormatException.ERROR_MESSAGE);
+ }
+ else
+ {
+ // move it along.
+ i++;
+
+ // expected it.
+ if (expected == '{')
+ expected = '}';
+ else
+ expected = '{';
+ }
+ }
+
+ if (expected == '}')
+ {
+ // orpaned opening brace. Bad format.
+ throw new FormatException(FormatException.ERROR_MESSAGE);
+ }
+
+ }
+
+
+ /// <summary>
+ /// Format the provided object using the provided format string.
+ /// </summary>
+ /// <param name="p">Object to be formatted</param>
+ /// <param name="formatString">Format string to be applied to the object</param>
+ /// <returns>Formatted string for the object</returns>
+ private static string FormatParameter(object p, string formatString)
+ {
+ if (formatString == string.Empty)
+ return p.ToString();
+
+ if (p as IFormattable != null)
+ {
+ return ((IFormattable)p).ToString(formatString,null);
+ }
+ else if (p is DateTime)
+ {
+ return ((DateTime)p).ToString(formatString);
+ }
+ else if (p is Double)
+ {
+ return ((Double)p).ToString(formatString);
+ }
+ else if (p is Int16)
+ {
+ return ((Int16)p).ToString(formatString);
+ }
+ else if (p is Int32)
+ {
+ return ((Int32)p).ToString(formatString);
+ }
+ else if (p is Int64)
+ {
+ return ((Int64)p).ToString(formatString);
+ }
+ else if (p is SByte)
+ {
+ return ((SByte)p).ToString(formatString);
+ }
+ else if (p is Single)
+ {
+ return ((Single)p).ToString(formatString);
+ }
+ else if (p is UInt16)
+ {
+ return ((UInt16)p).ToString(formatString);
+ }
+ else if (p is UInt32)
+ {
+ return ((UInt32)p).ToString(formatString);
+ }
+ else if (p is UInt64)
+ {
+ return ((UInt64)p).ToString(formatString);
+ }
+ else
+ {
+ return p.ToString();
+ }
+
+ }
+
+
+
+ }
+}
View
208 Elastacloud.AzureBlobDemo/Table/TableClient.cs
@@ -0,0 +1,208 @@
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using ElzeKool;
+using Microsoft.SPOT;
+using NetMf.CommonExtensions;
+
+namespace Elastacloud.AzureBlobDemo.Table
+{
+ public class TableClient
+ {
+ public static string AccountName;
+ public static string AccountKey;
+
+ #region private members
+
+ private string _httpVerb = "POST";
+
+ #endregion
+
+ #region constants
+
+ internal const string HttpVerbPut = "PUT";
+ internal const string HttpVerbDelete = "DELETE";
+ internal const string HttpVerbPost = "POST";
+ internal const string HttpVerbGet = "GET";
+ internal const string VersionHeader = "2011-08-18";
+ internal const string ContentType = "application/atom+xml";
+
+ #endregion
+
+ #region Properties
+
+ internal string TableName { get; set; }
+
+ internal string HttpVerb
+ {
+ get { return _httpVerb; }
+ set { _httpVerb = value; }
+ }
+
+ internal DateTime InstanceDate { get; set; }
+
+ #endregion
+
+ protected byte[] GetBodyBytesAndLength(string body, out int contentLength)
+ {
+ var content = Encoding.UTF8.GetBytes(body);
+ contentLength = content.Length;
+ return content;
+ }
+
+ public TableClient(string accountName, string accountKey)
+ {
+ InstanceDate = DateTime.UtcNow;
+ AccountName = accountName;
+ AccountKey = accountKey;
+ }
+
+ public void CreateTable(string tableName)
+ {
+ string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" +
+ "<entry xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" " +
+ "xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" " +
+ "xmlns=\"http://www.w3.org/2005/Atom\"> " +
+ "<id>http://myaccount.table.core.windows.net/Tables('"
+ + tableName +
+ "')</id>" +
+ "<title />" +
+ "<updated>2012-11-06T11:48:34.9840639+00:00</updated>" +
+ "<author><name/></author> " +
+ "<content type=\"application/xml\"><m:properties><d:TableName>" + tableName + "</d:TableName></m:properties></content></entry>";
+
+ int contentLength = 0;
+ byte[] payload = GetBodyBytesAndLength(xml, out contentLength);
+ string header = CreateAuthorizationHeader(payload, ContentType, "/netmf/Tables()");
+ SendWebRequest("http://netmf.table.core.windows.net/Tables()", header, payload, contentLength);
+ }
+
+ public void AddTableEntityForTemperature(string tablename, string partitionKey, string rowKey, DateTime timeStamp, double temperature, string country)
+ {
+ var timestamp = timeStamp.ToString("yyyy-MM-ddTHH:mm:ss.0000000Z");
+
+ string xml =
+ StringUtility.Format("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?><entry xml:base=\"http://{0}.table.core.windows.net/\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" m:etag=\"W/&quot;datetime'2008-09-18T23%3A46%3A19.4277424Z'&quot;\" xmlns=\"http://www.w3.org/2005/Atom\">" +
+ "<id>http://{0}.table.core.windows.net/{6}(PartitionKey='{2}',RowKey='{3}')</id>" +
+ "<title/><updated>{1}</updated><author><name /></author>" +
+ "<link />" +
+ "<category term=\"{0}.Tables\" scheme=\"http://schemas.microsoft.com/ado/2007/08/dataservices/scheme\" />" +
+ "<content type=\"application/xml\"><m:properties><d:PartitionKey>{2}</d:PartitionKey><d:RowKey>{3}</d:RowKey>" +
+ "<d:Timestamp m:type=\"Edm.DateTime\">{1}</d:Timestamp>" +
+ "<d:Temperature m:type=\"Edm.Double\">{4}</d:Temperature> " +
+ "<d:Country>{5}</d:Country>" +
+ "</m:properties>" +
+ "</content>" +
+ "</entry>", AccountName, timestamp, partitionKey, rowKey, temperature.ToString(), country, tablename);
+
+ int contentLength = 0;
+ byte[] payload = GetBodyBytesAndLength(xml, out contentLength);
+ string header = CreateAuthorizationHeader(payload, ContentType, StringUtility.Format("/{0}/{1}", AccountName, tablename));
+ SendWebRequest(StringUtility.Format("http://{0}.table.core.windows.net/{1}", AccountName, tablename), header, payload, contentLength);
+ }
+
+ #region Request Handling
+
+ //DataServiceVersion: Set the value of this header to 1.0;NetFx.
+ //MaxDataServiceVersion: Set the value of this header to 1.0;NetFx.
+
+ private HttpWebRequest PrepareRequest(string url, string authHeader, byte[] fileBytes = null, int contentLength = 0)
+ {
+ var uri = new Uri(url);
+ var request = (HttpWebRequest)WebRequest.Create(uri);
+ request.Method = HttpVerb;
+ request.Headers.Add("x-ms-date", InstanceDate.ToString("R"));
+ request.Headers.Add("DataServiceVersion", "1.0;NetFx");
+ request.Headers.Add("MaxDataServiceVersion", "1.0;NetFx");
+ request.ContentType = ContentType;
+ request.ContentLength = contentLength;
+ request.Headers.Add("Date", InstanceDate.ToString("R"));
+ request.Headers.Add("x-ms-version", VersionHeader);
+ request.Headers.Add("Authorization", authHeader);
+ if (contentLength != 0)
+ {
+ request.GetRequestStream().Write(fileBytes, 0, fileBytes.Length);
+ }
+ return request;
+ }
+
+ protected void SendWebRequest(string url, string authHeader, byte[] fileBytes = null, int contentLength = 0)
+ {
+ HttpWebRequest request = PrepareRequest(url, authHeader, fileBytes, contentLength);
+ try
+ {
+ HttpWebResponse response;
+ using (response = (HttpWebResponse)request.GetResponse())
+ {
+ if (response.StatusCode == HttpStatusCode.Created)
+ {
+ Debug.Print("Resource has been created");
+ }
+ else
+ {
+ Debug.Print("Status was " + response.StatusCode);
+ var ResponseBody = "";
+ using (var responseStream = response.GetResponseStream())
+ using (var reader = new StreamReader(responseStream))
+ {
+ char[] bytes = new char[(int)responseStream.Length];
+
+ if (bytes.Length > 0)
+ {
+ reader.Read(bytes, 0, bytes.Length);
+
+ ResponseBody = new string(bytes);
+ }
+ }
+ Debug.Print(ResponseBody);
+ }
+ //if (response.StatusCode == HttpStatusCode.Accepted)
+ //{
+ // Trace.WriteLine("Container or blob action has been completed");
+ //}
+ }
+ }
+ catch (WebException ex)
+ {
+ if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Conflict)
+ {
+ Debug.Print("container or blob already exists!");
+ }
+ if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Forbidden)
+ {
+ Debug.Print("problem with signature!");
+ }
+ }
+ }
+
+ #endregion
+
+ #region Shared Access Signature
+
+
+ /*StringToSign = VERB + "\n" +
+ Content-MD5 + "\n" +
+ Content-Type + "\n" +
+ Date + "\n" +
+ CanonicalizedResource;*/
+ /*StringToSign =
+ Date + "\n" +
+ CanonicalizedResource;*/
+ // Signature=Base64(HMAC-SHA256(UTF8(StringToSign)))
+ protected string CreateAuthorizationHeader(byte[] content, string contentType, string canonicalResource)
+ {
+ //string toSign = String.Format("{0}\n{1}\n{2}\n{3}\n{4}",
+ // HttpVerb, hash, contentType, InstanceDate, canonicalResource);
+ string toSign = StringUtility.Format("{0}\n{1}", InstanceDate.ToString("R"), canonicalResource);
+ string signature;
+ var hmacBytes = SHA.computeHMAC_SHA256(Convert.FromBase64String(AccountKey), Encoding.UTF8.GetBytes(toSign));
+ signature = Convert.ToBase64String(hmacBytes).Replace("!", "+").Replace("*", "/"); ;
+
+ return "SharedKeyLite " + AccountName + ":" + signature;
+ }
+
+ #endregion
+ }
+}
+
View
2  README.md
@@ -1,2 +0,0 @@
-netmfazurestorage
-=================
Please sign in to comment.
Something went wrong with that request. Please try again.