Changeset 38533
- Timestamp:
- 10/01/10 09:54:32 (3 years ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
lang/javascript/vimperator-plugins/trunk/twittperator.js
r38531 r38533 29 29 <description>Twitter Client using ChirpStream</description> 30 30 <description lang="ja">OAuth対応Twitterクライアント</description> 31 <version>1. 7.3</version>31 <version>1.8.0</version> 32 32 <minVersion>2.3</minVersion> 33 33 <maxVersion>2.4</maxVersion> … … 1222 1222 1223 1223 // Twittperator 1224 function Stream({ name, host, path }) { // {{{ 1225 let connectionInfo; 1224 function HTTPConnection(url, options) { // {{{ 1225 const ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); 1226 1227 this.events = {}; 1228 1229 this.channel = 1230 ioService.newChannelFromURI(ioService.newURI(url, null, null)).QueryInterface(Ci.nsIHttpChannel); 1231 this.channel.notificationCallbacks = this; 1232 1233 if (options) { 1234 if ("headers" in options) { 1235 for (let [n, v] in Iterator(options.headers)) 1236 this.channel.setRequestHeader(n, v, true); 1237 } 1238 1239 for (let [n, v] in Iterator(options)) { 1240 if (/^on[A-Z]/(n) && (v instanceof Function)) 1241 this.events[n.toLowerCase()] = v; 1242 } 1243 1244 this.onRecv = options.onReceive; 1245 } 1246 1247 this.channel.asyncOpen(this, null); 1248 } 1249 HTTPConnection.prototype = { 1250 callEvent: function(name) { 1251 name = name.toLowerCase(); 1252 if (name in this.events) 1253 return this.events[name].apply(this, Array.slice(arguments, 1)); 1254 }, 1255 1256 cancel: function() { 1257 if (this.channel) 1258 return this.channel.cancel(Cr.NS_ERROR_NOT_AVAILABLE); 1259 }, 1260 1261 // 実装しないと例外になるメソッドとか 1262 onStartRequest: function(request, context) {}, 1263 onProgress : function(request, context, progress, progressMax) {}, 1264 onStatus : function(request, context, status, statusArg) {}, 1265 onRedirect : function(oldChannel, newChannel) {}, 1266 1267 onDataAvailable: function(request, context, stream, sourceOffset, length) { 1268 let inputStream = 1269 Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); 1270 inputStream.init(stream); 1271 let data = inputStream.read(length); 1272 this.callEvent("onReceive", data); 1273 }, 1274 1275 onStopRequest: function(request, context, status) { 1276 if (Components.isSuccessCode(status)) { 1277 this.callEvent("onComplete"); 1278 } else { 1279 this.callEvent("onError"); 1280 } 1281 delete this.channel; 1282 }, 1283 1284 onChannelRedirect: function(oldChannel, newChannel, flags) { 1285 this.channel = newChannel; 1286 }, 1287 1288 // nsIInterfaceRequestor 1289 getInterface: function(IID) { 1290 try { 1291 return this.QueryInterface(IID); 1292 } catch (e) { 1293 throw Components.results.NS_NOINTERFACE; 1294 } 1295 }, 1296 1297 // XPCOM インターフェイスに見せかけているので、QI を実装する必要がある 1298 QueryInterface : function(IID) { 1299 if (IID.equals(Ci.nsISupports) || 1300 IID.equals(Ci.nsIInterfaceRequestor) || 1301 IID.equals(Ci.nsIChannelEventSink) || 1302 IID.equals(Ci.nsIProgressEventSink) || 1303 IID.equals(Ci.nsIHttpEventSink) || 1304 IID.equals(Ci.nsIStreamListener)) 1305 return this; 1306 1307 throw Components.results.NS_NOINTERFACE; 1308 } 1309 }; // }}} 1310 function Stream({ name, url }) { // {{{ 1311 let connection; 1226 1312 let restartCount = 0; 1227 let startTime;1228 1313 let lastParams; 1229 let lastReceivedTime;1230 1314 let listeners = []; 1231 1315 … … 1242 1326 function restart() { 1243 1327 stop(); 1244 1245 1328 if (restartCount > 13) 1246 1329 return liberator.echoerr("Twittperator: Gave up to connect to " + name + "..."); 1247 1248 1330 liberator.echoerr("Twittperator: " + name + " will be restared..."); 1249 1250 1331 // 試行済み回数^2 秒後にリトライ 1251 1332 setTimeout(function() start(lastParams), Math.pow(2, restartCount) * 1000); 1252 1253 1333 restartCount++; 1254 1334 } 1255 1335 1256 1336 function stop() { 1257 if (!connection Info)1337 if (!connection) 1258 1338 return; 1259 1339 connection.cancel(); 1260 1340 liberator.log("Twittperator: stop " + name); 1261 1262 clearInterval(connectionInfo.interval);1263 connectionInfo.sos.close();1264 connectionInfo.sis.close();1265 1266 connectionInfo = void 0;1267 1341 } 1268 1342 … … 1272 1346 liberator.log("Twittperator: start " + name); 1273 1347 1274 startTime = new Date().getTime();1275 1348 lastParams = params; 1276 1349 1277 1350 let useProxy = !!setting.proxyHost; 1278 let request Path = path;1351 let requestUrl = url; 1279 1352 1280 1353 if (params) { 1281 1354 // XXX Twitter がなぜか + を許容しない気がする(401 を返す)ので、再変換する 1282 1355 let query = tw.buildQuery(params).replace(/\+/g, "%20"); 1283 requestPath += '?' + query; 1284 } 1285 1286 let authHeader = tw.getAuthorizationHeader("http://" + host + requestPath); 1287 1288 if (useProxy) 1289 requestPath = "http://" + host + requestPath; 1290 1291 let get = [ 1292 "GET " + requestPath + " HTTP/1.1", 1293 "Host: " + host, 1294 "Authorization: " + authHeader, 1295 "Content-Type: application/x-www-form-urlencoded", 1296 "", 1297 "", 1298 ].join("\n"); 1299 1300 let socketService = 1301 let (stsvc = Cc["@mozilla.org/network/socket-transport-service;1"]) 1302 let (svc = stsvc.getService()) 1303 svc.QueryInterface(Ci["nsISocketTransportService"]); 1304 1305 let transport = 1306 socketService.createTransport( 1307 null, 0, 1308 useProxy ? setting.proxyHost : host, 1309 useProxy ? parseInt(setting.proxyPort || "3128", 10) : 80, 1310 null); 1311 let os = transport.openOutputStream(0, 0, 0); 1312 let is = transport.openInputStream(0, 0, 0); 1313 let sis = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); 1314 let sos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIBinaryOutputStream); 1315 1316 sis.init(is); 1317 sos.setOutputStream(os); 1318 1319 sos.write(get, get.length); 1320 1356 requestUrl += '?' + query; 1357 } 1358 1359 let authHeader = tw.getAuthorizationHeader(requestUrl); 1321 1360 let buf = ""; 1322 let first = true; 1323 1324 let interval = setInterval(function() { 1361 1362 let onReceive = function(data) { 1325 1363 try { 1326 let len = sis.available();1327 if (len <= 0) {1328 // 30秒ごとにゴミデータを送ってくる仕様っぽいので、30x2+10秒 まつことにする。1329 if (lastReceivedTime && ((new Date().getTime() - lastReceivedTime) > 70 * 1000)) {1330 lastReceivedTime = 0;1331 liberator.echoerr("Twittperator: " + name + " timed out");1332 restart();1333 }1334 return;1335 }1336 1337 // 5分間接続されていたら、カウントをクリア1338 // 何かの事情で即切断されてしまうときに、高頻度でアクセスしないための処置です。1339 if (restartCount && (new Date().getTime() - startTime) > (5 * 60 * 1000))1340 restartCount = 0;1341 1342 lastReceivedTime = new Date().getTime();1343 let data = sis.read(len);1344 1364 let lines = data.split(/\r\n|[\r\n]/); 1345 1365 if (lines.length >= 2) { … … 1347 1367 for (let [, line] in Iterator(lines.slice(0, -1))) { 1348 1368 try { 1349 if (first) {1350 first = false;1351 let [, code] = line.match(/^\S+\s+(\d+)/);1352 if (code != '200') {1353 stop();1354 return liberator.echoerr("Twittperator: " + name + "'s response code is " + code + ".");1355 }1356 }1357 1369 if (/^\s*\{/(line)) 1358 1370 onMsg(Utils.fixStatusObject(JSON.parse(line)), line); 1359 else1360 liberator.log(name + ': \n' + line);1361 1371 } catch (e) { liberator.log(e); } 1362 1372 } … … 1365 1375 buf += data; 1366 1376 } 1367 } catch (e if /^NS_(?:ERROR_NET_RESET|BASE_STREAM_CLOSED)$/(e)) {1368 liberator.echoerr("Twittperator: " + name + " was stopped by " + e.name + ".");1369 restart();1370 stop();1371 1377 } catch (e) { 1372 1378 liberator.echoerr("Twittperator: Unknown error on " + name + " connection: " + e.name); 1373 restart(); 1374 stop(); 1375 } 1376 }, 500); 1377 1378 connectionInfo = { 1379 sos: sos, 1380 sis: sis, 1381 interval: interval, 1382 params: params 1379 } 1383 1380 }; 1381 1382 connection = new HTTPConnection( 1383 requestUrl, 1384 { 1385 headers: { 1386 Authorization: authHeader, 1387 }, 1388 onReceive: onReceive, 1389 onError: restart 1390 } 1391 ); 1384 1392 } 1385 1393 … … 1890 1898 } 1891 1899 }, 1892 completer: function (context, args) {1900 completer: function(context, args) { 1893 1901 if (setting.trackWords) 1894 1902 context.completions = [[setting.trackWords, "Global variable"]]; … … 2094 2102 2095 2103 // ストリーム 2096 let ChirpUserStream = Stream({ name: 'chirp stream', host: "chirpstream.twitter.com", path: "/2b/user.json" });2097 let TrackingStream = Stream({ name: 'tracking stream', host: "stream.twitter.com", path: "/1/statuses/filter.json" });2104 let ChirpUserStream = Stream({ name: 'chirp stream', url: "https://userstream.twitter.com/2/user.json" }); 2105 let TrackingStream = Stream({ name: 'tracking stream', url: "http://stream.twitter.com/1/statuses/filter.json" }); 2098 2106 2099 2107 // 公開オブジェクト
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)