9. Windows Store
Single Platform Push Notifications
push.wns.sendToastText04(item.channel, {text1: text}, … );
Windows Phone
push.mpns.sendFlipTile(item.channel, {title: text}, …);
iOS
push.apns.send(item.token, { alert: text, payload:
inAppMessage: Details }}, …);
Android
push.gcm.send(item.registrationId, item.text, …);
{
10.
11. Multi-Platform Push Notifications
function sendNotifications() {
var deviceInfoTable = tables.getTable('DeviceInfo');
deviceInfoTable.where({ userId : user.userId }).read({
success: function(deviceInfos){
deviceInfos.forEach(function(deviceInfo){
if (deviceInfo.uuid != request.parameters.uuid) {
if (deviceInfo.pushToken != null && deviceInfo.pushToken != 'SimulatorToken') {
if (deviceInfo.platform == 'iOS') {
push.apns.send(deviceInfo.pushToken, {
alert: "New something created"
} , { //success / error block});
} else if (deviceInfo.platform == 'Android') {
push.gcm.send(deviceInfo.pushToken, "New something created", { success / error block});
}
}
}
});
}
});
}
12. Don’t forget to check the response on error
(or getFeedback for APNS)
Also, check out
Delivering Push Notifications to Millions of
Devices – Friday @12pm
31. //var crypto = require('crypto');
//item.tempId = new Buffer(crypto.randomBytes(16)).toString('hex');
Sending an Email
function sendEmail(item) {
var sendgrid = new SendGrid('myaccount@azure.com', 'mypassword');
var email = {
to : item.email,
from : 'from-me@chrisrisner.com',
subject : 'Welcome to MyApp',
text: 'Thanks for installing My App!
Click this link to verify:nn'
+ 'http://myapp.azurewebsites.net/activate.html?id=' + item.id + '&tid=' + item.tempId,
createDate : new Date()
};
sendgrid.send({
to: item.email,
from: email.from,
subject: email.subject,
text: email.text
}, function(success, message) {
// If the email failed to send, log it as an error so we can investigate
if (!success) {
console.error(message);
} else {
saveSentEmail(email);
}
});
}
38. Sending Version Info with Each Request
- (void)handleRequest:(NSURLRequest *)request next:(MSFilterNextBlock)next response:(MSFilterResponseBlock)response
{
MSFilterResponseBlock wrappedResponse = ^(NSHTTPURLResponse *innerResponse, NSData *data, NSError *error) {
response(innerResponse, data, error);
};
// add additional versioning information to the querystring for versioning purposes
NSString *append = [NSString stringWithFormat:@"build=%@&version=%@", self.build, self.version];
NSURL *url = nil;
NSRange range = [request.URL.absoluteString rangeOfString:@"?"];
if (range.length > 0) {
url = [NSURL URLWithString:[NSString stringWithFormat:@"%@&%@&p=iOS", request.URL.absoluteString, append]];
}
else {
url = [NSURL URLWithString:[NSString stringWithFormat:@"%@?%@&p=iOS", request.URL.absoluteString, append]];
}
NSMutableURLRequest *newRequest = [request mutableCopy];
newRequest.URL = url;
next(newRequest, wrappedResponse);
}
39. DelegatingHandlers are Service Filters
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://<your subdomain>.azure-mobile.net/",
"<your app key>",
new VersionHandler()
);
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace WindowsStore
{
public class VersionHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
System.Threading.CancellationToken cancellationToken)
{
request.RequestUri = new Uri(request.RequestUri.AbsoluteUri.ToString() + "?version=v2");
return base.SendAsync(request, cancellationToken);
}
}
}
45. function generateOAuthSignature(method, url, data){
var index = url.indexOf('?');
if (index > 0)
url = url.substring(0, url.indexOf('?'));
var signingToken = encodeURIComponent('Your Consumer Secret') + "&" + encodeURIComponent('Your Access Token Secret');
var keys = [];
for (var d in data){
if (d != 'oauth_signature') {
console.log('data: ' , d);
keys.push(d);
}
}
keys.sort();
var output = "GET&" + encodeURIComponent(url) + "&";
var params = "";
keys.forEach(function(k){
params += "&" + encodeURIComponent(k) + "=" + encodeURIComponent(data[k]);
});
params = encodeURIComponent(params.substring(1));
return hashString(signingToken, output+params, "base64");
}
function hashString(key, str, encoding){
var hmac = crypto.createHmac("sha1", key);
hmac.update(str);
return hmac.digest(encoding);
}
function generateNonce() {
var code = "";
for (var i = 0; i < 20; i++) {
code += Math.floor(Math.random() * 9).toString();
}
return code;
}
Part 1: The Helpers
46. var crypto = require('crypto');
var querystring = require('querystring');
function read(query, user, request) {
var result = {
id: query.id,
identities: user.getIdentities(),
userName: ''
};
var identities = user.getIdentities();
var userId = user.userId;
var twitterId = userId.substring(userId.indexOf(':') + 1);
//API 1.0
//url = 'https://api.twitter.com/1/users/show/' + twitterId + '.json';
//API 1.1
var url = 'https://api.twitter.com/1.1/users/show.json?user_id=' + twitterId;
var key = 'This is your consumer key';
var nonce = generateNonce();
var sigmethod = 'HMAC-SHA1';
var version = '1.0';
var twitterAccessToken = identities.twitter.accessToken;
var oauth_token = 'The Access Token';
var seconds = new Date() / 1000;
seconds = Math.round(seconds);
var requestType = 'GET';
var oauthData = { oauth_consumer_key: key, oauth_nonce: nonce, oauth_signature:null,
oauth_signature_method: sigmethod, oauth_timestamp: seconds,
oauth_token: oauth_token, oauth_version: version };
var sigData = {};
for (var k in oauthData){
sigData[k] = oauthData[k];
}
sigData['user_id'] = twitterId;
Part 2: The Work (part 1)
47. var sig = generateOAuthSignature('GET', url, sigData);
oauthData.oauth_signature = sig;
var oauthHeader = "";
for (k in oauthData){
oauthHeader += ", " + encodeURIComponent(k) + "="" + encodeURIComponent(oauthData[k]) + """;
}
oauthHeader = oauthHeader.substring(1);
var authHeader = 'OAuth' + oauthHeader;
//Generate callback for response from Twitter API
var requestCallback = function (err, resp, body) {
if (err || resp.statusCode !== 200) {
console.error('Error sending data to the provider: ', err);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, body);
} else {
try {
var userData = JSON.parse(body);
if (userData.name != null)
result.UserName = userData.name;
else
result.UserName = "can't get username";
request.respond(200, [result]);
} catch (ex) {
console.error('Error parsing response from the provider API: ', ex);
request.respond(statusCodes.INTERNAL_SERVER_ERROR, ex);
}
}
}
//Create the request and execute it
var req = require('request');
var reqOptions = {
uri: url,
headers: { Accept: "application/json" }
};
if (authHeader != null)
reqOptions.headers['Authorization'] = authHeader;
req(reqOptions, requestCallback);
}
Part 2.2: The Work
49. The Easy Way
exports.post = function(request, response) {
var twitter = require(‘ctwitter.js’);
twitter.init(’consumer key',’consumer secret');
twitter.tweet(request.body.tweettext, request.user, request);
}
Get the script here: http://bit.ly/14b73Gg
80. On-Prem Solutions in Windows Azure
Data
Synchronization
SQL Data Sync
Application-Layer
Connectivity & Messaging
Service Bus
Secure Point-to-Site Network
Connectivity
Windows Azure Virtual Network
Secure Site-to-Site
Network Connectivity
Windows Azure Virtual Network
81.
82. Windows Azure
Point-to-Site VPNs
<subnet 1>
<subnet 2>
<subnet 3>
DNS
Server
On-premises
VPN
Gateway
Route-based
VPN
Your datacenter
Individual
computers behind
corporate firewall
Virtual Network
83. Site-to-Site Connectivity
•
•
On-ramp for migrating services to the cloud
•
Windows Azure
Extend your premises to the cloud securely
Use your on-prem resources in Azure (monitoring, AD, …)
On-premises
<subnet 2>
<subnet 3>
DNS
Server
VPN
Gateway
Hardware VPN or
Windows RRAS
Your datacenter
<subnet 1>
Virtual Network