之前的星期看完了Coursera的那個Node 的課程,內容是充實的,繼之前的內容後,還有HTTP 的session , https, authorise token。 不過未有用到的想法,看完也像過眼雲煙。能夠上心的反而只有自己試的Socket.IO。會這樣做是因為看到一篇Socket.IO 的文章,可以讓客戶端的瀏覽器和伺服器端作實時雙向溝通,不必客戶端去不斷刷新。
Socket.IO 由兩部份組成:
- 整合在Node.JS HTTP Server的伺服端: "socket.io"
- 瀏覽器端掛載的 Client Library: "socket.io-client"
在處理在客戶端的瀏覽器網頁,先加入引用Socket.io 和 jQuery 的JS庫:
<script src="/socket.io/socket.io.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
之後呼叫 var socket = io.connect() 設定連線位置及初始化。 之後的socket.on('event', eventHandler); 會監聽server 傳來名為'stockSnap'的事件,當中的eventHandler會處理連接收後的工作,這裡把它寫成匿名函式,就是把伺服器傳來的資料'data'用jQuery方式更新到HTML Table中的相應 #id 的 <div>。
<script>
var socket = io.connect();
socket.on('stockSnap', function(data) {
$('#stock').text(data.symbol);
$('#name').text(data.name);
$('#price').text(data.lastTradePriceOnly);
$('#lastTradeDate').text(data.lastTradeDate);
});
</script>
伺服器和以往一樣開設HTTP Server,每5分鐘提取yahoo-finance 的snapshot data,當然也要預先安裝Socket.IO的套件。
在Socket.IO的部份,var serv_io = io.listen(server) 會開設一個Server: "serv_io" 依附到原本的HTTP Server 上,之後用serv_io.on('connect', callback)監聽外來到的連線。連線過程中用socket.emit('stockSnap',[arg])發出名為'stockSnap'的事件,當然[arg]其中的資料就是Yahoo-finance拿來的股票資料,或再經運算出來的自定指標。
var server = http.createServer()
server.listen(8080);
var serv_io = io.listen(server);
serv_io.on('connect', function(socket) {
socket.emit('stockSnap', {
'symbol': snapshot['symbol'],
'name': snapshot['name'],
'lastTradePriceOnly': snapshot['lastTradePriceOnly'],
'lastTradeDate': snapshot['lastTradeDate']
});
所以,基本使用方面就是這些指令:
server.listen(httpServer) // 基於Node.JS原有的http Server上開設一個Server
server.on('connect', callback) // 伺服器端監聽外來查詢的連線
server.on('disconnect', callback) // 伺服器端監聽現有連線的中斷
socket.connect('http://127.0.0.1:8080/') // 網頁端打開一個Socket連接到localhost:8080
socket.close() // 手動在網頁端關閉一個Socket
socket.emit(eventName[, ...args][, ack]) //發送一個事件
socket.on(eventName, callback) //監聽一個事件,執行callback
如果在網頁加上一個文字的輸入欄,按「確定」後觸發socket.emit()將股票編號傳回,更新伺服器程式中的股票名單SYMBOLS,就可以做到更互動的查詢。這個已加入到下面的完整代碼中。
//----------Code part.1 -----------//
socket-stock.html
<html>
<head>
<style>
div {display:inline}
table, th, td {
border: 1px solid black;
}
</style>
<script src="/socket.io/socket.io.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<script>
var socket = io.connect();
socket.on('connect', function(data) {
socket.on('stockSnap', function(data) {
$('#stock').text(data.symbol);
$('#name').text(data.name);
$('#price').text(data.lastTradePriceOnly);
$('#lastTradeDate').text(data.lastTradeDate);
$('#lastTradeTime').text(data.lastTradeTime);
$('#customIndicator').text(data.customIndicator);
$('#sysTimestamp').text(data.sysTimestamp);
});
$('#form').submit(function(){
socket.emit('stockReq', $('#stockCode').val() );
return false;
});
});
</script>
<table style="width:100%">
<tr>
<th>Symbol</th>
<th>Name</th>
<th>Last Trade Price</th>
<th>Last Trade Date</th>
<th>Last Trade Time</th>
<th>Custom Indicator</th>
<th>System Timestamp</th>
</tr>
<tr>
<td><div id="stock"></div></td>
<td><div id="name"></div></td>
<td><div id="price"></div></td>
<td><div id="lastTradeDate"></div></td>
<td><div id="lastTradeTime"></div></td>
<td><div id="customIndicator"></div></td>
<td><div id="sysTimestamp"></div></td>
</tr>
</table>
<form id = "form" action = "">
Input: <input type="text" id="stockCode"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
//----------Code part.2 -----------//
app-stock.js
var http = require("http");
var url = require('url');
var fs = require('fs');
//var util = require('util');
//require('colors');
var _ = require('lodash');
var io = require('socket.io'); // 加入 Socket.IO
var yahooFinance = require('yahoo-finance');
var FIELDS01 = _.flatten([
['n'], //name
['l1','d1','d2','t1'], //Last Trade, Last Trade Date, Trade Date, Last Trade Time
['p','c1','w','j6','k5'],
['y','r','p6']
]);
var SYMBOLS = ['0823.HK'];
var INDICATORS = ['Positive', 'Neutral', 'Negative'];
var result;
var server = http.createServer(function(request, response) {
console.log('Connection');
var path = url.parse(request.url).pathname;
switch (path) {
case '/':
response.writeHead(200, {'Content-Type': 'text/html'});
response.write('Hello, World.');
response.end();
break;
case '/socket-stock.html':
fs.readFile(__dirname + path, function(error, data) {
if (error){
response.writeHead(404);
response.write("opps this doesn't exist - 404");
} else {
response.writeHead(200, {"Content-Type": "text/html"});
response.write(data, "utf8");
}
response.end();
});
break;
default:
response.writeHead(404);
response.write("Opps, this doesn't exist - 404");
response.end();
break;
}
});
server.listen(8080);
console.log('Page shown in http://127.0.0.1:8080/socket-stock.html');
var serv_io = io.listen(server);
serv_io.on('connect', function(socket) {
// 定時接收yahoo-finance的資料,並發出到瀏覽器
setInterval(function() {
yahooFinance.snapshot({
fields: FIELDS01,
symbols: SYMBOLS
}, function (err, result) {
if (err) { throw err; }
_.forEach(result, function (snapshot, symbol) {
var d = new Date();
var dString = d.toLocaleTimeString();
var customIndicator = INDICATORS[Math.floor(Math.random() * INDICATORS.length)];
console.log(util.format('=== %s ===', (dString + " - " +snapshot['symbol']).cyan ));
console.log(JSON.stringify(snapshot, null, 2));
socket.emit('stockSnap', {
'symbol': snapshot['symbol'].toString(),
'name': snapshot['name'].toString(),
'lastTradePriceOnly': snapshot['lastTradePriceOnly'].toString(),
'lastTradeDate': snapshot['lastTradeDate'].toLocaleDateString("en-GB"),
'lastTradeTime': snapshot['lastTradeTime'].toString(),
'customIndicator': customIndicator,
'sysTimestamp': dString
});
});
});
}, 10*1000);
// 接收來自於瀏覽器的資料
socket.on('stockReq', function(data) {
console.log('message: ' + data);
SYMBOLS[0] = data;
});
});
沒有留言:
張貼留言