По большей части работающий пример приложения Twitter OAuth2, использующий библиотеку обещаний Криса Q с https.request
, маршрут API Nodejs Express.Первая попытка пользователя временной шкалы GET.Если 401 ответит, обновляя токен-носитель, тогда повторите пользовательскую временную шкалу.Мне пришлось использовать Q.when
для обработки обещания, которое возвращает другое обещание (цепочку) или значение.
/**
* Using Rails-like standard naming convention for endpoints.
* GET /things -> index
* POST /things -> create
* GET /things/:id -> show
* PUT /things/:id -> update
* DELETE /things/:id -> destroy
*/
'use strict';
// var _ = require('lodash');
var http = require('http');
var https = require('https');
var querystring = require('querystring');
var Q = require('q')
// Get list of twtimelines
exports.index = function(req, res) {
var tid = req.query.tid
if (tid) {
Q.when(reqTimeline(tid, true, res), function(value) {
// > value
// 404
// > body1
// '{"errors":[{"code":34,"message":"Sorry, that page does not exist."}]}'
})
} else {
res.json({
errors: [{
message: 'no tid specified in query'
}]
});
}
};
function reqPromise(options, postData) {
var deferred = Q.defer()
var req = https.request(options, function(res) {
// console.log("statusCode: ", res.statusCode);
// console.log("headers: ", res.headers);
var statusCode = res.statusCode
deferred.notify(res)
res.on('data', function(d) {
//process.stdout.write(d);
deferred.notify(d)
}).on('end', function() {
deferred.resolve(statusCode)
});
});
req.on('error', function(e) {
console.error(e);
deferred.reject(e)
});
req.write(postData);
req.end();
return deferred.promise
} // deferRequest
function isIncomingMessage(ot) {
return ot instanceof http.IncomingMessage
}
function isBuffer(ot) {
return ot instanceof Buffer
}
function reqTimeline(screen_name, reqBearerTokenOn401, res) {
var optionsUserTimeline = {
hostname: 'api.twitter.com',
path: '/1.1/statuses/user_timeline.json?' + querystring.stringify({
count: '3',
screen_name: screen_name
}),
method: 'GET',
headers: {
//'Authorization': 'Bearer ' + JSON.parse(body1).access_token
'Authorization': 'Bearer ' + process.env.BEARER_TOKEN
} // headers
};
console.log("optionsUserTimeline", optionsUserTimeline)
var statusCode;
var body1 = new Buffer(''); // default utf8 string buffer ?
return reqPromise(optionsUserTimeline, '')
.then(function(value) { // done
if (reqBearerTokenOn401 && value === 401) {
console.log("reqTimeline - requesting bearer token")
return reqBearerToken(screen_name, res)
}
console.log("reqTimeline - done done:", value)
res.end()
return value
},
function(reason) { // error
console.log("reqTimeline - error:", body1)
},
function(progress) {
console.log("reqTimeline - progress:", body1)
if (isIncomingMessage(progress)) {
body1 = body1.slice(0, 0) // re-set buffer
statusCode = progress.statusCode;
if (reqBearerTokenOn401 && statusCode === 401) {
// readyn for retry
} else {
res.writeHead(statusCode)
}
} else if (isBuffer(progress)) {
if (reqBearerTokenOn401 && statusCode === 401) {
body1 += progress
} else {
res.write(progress)
}
} else {
throw "reqTimeline - unexpected progress"
}
});
} // reqTimeline
function reqBearerToken(screen_name, res) {
var postData = querystring.stringify({
'grant_type': 'client_credentials'
})
var optionsBearerToken = {
hostname: 'api.twitter.com',
path: '/oauth2/token',
method: 'POST',
headers: {
'Authorization': 'Basic ' + new Buffer(
process.env.CONSUMER_KEY + ":" + process.env.CONSUMER_SECRET
).toString('base64'),
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Content-Length': postData.length
} // headers
}
// console.log("key", process.env.CONSUMER_KEY)
// console.log("secret", process.env.CONSUMER_SECRET)
// console.log("buf", new Buffer(
// process.env.CONSUMER_KEY + ":" + process.env.CONSUMER_SECRET
// ).toString())
console.log("optionsBearerToken", optionsBearerToken)
var body2 = new Buffer(''); // default utf8 string buffer ?
return reqPromise(optionsBearerToken, postData)
.then(function(value) { // done
console.log("reqBearerToken - done:", body2)
if (value === 200) {
console.log("reqBearerToken - done done")
process.env.BEARER_TOKEN = JSON.parse(body2).access_token;
return reqTimeline(screen_name, false, res)
}
return value
}, function(reason) {
throw "reqBearerToken - " + reason
}, function(progress) {
if (isIncomingMessage(progress)) {
body2 = body2.slice(0, 0) // reset buffer
} else if (isBuffer) {
body2 += progress
} else {
throw "reqBearerToken - unexpected progress"
}
});
} // reqBearerToken