วันศุกร์ที่ 16 พฤษภาคม พ.ศ. 2557

HTML5 : node.js and WebSocket - Practical 1 Room Manage


วันนี้ทำจริงจังครับ แต่แรงพอแค่สร้างส่วนจัดการห้อง เหมือนเกมออนไลน์เลยครับมี 3 ส่วน
1. ส่วนหน้า connect server
 

2. ส่วนหน้า Room List คือดูห้องที่เราจะเข้าไปอาศัย แล้วก็สามารถสร้างห้องของตัวเองได้ครับ
 

3. ส่วนหน้า Room Waiting คือหน้าที่เราเข้าห้องแล้วรอเล่นเกมนะครับ
 

ขอไม่อธิบายโค้ดละเอียดนะครับ เยอะมาก เอาไปลองรันเล่นกันได้เลยครับ ใครที่อ่านโค้ดไม่รู้เรื่องให้อ่าน part1 ,part2, part3 ก่อนครับ แล้วก็จะอ่านของตอนนี้รู้เรื่องครับ ขอให้ความรู้อยู่คู่ทุกคนครับ 555

-------------------------------------------------------------------------

โค้ดๆ
ฝั่ง server  มีพระเอก 3 ตัวครับ

socket ทุกคนคงรู้จักแล้ว เป็น socket ใช้ในการติดต่อหากันระหว่า client กับ server

user ผมใช้เป็นตัวแทน user ครับ ตอนนี้มี 3 field คือ socketId(ไว้อ้างอิงเพื่อดึง socket), name, roomId(ใช้ระบุว่า user นี้อยู่ห้องไหน หากไม่ได้อยู่จะเป็น null)

room เป็นตัวแทนห้องครับ ถูกสร้างเมื่อ create ครับใครมา join ก็รับเอา roomId ไปใส่ให้ user ได้เลยครับ

