IM 即时聊天-服务端代码 Nodejs

/*============自定义对象===========*/

/* 
*  方法:Array.remove(dx) 通过遍历,重构数组 
*  功能:删除数组元素. 
*  参数:dx删除元素的下标. 
*/ 
Array.prototype.remove=function(dx) 

    if(isNaN(dx)||dx>this.length){return false;} 
    for(var i=0,n=0;i<this.length;i++) 
    { 
        if(this[i]!=this[dx]) 
        { 
            this[n++]=this[i] 
        } 
    } 
    this.length-=1 

/*寻找元素在数组中的位置*/
Array.prototype.indexOf = function (obj) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == obj) {
            return i;
        }
    }
    return -1;
}

//生成GUID,加上时间
function newGuid()
{
    var guid = "";
    for (var i = 1; i <= 32; i++){
      var n = Math.floor(Math.random()*16.0).toString(16);
      guid +=   n;
      if((i==8)||(i==12)||(i==16)||(i==20))
        guid += "-";
    }
    guid+="_"+new Date().getTime();
    return guid;    
}

//声明消息对象
function SfjWsMsg(key,value){
    this.key=key;
    this.value=value;
    this.loginguid=null; //当前登录标识
    this.identifyid=null;//每条消息唯一标识
    this.state=null;//消息状态
}

/*============缓存管理===========*/
function HisMsgCache(){
    this.msgcache=new Array();
    
    //添加消息到缓存,
    //hidelog notnull-不显示 null-显示(默认值)
    this.addMsgToCache = function(userId,msg,hidelog){
        if (!this.msgcache[userId]){
            this.msgcache[userId]=new Array();            
        }
        var msglist=this.msgcache[userId];
        if (!hidelog){
            console.log('User['+userId+'] addMsgToCache:'+msg);
        }
        msglist.push(msg);        
    }
    //移除消息从缓存中
    this.delMsgFromCache=function(userId,msg){
        var msglist=this.msgcache[userId];
        var index=msglist.indexOf(msg);
        msglist.remove(index);
    }
    
    //返回用户对应消息列表
    this.getMsgListFromCache=function(userId){
        if (!this.msgcache[userId]){
            this.msgcache[userId]=new Array();            
        }
        var msglist=this.msgcache[userId];
        return msglist;
    }
    
    //转换消息缓存中的waitback消息转换为nosend消息
    this.transWaitBackToNoSend=function(userId){
        if (!this.msgcache[userId]){
            this.msgcache[userId]=new Array();            
        }        
        var msglist=this.msgcache[userId];
        for(var i=msglist.length-1;i>=0;i--){
            var msg=msglist[i];
            var m=JSON.parse(msg)[0];
            if (m.state===MSGSTATE_WAITBACK){
                m.state=MSGSTATE_NOSEND;
                msglist[i]='['+JSON.stringify(m)+']';
                console.log('user['+userId+'] transWaitBackToNoSend:'+msglist[i]);
            }
        }
    }
}

//消息缓存对象
var cache=new HisMsgCache();
//消息状态枚举值
var MSGSTATE_NOSEND="nosend"; //历史未发送消息
var MSGSTATE_WAITBACK="waitback"; //已发送未收到返回


/*============express管理===========*/


var app = require('express')(); 
app.get('/', function(req, res){ 
    res.send('<h1>Welcome Realtime Server</h1>'); 
}); 


//在线用户列表
var onLineUsers={};


/*============Redis管理===========*/

//读取redis配置文件
var fs= require('fs');
var path = require('path');
//redis 链接
var redis = require('redis');
var pub;//发布消息
var store,store_a;//存储消息
var param;

//给消息增加唯一标识
function addMsgIdentID(msg){
    var m=JSON.parse(msg)[0];
    m.identifyid=newGuid();
    var msg1='['+JSON.stringify(m)+']';
    return msg1;
}

//给消息增加登录标识
function addMsgLoginGuid(msg,loginguid){
    var m=JSON.parse(msg)[0];
    m.loginguid=loginguid;
    var msg1='['+JSON.stringify(m)+']';
    return msg1;    
}

//给消息增加状态标识
function addMsgState(msg,state){
    var m=JSON.parse(msg)[0];
    m.state=state;
    var msg1='['+JSON.stringify(m)+']';
    return msg1;    
}


