Events.php<?php
use \GatewayWorker\Lib\Gateway;
use \GatewayWorker\Lib\Db;
if(!isset($_SESSION)){
session_start();
}
/**
&
Events.php
<?php use \GatewayWorker\Lib\Gateway; use \GatewayWorker\Lib\Db; if(!isset($_SESSION)){ session_start(); } /** * 主逻辑 * 主要是处理 onConnect onMessage onClose 三个方法 * onConnect 和 onClose 如果不需要可以不用实现并删除 */ class Events { /** * 当客户端发来消息时触发 * @param int $client_id 连接id * @param mixed $message 具体消息 */ public static function onMessage($client_id, $data) { $message = json_decode($data, true); $message_type = strtolower($message['type']); switch($message_type) { case 'init': if(isset($message['id'])){ // 用户id 用户名 个性签名 头像等信息 $id = $message['id']; $username = $message['username']; $sign = $message['sign']; $avatar = $message['avatar']; // 将client_id与uid绑定,通过Gateway::sendToUid给这个uid发消息(在send_message.php中有调用) $_SESSION['laychat']['id'] = $id; Gateway::bindUid($client_id, $id); } // 通知当前客户端初始化 $init_message = array( 'message_type' => 'init', 'client_id' => $client_id, ); $_SESSION['laychat']['client_id'] = $client_id; Gateway::sendToClient($client_id, json_encode($init_message)); if(isset($message['id'])){ Gateway::updateSession($client_id, $message); // 获取用户所在群组id $db = Db::instance('laychat'); $group_id_array = $db->select('gid')->from('group_members')->where('uid=:uid')->bindValue('uid',$id)->column(); if($group_id_array){ foreach($group_id_array as $gid){ // 让当前客户端加入群组 Gateway::joinGroup($client_id, $gid); } } // 通知所有客户端当前用户上线 $online_message = array( 'message_type' => 'online', 'id' => $id ); Gateway::sendToAll(json_encode($online_message)); } return; case 'hide': $status_message = array( 'message_type' => $message_type, 'id' => $message['uid'], ); Gateway::sendToAll(json_encode($status_message)); return; case 'online': $status_message = array( 'message_type' => $message_type, 'id' => $message['uid'], ); $_SESSION['online'] = $message_type; Gateway::sendToAll(json_encode($status_message)); return; case 'ping': return; case 'logout': if(isset($message['id']) && !Gateway::isUidOnline($message['id'])){ $logout_message = array( 'message_type' => 'logout', 'id' => $message['id'] ); Gateway::sendToAll(json_encode($logout_message)); Db::instance('laychat')->update('user')->cols(array('logout_timestamp'=>time(), 'status'=>'offline'))->where('uid = :uid')->bindValue('uid',$message['id'])->query(); } return; case 'chatMessage': // 聊天数据 $data = $message['data']; // 发送者,也就是当前登录用户的id $from = $data['mine']['id']; // 发送给谁 $to = $data['to']['id']; // 类型,私聊(friend)还是群组(group) $type = $data['to']['type']; // 消息格式 $message_data = array( 'username' => $data['mine']['username'], 'avatar' => $data['mine']['avatar'], 'id' => $type === 'friend' ? $from : $to, 'type' => $type, 'content' => htmlspecialchars($data['mine']['content']), 'timestamp'=> time()*1000, 'from_id' => $from, ); $new_message = array( 'message_type' => 'chatMessage', 'data' => $message_data ); // 根据类型走不同的接口发送 switch($message['data']['to']['type']){ // 私聊 case 'friend': Gateway::sendToUid($message['data']['to']['id'], json_encode($new_message)); break; // 群聊 case 'group': Gateway::sendToGroup($message['data']['to']['id'], json_encode($new_message), $client_id); break; } //自己 //Gateway::sendToCurrentClient(json_encode($new_message)); //自己 //Gateway::sendToClient($client_id, json_encode($new_message)); //私聊 //Gateway::sendToUid($message['data']['to']['id'], json_encode($new_message)); //群聊 //Gateway::sendToGroup($message['data']['to']['id'], json_encode($new_message), $client_id); //所有 //Gateway::sendToAll(json_encode($new_message)); return; default: echo "unknown message $data"; //Gateway::sendToClient($client_id, $data); } } /** * 当用户断开连接时触发 * @param int $client_id 连接id */ public static function onClose() { // 有可能多页面登录,没有全部下线 if(isset($_SESSION['laychat']['id']) && !Gateway::isUidOnline($_SESSION['laychat']['id'])){ $logout_message = array( 'message_type' => 'logout', 'id' => $_SESSION['laychat']['id'] ); Gateway::sendToAll(json_encode($logout_message)); Db::instance('laychat')->update('user')->cols(array('logout_timestamp'=>time(), 'status'=>'offline'))->where('uid = :uid')->bindValue('uid',$_SESSION['laychat']['id'])->query(); } } }
start_businessworker.php
<?php use \Workerman\Worker; use \GatewayWorker\BusinessWorker; use \Workerman\Autoloader; // 自动加载类 require_once __DIR__ . '/../vendor/autoload.php'; // bussinessWorker 进程 $worker = new BusinessWorker(); // worker名称 $worker->name = 'artimax_laychat'; // bussinessWorker进程数量 $worker->count = 4; // 服务注册地址 $worker->registerAddress = __host__.':1238'; // 如果不是在根目录启动,则运行runAll方法 if(!defined('GLOBAL_START')) { Worker::runAll(); }
start_gateway.php
<?php use \Workerman\Worker; use \GatewayWorker\Gateway; // 自动加载类 require_once __DIR__ . '/../vendor/autoload.php'; // gateway 进程,这里使用Text协议,可以用telnet测试 $gateway = new Gateway("websocket://".__host__.":2346"); // gateway名称,status方便查看 $gateway->name = 'artimax_laychat'; // gateway进程数 $gateway->count = 1; // 本机ip,分布式部署时使用内网ip $gateway->lanIp = __host__; // 内部通讯起始端口,假如$gateway->count=4,起始端口为4000 // 则一般会使用4000 4001 4002 4003 4个端口作为内部通讯端口 $gateway->startPort = 2900; // 服务注册地址 $gateway->registerAddress = __host__.':1238'; // 心跳间隔 $gateway->pingInterval = 12; // 心跳数据 //$gateway->pingData = '{"message_type":"ping"}'; // 25秒内客户端不发来任何消息则认为客户端下线 $gateway->pingNotResponseLimit = 1; // 如果不是在根目录启动,则运行runAll方法 if(!defined('GLOBAL_START')) { Worker::runAll(); }
start_register.php
<?php use \Workerman\Worker; use \GatewayWorker\Register; // 自动加载类 require_once __DIR__ . '/../vendor/autoload.php'; $register = new Register('text://'.__host__.':1238'); // 如果不是在根目录启动,则运行runAll方法 if(!defined('GLOBAL_START')) { Worker::runAll(); }
javascript.js
/* // +---------------------------------------------------------------------- // | Chat函数库 // +---------------------------------------------------------------------- // | Copyright (c) 2016-2017 http://www.nswlp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.nswlp.cn ) // +---------------------------------------------------------------------- // | Author: lwj <nswlp@nswlp.cn> // +---------------------------------------------------------------------- */ var WEB_SOCKET_SWF_LOCATION = SITE_URL + "/ymchat/static/swf/WebSocketMain.swf"; var WEB_SOCKET_DEBUG = true; var WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true; var imgerror = SITE_URL + '/ymchat/static/imgs/onerror.jpg'; var requrl = SITE_URL + '/ymchat.php?app=ymchat/'; var laychat = { appName : 'YaMeichat', initUrl : requrl + 'default&act=init', sendMessageUrl : requrl + 'default&act=sendmessage', membersUrl : requrl + 'haystack&act=members&', uploadImageUrl : requrl + 'haystack&act=uploadimg&', uploadFileUrl : requrl + 'haystack&act=uploadfile&', chatLogUrl : requrl + 'haystack&act=chatlog&', bindUrl : requrl + 'default&act=bind', updateSignUrl : requrl + 'haystack&act=updatesign&', msgBoxUrl : requrl + 'haystack&act=msgbox&', sysmsgbox : requrl, agreeUrl : requrl + 'haystack&act=agree&', getNoticeUrl : requrl + 'haystack&act=getnotice&', ligature : requrl + 'default&act=connected', address : (_con.is_ssl ? 'wss://' : 'ws://') + (_con.__host__ || document.domain) +':' + _con._wsport_, isMobile : false, setMin : true, enableAudio : false, enableVideo : false, enableGroup : false, enableFriend : false, initSkins : '24.jpg', voice : 'default.mp3', findUrl : false, inited : 0, socket : null, jq : null, /*系统分组tab*/ issystemtab : true, /*开启在线状态*/ islinestate : false, /*开启签名*/ issign : false, /*开启关于*/ copyright : true, /*开启皮肤*/ skins : false, /*开启底部消息中心*/ sysmsg : true, /*开启搜索*/ searchs : false, /*客服是否可查看聊天记录*/ brief : false, notice : _con.notice, // 是否开启桌面消息提醒,默认false //skin : ['aaa.jpg'], //新增皮肤 //right : '5px', // 主面板相对浏览器右侧距离 //minRight : '5px', // 聊天面板最小化时相对浏览器右侧距离 /*特效*/ effects : false, /*自动匹配回复*/ automatching : true, /*end*/ open : function() { if (this.inited) return; if(this.isIE6or7()) return; if(!this.jq) this.jq = $; this.connectWorkerman(); this.inited = 1; }, isIE6or7 : function(){ var b = document.createElement('b'); b.innerHTML = '<!--[if IE 5]><i></i><![endif]--><!--[if IE 6]><i></i><![endif]--><!--[if IE 7]><i></i><![endif]-->'; return b.getElementsByTagName('i').length === 1; }, connectWorkerman : function() { laychat.socket = new WebSocket(laychat.address); laychat.socket.onopen = function(){ var login_data = '{"type":"init","id":"'+ _con.uinfo.id + '","username":"'+ _con.uinfo.username + '","avatar":"'+ _con.uinfo.avatar + '","sign":"'+ _con.uinfo.sign + '"}'; //laychat.socket.send(JSON.stringify({type: 'init',id:_con.uinfo.id})); laychat.socket.send(login_data); }; laychat.socket.onmessage = function(e){ var msg = JSON.parse(e.data); // 如果layim还没有初始化就收到消息则忽略(init消息除外) if(!msg.message_type || (msg.message_type != 'init' && !layui.layim)) return; switch(msg.message_type) { // 初始化im case 'init': /*ajax请求,绑定client_id和uid*/ $.ajax({ url: laychat.bindUrl, type: 'post', data: {client_id: msg.client_id}, dataType: 'json', success: function(bindJson){ if(bindJson.code == 0){ $.ajax({ url: laychat.initUrl, type: 'post', data: {}, dataType: 'json', success: function(initData){ if(initData.code != 0){ console.log('初始化数据失败:' + initData.msg); }else{ laychat.initIM(bindJson, initData.data); } }, error: function(xhr, ajaxOptions, thrownError){ console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); }else{ console.log('绑定客户端失败:' + bindJson.msg); } }, error: function(xhr, ajaxOptions, thrownError){ console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); return; // 添加一个用户到好友列表 case 'addList': if($('#layim-friend'+msg.data.id).length == 0 && layui.layim.cache() && layui.layim.cache().id != msg.data.id){ return layui.layim.addList && layui.layim.addList(msg.data); } if (msg.data.type == 'friend') { layui.layim.setFriendStatus && layui.layim.setFriendStatus(msg.data.id, 'online'); } return; // 收到一个消息 case 'chatMessage': msg.data.content = String(msg.data.content); if(msg.data.type == 'group') { if(msg.data.from_id != layui.layim.cache().mine.id){ layui.layim.getMessage(msg.data); } }else if(layui.layim.cache().mine.id != msg.data.id){ layui.layim.getMessage(msg.data); } if(laychat.effects){ autoword.getword(msg.data.content); } lastspeech(msg.data.content,msg.data.from_id); if(msg.data.type == 'kefu'){ /*重置超时 - 按正常道理接收不应该触发重置超时*-/ time_out(); /*重置超时自动断开*/ break_out(); layui.layim.setChatStatus(''); } return; case 'msgbox': layui.layim.msgbox && layui.layim.msgbox(msg.count); return; case 'oppo': layui.layim.setChatStatus(msg.msg_data); layui.layim.setFriendStatus && layui.layim.setFriendStatus(msg.id, msg.status); return; // 退出 case 'logout': //layui.layim.setChatStatus('<span style="color:#FF5722;">对方不在线</span>'); return layui.layim.setFriendStatus && layui.layim.setFriendStatus(msg.id, 'offline'); // 隐身 case 'hide': //layui.layim.setChatStatus('<span style="color:#FF5722;">对方不在线</span>'); return layui.layim.setFriendStatus && layui.layim.setFriendStatus(msg.id, 'offline'); // 上线 case 'online': //layui.layim.setChatStatus('<span>在线</span>'); return layui.layim.setFriendStatus && layui.layim.setFriendStatus(msg.id, 'online'); // 人工客服 case 'ligature': if(_con.ligature){ $.ajax({ url: laychat.ligature, type: 'post', data: {data:{kefu:_con.ligature,laun:msg.data,to:_con.uinfo}}, dataType: 'json', success: function(lgt){}, error: function(xhr, ajaxOptions, thrownError){ console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); }else{ /*接收客服信息*/ _con.ligature = msg.data; /*给客服提示已接上*/ var kdata = {system:true,mine:_con.uinfo,to:_con.ligature}; kdata.mine.content = sprintf(_con.d_replay.userhrough,_con.uinfo.username); kdata.mine.mine = true; kdata.to.type = 'service'; $.post(laychat.sendMessageUrl, {data: kdata}, function(data){ if(data.code != 0) { ymservice.getms(_con.d_replay.userfailure); _con.ligature = null; }else{ /*提示已接上*/ ymservice.getms(sprintf(_con.d_replay.yetthrough,_con.ligature.username),true); /*开始超时自动断开*/ if(_con.d_replay.break_out) break_out(); /*接上客服就不要默认的超时了*/ keeptimes({ key : 'time_out', num : 0, bac : null, feed : null, clear : true }); /*end*/ } }, 'json'); } return; // 订单消息 case 'ordermsg': // 自动弹出 $('[type-id="sysmsgbox"]').click(); return; // 物流消息 case 'logistics': // 自动弹出 $('[type-id="logistics"]').click(); return; // 系统消息 case 'systemmsg': // 自动弹出 $('[type-id="systemmsg"]').click(); return; // 全部消息 case 'allmsg': // 自动弹出 $('[type-id="systemmsg"]').click(); return; case 'beiyong': return; } } laychat.socket.onclose = laychat.connectWorkerman; }, sendHeartbeat : function() { if(this.socket && this.socket.readyState == 1) { this.socket.send(JSON.stringify({type :'ping'})); } }, /*关闭事件*/ unload : function(){ if(this.socket){ this.socket.send(JSON.stringify({type :'logout',id:_con.uinfo.id})); //layui.layer.msg(_con.uinfo.username + ' 下线了', {time: 7000}); } }, initIM : function(msg_data, init_data){ var unread_msg_tips = function(msg_data){ // 离线交易消息 if(msg_data.msgcentre){ var clicks = false; $.each(msg_data.msgcentre,function(i,v){ if(parseInt(v)){ if(i == 'systemmsg') layui.layim.msgbox('new'); else $('[type-id="+i+"]').addClass('msgnotify'); clicks = true; } }); if(clicks) $('.layui-layim-min').click(); } // 离线消息 for(var key in msg_data.unread_message){ layui.layim.getMessage(JSON.parse(msg_data.unread_message[key])); } if (msg_data.unread_notice_count) { // 设置消息盒子未读计数 layui.layim.msgbox && layui.layim.msgbox(msg_data.unread_notice_count); } return; }; // layim已经初始化了,则只提示未读消息 if(this.inited == 2) { return unread_msg_tips(msg_data); } this.inited = 2; // 心跳数据,用来保持长链接,避免socket链接长时间不通讯被路由节点防火墙关闭 setInterval('laychat.sendHeartbeat()', 12000); var module = laychat.isMobile ? ['mobile','layedit'] : ['layim','layedit']; layui.use(module, function(layim){ _con.layedit_s = layui.layedit; _con.ymlayim = layim; _con.ymmsg = layui.layer; if (laychat.isMobile) { var mobile = layui.mobile , layim = mobile.layim , layer = mobile.layer; layui.layim = layim; layui.layer = layer; } //layim建立就绪 layim.on('ready', function(res){ // 离线消息 return unread_msg_tips(msg_data); }); //监听发送消息 layim.on('sendMessage', function(data){ var sendata = data; if(_con.ligature){ var kdata = {mine:_con.uinfo,to:_con.ligature}; kdata.mine.content = data.mine.content; kdata.mine.mine = true; kdata.to.type = 'service'; sendata = kdata; } $.ajax({ url: laychat.sendMessageUrl, type: 'post', data: {data: sendata}, dataType: 'json', success: function(sendData){ if(sendData.code != 0){ layui.layer.msg(sendData.msg, {time: 7000}); } }, error: function(xhr, ajaxOptions, thrownError){ console.log(thrownError + "\r\n" + xhr.statusText + "\r\n" + xhr.responseText); } }); if(laychat.effects){ autoword.sendword(data.mine.content); } lastspeech(data.mine.content,data.to.id); if(data.to.type == 'kefu'){ /*重置超时*/ time_out(); /*重置超时自动断开*/ break_out(); if(!_con.ligature){ layim.setChatStatus('<span style="color:#FF5722;">对方正在输入......</span>'); } } }); //监听在线状态的切换事件 layim.on('online', function(data){ laychat.socket.send(JSON.stringify({type: data,uid:layui.layim.cache().mine.id})); }); //更改个性签名 layim.on('sign', function(value){ $.post(laychat.updateSignUrl, {sign: value} , function(data){ if(data.code != 0) { layui.layer.msg(data.msg, {time: 7000}); } }, 'json'); }); //监听自定义工具栏点击,以添加代码为例 layim.on('tool(code)', function(insert){ layui.layer.prompt({ title: '插入代码 - 工具栏扩展示例' ,formType: 2 ,shade: 0 }, function(text, index){ layui.layer.close(index); insert('[pre class=layui-code]' + text + '[/pre]'); //将内容插入到编辑器 }); }); layim.on('close', function(value){ alert(999999); }); //富文本 //layedit.build('ftextarea'); layui.layim.config({ //初始化接口 init: init_data //查看群员接口 ,members: { url: laychat.membersUrl } // 上传图片 ,uploadImage: { url: laychat.uploadImageUrl } // 上传文件 ,uploadFile: { url: laychat.uploadFileUrl } //扩展工具栏 /*,tool: [ { alias : 'code' ,title: '代码' ,icon : '' } ]*/ ,initSkin: laychat.initSkins ,isgroup: laychat.enableGroup ,isfriend: laychat.enableFriend ,msgbox: laychat.msgBoxUrl ? laychat.msgBoxUrl+(laychat.msgBoxUrl.indexOf('?') == -1 ? '?' : '&')+'getNoticeUrl='+encodeURI(laychat.getNoticeUrl)+'&agreeUrl='+encodeURI(laychat.agreeUrl) : false //聊天记录地址 ,chatLog: laychat.chatLogUrl ,find: laychat.findUrl ,issigns: laychat.issign ,copyright: laychat.copyright ,skins: laychat.skins ,sysmsg: laychat.sysmsg ,sysmsgbox: laychat.sysmsgbox ,issystemtab: laychat.issystemtab ,islinestate: laychat.islinestate ,title: _con.uinfo.username ? _con.uinfo.username : laychat.appName ,min: laychat.setMin ,searchs: laychat.searchs ,isAudio: laychat.enableAudio ,isVideo: laychat.enableVideo ,voice: laychat.voice ,_brief_: laychat.brief }); }); } }; if(_con.ymopen) laychat.open();
评论列表
发表评论
热评文章
相关阅读