From 3c78c7f4c24fe56a51f2ac18a34baefac2ae6e0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=B0=E5=B9=BF=E9=93=B6?= <273650669@qq.com> Date: Fri, 27 Oct 2017 19:35:03 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E7=A1=80=E5=8A=9F=E8=83=BD=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.js | 5 + io/io.js | 111 ++++++++++- public/css/client.css | 1 + public/images/server/mine_fill.png | Bin 0 -> 5384 bytes public/js/client/client.js | 27 ++- public/js/fingerprint.js | 293 +++++++++++++++++++++++++++++ public/js/server/index.js | 173 +++++++++++++++++ routes/users.js | 15 +- views/client/index.ejs | 3 +- views/server/index.ejs | 141 ++++++++++++-- 10 files changed, 745 insertions(+), 24 deletions(-) create mode 100644 config.js create mode 100644 public/images/server/mine_fill.png create mode 100755 public/js/fingerprint.js create mode 100644 public/js/server/index.js diff --git a/config.js b/config.js new file mode 100644 index 0000000..3ceb278 --- /dev/null +++ b/config.js @@ -0,0 +1,5 @@ +const APP = { + "KEFUUUID":'chat-kefu-admin' +}; + +module.exports = APP; \ No newline at end of file diff --git a/io/io.js b/io/io.js index a4ee67d..7a6e62b 100644 --- a/io/io.js +++ b/io/io.js @@ -6,6 +6,7 @@ var redis = require('../utils/redis'); var msgType = require('./messageTpye'); var ioSvc = require('./ioHelper').ioSvc; +var AppConfig = require('../config'); //服务端连接 function ioServer(io) { @@ -20,6 +21,13 @@ function ioServer(io) { } }); + Array.prototype.remove = function(val) { + var index = this.indexOf(val); + if (index > -1) { + this.splice(index, 1); + } + }; + io.on('connection', function (socket) { console.log('SocketIO有新的连接!'); @@ -28,22 +36,76 @@ function ioServer(io) { //用户与Socket进行绑定 socket.on('login', function (uid) { console.log(uid+'登录成功'); + + //通知用户上线 + if(uid != AppConfig.KEFUUUID){ + redis.get(AppConfig.KEFUUUID,function (err,sid) { + if(err){ + console.error(err); + } + if(sid){ + redis.get('online_count',function (err,val) { + if(err){ + console.error(err); + } + if(!val){ + val = 0; + } + if(typeof val == 'string'){ + val = parseInt(val); + } + var info = { + "uid":uid, + "name":'客户'+val, + "type":'online' + }; + io.to(sid).emit('update-users',info); + }); + } + }); + + redis.get('user-uuids',function (err,uuids) { + if(err){ + console.error(err); + } + if(uuids){ + uuids =JSON.parse(uuids); + }else{ + uuids = []; + } + if(uuids.indexOf(uid) == -1){ + uuids.push(uid); + uuids = JSON.stringify(uuids); + redis.set('user-uuids',uuids,null,function (err,ret) { + if(err){ + console.error(err); + } + }); + } + }); + + } + 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); @@ -59,6 +121,43 @@ function ioServer(io) { console.error(err); } }); + //通知用户下线 + if(val != AppConfig.KEFUUUID){ + redis.get(AppConfig.KEFUUUID,function (err,sid) { + if(err){ + console.error(err); + } + if(sid){ + var info = { + "uid":val, + "name":'客户下线', + "type":'offline' + }; + io.to(sid).emit('update-users',info); + } + }); + + redis.get('user-uuids',function (err,uuids) { + if(err){ + console.error(err); + } + if(uuids){ + uuids =JSON.parse(uuids); + }else{ + uuids = []; + } + + if(uuids.indexOf(val) != -1){ + uuids.remove(val); + uuids = JSON.stringify(uuids); + redis.set('user-uuids',uuids,null,function (err,ret) { + if(err){ + console.error(err); + } + }); + } + }); + } }); }); @@ -70,7 +169,11 @@ function ioServer(io) { //监听客户端发送的信息,实现消息转发到各个其他客户端 socket.on('message',function(msg){ if(msg.type == msgType.messageType.public){ - socket.broadcast.emit("message",msg.content); + var mg = { + "uid" : msg.from_uid , + "content": msg.content + }; + socket.broadcast.emit("message",mg); }else if(msg.type == msgType.messageType.private){ var uid = msg.uid; redis.get(uid,function (err,sid) { @@ -79,7 +182,11 @@ function ioServer(io) { } if(sid){ //给指定的客户端发送消息 - io.sockets.socket(sid).emit('message', msg.content); + var mg = { + "uid" : msg.from_uid, + "content": msg.content + }; + io.to(sid).emit('message',mg); } }); } diff --git a/public/css/client.css b/public/css/client.css index 98158bc..6e001e9 100644 --- a/public/css/client.css +++ b/public/css/client.css @@ -193,4 +193,5 @@ a { line-height: 44px; font-size: 14px; color: #858e99; + cursor: pointer; } diff --git a/public/images/server/mine_fill.png b/public/images/server/mine_fill.png new file mode 100644 index 0000000000000000000000000000000000000000..b24b78e4c68066c95dadee1116ba60b829f34116 GIT binary patch literal 5384 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 X{qk}?5!QFgB&?{ literal 0 HcmV?d00001 diff --git a/public/js/client/client.js b/public/js/client/client.js index c723d72..05ae6ef 100644 --- a/public/js/client/client.js +++ b/public/js/client/client.js @@ -1,6 +1,7 @@ $(function(){ //Socket.IO 连接 var socket = io.connect('http://'+document.domain+':9010'); + var uuid = ''; function insert_client_html(time,content){ var tpl = '
'+ @@ -33,17 +34,36 @@ $(function(){ $(".msg-container").append(tpl); } + //聊天窗口自动滚到底 + function scrollToBottom() { + var div = document.getElementById('msg-container'); + div.scrollTop = div.scrollHeight; + } + $("#btnSend").click(function(){ var date = dateFormat(); var msg = $("#textarea").val(); - insert_client_html(date,msg); + if(msg){ + var msg_sender = { + "type":'private', + "uid":'chat-kefu-admin', + "content":msg, + "from_uid":uuid + }; + socket.emit('message', msg_sender); + insert_client_html(date,msg); + scrollToBottom(); + $("#textarea").val(''); + } }); //连接服务器 socket.on('connect', function () { - console.log('连接成功...'); - var uuid = 'chat'+ guid(); + //uuid = 'chat'+ guid(); + var fp1 = new Fingerprint(); + uuid = fp1.get(); + console.log('连接成功...'+uuid); socket.emit('login', uuid); }); @@ -54,6 +74,7 @@ $(function(){ // */ socket.on('message', function(msg){ insert_agent_html(dateFormat(),msg.content); + scrollToBottom(); }); }); \ No newline at end of file diff --git a/public/js/fingerprint.js b/public/js/fingerprint.js new file mode 100755 index 0000000..75e0a22 --- /dev/null +++ b/public/js/fingerprint.js @@ -0,0 +1,293 @@ +/* +* fingerprintJS 0.5.5 - Fast browser fingerprint library +* https://github.com/Valve/fingerprintjs +* Copyright (c) 2013 Valentin Vasilyev (valentin.vasilyev@outlook.com) +* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +;(function (name, context, definition) { + if (typeof module !== 'undefined' && module.exports) { module.exports = definition(); } + else if (typeof define === 'function' && define.amd) { define(definition); } + else { context[name] = definition(); } +})('Fingerprint', this, function () { + 'use strict'; + + var Fingerprint = function (options) { + var nativeForEach, nativeMap; + nativeForEach = Array.prototype.forEach; + nativeMap = Array.prototype.map; + + this.each = function (obj, iterator, context) { + if (obj === null) { + return; + } + if (nativeForEach && obj.forEach === nativeForEach) { + obj.forEach(iterator, context); + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + if (iterator.call(context, obj[i], i, obj) === {}) return; + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (iterator.call(context, obj[key], key, obj) === {}) return; + } + } + } + }; + + this.map = function(obj, iterator, context) { + var results = []; + // Not using strict equality so that this acts as a + // shortcut to checking for `null` and `undefined`. + if (obj == null) return results; + if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); + this.each(obj, function(value, index, list) { + results[results.length] = iterator.call(context, value, index, list); + }); + return results; + }; + + if (typeof options == 'object'){ + this.hasher = options.hasher; + this.screen_resolution = options.screen_resolution; + this.screen_orientation = options.screen_orientation; + this.canvas = options.canvas; + this.ie_activex = options.ie_activex; + } else if(typeof options == 'function'){ + this.hasher = options; + } + }; + + Fingerprint.prototype = { + get: function(){ + var keys = []; + keys.push(navigator.userAgent); + keys.push(navigator.language); + keys.push(screen.colorDepth); + if (this.screen_resolution) { + var resolution = this.getScreenResolution(); + if (typeof resolution !== 'undefined'){ // headless browsers, such as phantomjs + keys.push(resolution.join('x')); + } + } + keys.push(new Date().getTimezoneOffset()); + keys.push(this.hasSessionStorage()); + keys.push(this.hasLocalStorage()); + keys.push(this.hasIndexDb()); + //body might not be defined at this point or removed programmatically + if(document.body){ + keys.push(typeof(document.body.addBehavior)); + } else { + keys.push(typeof undefined); + } + keys.push(typeof(window.openDatabase)); + keys.push(navigator.cpuClass); + keys.push(navigator.platform); + keys.push(navigator.doNotTrack); + keys.push(this.getPluginsString()); + if(this.canvas && this.isCanvasSupported()){ + keys.push(this.getCanvasFingerprint()); + } + if(this.hasher){ + return this.hasher(keys.join('###'), 31); + } else { + return this.murmurhash3_32_gc(keys.join('###'), 31); + } + }, + + /** + * JS Implementation of MurmurHash3 (r136) (as of May 20, 2011) + * + * @author Gary Court + * @see http://github.com/garycourt/murmurhash-js + * @author Austin Appleby + * @see http://sites.google.com/site/murmurhash/ + * + * @param {string} key ASCII only + * @param {number} seed Positive integer only + * @return {number} 32-bit positive integer hash + */ + + murmurhash3_32_gc: function(key, seed) { + var remainder, bytes, h1, h1b, c1, c2, k1, i; + + remainder = key.length & 3; // key.length % 4 + bytes = key.length - remainder; + h1 = seed; + c1 = 0xcc9e2d51; + c2 = 0x1b873593; + i = 0; + + while (i < bytes) { + k1 = + ((key.charCodeAt(i) & 0xff)) | + ((key.charCodeAt(++i) & 0xff) << 8) | + ((key.charCodeAt(++i) & 0xff) << 16) | + ((key.charCodeAt(++i) & 0xff) << 24); + ++i; + + k1 = ((((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16))) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = ((((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16))) & 0xffffffff; + + h1 ^= k1; + h1 = (h1 << 13) | (h1 >>> 19); + h1b = ((((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16))) & 0xffffffff; + h1 = (((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16)); + } + + k1 = 0; + + switch (remainder) { + case 3: k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16; + case 2: k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8; + case 1: k1 ^= (key.charCodeAt(i) & 0xff); + + k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff; + k1 = (k1 << 15) | (k1 >>> 17); + k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff; + h1 ^= k1; + } + + h1 ^= key.length; + + h1 ^= h1 >>> 16; + h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff; + h1 ^= h1 >>> 13; + h1 = ((((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16))) & 0xffffffff; + h1 ^= h1 >>> 16; + + return h1 >>> 0; + }, + + // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 + hasLocalStorage: function () { + try{ + return !!window.localStorage; + } catch(e) { + return true; // SecurityError when referencing it means it exists + } + }, + + hasSessionStorage: function () { + try{ + return !!window.sessionStorage; + } catch(e) { + return true; // SecurityError when referencing it means it exists + } + }, + + hasIndexDb: function () { + try{ + return !!window.indexedDB; + } catch(e) { + return true; // SecurityError when referencing it means it exists + } + }, + + isCanvasSupported: function () { + var elem = document.createElement('canvas'); + return !!(elem.getContext && elem.getContext('2d')); + }, + + isIE: function () { + if(navigator.appName === 'Microsoft Internet Explorer') { + return true; + } else if(navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)){// IE 11 + return true; + } + return false; + }, + + getPluginsString: function () { + if(this.isIE() && this.ie_activex){ + return this.getIEPluginsString(); + } else { + return this.getRegularPluginsString(); + } + }, + + getRegularPluginsString: function () { + return this.map(navigator.plugins, function (p) { + var mimeTypes = this.map(p, function(mt){ + return [mt.type, mt.suffixes].join('~'); + }).join(','); + return [p.name, p.description, mimeTypes].join('::'); + }, this).join(';'); + }, + + getIEPluginsString: function () { + if(window.ActiveXObject){ + var names = ['ShockwaveFlash.ShockwaveFlash',//flash plugin + 'AcroPDF.PDF', // Adobe PDF reader 7+ + 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr + 'QuickTime.QuickTime', // QuickTime + // 5 versions of real players + 'rmocx.RealPlayer G2 Control', + 'rmocx.RealPlayer G2 Control.1', + 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', + 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', + 'RealPlayer', + 'SWCtl.SWCtl', // ShockWave player + 'WMPlayer.OCX', // Windows media player + 'AgControl.AgControl', // Silverlight + 'Skype.Detection']; + + // starting to detect plugins in IE + return this.map(names, function(name){ + try{ + new ActiveXObject(name); + return name; + } catch(e){ + return null; + } + }).join(';'); + } else { + return ""; // behavior prior version 0.5.0, not breaking backwards compat. + } + }, + + getScreenResolution: function () { + var resolution; + if(this.screen_orientation){ + resolution = (screen.height > screen.width) ? [screen.height, screen.width] : [screen.width, screen.height]; + }else{ + resolution = [screen.height, screen.width]; + } + return resolution; + }, + + getCanvasFingerprint: function () { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + // https://www.browserleaks.com/canvas#how-does-it-work + var txt = 'http://valve.github.io'; + ctx.textBaseline = "top"; + ctx.font = "14px 'Arial'"; + ctx.textBaseline = "alphabetic"; + ctx.fillStyle = "#f60"; + ctx.fillRect(125,1,62,20); + ctx.fillStyle = "#069"; + ctx.fillText(txt, 2, 15); + ctx.fillStyle = "rgba(102, 204, 0, 0.7)"; + ctx.fillText(txt, 4, 17); + return canvas.toDataURL(); + } + }; + + + return Fingerprint; + +}); diff --git a/public/js/server/index.js b/public/js/server/index.js new file mode 100644 index 0000000..b130287 --- /dev/null +++ b/public/js/server/index.js @@ -0,0 +1,173 @@ +//一般直接写在一个js文件中 +layui.use(['layer', 'form', 'jquery'], function () { + var layer = layui.layer + , form = layui.form + , $ = layui.jquery; + + var currentUUID = ''; + var uuid = ''; + var socket = io.connect('http://'+document.domain+':9010'); + + var uuids = []; + + Array.prototype.remove = function(val) { + var index = this.indexOf(val); + if (index > -1) { + this.splice(index, 1); + } + }; + + + //页面初始化函数 + function init() { + $(".admin-index").addClass("layui-this"); + + var height = document.body.clientHeight - 262; + $(".message-container").css("height", height); + + window.onresize = function(){ + var height = document.body.clientHeight - 262; + $(".message-container").css("height", height); + } + } + + //聊天窗口自动滚到底 + function scrollToBottom() { + var div = document.getElementById('message-container'); + div.scrollTop = div.scrollHeight; + } + + function insert_section(uid) { + var html = '
'; + $(".message-container").append(html); + } + + function insert_agent_html(content){ + var date = dateFormat(); + var html = '
\n' + + '
\n' + + ' ' + date + '\n' + + ' \n' + + '
\n' + + '
\n' + + '
' + content + '
\n' + + '
\n' + + '
'; + $('#section-'+currentUUID).append(html); + } + + + function insert_client_html(uid,content){ + var date = dateFormat(); + var html = '
\n' + + '
\n' + + ' ' + date + '\n' + + ' 客户\n' + + '
\n' + + '
\n' + + '
' + content + '
\n' + + '
\n' + + '
'; + $('#section-'+uid).append(html); + } + + function insert_user_html(id,name) { + var html = ''; + $('.chat-user').append(html); + } + + function getUsers() { + $.get('/users',function (data) { + if(data.code == 200){ + $('.chat-user').html(''); + + var data = data.data; + var count = 1; + data.forEach(function (uid) { + insert_user_html(uid,'客户' + count++); + //创建聊天section + insert_section(uid); + }); + if(data.length > 0 && !currentUUID){ + currentUUID = data[0]; + } + + $(".user-info").css("background","#ffffff"); + $("#"+currentUUID).css("background","#f2f3f5"); + $(".user-section").hide(); + $("#section-"+currentUUID).show(); + } + }); + } + + $(".btnMsgSend").click(function(){ + var msg = $("#msg-send-textarea").val(); + if(msg){ + var msg_sender = { + "type":'private', + "uid":currentUUID, + "content":msg, + "from_uid":uuid + }; + socket.emit('message', msg_sender); + insert_agent_html(msg); + scrollToBottom(); + $("#msg-send-textarea").val(''); + } + }); + + //连接服务器 + socket.on('connect', function () { + console.log('连接成功...'); + uuid = 'chat-kefu-admin'; + socket.emit('login', uuid); + }); + + //后端推送来消息时 + socket.on('message', function(msg){ + insert_client_html(msg.uid,msg.content); + scrollToBottom(); + }); + + //后端推送来消息时 + socket.on('update-users', function(msg){ + if(msg.type == 'offline'){ + $("#"+msg.uid).remove(); + uuids.remove(msg.uid); + }else if(msg.type == 'online'){ + if(!currentUUID){ + currentUUID = msg.uid; + } + if(uuids.indexOf(msg.uid) == -1){ + uuids.push(msg.uid); + insert_user_html(msg.uid,msg.name); + //创建聊天section + insert_section(msg.uid); + } + } + }); + + //更新用户在线数 + socket.on('update_online_count', function(msg){ + $(".friend-head-right").html( (msg.online_count - 1) + '人' ); + }); + + //切换用户 + $(document).on('click','.user-info',function(){ + var uid = $(this).attr("id"); + currentUUID = uid; + $(".user-info").css("background","#ffffff"); + $("#"+uid).css("background","#f2f3f5"); + $(".user-section").hide(); + $("#section-"+uid).show(); + }); + + + init(); + getUsers(); +}); \ No newline at end of file diff --git a/routes/users.js b/routes/users.js index 623e430..62bea67 100644 --- a/routes/users.js +++ b/routes/users.js @@ -1,9 +1,22 @@ var express = require('express'); var router = express.Router(); +var redis = require('../utils/redis'); /* GET users listing. */ router.get('/', function(req, res, next) { - res.send('respond with a resource'); + redis.get('user-uuids',function (err,uuids) { + if(err){ + console.error(err); + return res.send({code:400,msg:'获取失败'}); + } + if(uuids){ + uuids =JSON.parse(uuids); + }else{ + uuids = []; + } + + return res.send({code:200,msg:'获取成功',data:uuids}); + }); }); module.exports = router; diff --git a/views/client/index.ejs b/views/client/index.ejs index 1f1d5a6..588f41d 100644 --- a/views/client/index.ejs +++ b/views/client/index.ejs @@ -25,7 +25,7 @@
-
+
@@ -44,6 +44,7 @@ + diff --git a/views/server/index.ejs b/views/server/index.ejs index 113af2c..751caba 100644 --- a/views/server/index.ejs +++ b/views/server/index.ejs @@ -1,6 +1,6 @@ <% include header.ejs %>
- 0 / 2 + 0人 我的对话
+
+ +
- 1111 +
+ +
+
+
+ +
发送
+
+
- - - + + + + <% include footer.ejs %> \ No newline at end of file