-- การไล่โค้ด --
แบ่งเป็น 2 ส่วนโดยคั่นกลางด้วย Listener method นั่นก็คือ socketio.listen(server).on('connection' นั่นเอง
- โดย function ที่อยู่ด้านบนจะเป็นส่วนที่ listener เรียกใช้
- และ function ที่อยู่ด้านล่างจะเป็นส่วนจัดการข้อมูลเรียกว่าเป็น utility function ละกันครับ


// practical1/server.js
var http = require('http');
var formidable = require("formidable");
var socketio = require('socket.io');
var server = http.createServer(function(req, res) {
        form = new formidable.IncomingForm();
        form.parse(req, function(e, fields, files){
                res.writeHead(200, [['Content-type','text/plain'],['Content-Length',0]]);
                res.write('');
                res.end();
                //Handle sending data back through the socket to the web client
                handleServerNotice(fields);
        });
}).listen(1333, function() {
        console.log('listening on 1333');
});

var RoomStatusEnum = { WAITING: 1, PLAYING: 2 };
if(Object.freeze){
    Object.freeze(RoomStatusEnum);   
}


var sockets = new Array();
var users = new Array();
var rooms = new Array();


function registerUser(socketId,name){
    var user = new Object();
    user.socketId = socketId;
    user.name = name;
    user.roomId = null;
    users.push(user);
   
    var socket = socketManage.getSocket(socketId);
    socket.emit("registerUser",JSON.stringify(user));
   
    userList();
    roomList();
}

function disconnectUser(socketId){
     var user = userManage.getUser(socketId);
    console.log('disconnectUser = ' + JSON.stringify(user));
    for(var i=0;i<users.length;i++){
        var queryuser = users[i];
        var socket = socketManage.getSocket(queryuser.socketId);
        if(socket != null){
            socket.emit("disconnectUser",JSON.stringify(user));
        }
    }
   
    if(user.roomId != null){
        leaveRoom(user.roomId);
    }
   
    userManage.removeUser(socketId);
    socketManage.removeSocket(socketId);
    userList();
}

function userList(){
    for(var i=0;i<users.length;i++){
        var user = users[i];
        var socket = socketManage.getSocket(user.socketId);
        if(socket != null){
            socket.emit("userList",JSON.stringify(users));
        }
    }
}

function createRoom(socket,roomName){
        var room = new Object();
        room.id = socket.manager.generateId();
        room.name = roomName;
         var user = userManage.getUser(socket.id);
        room.ownerId = user.socketId;
        room.ownerName = user.name;
        room.status = RoomStatusEnum.WAITING;
       
        user.roomId = room.id;
       
       
        rooms.push(room);
       
        var socket = socketManage.getSocket(user.socketId);
        socket.emit("createRoom",JSON.stringify(room));
       
        //updateRoom(room.id); // update room status
        roomList(); // notify user outside room
        userRoomList(socket,room.id); // notify user inside room
}

function joinRoom(socket,roomId){
     var room = roomManage.getRoom(roomId);
   
    var user = userManage.getUser(socket.id);
    user.roomId = room.id;
   
    var socket = socketManage.getSocket(user.socketId);
    socket.emit("joinRoom",JSON.stringify(room));
   
    //updateRoom(room.id); // update room status
    userRoomList(socket,room.id); // notify user inside room
}

function leaveRoom(socket,roomId){
    var room = roomManage.getRoom(roomId);
    var user = userManage.getUser(socket.id);
   
    // leave
    user.roomId = null;
   
    var userRooms = userManage.getUserRoom(roomId);
   
    // no anybody in room
    if(userRooms.length == 0){
        roomManage.removeRoom(roomId);
    }else{
        // user is owner then grant the next user to be the next owner and update room status
        if(room.ownerId == user.socketId){
            room.ownerId = userRooms[0].socketId;
            room.ownerName = userRooms[0].name;           
            updateRoom(roomId);
        }
       
    }
   
    var socket = socketManage.getSocket(user.socketId);
    socket.emit("leaveRoom",JSON.stringify(user));
   
    userRoomList(socket,room.id); // notify user inside room
   
    roomList();
}

function updateRoom(roomId){
    var room = roomManage.getRoom(roomId);
    var userRooms = userManage.getUserRoom(roomId);
    for(var i=0;i<userRooms.length;i++){
        var userRoom = userRooms[i];
        var socket = socketManage.getSocket(userRoom.socketId);
        if(socket != null){
            socket.emit("updateRoom",JSON.stringify(room));
        }
    }
}

function roomList(){
    for(var i=0;i<users.length;i++){
        var user = users[i];
        // send to user that not in the room
        if(user.roomId == undefined || user.roomId == null){
            var socket = socketManage.getSocket(user.socketId);
            if(socket != null){
                socket.emit("roomList",JSON.stringify(rooms));
            }
        }       
    }
}

/**
 show user in the room
*/
function userRoomList(socket,roomId){
    var userRooms = userManage.getUserRoom(roomId);
   
    for(var i=0;i<userRooms.length;i++){
        var userRoom = userRooms[i];
        var socket = socketManage.getSocket(userRoom.socketId);
        if(socket != null){
            socket.emit("userRoomList",JSON.stringify(userRooms));
        }
    }
}

// Listener method
socketio.listen(server).on('connection', function(socket){
        console.log("generatedId = " + socket.manager.generateId());
       
        sockets.push(socket);
       
        socket.on('registerUser', function (data) {
            console.log(socket.id + " registerUser = " + data);
            var user = JSON.parse(data);
            registerUser(socket.id,user.name);
        });
       
        socket.on('userList', function (data) {
            userList();
        });
       
        socket.on('createRoom', function (data) {
            var room = JSON.parse(data);
            createRoom(socket,room.name);
        });
       
        socket.on('joinRoom', function (data) {
            var room = JSON.parse(data);
            joinRoom(socket,room.id);
        });
       
        socket.on('leaveRoom', function (data) {
            var room = JSON.parse(data);
            //console.log("leaveRoom = " +data);
            leaveRoom(socket,room.id);
        });
       
        socket.on('roomList', function (data) {
            roomList();
        });
       
        socket.on('userRoomList', function (data) {
            var room = JSON.parse(data);
            userRoomList(room.id);
        });

        socket.on('disconnect', function(data){
            console.log('disconnect socket id', socket.id);
            disconnectUser(socket.id);
            //socketManage.removeSocket(socket.id);
        });


});

/***************************************************************************
 User Manage
****************************************************************************/
 var userManage = new Object();

/**
    @Description
    find socket index by socketId
     @Return
     index of Socket in sockets array
**/
 userManage.getUserIndex = function(socketId){
        var selectIndex = -1;
    for(var i=0;i<users.length;i++){
        var user= users[i];
        if(user.socketId == socketId){
            selectIndex = i;
            break;
        }
    }
    return selectIndex;
 };

 /**
     @Description
    find user in the room
     @Return
     all user in the room
 **/
 userManage.getUserRoom = function(roomId){
     var userRooms = new Array();
    for(var i=0;i<users.length;i++){
        var user= users[i];
        if(user.roomId == roomId){
            userRooms.push(user);
        }
    }
    return userRooms;
 };


/**
    @Description
    get socket by socketId
    @Return
    Socket or null if not found
**/
userManage.getUser = function(socketId){
    var selectIndex = userManage.getUserIndex(socketId);
    if(selectIndex != -1){
        return users[selectIndex];   
    }else{
        return null;   
    }
};

/**
    @Description
    remove socket by socketId
**/
 userManage.removeUser = function(socketId){
        var selectIndex = userManage.getUserIndex(socketId);
    if(selectIndex != -1){
        users.splice(selectIndex,1);
    }
};


/***************************************************************************
 Room Manage
****************************************************************************/
 var roomManage = new Object();

/**
    @Description
    find room index by roomId
     @Return
     index of room in rooms array
**/
  roomManage.getRoomIndex = function(roomId){
        var selectIndex = -1;
    for(var i=0;i<rooms.length;i++){
        var room= rooms[i];
        if(room.id == roomId){
            selectIndex = i;
            break;
        }
    }
    return selectIndex;
 };


/**
    @Description
    get room by roomId
    @Return
    Room or null if not found
**/
roomManage.getRoom = function(roomId){
    var selectIndex = roomManage.getRoomIndex(roomId);
    if(selectIndex != -1){
        return rooms[selectIndex];   
    }else{
        return null;   
    }
};

/**
    @Description
    remove socket by socketId
**/
 roomManage.removeRoom = function(roomId){
        var selectIndex = roomManage.getRoomIndex(roomId);
    if(selectIndex != -1){
        rooms.splice(selectIndex,1);
    }
};




/***************************************************************************
 Socket Manage
****************************************************************************/
 var socketManage = new Object();

/**
    @Description
    find socket index by socketId
     @Return
     index of Socket in sockets array
**/
 socketManage.getSocketIndex = function(socketId){
        var selectIndex = -1;
    for(var i=0;i<sockets.length;i++){
        var socket = sockets[i];
        if(socket.id == socketId){
            selectIndex = i;
            break;
        }
    }
    return selectIndex;
 };


/**
    @Description
    get socket by socketId
    @Return
    Socket or null if not found
**/
socketManage.getSocket = function(socketId){
    var selectIndex = socketManage.getSocketIndex(socketId);
    if(selectIndex != -1){
        return sockets[selectIndex];   
    }else{
        return null;   
    }
};

/**
    @Description
    remove socket by socketId
**/
 socketManage.removeSocket = function(socketId){
        var selectIndex = socketManage.getSocketIndex(socketId);
    if(selectIndex != -1){
        sockets.splice(selectIndex,1);
    }
};

//Emit a message to the client that we received a blank message from the php script. (Via POST)
function handleServerNotice(data){
        console.log("HTML Message Received: ", data);
}

//-------------------------- client -------------------//
// practical1/worker.js อันนี้สวยอยู่แล้วไม่ต้องบอกอะไร 55
importScripts('js/socket.io.js');
var socket;
var user;
var room;
var game;
self.onmessage = function (ev) {
   
      var data = ev.data;
    switch (data.cmd) {
       
  // connect
    case 'connect':
    {
       
        self.postMessage({'type': 'status', 'msg': 'Client Connect '});
        user = null;
        room = null;
        game = null;
       
        var url = data.msg;
        if(socket !=  undefined){
            socket.socket.connect();
        }else{
            socket = io.connect(url);
           
            socket.on('done', function () {
                self.postMessage({'type': 'status', 'msg': 'done!'});
              });
           
              socket.on('connect_failed', function () {
                self.postMessage({'type': 'status', 'msg': 'connect failed'});
              });
           
              socket.on('error', function () {
                self.postMessage({'type': 'status', 'msg': 'error'});
              });
             
       
              // listener registerUser send back from server
              socket.on('registerUser', function (data) {
                  user = JSON.parse(data);
                  self.postMessage({'type': 'registerUser', 'msg': data});
              });
             
              // listener disconnectUser send back from server
              socket.on('disconnectUser', function (data) {
                var user = JSON.parse(data);
                self.postMessage({'type': 'status', 'msg': 'disconnectUser '+user.name}); // send from worker to web page
              });
       
              // listener userList send back from server
              socket.on('userList', function (data) {
                self.postMessage({'type': 'userList', 'msg': data}); // send from worker to web page
              });
             
              socket.on('updateRoom', function (data) {
                  room = JSON.parse(data);
                  self.postMessage({'type': 'updateRoom', 'msg': data});
              });
             
              socket.on('createRoom', function (data) {
                  room = JSON.parse(data);
                  self.postMessage({'type': 'createRoom', 'msg': data});
              });
             
              socket.on('joinRoom', function (data) {
                  room = JSON.parse(data);
                  self.postMessage({'type': 'joinRoom', 'msg': data});
              });
             
              socket.on('leaveRoom', function (data) {
                  //user = JSON.parse(data);
                  room = null;
                  self.postMessage({'type': 'leaveRoom', 'msg': data});
              });
             
              socket.on('roomList', function (data) {
                self.postMessage({'type': 'roomList', 'msg': data}); // send from worker to web page
              });
             
              socket.on('userRoomList', function (data) {
                self.postMessage({'type': 'userRoomList', 'msg': data}); // send from worker to web page
              });
       
             
        }
        
   
     

    }
     
      break;
   
   
    // stop
    case 'disconnect':
        self.postMessage({'type': 'status', 'msg': 'Client Disconnect '});
      socket.disconnect();
     
      break;
   
    // send to Server
    case  'registerUser':
            socket.emit('registerUser',data.msg);
    break;
   
    case  'createRoom':
            socket.emit('createRoom',data.msg);
    break;
   
    case  'joinRoom':
            socket.emit('joinRoom',data.msg);
    break;
   
    case  'leaveRoom':
            socket.emit('leaveRoom',JSON.stringify(room));
    break;
   
   
   
    default:
      //self.postMessage('Unknown command: ' + data.msg);
  };

}


// practical1/client.php ผมใช้ jquery ด้วยนะครับ ใช้มี version ไหนอยู่ก็ใช้ได้เลยครับ
<!DOCTYPE HTML>
<html>
<head>
<title>NodeJS Practical1</title>
<script type="text/javascript" src="js/jquery_1.9.js"></script>
<script>
var worker = new Worker('worker.js');

worker.onmessage = function (event) {
    //alert(event.data);
    var data = event.data;
    switch (data.type) {
        case 'status' :
            document.getElementById('result').innerHTML = document.getElementById('result').innerHTML+data.msg+"\r\n";
            break;
        case 'data'  :
        ;
        break;
        case 'userList'  :
            var users = JSON.parse(data.msg);
            var response = '';
            for(var i=0;i<users.length;i++){
                var user = users[i];
                response += user.name+" ,socketId = " + user.socketId+"<br/>";
            }
            document.getElementById('response').innerHTML = response;
        break;

        case 'registerUser' :
        {
            var user = JSON.parse(data.msg);
            document.getElementById('displayName').innerHTML = user.socketId + ' - ' +user.name;

            // disable connectBtn   
            var connectBtn = document.getElementById('connectBtn');
            var disconnectBtn = document.getElementById('disconnectBtn');
       
            connectBtn.disabled = true;
            disconnectBtn.disabled = false;
           
            // go to room list step
            document.getElementById('connectSection').style.display = 'none';
            document.getElementById('roomSection').style.display = 'block';
           
            break;
        }
       
        case 'createRoom' :
        case 'joinRoom' :
        {
            var room = JSON.parse(data.msg);
            $('#roomWaitingSection .roomName').html(room.id +' - '+room.name);
            $('#roomWaitingSection .roomOwner').html(room.ownerId + ' - ' +room.ownerName);
           
            // go to room waiting step
            document.getElementById('roomSection').style.display = 'none';
            document.getElementById('roomWaitingSection').style.display = 'block';
           
            break;
        }
       
        case 'leaveRoom'  :
        {
            document.getElementById('roomSection').style.display = 'block';
            document.getElementById('roomWaitingSection').style.display = 'none';
            break;
        }
       
        case 'roomList'  :
        {
                var rooms = JSON.parse(data.msg);
                roomSection.updateRoomList(rooms);
            break;
        }
       
        case 'userRoomList'  :
        {
                var userRooms = JSON.parse(data.msg);
                roomSection.updateUserRoomList(userRooms);
            break;
        }
       
    };

};

var roomSection = new Object();

// Room List
roomSection.templateRow = function(row,rowItem){

    if(rowItem.id != undefined){
        row.find('.roomId').text(rowItem.id+".");
    }else{
        row.find('.roomId').text("");
    }
   
   
    if(rowItem.name != undefined){
        row.find('.roomName').text(rowItem.name);
    }else{
        row.find('.roomName').text("");
    }
   
    if(rowItem.ownerId != undefined){
        row.find('.roomOwner').text(rowItem.ownerId +" - " + rowItem.ownerName);
    }else{
        row.find('.roomOwner').text("");
    }
   
   
    row.find('.joinBtn').attr('onclick',"roomSection.joinRoom('"+rowItem.id+"');");
   
    row.addClass("table_row");
    return row;
};

roomSection.updateRoomList = function(rooms){
    var root = $('.roomList');
    root.find('.table_row').remove();
   
    for(var item = 0;item<rooms.length;item++ ){
        var newRow = root.find('.template_row').clone().removeClass('template_row');
        roomSection.templateRow(newRow,rooms[item]).appendTo(root).fadeIn();
    }
};

// User Room List
roomSection.templateUserRoomRow = function(row,rowItem){

    if(rowItem.socketId != undefined){
        row.find('.userId').text(rowItem.socketId+".");
    }else{
        row.find('.userId').text("");
    }
   
   
    if(rowItem.name != undefined){
        row.find('.userName').text(rowItem.name);
    }else{
        row.find('.userName').text("");
    }
   
    row.addClass("table_row");
    return row;
};


roomSection.updateUserRoomList = function(userRooms){
    var root = $('.userRoomList');
    root.find('.table_row').remove();
   
    for(var item = 0;item<userRooms.length;item++ ){
        var newRow = root.find('.template_row').clone().removeClass('template_row');
        roomSection.templateUserRoomRow(newRow,userRooms[item]).appendTo(root).fadeIn();
    }
};

roomSection.createRoom = function(){
   
    var roomName = document.getElementById('roomName').value;
    if(roomName == ''){
        alert("Please enter room name");
        return;
    }

    var room = new Object();
    room.name = roomName;
    worker.postMessage({'cmd': 'createRoom', 'msg': JSON.stringify(room)});
};

roomSection.joinRoom = function(roomId){
    var room = new Object();
    room.id = roomId;
    worker.postMessage({'cmd': 'joinRoom', 'msg': JSON.stringify(room)});
};

roomSection.leaveRoom = function(){
    worker.postMessage({'cmd': 'leaveRoom', 'msg': ''});
};


function connect(){
    var name = document.getElementById('name').value;
    if(name == ''){
        alert("Please enter  your name");
        return;
    }

    worker.postMessage({'cmd': 'connect', 'msg': '127.0.0.1:1333'}); // connect at 127.0.0.1:1333
   
    var user = new Object();
    user.name = name;
    worker.postMessage({'cmd': 'registerUser', 'msg': JSON.stringify(user)});

}

function disconnect(){
worker.postMessage({'cmd': 'disconnect', 'msg': ''});
    var connectBtn = document.getElementById('connectBtn');
    var disconnectBtn = document.getElementById('disconnectBtn');
   
    connectBtn.disabled = false;
    disconnectBtn.disabled = true;
}


</script>

</head>
<body>
<div style="height:200px;">
    <div style="float:left">
<p style="vertical-align:text-top">Server Status: <br/><textarea id="result"  cols="80" rows="8" ></textarea></p>
</div>
<div style="float:right;width:400px;border:1px solid;height:150px;overflow:scroll">
User in Server : <br/>
<span id="response"></span>
</div>
</div>

<br/><br/>
<div>

<div id="displayName" style="font-weight:bold;color:blue"></div>
<br/>

<div id="connectSection">
Name : <input type="text" id="name" name="name" /> <br/>
<input onClick="connect();" type="button" name="connectBtn" id="connectBtn" value="Connect" />
<input onClick="disconnect();" type="button" name="disconnectBtn" id="disconnectBtn" value="Disconnect" disabled="disabled"/>
</div>

<div id="roomSection" style="display:none;">
<div style="font-weight:bold;color:blue">Room List Page</div>
    <br/>
    New Room : <input type="text" id="roomName" name="roomName" />
<input onClick="roomSection.createRoom();" type="button" name="createRoom" id="createRoom" value="Create Room" />
<br/><br/>
    <table class="roomList" border="1" cellspacing="0">
        <tr style="font-weight:bold;">
            <td width="120" align="center">Room Id</td>
            <td width="150" align="center">Room Name</td>
            <td width="200" align="center">Room Owner</td>
            <td width="80">&nbsp;</td>
        </tr>
        <tr class="template_row" style="display:none">
            <td class="roomId" align="left">1234567890</td>
            <td class="roomName" align="left">Test</td>
            <td class="roomOwner" align="left">12345678 - tester</td>
            <td align="center"><input class="joinBtn" type="button" value="Join" style="width:60px;" /></td>
        </tr>
    </table>
</div>

<div id="roomWaitingSection" style="display:none;">
    <div style="font-weight:bold;color:blue">Room Waiting Page</div>
    <br/>
    Room Name : <span class="roomName"></span>
    <br/>
    Room Owner : <span class="roomOwner"></span>
    <br/><br/>
    User :
    <table class="userRoomList" border="1" cellspacing="0">
        <tr style="font-weight:bold;">
            <td width="120" align="center">User Id</td>
            <td width="150" align="center">User Name</td>
        </tr>
        <tr class="template_row" style="display:none">
            <td class="userId" align="left">1234567890</td>
            <td class="userName" align="left">Test</td>
        </tr>
    </table>
    <br/>
    <input type="button" value="Start Game" /> <input type="button" value="Leave Room" onClick="roomSection.leaveRoom();"/>
   
</div>

</div>
</body>
</html>
สุดท้ายมารันกันครับ
อย่าลืม socket.io.js และ socket.io.min.js เอามาใส่ในโฟลเดอร์ js ด้วยนะครับ เอามาจาก module client ของ node.js นะครับ
รัน server ด้วย node server.js
ใครรันได้แล้วรู้เรื่องมากขึ้นก็แจ้งมาได้นะครับ 555

วันจันทร์ที่ 12 พฤษภาคม พ.ศ. 2557

HTML5 : javascript enum

ถ้าพูดถึง enum หลายท่านอาจจะรู้จักดีอยู่แล้วในภาษาอื่นครับ

enum WeekDay = {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};

ผมยกตัวอย่างเป็นของ java ครับ

Enum หน้าที่หลักคือเป็น user define type คือ type ที่สร้างขึ้นมาเองเพื่อใช้ในการเปรียบเทียบต่างๆ ครับ

WeekDay today = WeekDay.MONDAY;

If(today == WeekDay.MONDAY){
  System.out.println(“Today is Monday”);
}else{
   System.out.println(“Today is Other day”);
}



ก็จะแสดงว่า Today is Monday นั่นเองครับ


-----------------------------------------------------------------------------------
Java Script Enum

โอเค หวังว่าคงจะคุ้นเคยกันมาบ้างแล้วนะครับ แล้วใน Javascript เราหละเขียนยังไงมาดูครับ

var SizeEnum = {
  SMALL: 1,
  MEDIUM: 2,
  LARGE: 3,
  properties: {
    1: {name: "small", value: 1, code: "S"},
    2: {name: "medium", value: 2, code: "M"},
    3: {name: "large", value: 3, code: "L"}
  }
};


ในการสร้าง enum แม้ว่าค่าที่เราเอามากำหนดให้จะสามารถใส่เป็น object ได้แต่ก็จะมีปัญหาในการ serialize แล้วทำให้ค่าเปลี่ยนไปได้ จึงควรที่จะใช้เป็น primitive type เช่นตัวเลข ครับ ส่วนใครที่อยากจะได้คำอธิบายเพิ่มเติมของค่านั้นๆ ก็สามารถใช้ properties มาช่วยในจุดนี้ได้ตามตัวอย่างข้างบนครับ

var mySize = SizeEnum.MEDIUM; // กำหนดให้ mySize เป็น SizeEnum.MEDIUM
var myCode = SizeEnum.properties[mySize].code; // ดึงค่า code ของ properties ค่า 2 ได้ myCode == "M"


ต่อไป มาพบกับพระเอกครับ หากไม่มีตัวนี้ enum เราจะไม่สมบูรณ์ นั่นก็คือการทำให้ enum เป็นค่าคงที่ ไม่สามารถแก้ไขได้นั่นเองครับ โอ้ของแบบนี้มีด้วยหรอ ต้องมีสิซาร่า

Object.freeze ใช้เพื่อทำให้ object ใดๆ ไม่สามารถเพิ่ม ลบ หรือแก้ไข property ได้ มันสุดยอดมาก

if (Object.freeze)
  Object.freeze(SizeEnum);


ใช้ง่ายๆ ครับ if(Object.freeze) เพื่อตรวจสอบว่า browser เราสามารถใช้ได้รึเปล่า หากใช้ได้ก็ freeze เลย หาก freeze แล้วเมื่อเราแก้ไขค่าจะพบว่าไม่มีฟ้อง error ใดๆ ทั้งสิ้นแต่ค่าจะไม่สามารถแก้ไขได้ครับ

ตัวอย่างโค้ดไปลองรันเล่นดูครับ
// enum_test.php
<!DOCTYPE html>
<head>
    <meta charset="utf-8" />
    <title>Javascript Enumeration</title>

</head>
<body>
<script type="text/javascript">
    var SizeEnum = {
  SMALL: 1,
  MEDIUM: 2,
  LARGE: 3,
  properties: {
    1: {name: "small", value: 1, code: "S"},
    2: {name: "medium", value: 2, code: "M"},
    3: {name: "large", value: 3, code: "L"}
  }
};

// freeze data
if (Object.freeze)
  Object.freeze(SizeEnum);



var mySize = SizeEnum.MEDIUM;
var myCode = SizeEnum.properties[mySize].code;

document.write("var mySize = SizeEnum.MEDIUM;");
document.write("<br/>var myCode = SizeEnum.properties[mySize].code; ");

document.write("<br/><br/>");

document.write("mySize = " + mySize);
document.write("<br/>myCode = " + myCode);

document.write("<br/>mySize == SizeEnum.MEDIUM  -> " + (mySize == SizeEnum.MEDIUM));
document.write("<br/>mySize == SizeEnum.SMALL  -> " + (mySize == SizeEnum.SMALL));

</script>

</body>
</html>


อ้างอิงเนื้อหา http://stijndewitt.wordpress.com/2014/01/26/enums-in-javascript/
อ้างอิงเนื้อหา  http://kangax.github.io/compat-table/es5/


วันอังคารที่ 6 พฤษภาคม พ.ศ. 2557

HTML5 : node.js and WebSocket - Part 3 Socket ID and maintain socket state

บทนี้จะมาพูดถึงคุณลักษณะของการจัดการ client socket ที่มาติดต่อนะครับ

1 หน้าบราวเซอร์ = 1 socket นะครับ เช่นใช้ chrome เปิดขึ้นมา 2 หน้า ทั้งสองหน้าก็จะเป็นคนละ socket กันครับ ซึ่งการอ้างถึงแต่ละหน้าว่าจะอ้างอิงด้วยอะไรดี ซึ่งนั่นก็คือประเด็นของวันนี้ครับ socket.id นั่นเอง
socket.id เป็น id ที่จะ unique คือไม่ซ้ำกันเลยเราสามารถใช้ในการอ้างอิงเพื่อส่งข้อมูลกลับ หรือสั่งให้ disconnect ได้ครับ

maintain socket state
มาดูว่าเจ้า server เราใช้วิธีการไหนในการเช็คว่า socket ตัวไหน alive หรือใช้งานอยู่ ตัวไหนปิดหน้าเว็บไปแล้วครับ ซึ่งเราเรียกว่า heartbeat packet ครับ จังหวะหัวใจ 555 เป็นบี้เดอะสตาร์แล้ว ซึ่งจะมีการ request ไปกา client socket ทุกๆ ช่วงเวลา แล้วถ้าไม่มี packet ตอบกลับก็จะเข้าสู่สถานะ disconnect ทันทีครับ

โอเค มาดูการทำงานของ heartbeat packet กันครับ



Alive Condition -> ที่ผมครอบสีเขียวครับ เป็น heartbeat ที่ได้รับการตอบกลับจาก client
set heartbeat time out for client 855pstHg3R8L9RKC01EQ (socket id)
got heartbeat packet
แสดงว่าได้รับกลับมาครับ

Disconnect Condition -> สีแดงเป็นสถานะของการ disconnect การ heartbeat packet ครับ ซึ่งจะเกิดขึ้นเมื่อปิดหน้า page ที่ connect socket อยู่ครับ ซึ่งถ้า server ส่งไปแล้วไม่ได้รับตอบกลับก็จะเข้าสถานะ disconnect ทันทีครับ
set heartbeat interval for client 855pstHg3R8L9RKC01EQ (socket id)
transport end
set close timeout for client 855pstHg3R8L9RKC01EQ
cleared close timeout for client
cleared heartbeat interval for client 855pstHg3R8L9RKC01EQ

------------------------------------------------------------------------------------
จบ section ของเนื้อหา มาเริ่มโค้ดกันดีกว่าครับ เด๋วเข้าใจเองครับ
 

วันนี้เราจะมาเล่นกันเรื่อง connect กับ Disconnect กันครับ

มาดูฝั่ง server.js ของเรากัน
var sockets = new Array();
var users = new Array();
เราจะสร้าง sockets ไว้สำหรับเก็บ socket ที่ client connect เข้ามาครับ
ส่วน users สำหรับเก็บข้อมูล user คู่กับ socketId ที่ user คนนั้นใช้
socket.on('disconnect', function(data)
เป็น event ที่จะเข้าเมื่อเกิดการ Disconnect ทั้งจาก heartbeat packet และการส่ง disconnect packet มาจาก client ซึ่งเราจะดักแล้ว remove user ออกจาก array ที่เราใส่ไว้ครับ

ส่วนจัดการข้อมูล ผมใช้ javascript Object ที่ชื่อว่า userManage ครับใช้สำหรับการจัดการกับ user ใน server และ socketManage ใช้จัดการกับข้อมูล socket ที่ติดต่อเข้ามาซึ่งเราจะใช้ socketId ในการอ้างอิงนะครับ
var userManage = new Object();
userManage.getUserIndex = function(socketId) // get array index from socketId
userManage.getUser = function(socketId) // get user object from array by socketId
userManage.removeUser = function(socketId) // remove user object from array by socketId


var socketManage = new Object();
socketManage.getSocketIndex = function(socketId) // get array index from socketId
socketManage.getSocket = function(socketId) // get socket object from array by socketId
socketManage.removeSocket = function(socketId) // remove socket object from array by socketId

ฝั่ง client worker.js ครับ
socket = io.connect(url); // ใช้สำหรับการ connect ครั้งแรก
socket.socket.connect(); // ใช้สำหรับ connect อีกครั้งหลังจาก disconnect ไปแล้วซึ่งจะได้ socketId ใหม่
socket.disconnect(); // ใช้สำหรับส่ง disconnect packet ไปยัง server เพื่อ disconnect

------------------------------------------------------------------
ตัวอย่างโค้ดวันนี้ครับ
//----------- Server Side ---------------//
// part3/server.js

var http = require('http');
var formidable = require("formidable");
var socketio = require('socket.io');
var server = http.createServer(function(req, res) {
        form = new formidable.IncomingForm();
        form.parse(req, function(e, fields, files){
                res.writeHead(200, [['Content-type','text/plain'],['Content-Length',0]]);
                res.write('');
                res.end();
                //Handle sending data back through the socket to the web client
                handleServerNotice(fields);
        });
}).listen(1333, function() {
        console.log('listening on 1333');
});


var sockets = new Array();
var users = new Array();

function registerUser(socketId,name){
    var user = new Object();
    user.socketId = socketId;
    user.name = name;
    users.push(user);
   
    //var socket = socketManage.getSocket(socketId);
    //socket.emit("registerUser",JSON.stringify(user));
    for(var i=0;i<users.length;i++){
        var queryuser = users[i];
        var socket = socketManage.getSocket(queryuser.socketId);
        if(socket != null){
            socket.emit("registerUser",JSON.stringify(user));
        }
    }
   
   
    userList();
}

function disconnectUser(socketId){
     var user = userManage.getUser(socketId);
    console.log('disconnectUser = ' + JSON.stringify(user));
    for(var i=0;i<users.length;i++){
        var queryuser = users[i];
        var socket = socketManage.getSocket(queryuser.socketId);
        if(socket != null){
            socket.emit("disconnectUser",JSON.stringify(user));
        }
    }
   
    userManage.removeUser(socketId);
    socketManage.removeSocket(socketId);
    userList();
}

function userList(){
    for(var i=0;i<users.length;i++){
        var user = users[i];
        var socket = socketManage.getSocket(user.socketId);
        if(socket != null){
            socket.emit("userList",JSON.stringify(users));
        }
    }
}

socketio.listen(server).on('connection', function(socket){
        sockets.push(socket);
       
        socket.on('registerUser', function (data) {
            console.log(socket.id + " registerUser = " + data);
            var user = JSON.parse(data);
            registerUser(socket.id,user.name);
        });
       
        socket.on('userList', function (data) {
            userList();
        });
       

        socket.on('disconnect', function(data){
            console.log('disconnect socket id', socket.id);
            disconnectUser(socket.id);
            //socketManage.removeSocket(socket.id);
        });


});

/***************************************************************************
 User Manage
****************************************************************************/
 var userManage = new Object();

/**
    @Description
    find socket index by socketId
     @Return
     index of Socket in sockets array
**/
 userManage.getUserIndex = function(socketId){
        var selectIndex = -1;
    for(var i=0;i<users.length;i++){
        var user= users[i];
        if(user.socketId == socketId){
            selectIndex = i;
            break;
        }
    }
    return selectIndex;
 };


/**
    @Description
    get socket by socketId
    @Return
    Socket or null if not found
**/
userManage.getUser = function(socketId){
    var selectIndex = userManage.getUserIndex(socketId);
    if(selectIndex != -1){
        return users[selectIndex];   
    }else{
        return null;   
    }
};

/**
    @Description
    remove socket by socketId
**/
 userManage.removeUser = function(socketId){
        var selectIndex = userManage.getUserIndex(socketId);
    if(selectIndex != -1){
        users.splice(selectIndex,1);
    }
};




/***************************************************************************
 Socket Manage
****************************************************************************/
 var socketManage = new Object();

/**
    @Description
    find socket index by socketId
     @Return
     index of Socket in sockets array
**/
 socketManage.getSocketIndex = function(socketId){
        var selectIndex = -1;
    for(var i=0;i<sockets.length;i++){
        var socket = sockets[i];
        if(socket.id == socketId){
            selectIndex = i;
            break;
        }
    }
    return selectIndex;
 };


/**
    @Description
    get socket by socketId
    @Return
    Socket or null if not found
**/
socketManage.getSocket = function(socketId){
    var selectIndex = socketManage.getSocketIndex(socketId);
    if(selectIndex != -1){
        return sockets[selectIndex];   
    }else{
        return null;   
    }
};

/**
    @Description
    remove socket by socketId
**/
 socketManage.removeSocket = function(socketId){
        var selectIndex = socketManage.getSocketIndex(socketId);
    if(selectIndex != -1){
        sockets.splice(selectIndex,1);
    }
};

//Emit a message to the client that we received a blank message from the php script. (Via POST)
function handleServerNotice(data){
        console.log("HTML Message Received: ", data);
}

// end  part3/server.js

//----------- Client Side ---------------//
อย่าลืมเอา socket.io.js ที่เป็น client script มาใส่ใน project ด้วยนะครับ

//----------------  part3/worker.js

importScripts('js/socket.io.js');
var socket;
self.onmessage = function (ev) {
   
      var data = ev.data;
    switch (data.cmd) {
       
  // connect
    case 'connect':
    {
       
        self.postMessage({'type': 'status', 'msg': 'Client Connect '});
       
        var url = data.msg;
        if(socket !=  undefined){
            socket.socket.connect();
        }else{
            socket = io.connect(url);
           
            socket.on('done', function () {
                self.postMessage({'type': 'status', 'msg': 'done!'});
              });
           
              socket.on('connect_failed', function () {
                self.postMessage({'type': 'status', 'msg': 'connect failed'});
              });
           
              socket.on('error', function () {
                self.postMessage({'type': 'status', 'msg': 'error'});
              });
             
       
              // listener registerUser send back from server
              socket.on('registerUser', function (data) {
                var user = JSON.parse(data);
                self.postMessage({'type': 'status', 'msg': 'registerUser '+user.name}); // send from worker to web page
              });
       
              // listener disconnectUser send back from server
              socket.on('disconnectUser', function (data) {
                var user = JSON.parse(data);
                self.postMessage({'type': 'status', 'msg': 'disconnectUser '+user.name}); // send from worker to web page
              });
       
              // listener userList send back from server
              socket.on('userList', function (data) {
                self.postMessage({'type': 'userList', 'msg': data}); // send from worker to web page
              });
        }
        
   
     

    }
     
      break;
   
   
    // stop
    case 'disconnect':
        self.postMessage({'type': 'status', 'msg': 'Client Disconnect '});
      socket.disconnect();
     
      break;
   
    // send to Server
    case  'registerUser':
            socket.emit('registerUser',data.msg);
    break;
   
   
   
    default:
      //self.postMessage('Unknown command: ' + data.msg);
  };

}

// end worker.js

//----------------  part3/client.php
<!DOCTYPE HTML>
<html>
<head>
<title>NodeJS Part 3</title>

<script>
var worker = new Worker('worker.js');

worker.onmessage = function (event) {
    //alert(event.data);
    var data = event.data;
    switch (data.type) {
        case 'status' :
            document.getElementById('result').innerHTML = document.getElementById('result').innerHTML+data.msg+"\r\n";
            break;
        case 'data'  :
        ;
        break;
        case 'userList'  :
            var users = JSON.parse(data.msg);
            var response = '';
            for(var i=0;i<users.length;i++){
                var user = users[i];
                response += user.name+" ,socketId = " + user.socketId+"<br/>";
            }
            document.getElementById('response').innerHTML = response;
        break;

       

    };


};


function connect(){
    var name = document.getElementById('name').value;
    if(name == ''){
        alert("Please enter  your name");
        return;
    }

    worker.postMessage({'cmd': 'connect', 'msg': '127.0.0.1:1333'}); // connect at 127.0.0.1:1333
   
    var user = new Object();
    user.name = name;
    worker.postMessage({'cmd': 'registerUser', 'msg': JSON.stringify(user)});

    var connectBtn = document.getElementById('connectBtn');
    var disconnectBtn = document.getElementById('disconnectBtn');

    connectBtn.disabled = true;
    disconnectBtn.disabled = false;
}

function disconnect(){
worker.postMessage({'cmd': 'disconnect', 'msg': ''});
    var connectBtn = document.getElementById('connectBtn');
    var disconnectBtn = document.getElementById('disconnectBtn');
   
    connectBtn.disabled = false;
    disconnectBtn.disabled = true;
}

</script>

</head>
<body>
<p style="vertical-align:text-top">Server Status: <br/><textarea id="result"  cols="80" rows="8" ></textarea></p>

<!--
<input onclick="connect()" type="button" value="Connect" /> <input onClick="disconnect();" type="button" value="Disconnect" />
-->
<br/><br/>
Name : <input type="text" id="name" name="name" /> <br/>
<input onClick="connect();" type="button" name="connectBtn" id="connectBtn" value="Connect" />
<input onClick="disconnect();" type="button" name="disconnectBtn" id="disconnectBtn" value="Disconnect" disabled="disabled"/>

<br/>
<br/>
User in Server : <br/>
<span id="response"></span>
<br/>
<br/>

</body>
</html>

//------------------- Running -----------------//
อย่าลืมเปิด server ด้วยคำสั่ง node server.js นะครับ

วันพุธที่ 30 เมษายน พ.ศ. 2557

HTML5 : node.js and WebSocket - Part 2 socket.io and sayHello


Socket.io เป็น module ที่ช่วยในการทำ WebSocket ซึ่งเป็น tcp อ้างเชื่อมต่อจะต้องมี weburl และ port
ซึ่งใน module ก็มีทั้งฝั่ง client และ server

ส่วน server จะผูกกับ node.js ที่เราได้ตั้ง path ไว้เรียบร้อยแล้วใน part1 ซึ่งสามารถเรียกใช้ได้ทันที

ส่วน client เราต้องนำ javascript ไฟล์ที่อยู่ใน module ถ้าเครื่องผมจะอยู่ที่ E:\Program Files\nodejs\node_modules\npm\node_modules\socket.io\node_modules\socket.io-client\dist

ซึ่งมีอยู่ 2 ไฟล์ socket.io.js และ socket.io.min.js ซึ่งสามารถเลือกเอาไปใช้ได้ครับ .min แค่บีบอัดแล้วครับทำให้ไฟล์เล็กลง

ใน โฟลเดอร์ socket.io-client มีโฟลเดอร์ test ให้ด้วยนะครับเป็นตัวอย่างโค้ดให้เรานำเอาไปประยุกต์ต่อได้ครับ

เข้าเนื้อหาวันนี้กัน
- main entrance ของ client ครับ ใครติดต่อเข้ามาก็จะเข้ามาที่นี่ก่อนเลย ซึ่ง socket ที่ได้มาคือ clent socket ไว้สำหรับใช้ในการอ้างอิงเพื่อส่งข้อมูลกลับไปหา client ได้ครับ

socketio.listen(server).on('connection', function(socket){
   
}


ในการรับส่งข้อมูลเราจะใช้ผ่าน object ของ socket ครับ ซึ่งมี 2 method หลักๆ

- socket.on เป็น listener method สำหรับรอรับข้อมูลที่ส่งมาจาก client ซึ่งรับชื่อสำหรับการติดต่อ ตามตัวอย่างคือ sayHello และ ข้อมูลที่ได้รับมา

ตัวอย่าง
socket.on('sayHello', function (data) {
    console.log("sayHello = " + data);
    socket.emit("sayHello","Hello " + data); // send back to client
});


- socket.emit ใช้สำหรับส่งค่าไปยัง listener ที่เราสร้างไว้  ซึ่งใช้ทั้ง client และ server เหมือนกัน
ตัวอย่าง

socket.emit("sayHello","Piti"); // client ส่งค่า Piti ไปยัง on("sayHello") ที่ได้สร้างไว้

- socket.broadcast.emit ใช้ในการส่งหาทุก socket ยกเว้น socket ของคนส่งครับ ถ้าอยากส่งให้คนส่งด้วยก็ต้อง socket.emit ของตัวเองเพิ่มอีกหนึ่งอันครับ

--------------------------------------------------------------------------------------

มาภาคปฏิบัติครับ

//----------- Server Side ---------------//

// part2/server.js
var http = require('http');
var formidable = require("formidable");
var socketio = require('socket.io');
var server = http.createServer(function(req, res) {
        form = new formidable.IncomingForm();
        form.parse(req, function(e, fields, files){
                res.writeHead(200, [['Content-type','text/plain'],['Content-Length',0]]);
                res.write('');
                res.end();
                //Handle sending data back through the socket to the web client
                handleServerNotice(fields);
        });
}).listen(1333, function() {
        console.log('listening on 1333');
});


var sockets = new Array();

socketio.listen(server).on('connection', function(socket){
        sockets.push(socket);
       
        socket.on('sayHello', function (data) {
            console.log("sayHello = " + data);
            socket.emit("sayHello","Hello " + data); // send back to client
        });
       
        socket.on('sayGoodBye', function (data) {
            console.log("sayGoodBye = " + data);
            socket.emit("sayGoodBye","GoodBye " + data); // send back to client
        });
       
        socket.on('sayToAll', function (msg) {
                console.log('message received', msg);
               
                // send back to all client
                socket.broadcast.emit('sayToAll', msg);
                socket.emit('sayToAll', msg);
        });
});

//Emit a message to the client that we received a blank message from the php script. (Via POST)
function handleServerNotice(data){
        console.log("HTML Message Received: ", data);
}
// end  part2/server.js


//----------- Client Side ---------------//
อย่าลืมเอา socket.io.js ที่เป็น client script มาใส่ใน project ด้วยนะครับ
ผมใช้ WebWorker มาใช้นะครับ เผื่อจะใช้ร่วมกันหลายหน้า จะได้เปลี่ยนเป็น shared worker ได้ทันทีครับ


//----------------  part2/worker.js
importScripts('js/socket.io.js');
var socket;
self.onmessage = function (ev) {
   
      var data = ev.data;
    switch (data.cmd) {
       
  // connect
    case 'connect':
    {
        //self.postMessage("Client Connect ");
        self.postMessage({'type': 'status', 'msg': 'Client Connect '});
       
        var url = data.msg;
         socket = io.connect(url);
   
      socket.on('done', function () {
        self.postMessage({'type': 'status', 'msg': 'done!'});
      });
   
      socket.on('connect_failed', function () {
        self.postMessage({'type': 'status', 'msg': 'connect failed'});
      });
   
      socket.on('error', function () {
        self.postMessage({'type': 'status', 'msg': 'error'});
      });
     

      // listener sayHello send back from server
      socket.on('sayHello', function (data) {
        self.postMessage({'type': 'sayHello', 'msg': data}); // send from worker to web page
      });

      // listener sayGoodBye send back from server
      socket.on('sayGoodBye', function (data) {
        self.postMessage({'type': 'sayGoodBye', 'msg': data}); // send from worker to web page
      });

      // listener sayToAll send back from server
      socket.on('sayToAll', function (data) {
        self.postMessage({'type': 'sayToAll', 'msg': data}); // send from worker to web page
      });

    }
     
      break;
   
   
    // stop
    case 'disconnect':
        self.postMessage({'type': 'status', 'msg': 'Client Disconnect '});
      socket.disconnect();
     
      break;
   
    // send to Server
    case  'sayHello':
            socket.emit('sayHello',data.msg);
    break;
   
    // send to Server
    case  'sayGoodBye':
            socket.emit('sayGoodBye',data.msg);
    break;

    // send to Server
    case  'sayToAll':
            socket.emit('sayToAll',data.msg);
    break;
   
   
    default:
      //self.postMessage('Unknown command: ' + data.msg);
  };

}
// end worker.js

//----------------  part2/client.php
<!DOCTYPE HTML>
<html>
<head>
<title>NodeJS Part 2</title>

<script>
var worker = new Worker('worker.js');

worker.onmessage = function (event) {
    //alert(event.data);
    var data = event.data;
    switch (data.type) {
        case 'status' :
            document.getElementById('result').innerHTML = document.getElementById('result').innerHTML+data.msg+"<br/>";
            break;
        case 'data'  :
        ;
        break;
        case 'sayHello'  :
            document.getElementById('response').innerHTML = data.msg;
        break;

        case 'sayGoodBye'  :
            document.getElementById('response').innerHTML = data.msg;
        break;

        case 'sayToAll'  :
            document.getElementById('responseBroadcast').innerHTML = document.getElementById('responseBroadcast').innerHTML + data.msg +"<br/>";
        break;

    };


};

function sayHello(){
    var name = document.getElementById('name').value;
    var user = new Object();
    user.name = name;
    worker.postMessage({'cmd': 'sayHello', 'msg': JSON.stringify(user)});
}

function sayGoodBye(){
    var name = document.getElementById('name').value;
    var user = new Object();
    user.name = name;
    worker.postMessage({'cmd': 'sayGoodBye', 'msg': JSON.stringify(user)});
}

function sayToAll(){
    var name = document.getElementById('name').value;
    worker.postMessage({'cmd': 'sayToAll', 'msg': name});
}


function connect(){
worker.postMessage({'cmd': 'connect', 'msg': '127.0.0.1:1333'}); // connect at 127.0.0.1:1333
}

function disconnect(){
worker.postMessage({'cmd': 'disconnect', 'msg': ''});
}


// connect server at start up
connect();
</script>

</head>
<body>
<p>Status: <span id="result" /></p>

<!--
<input onclick="connect()" type="button" value="Connect" /> <input onClick="disconnect();" type="button" value="Disconnect" />
-->
<br/><br/>
Name : <input type="text" id="name" name="name" /> <br/>
<input onClick="sayHello();" type="button" value="Say Hello"/> <input onClick="sayGoodBye();" type="button" value="Say GoodBye"/> <input onClick="sayToAll();" type="button" value="Say To All"/>

<br/>
<br/>
Response : <br/>
<span id="response"></span>
<br/>
<br/>

Response Broadcast : <br/>
<span id="responseBroadcast"></span>
</body>
</html>
// end client.php



//------------------- Running -----------------//
อย่าลืมเปิด server ด้วยคำสั่ง node server.js นะครับ




อ้างอิง http://socket.io/

วันอังคารที่ 29 เมษายน พ.ศ. 2557

HTML5 : node.js and WebSocket - Part 1 Installation and setup


node.js คือ โปรแกรมที่รันบน server-side แต่เขียนด้วย javascript ซึ่งถูกรันด้วย Java Script Engine ของ Google
ความสามารถเบื้องต้น
สามารถตั้งตนเป็น HTTP Server และเปิด Socket ได้ แต่จริงๆ ยังมีอีกหลายอย่างนะครับ ขอ scope แค่นี้ก่อน

ซึ่งผมจะเน้นในการเปิด Socket เพื่อใช้ทำ WebSocket ตาม standard ของ HTML5 เป็นหลักครับ
Mission Start

Mission 1 -> Install node.js
http://nodejs.org/
ผมใช้ node-v0.10.26-x64.msi เป็นตัวติดตั้งครับ (เครื่องผมเป็น Window)
จากนั้นก็ install จนเสร็จ
มาดูโครงสร้างกัน
 

ใน nodejs มี

- npm.cmd เป็นพระเอกในการจัดการ module ต่างๆ ผมเดาว่าย่อมาจาก node package manager ผมคิดเองนะครับ 555 ตัวอย่างคำสั่ง npm install socket.io

- node.exe ใช้ในการรัน script ที่เราเขียนไว้นะครับ เช่น node server.js

- โฟลเดอร์ node_modules สังเกตว่าจะมีสองที่ครับคืออยู่ที่ root แล้วอยู่ใน npm อีกที ส่วนตัวผมเวลา install module ใหม่ ผมจะลงไปใน node_modules ของ npm เลยครับ จะได้อ้างที่เดียว เห็นมี module อื่นอยู่เยอะดีครับ

Mission 2 -> setup environment
สร้าง environment variable ชื่อ NODE_PATH ให้มีค่า
E:\Program Files\nodejs\node_modules\npm\node_modules นี่เครื่องผมครับ ใครลงตรงไหนก็ปรับไปละกันครับ ซึ่ง NODE_PATH

ตัว node.js จะใช้ในการอ้างไปยัง module ที่เราจะเรียกใช้ครับ ดังนั้นหากเราใส่ module เข้าไปที่โฟลเดอร์นี้ เราก็จะสามารถอ้างถึง module ที่ลงใหม่ได้ทันทีครับ



Mission 3 -> มาลง module ที่จำเป็นกันเถอะครับ
module ของ node.js มีเยอะแยะครับ ต่อ database ต่อ websocket และ utility ต่างๆ ครับ ที่เราจะใช้งานคือ socket.io และ formidable

เข้า command line ครับ จากนั้น ไปที่ E:\Program Files\nodejs\node_modules\npm
- รัน npm install socket.io
- รัน npm install formidable

ปล. ลงแล้วไปเช็คใน node_modules ว่ามี socket.io เพิ่มมารึเปล่านะครับ ถ้ามีก็โอเคครับ ถ้าลงผิดที่ก็ลบ socket.io ตัวที่ผิดแล้วรันใหม่ได้เลยครับ เป็นการการ download script มาไว้ในเครื่องเฉยๆ ไม่ต้องหา uninstall ครับ


ใครอยากรู้ว่ามีคำสั่งอะไรบ้างลอง npm help ได้นะครับ


Last Mission -> test
มาสร้างไฟล์ทดสอบกันครับ

// hello_world.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1333, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1333/');

โอเค นี่คือการทำ Hello World แบบฉบับ node.js ครับ รันด้วย node hello_world.js
จากนั้นเปิด browser ครับแล้วพิมพ์ http://127.0.0.1:1333/ คุณก็ได้จะได้ Hello World ดังใจ



Trick
ในการรันเราสามารถสร้าง .bat มาใช้ได้ครับเพื่อสะดวกในการรัน

// hello_world.bat ไว้ที่เดียวกับ hello_world.js ครับ
node hello_world.js

เวลารันก็แค่คลิก hello_world.bat ก็เรียบร้อย

วันพฤหัสบดีที่ 25 เมษายน พ.ศ. 2556

HTML5 :Notification API

วันนี้มีลูกเล่นที่น่าสนใจมานำเสนออีกแล้วครับ อ่านจากชื่อตอนแล้วใครนึกออกบ้างเอ่ย

พูดถึง Notification ทุกคนน่าจะนึกถึง facebook หรือ window live messenger ใช่ครับเราจะทำประมาณนั้น

Notication API หรือชื่อเต็มคือ Web Notification API เป็น API ที่ทำให้เราสามารถสร้าง notification ไว้เด้งขึ้นมาบนเดสก์ท็อปของผู้ใช้ได้นั่นเอง เหมือน window live messenger เลยเชียวหละ ซึ่งประโยชน์เช่นคอยแสดงราคาทองทุกครั้งเมื่อมีการเปลี่ยนแปลง ช่วงนี้ยิ่งฮ็อตๆ อยู่ครับ

วันนี้จะมาเสนอ Notification API ของ WebKit ครับ ซึ่งรันได้บน chrome นั่นเอง ซึ่งมี 2 อินเทอร์เฟซ สำหรับใช้งาน

1. NotificationCenter ซึ่งใช้ในการร้องขอ permission ในการใช้งาน Notification API , คงสถานะของการอนุญาตและสร้าง Notification ซึ่งมี method ให้ใช้งานดังนี้

 - Notification createNotification(in DOMString iconUrl, in DOMString title, in DOMString body) ใช้ในการสร้าง notification โดยระบุ icon , title และ body ครับ

 - Notification createHTMLNotification(in DOMString url) ใช้ในการสร้าง Notification แบบหน้า HTML ครับ คือโยน url ของหน้าที่ต้องการใช้เป็น notification ลงไปเลยนั่นเอง

 - Int checkPermission(); ใช้สำหรับเรียกดูระดับการใช้งานว่าอนุญาตรึเปล่า

 - void requestPermission([in Fuction callback]) ใช้สำหรับขอคำยินยอมในการใช้ Notification API ครับ

Demo
    window.webkitNotifications.createNotification(‘icon.png’,’My Title’,’My Notification’);

2. Notification คือตัว notification ที่เราสามารถนำมาแสดงได้เลยผ่านเมธอดตามด้านล่างครับ

 - show() ใช้สำหรับแสดง notification บนเดสก์ท็อปของผู้ใช้
 - cancel() ใช้ในการลบ notification ออกจากเดสก์ท็อปหรอคิว

ต่อไปเป็น event ที่เราสามารถเล่นได้ครับ

 - ondisplay : ตอนแสดงบนเดสก์ท็อป
 - onclose : ตอนปิด notification ทั้งจากคลิกปิดเอง และจาก cancel()
 - onerror : เมื่อเกิดข้อผิดพลาด

มาเล่นกันดีกว่าโค้ดอยู่ด้านล่างครับ รันใน chrome ได้เท่านั้นครับ

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>Notification API</title>

    <script type="text/javascript">
        var notificationCount = 0;

        function setPermission(){

            if(webkitNotifications){
                window.webkitNotifications.requestPermission();
            }else{
                alert("Not Support Nofication API");
            }
        }

        function fireNotification(){
            notificationCount++;

            var notification = webkitNotifications.createNotification(null,'Number : '+notificationCount, 'This is Notification '+notificationCount);

            notification.show();
        }
    </script>
</head>
<body>
    <p>Click set permission to allow notifications, then fire a notification</p>
    <section>
        <button id="setPermission" onclick="setPermission();">Set Permission</button>
        <button id="fireNotification" onclick="fireNotification();">Fire Notification</button>
    </section>
</body>
</html>

ผลลัพธ์


ความรู้จาก HTML5 Developer's Cookbook ครับผม