master 3256674041c2 cached
14 files
24.0 KB
7.2k tokens
1 symbols
1 requests
Download .txt
Repository: gytai/node-websocket-msg-sender
Branch: master
Commit: 3256674041c2
Files: 14
Total size: 24.0 KB

Directory structure:
gitextract_2wts0mrp/

├── README.md
├── app.js
├── bin/
│   └── www
├── io/
│   ├── io.js
│   ├── ioHelper.js
│   └── messageTpye.js
├── package.json
├── public/
│   ├── javascripts/
│   │   └── notify.js
│   └── stylesheets/
│       └── style.css
├── routes/
│   ├── index.js
│   └── users.js
├── utils/
│   └── redis.js
└── views/
    ├── error.ejs
    └── index.ejs

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
基于Nodejs websocket socket.io的消息转发系统  message pusher written in nodejs based on socket.io
==============

消息实时推送,支持在线用户数实时统计。基于[Socket.IO](https://socket.io/)开发,使用websocket推送数据,当浏览器不支持websocket时自动切换comet推送数据。

支持Linux,mac,windows等环境部署。



效果截图
======
![node-msg-sender-demo](http://112.74.81.224:3000/images/demo.png)
 
线上demo  
======

http://112.74.81.224:3000/

可以通过url:http://112.74.81.224:3000/sendMsg/?type=private&uid=1504936989000&content=消息内容 向当前用户发送消息

可以通过url:http://112.74.81.224:3000/sendMsg/?type=public&content=消息内容 向所有在线用户推送消息

uid为接收消息的uid,如果不传递则向所有人推送消息  
content 为消息内容

注:可以通过php或者其它语言的curl功能实现后台推送

下载安装
======
1、git clone https://github.com/gytai/node-websocket-msg-sender.git

2、npm install

3、apt-get install redis-server

4、redis-server

后端服务启动停止,先安装PM2(Advanced Node.js process manager,http://pm2.keymetrics.io/)
======
### 启动服务
pm2 start bin/www --name msg-sender

### 停止服务
pm2 stop msg-sender

Web前端代码类似:
====
```javascript
// 引入前端文件
<script src="/socket.io/socket.io.js"></script>
<script>
      var socket = io.connect('http://localhost:3000');
      socket.emit('login', new Date().getTime());

      // 后端推送来消息时
      socket.on('message', function(msg){
          $('#content').html('收到消息:'+msg);
          $('.notification.sticky').notify();
      });

      // 后端推送来在线数据时
      socket.on('update_online_count', function(data){
          console.log(data);
          $('#online_box').html('当前在线客户端数:&nbsp;'+data.online_count);
      });
</script>
```

其他客户端
====
根据websocket协议即可。具体参考websocket协议。


Nodejs后端调用api向任意用户推送数据
====
```javascript
    var type = req.query.type || msgType.public;
    var content = req.query.content || 'none';
    var uid = req.query.uid;

    switch (type){
        case msgType.public:
            ioSvc.serverBroadcastMsg(content);
            break;
        case msgType.private:
            if(!uid){
                return res.send({code:400,msg:'uid参数必传'});
            }
            ioSvc.serverToPrivateMsg(uid,content);
            break;
    }
```

Http 发送数据,可以配置跨站发送(需要设置跨域放行)。例如安卓或者IOS等其他客户端也可以方便的发送消息。
====
可以通过url:http://localhost:3000/sendMsg/?type=private&uid=1504936989000&content=消息内容 向当前用户发送消息

可以通过url:http://localhost:3000/sendMsg/?type=public&content=消息内容 向所有在线用户推送消息





================================================
FILE: app.js
================================================
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var app = express();

var index = require('./routes/index');
var users = require('./routes/users');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;


================================================
FILE: bin/www
================================================
#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('nodemessage:server');
var http = require('http');
var ioSvc = require('../io/io');
/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

//??Socket.IO
var io = require('socket.io')(server);
ioSvc.ioServer(io);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}


================================================
FILE: io/io.js
================================================
/*
*介绍:socket.io 功能封装
*作者:TaiGuangYin
*时间:2017-09-09
* */
var redis = require('../utils/redis');
var msgType = require('./messageTpye');
var ioSvc = require('./ioHelper').ioSvc;

//服务端连接
function ioServer(io) {

    var _self = this;
    ioSvc.setInstance(io);

    //初始化连接人数
    redis.set('online_count',0,null,function (err,ret) {
        if(err){
            console.error(err);
        }
    });

    io.on('connection', function (socket) {
        console.log('SocketIO有新的连接!');

        _self.updateOnlieCount(true);

        //用户与Socket进行绑定
        socket.on('login', function (uid) {
            console.log(uid+'登录成功');
            redis.set(uid,socket.id,null,function (err,ret) {
                if(err){
                    console.error(err);
                }
            });
            redis.set(socket.id,uid,null,function (err,ret) {
                if(err){
                    console.error(err);
                }
            });
        });

        //断开事件
        socket.on('disconnect', function() {
            console.log("与服务其断开");
            _self.updateOnlieCount(false);
            redis.get(socket.id,function (err,val) {
                if(err){
                    console.error(err);
                }
                redis.del(socket.id,function (err,ret) {
                    if(err){
                        console.error(err);
                    }

                });
                redis.del(val,function (err,ret) {
                    if(err){
                        console.error(err);
                    }
                });
            });
        });

        //重连事件
        socket.on('reconnect', function() {
            console.log("重新连接到服务器");
        });

        //监听客户端发送的信息,实现消息转发到各个其他客户端
        socket.on('message',function(msg){
            if(msg.type == msgType.messageType.public){
                socket.broadcast.emit("message",msg.content);
            }else if(msg.type == msgType.messageType.private){
                var uid = msg.uid;
                redis.get(uid,function (err,sid) {
                   if(err){
                       console.error(err);
                   }
                   if(sid){
                       //给指定的客户端发送消息
                       io.sockets.socket(sid).emit('message', msg.content);
                   }
                });
            }

        });
    });

    this.updateOnlieCount = function (isConnect) {
        //记录在线客户连接数
        redis.get('online_count',function (err,val) {
            if(err){
                console.error(err);
            }
            if(!val){
                val = 0;
            }
            if(typeof val == 'string'){
                val = parseInt(val);
            }
            if(isConnect){
                val += 1;
            }else{
                val -= 1;
                if(val<=0){
                    val = 0;
                }
            }

            console.log('当前在线人数:'+val);
            io.sockets.emit('update_online_count', { online_count: val });

            redis.set('online_count',val,null,function (err,ret) {
                if(err){
                    console.error(err);
                }
            });
        });
    };

}


//模块导出
exports.ioServer = ioServer;

================================================
FILE: io/ioHelper.js
================================================
var redis = require('../utils/redis');

var ioSvc = {};
ioSvc.io = null;

//初始化实例
ioSvc.setInstance = function (io) {
    this.io = io;
};

ioSvc.getInstance =function () {
    return this.io;
};

//服务器给所有客户端广播消息
ioSvc.serverBroadcastMsg = function (data) {
    console.log('发送广播消息');
    console.log(data);
    this.io.sockets.emit('message',data);
};

//服务端给指定用户发消息
ioSvc.serverToPrivateMsg = function (uid,data) {
    console.log('发送私人消息');
    console.log(data);
    redis.get(uid,function (err,sid) {
        if(err){
            console.error(err);
        }
        if(sid){
            //给指定的客户端发送消息
            this.io.sockets.socket(sid).emit('message',data);
        }
    });
};

exports.ioSvc = ioSvc;

================================================
FILE: io/messageTpye.js
================================================
const messageType= {
    'public':'public',
    'private':'private'
};

exports.messageType = messageType;

================================================
FILE: package.json
================================================
{
  "name": "nodemessage",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.17.1",
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.3",
    "ejs": "~2.5.6",
    "express": "~4.15.2",
    "morgan": "~1.8.1",
    "serve-favicon": "~2.4.2",
    "socket.io": "^2.0.3",
    "socket.io-client": "^2.0.3",
    "redis": "^2.8.0"
  }
}


================================================
FILE: public/javascripts/notify.js
================================================
(function ($) {
    $.fn.extend({
        notify: function (options) {
            var settings = $.extend({ type: 'sticky', speed: 500, onDemandButtonHeight: 35 }, options);
            return this.each(function () {
                var wrapper = $(this);
                var ondemandBtn = $('.ondemand-button');
                var dh = -35;
                var w = wrapper.outerWidth() - ondemandBtn.outerWidth();
                ondemandBtn.css('left', w).css('margin-top',  dh + "px" );
                var h = -wrapper.outerHeight();
                wrapper.addClass(settings.type).css('margin-top', h).addClass('visible').removeClass('hide');
                if (settings.type != 'ondemand') {
                    wrapper.stop(true, false).animate({ marginTop: 0 }, settings.speed);
                }
                else {
                    ondemandBtn.stop(true, false).animate({ marginTop: 0 }, settings.speed);
                }

                var closeBtn = $('.close', wrapper);
                closeBtn.click(function () {
                    if (settings.type == 'ondemand') {
                        wrapper.stop(true, false).animate({ marginTop: h }, settings.speed, function () {
                            wrapper.removeClass('visible').addClass('hide');
                            ondemandBtn.stop(true, false).animate({ marginTop: 0 }, settings.speed);
                        });
                    }
                    else {
                        wrapper.stop(true, false).animate({ marginTop: h }, settings.speed, function () {
                            wrapper.removeClass('visible').addClass('hide');
                        });
                    }
                });
                if (settings.type == 'floated') {
                    $(document).scroll(function (e) {
                        wrapper.stop(true, false).animate({ top: $(document).scrollTop() }, settings.speed);
                    }).resize(function (e) {
                        wrapper.stop(true, false).animate({ top: $(document).scrollTop() }, settings.speed);
                    });
                }
                else if (settings.type == 'ondemand') {
                    ondemandBtn.click(function () {
                        $(this).animate({ marginTop: dh }, settings.speed, function () {
                            wrapper.removeClass('hide').addClass('visible').animate({ marginTop: 0 }, settings.speed, function () {

                            });
                        })
                    });
                }

            });

        }
    });
})(jQuery);


================================================
FILE: public/stylesheets/style.css
================================================
@charset "utf-8";
body {
  margin:0px; padding:0px;
  font-family: Arial, Helvetica, sans-serif;
  background:url(/images/repeat.jpg);
  font-size:15px;
  color:#000;
}
ul{list-style:none; margin:0px; padding:0px; margin-top:20px;}
li{padding-bottom:20px;}
.sticky p, .floated p, .fixed p, .ondemand p{ float:left; padding:0px; margin:0px; margin-left:10px; line-height:45px; color:#fff; font-size:12px;}
.sticky a, .floated a, .fixed a, .ondemand a{ float:right; margin:13px 10px 0px 0px; }
img{border:0px;}
.wrapper{padding:20px;}

.sticky {

  position:fixed;
  top:0;
  left:0;
  z-index:1000;
  width:100%;
  border-bottom:3px solid #fff !important;

  background: #91BD09; /* Old browsers */
  background: -moz-linear-gradient(top, #91BD09 0%, #91BD09 100%); /* FF3.6+ */

  /* FireFox 3.6 */
  /* Safari4+, Chrome */
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#91BD09', endColorstr='#91BD09')";
  -pie-background: linear-gradient(#91BD09, #91BD09 100%);
  behavior: url(PIE.htc);
  -moz-box-shadow: 1px 1px 7px #676767;
  -webkit-box-shadow: 1px 1px 7px #676767;
  box-shadow: 1px 1px 7px #676767;
  height: 45px;
  background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, #91BD09),color-stop(1, #91BD09));/* IE6,IE7 */
  /* IE8 */
  /* Firefox F3.5+ */
  /* Safari3.0+, Chrome */
}


.floated {

  position:absolute;
  top:0;
  left:0;
  z-index:1000;
  width:100%;
  border-bottom:3px solid #fff !important;
  background: #0e59ae; /* Old browsers */
  background: -moz-linear-gradient(top, #0e59ae 0%, #0e59ae 100%); /* FF3.6+ */

  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#0E59AE', endColorstr='#0E59AE')";

  -moz-box-shadow: 1px 1px 7px #676767;
  -webkit-box-shadow: 1px 1px 7px #676767;
  box-shadow: 1px 1px 7px #676767;
  height: 45px;
  background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, #0E59AE),color-stop(1, #0E59AE));/* IE6,IE7 */
  -pie-background: linear-gradient(#0E59AE, #0E59AE 100%);
  behavior: url(PIE.htc);
}


.fixed {
  position:absolute;
  top:0;
  left:0;
  width:100%;
  border-bottom:3px solid #fff !important;

  background: #660099; /* Old browsers */
  background: -moz-linear-gradient(top, #660099 0%, #660099 100%); /* FF3.6+ */

  /* FireFox 3.6 */
  /* Safari4+, Chrome */
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#660099', endColorstr='#660099')";
  -pie-background: linear-gradient(#660099, #660099 100%);
  behavior: url(PIE.htc);
  -moz-box-shadow: 1px 1px 7px #676767;
  -webkit-box-shadow: 1px 1px 7px #676767;
  box-shadow: 1px 1px 7px #676767;
  height: 45px;
  background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, #660099),color-stop(1, #660099));/* IE6,IE7 */
  /* IE8 */
  /* Firefox F3.5+ */
  /* Safari3.0+, Chrome */
}

.ondemand {

  width:100%;
  border-bottom:3px solid #fff !important;
  position:absolute;
  top:0;
  left:0;
  z-index:1000;

  background: #CC0000; /* Old browsers */
  background: -moz-linear-gradient(top, #CC0000 0%, #CC0000 100%); /* FF3.6+ */

  /* FireFox 3.6 */
  /* Safari4+, Chrome */
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#CC0000', endColorstr='#CC0000')";
  -pie-background: linear-gradient(#CC0000, #CC0000 100%);
  behavior: url(PIE.htc);
  -moz-box-shadow: 1px 1px 7px #676767;
  -webkit-box-shadow: 1px 1px 7px #676767;
  box-shadow: 1px 1px 7px #676767;
  height: 45px;
  background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, #CC0000),color-stop(1, #CC0000));/* IE6,IE7 */
  /* IE8 */
  /* Firefox F3.5+ */
  /* Safari3.0+, Chrome */
}
.ondemand-button
{
  width:40px !important;
  height:40px;
  float:right !important;
  z-index:999;
  position:absolute;
  margin-right:100px!important;
}





#footer{width:100%; margin:0 auto; font-size:12px; color:#0E59AE; height:30px;  margin-top:200px;border-top:1px solid #CCC;padding:18px;}
.hide{display:none;}


/* Buttons */

.round.button {
  -moz-border-radius: 15px;
  -webkit-border-radius: 15px;
  border-radius: 15px;
  background-image: url(button-images/round-button-overlay.png);
  border: 1px solid rgba(0, 0, 0, 0.25);
  font-size: 13px;
  padding: 0;
}

.button {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.50);
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.50);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.50);
  background: #222;
  border: 1px solid rgba(0, 0, 0, 0.25);
  color: white !important;
  cursor: pointer;
  display: inline-block;
  font-size: 13px;
  font-weight: bold;
  line-height: 1;
  overflow: visible;
  padding: 5px 15px 6px;
  position: relative;
  text-decoration: none;
  text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
  width: auto;
  text-align: center;
}

.round.button span {
  -moz-border-radius: 14px;
  -webkit-border-radius: 14px;
  border-radius: 14px;
  display: block;
  line-height: 1;
  padding: 4px 15px 6px;
}


.green.button {
  background-color:#91BD09;
}
.green.button:hover {
  background-color:#749A02;
}
.green.button:active {
  background-color:#a4d50b;
}
.blue.button {
  background-color:#0E59AE;
}
.blue.button:hover {
  background-color:#063468;
}
.blue.button:active {
  background-color:#1169cc;
}
.purple.button {
  background-color:#660099;
}
.purple.button:hover {
  background-color:#330066;
}
.purple.button:active {
  background-color:#7f02bd;
}

.red.button {
  background-color:#CC0000;
}
.red.button:hover {
  background-color:#990000;
}
.red.button:active {
  background-color:#ea0202;
}
.close
{}

.show{

  background: #CC0000; /* Old browsers */
  background: -moz-linear-gradient(top, #CC0000 0%, #CC0000 100%); /* FF3.6+ */


  /* FireFox 3.6 */
  /* Safari4+, Chrome */
  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#CC0000', endColorstr='#CC0000')";
  -pie-background: linear-gradient(#CC0000, #CC0000 100%);
  behavior: url(PIE.htc);
  -moz-box-shadow: 1px 1px 7px #676767;
  -webkit-box-shadow: 1px 1px 7px #676767;
  box-shadow: 1px 1px 7px #676767;
  height: 35px;
  float: right;
  width: 30px;
  overflow:hidden;
  /*margin-top: 0px !important;*/
  margin-right: 10px !important;
  text-align: center;
  background-image: -webkit-gradient(linear,left bottom,left top,color-stop(0, #CC0000),color-stop(1, #CC0000));/* IE6,IE7 */
  /* IE8 */
  /* Firefox F3.5+ */
  /* Safari3.0+, Chrome */
  /* Opera 10.5, IE 9.0 */


}

.show img{margin-top:10px;}


================================================
FILE: routes/index.js
================================================
var express = require('express');
var router = express.Router();
var ioSvc = require('../io/ioHelper').ioSvc;
var msgType = require('../io/messageTpye').messageType;

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Node-Msg-Sender' });
});

router.get('/sendMsg', function(req, res, next) {
    var type = req.query.type || msgType.public;
    var content = req.query.content || 'none';
    var uid = req.query.uid;

    switch (type){
        case msgType.public:
            ioSvc.serverBroadcastMsg(content);
            break;
        case msgType.private:
            if(!uid){
                return res.send({code:400,msg:'uid参数必传'});
            }
            ioSvc.serverToPrivateMsg(uid,content);
            break;
    }
    return res.send({code:200,msg:'发送成功'});

});

module.exports = router;


================================================
FILE: routes/users.js
================================================
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;


================================================
FILE: utils/redis.js
================================================
var redisSvc = {};
var redis = require("redis");

if(!client){
    var client = redis.createClient();
}

client.on("error", function (err) {
    console.log("Redis Error :" , err);
    client = null;
});

client.on('connect', function(){
    console.log('Redis连接成功.');
});

/**
 * 添加string类型的数据
 * @param key 键
 * @params value 值
 * @params expire (过期时间,单位秒;可为空,为空表示不过期)
 * @param callBack(err,result)
 */
redisSvc.set = function(key, value, expire, callback){

    client.set(key, value, function(err, result){

        if (err) {
            console.log(err);
            callback(err,null);
            return;
        }

        if (!isNaN(expire) && expire > 0) {
            client.expire(key, parseInt(expire));
        }

        callback(null,result)
    })
};

/**
 * 查询string类型的数据
 * @param key 键
 * @param callBack(err,result)
 */
redisSvc.get = function(key, callback){

    client.get(key, function(err,result){

        if (err) {
            console.log(err);
            callback(err,null);
            return;
        }

        callback(null,result);
    });
};

/*
*删除String 类型的key
 * @param key 键
 * @param callBack(err,result)
*/
redisSvc.del = function(key, callback){

    client.del(key, function(err,result){

        if (err) {
            console.log(err);
            callback(err,null);
            return;
        }

        callback(null,result);
    });
};


module.exports = redisSvc;

================================================
FILE: views/error.ejs
================================================
<h1><%= message %></h1>
<h2><%= error.status %></h2>
<pre><%= error.stack %></pre>


================================================
FILE: views/index.ejs
================================================
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <script src='//cdn.bootcss.com/jquery/1.11.3/jquery.js'></script>
    <script src='/javascripts/notify.js'></script>
  </head>
  <body>
    <div class="notification sticky hide">
        <p id="content"> </p>
        <a class="close" href="javascript:"> <img src="/images/icon-close.png" /></a>
    </div>
    <div class="wrapper">
        <div style="width:850px;">
            <h3>介绍:</h3>
            <b>这是一个消息推送系统,基于<a rel="nofollow" href="https://socket.io/">Socket.IO</a>开发。<br><br><br></b>
            <h3>支持以下特性:</h3>
            <ul>
                <li>多浏览器支持</li>
                <li>多类型客户端支持</li>
                <li>支持针对单个用户推送消息</li>
                <li>支持向所有用户推送消息</li>
                <li>支持服务端主动推送消息</li>
                <li>支持客户端之前推送消息</li>
                <li>长连接推送(websocket或者comet),消息即时到达</li>
                <li>支持在线用户数实时统计推送(见页脚统计)</li>
            </ul>
            <h3>测试:</h3>
            当前用户uid:<b class="uid"></b><br>
            可以通过url:<a id="send_to_one" href="http://localhost:3000/sendMsg/?type=public&uid=1445590039000&content=消息内容" target="_blank"><font style="color:#91BD09">http://<font class="domain"></font>:3000/sendMsg/?type=private&uid=<b class="uid"></b>&content=消息内容</font></a>  向当前用户发送消息<br>
            可以通过url:<a href="http://localhost:3000/sendMsg/?type=publish&to=&content=消息内容" target="_blank"  id="send_to_all" ><font style="color:#91BD09">http://<font class="domain"></font>:3000/sendMsg/?type=public&content=消息内容</font></a> 向所有在线用户推送消息<br>
            <script>
                // 使用时替换成真实的uid,这里方便演示使用时间戳
                var uid = Date.parse(new Date());
                $('#send_to_one').attr('href', 'http://'+document.domain+':3000/sendMsg/?type=private&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9&uid='+uid);
                $('.uid').html(uid);
                $('#send_to_all').attr('href', 'http://'+document.domain+':3000/sendMsg/?type=public&content=%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9');
                $('.uid').html(uid);
                $('.domain').html(document.domain);
            </script>
        </div>
    </div>
    <div id="footer">
        <center id="online_box"></center>
        <center><p style="font-size:11px;color:#555;"> Powered by <a href="https://github.com/gytai/node-msg-sender.git" target="_blank"><strong>TaiGuangYin!</strong></a></p></center>
    </div>
  </body>
  <script src="/socket.io/socket.io.js"></script>

  <script>
      var socket = io.connect('http://'+document.domain+':3000');
      socket.on('connect', function () {
          console.log('连接成功...');
          socket.emit('login', new Date().getTime());
      });

      // 后端推送来消息时
      socket.on('message', function(msg){
          $('#content').text('收到消息:'+msg);
          $('.notification.sticky').notify();
      });

      // 后端推送来在线数据时
      socket.on('update_online_count', function(data){
          console.log(data);
          $('#online_box').html('当前在线客户端数:&nbsp;'+data.online_count);
      });

  </script>
</html>
Download .txt
gitextract_2wts0mrp/

├── README.md
├── app.js
├── bin/
│   └── www
├── io/
│   ├── io.js
│   ├── ioHelper.js
│   └── messageTpye.js
├── package.json
├── public/
│   ├── javascripts/
│   │   └── notify.js
│   └── stylesheets/
│       └── style.css
├── routes/
│   ├── index.js
│   └── users.js
├── utils/
│   └── redis.js
└── views/
    ├── error.ejs
    └── index.ejs
Download .txt
SYMBOL INDEX (1 symbols across 1 files)

FILE: io/io.js
  function ioServer (line 11) | function ioServer(io) {
Condensed preview — 14 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (28K chars).
[
  {
    "path": "README.md",
    "chars": 2251,
    "preview": "基于Nodejs websocket socket.io的消息转发系统  message pusher written in nodejs based on socket.io\n==============\n\n消息实时推送,支持在线用户数实"
  },
  {
    "path": "app.js",
    "chars": 1256,
    "preview": "var express = require('express');\nvar path = require('path');\nvar favicon = require('serve-favicon');\nvar logger = requi"
  },
  {
    "path": "bin/www",
    "chars": 1703,
    "preview": "#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar app = require('../app');\nvar debug = require('debug')('nodemes"
  },
  {
    "path": "io/io.js",
    "chars": 3248,
    "preview": "/*\n*介绍:socket.io 功能封装\n*作者:TaiGuangYin\n*时间:2017-09-09\n* */\nvar redis = require('../utils/redis');\nvar msgType = require('"
  },
  {
    "path": "io/ioHelper.js",
    "chars": 714,
    "preview": "var redis = require('../utils/redis');\n\nvar ioSvc = {};\nioSvc.io = null;\n\n//初始化实例\nioSvc.setInstance = function (io) {\n  "
  },
  {
    "path": "io/messageTpye.js",
    "chars": 106,
    "preview": "const messageType= {\n    'public':'public',\n    'private':'private'\n};\n\nexports.messageType = messageType;"
  },
  {
    "path": "package.json",
    "chars": 413,
    "preview": "{\n  \"name\": \"nodemessage\",\n  \"version\": \"0.0.0\",\n  \"private\": true,\n  \"scripts\": {\n    \"start\": \"node ./bin/www\"\n  },\n  "
  },
  {
    "path": "public/javascripts/notify.js",
    "chars": 2598,
    "preview": "(function ($) {\n    $.fn.extend({\n        notify: function (options) {\n            var settings = $.extend({ type: 'stic"
  },
  {
    "path": "public/stylesheets/style.css",
    "chars": 6502,
    "preview": "@charset \"utf-8\";\nbody {\n  margin:0px; padding:0px;\n  font-family: Arial, Helvetica, sans-serif;\n  background:url(/image"
  },
  {
    "path": "routes/index.js",
    "chars": 855,
    "preview": "var express = require('express');\nvar router = express.Router();\nvar ioSvc = require('../io/ioHelper').ioSvc;\nvar msgTyp"
  },
  {
    "path": "routes/users.js",
    "chars": 203,
    "preview": "var express = require('express');\nvar router = express.Router();\n\n/* GET users listing. */\nrouter.get('/', function(req,"
  },
  {
    "path": "utils/redis.js",
    "chars": 1418,
    "preview": "var redisSvc = {};\nvar redis = require(\"redis\");\n\nif(!client){\n    var client = redis.createClient();\n}\n\nclient.on(\"erro"
  },
  {
    "path": "views/error.ejs",
    "chars": 83,
    "preview": "<h1><%= message %></h1>\n<h2><%= error.status %></h2>\n<pre><%= error.stack %></pre>\n"
  },
  {
    "path": "views/index.ejs",
    "chars": 3192,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title><%= title %></title>\n    <link rel='stylesheet' href='/stylesheets/style.css'"
  }
]

About this extraction

This page contains the full source code of the gytai/node-websocket-msg-sender GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 14 files (24.0 KB), approximately 7.2k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!