//发送历史/当前消息
//his notnull-历史消息 null-当前消息
function sendMsg(userId,msg,his){
    
    //暂时加到缓存中,待收到客户端的ack后再删除
    msg=addMsgState(msg,MSGSTATE_WAITBACK);
    cache.addMsgToCache(userId,msg);

    var info;
    if (his){
        info='user['+userId+'] sendhismsg:'+msg;
    }else{
        info='user['+userId+'] sendmsg:'+msg;
    }
    
    
    //发送消息
    onLineUsers[userId].emit('message',msg,function (data) {
        if (data) {
            //参数说明:data=msg
            //打印日志
            console.log(info);
            //接收客户端ack,从消息缓存中删除该消息
            cache.delMsgFromCache(userId,data);
        }
    }
    );        

//发送历史消息
function sendHisMsg(userId){
    store.hget(param.mobileloginguid, userId.toString(), function (e, loginguid) {
        var msglist=cache.getMsgListFromCache(userId);
        var i=0;
        while (i<msglist.length){
            var msg=msglist[i];
            var m=JSON.parse(msg)[0];
            if (m.loginguid===loginguid){//本次登录后的消息
                if (m.state===MSGSTATE_NOSEND){ //未发送的消息
                    msglist.remove(i);
                    sendMsg(userId,msg,true);                                                                                                                        
                }else{ //等待回应的消息
                    i++;                    
                }
            }else{//非本次登录的历史消息作废
                msglist.remove(i);
            }            
        }
            
    });
}


fs.readFile('sysparam.properties',{encoding:'utf-8'}, function (err,data) {
    if (err) {
        throw err;
    }
    param=JSON.parse(data)[0];

    pub  = redis.createClient(param.redis_server_port, param.redis_server_ip);
    store   = redis.createClient(param.redis_server_port, param.redis_server_ip);
    store_a = redis.createClient(param.redis_server_port, param.redis_server_ip);
     // redis 链接错误
     pub.on("error", function(error) {
         console.log(error);
     });
     store.on("error", function(error) {
         console.log(error);
     });
     store_a.on("error", function(error) {
         console.log(error);
     });
     
     
     //redis 验证 (reids.conf未开启验证,此项可不需要)
     pub.auth(param.redis_server_pwd);
     store.auth(param.redis_server_pwd);
     store_a.auth(param.redis_server_pwd);
     
     console.log('connect redis');
     //订阅频道消息
     pub.subscribe(param.msgkey);
     pub.on('message', function(channel, message){
            //console.log('channel:'+channel);
            var i=message.indexOf(":");
            var userId=parseInt(message.substring(0,i));
            var msg=message.substring(i+1,message.length);
            
            msg=addMsgIdentID(msg);//增加唯一标识    
            
            store.hget(param.mobileloginguid, userId.toString(), function (e, loginguid) {
                
                msg=addMsgLoginGuid(msg,loginguid);//增加当前登录标识
                
                store.hget(param.mobileuserlist, userId.toString(), function (e, online) {
                    if (online && online==='true') {//用户已登录
                        //console.log("userId["+userId+'] online');
                        if (onLineUsers[userId]){//已连接客户端,发送当前消息
                            //发送当前消息
                            sendMsg(userId,msg);                                                        

                        }else{//与客户端断开,缓存当前消息

                            msg=addMsgState(msg,MSGSTATE_NOSEND);
                            cache.addMsgToCache(userId,msg);
                        }        
                    }else{//用户未登录,不用进行处理
                        //console.log("userId["+userId+'] outline');                    
                    }
                });
                
                
            });
            
     });
});


/*========socket.io管理=========*/
var http = require('http').Server(app); 
var io = require('socket.io')(http); 


io.on('connection', function(socket){ 
    console.log('new user connected'); 
     
    //监听新用户加入 
    socket.on('login', function(data){ 
        //消息缓存中的waitback消息转换为nosend消息
        cache.transWaitBackToNoSend(data.userId);
        //获取旧socket
        var old_socket=onLineUsers[data.userId];
        if (old_socket && old_socket !== socket){
            old_socket.isNowSocket=false;
            old_socket.disconnect();
        }
        //启用socket
        socket.isNowSocket=true;
        onLineUsers[data.userId]=socket;
        var userId=data.userId;
        socket.userId=userId;
        //打印日志
        console.log('user['+userId+'] login');
        //发送历史消息
        sendHisMsg(userId);       
    }); 
    
    //监听用户退出 
    socket.on('disconnect', function(){ 
        if (socket.isNowSocket===true){
            delete onLineUsers[socket.userId];
            //打印日志
            console.log('user['+socket.userId+'] loginout');             
        }
        //在线人数  
        //console.log('onlineCount:'+onLineUsers.count());
    }); 
     
    //监听用户发布聊天内容 
    socket.on('message', function(obj){ 
        //向所有客户端广播发布的消息 
        //io.emit('message', obj); 
        console.log('user['+socket.userId+'] ping'); 
    }); 
   
}); 
 
http.listen(9001, function(){ 
    console.log('listening on *:9001'); 
}); 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SF引流

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值