getAll(['user_id' => $user_ids], compact('_field'));
$users = arrayFormatKey($users, 'user_id');
$objGroupInfo = new TableHelper('group_info', 'dw_chat');
$_field = 'group_id, group_name, group_title, cover_photo, is_auth';
$groups = $objGroupInfo->getAll(['group_id' => $group_ids], compact('_field'));
$groups = arrayFormatKey($groups, 'group_id');
$userGroups = [];
if ($currentGroupId) {
$objUserGroup = new UserGroup();
$userGroups = $objUserGroup->objTable->getAll(['user_id' => $user_ids, 'group_id' => $currentGroupId], ['_field' => 'user_id, group_id']);
$userGroups = arrayFormatKey($userGroups, 'user_id', 'group_id');
}
$objRedis = dwRedis::init(Eos::REDIS_SERV);
$fieldTime = [];
$fieldPin = [];
foreach ($list as $i => $item) {
if ($item['is_group']) {
$group = $groups[$item['session_id']];
$item['name'] = $group['group_title'] ?: $group['group_name'];
$item['cover_photo'] = $group['cover_photo'];
$item['is_auth'] = $group['is_auth'];
} else {
// 把自己的用户名换掉
$key = self::getToUser($user_id, $item['session_id']);
$user = $users[$key];
$item['name'] = $user['nick_name'];
$item['cover_photo'] = $user['cover_photo'];
$item['in_group'] = $userGroups[$key] ? 1 : 0; // 已经在群
}
$lastNum = self::getLastMsgNum($item['session_id']);
$item['unread'] = max($lastNum - $item['read_num'], 0);
$item['cover_photo'] = coverReplaceImage($item['cover_photo']);
$item['last_msg'] = self::getLastMsg($item['session_id'], $objRedis);
$item['update_time_int'] = $item['last_msg']['time'] ?: 0;
$fieldPin[] = $item['pin_time_int'];
$fieldTime[] = $item['update_time_int'];
$list[$i] = $item;
}
array_multisort($fieldPin, SORT_DESC, $fieldTime, SORT_DESC, $list);
return $list;
}
public function getMsgList($session_id, $read_hash, $load_type, $is_group) {
$where2 = [];
if ($is_group) {
$_field = '`hash`, `from`, `msg`, `msg_type`, `state`, create_time_int, msg_num, ext_info';
$objMsg = new TableHelper('group_msg', 'dw_chat');
$where2['group_id'] = $session_id;
} else {
$_field = '`hash`, `from`, `to`, `msg`, `msg_type`, `state`, create_time_int, msg_num, ext_info';
$objMsg = new TableHelper('person_msg', 'dw_chat');
$where2['session_id'] = $session_id;
}
if ($read_hash) {
$currentRow = $objMsg->getRow(['hash' => $read_hash], compact('_field'));
$create_time_int = (int) $currentRow['create_time_int'];
} else {
$create_time_int = 0;
}
$_limit = 50;
if ($load_type == 0) {
$create_time_int && $_where = "create_time_int >= {$create_time_int}";
$_sortKey = "create_time_int DESC";
$keyWord2 = compact('_where', '_sortKey', '_limit', '_field');
$list = $objMsg->getAll($where2, $keyWord2);
} else {
// 加载历史记录
$_where = "create_time_int < {$create_time_int}";
$_sortKey = "create_time_int DESC";
$keyWord3 = compact('_where', '_sortKey', '_limit', '_field');
$list = $objMsg->getAll($where2, $keyWord3);
}
$list = array_reverse($list);
$list = $this->appendExtInfo($list);
$user_ids = array_column($list, 'from');
if (!$is_group) {
$to_ids = array_column($list, 'to');
$user_ids = array_merge($user_ids, $to_ids);
}
$user_ids = array_unique($user_ids);
$userMap = $this->getUserMap($user_ids);
return compact('userMap', 'list');
}
/**
* 额外信息
* @author solu
* @param $list
* @return mixed
*/
private function appendExtInfo($list) {
$userId = User::getUserId();
$objRedpackLog = new RedpackLog();
$trxIds = array_map(function($v) {
$msg = Utils::decodeRC4($v['msg']);
$data = json_decode($msg, true);
return $data['trxId'];
}, array_filter($list, function($v) {
return $v['msg_type'] == self::MSG_TYPE_REDPACK;
}));
$redpack = [];
if ($trxIds) {
$objRedpack = new Redpack();
$redpack = $objRedpack->objTable->getAll(['transfer_trx_id' => $trxIds], ['_field' => 'transfer_trx_id, status']);
$redpack = arrayFormatKey($redpack, 'transfer_trx_id', 'status');
}
foreach ($list as $k => $v) {
if ($v['msg_type'] == self::MSG_TYPE_REDPACK) {
$msg = Utils::decodeRC4($v['msg']);
$data = json_decode($msg, true);
$trxId = $data['trxId'];
$v['ext']['grabbed'] = $objRedpackLog->userGrabbed($userId, $trxId);
$v['ext']['redpack_status'] = intval($redpack[$trxId]);
}
$v['ext_info'] && $v['ext_info'] = json_decode($v['ext_info'], true);
$list[$k] = $v;
}
return $list;
}
public function getUserMap($user_ids) {
$objUserInfo = new TableHelper('user_info', 'dw_chat');
$datas = $objUserInfo->getAll(['user_id' => $user_ids], ['_field' => 'user_id, user_name, nick_name, cover_photo']);
coverReplaceArrImage($datas, 'cover_photo');
return arrayFormatKey($datas, 'user_id');
}
/**
* 修改状态
* @param $session_id
* @param $newData
* @param $ext;
*/
public function updateState($session_id, $newData, $ext = []) {
$where = compact('session_id');
$where = array_merge($where, $ext);
$newData['update_time'] = NOW;
$newData['update_time_int'] = microtime(true) * 1000;
$this->objTable->updateObject($newData, $where);
}
/**
* 检测私聊session
* @author solu
* @param $from
* @param $sessionId
* @return array
* @throws Exception
*/
public function checkPersonSession($from, $sessionId) {
$uids = explode('-', $sessionId);
$uids = array_filter($uids, function ($v) {return $v > 0;});
// if (count($uids) != 2 || !$this->objTable->getRow(['user_id' => $from, 'session_id' => $sessionId])) {
// throw new Exception('session_id error', CODE_PARAM_ERROR);
// }
if (!in_array($from, $uids)) {
throw new Exception('user not in session', CODE_NO_PERMITION);
}
$to = 0;
foreach ($uids as $uid) {
if ($uid != $from) {
$to = $uid;
break;
}
}
return [$from, $to];
}
/**
* 检测群session
* @author solu
* @param $from
* @param $sessionId
* @return bool
* @throws Exception
*/
public function checkGroupSession($from, $sessionId) {
if (!$this->objTable->getRow(['user_id' => $from, 'session_id' => $sessionId])) {
throw new Exception('user not in session', CODE_NO_PERMITION);
}
return true;
}
public static function getPersonSessionId($from, $to) {
if ($from > $to) {
return "{$to}-{$from}";
} else {
return "{$from}-{$to}";
}
}
private function initPersonSession($from, $to) {
$session_id = self::getPersonSessionId($from, $to);
$num = $this->objTable->getCount(compact('session_id'));
if ($num < 2) { // 单方面删除会话的情况
// 插入双方的session
$datas = [[
'user_id' => $from,
'session_id' => $session_id,
'is_group' => 0,
], [
'user_id' => $to,
'session_id' => $session_id,
'is_group' => 0,
]
];
// 第一次初始化,需要初始化
$this->objTable->addObjectsIfNoExist($datas);
}
}
/**
* 发送私聊消息
* @author solu
* @param $from
* @param $sessionId
* @param $msg_type
* @param $msg
* @param $noEvent
* @param $extInfo
* @return array
* @throws Exception
*/
public function sendPersonMsg($from, $sessionId, $msg_type, $msg, $noEvent = false, $extInfo = []) {
list($from, $to) = $this->checkPersonSession($from, $sessionId);
$this->initPersonSession($from, $to);
$t = self::getMS();
0 == $msg_type && $msg = htmlentities($msg);
$lastNum = self::incrLastMsgNum($sessionId);
$data = [
'session_id' => $sessionId,
'from' => intval($from),
'to' => intval($to),
'msg_type' => $msg_type,
'msg' => $msg,
'create_time' => NOW,
'create_time_int' => $t,
'msg_num' => $lastNum,
];
$extInfo && $data['ext_info'] = json_encode($extInfo);
$data['hash'] = self::_genHash($data);
$objPersonMsg = new TableHelper('person_msg', 'dw_chat');
if (!$objPersonMsg->addObject($data)) {
throw new Exception('send message error', CODE_NORMAL_ERROR);
}
// 更新发送人已读序号
$this->updateState($sessionId, ['read_num' => $lastNum], ['user_id' => $from]);
$name = User::getUserNameById($from);
$content = self::_msgHandle($msg, $msg_type);
$eventData = [
'type' => 'msg',
'msg_type' => $msg_type,
'from' => intval($from),
'to' => intval($to),
'name' => $name,
'nick_name' => User::getUserNameById($from),
'content' => $content,
'hash' => $data['hash'],
'timestamp' => $t,
'ext_info' => $extInfo,
];
!$noEvent && ThirdApi::pushPersonEvent($to, $eventData);
!$noEvent && ThirdApi::pushPersonEvent($from, $eventData);
self::setLastMsg($sessionId, $msg_type, $content, $from, $name, $extInfo);
$eventData['content'] = $msg;
return $eventData;
}
/**
* 发送群聊消息
* @author solu
* @param $from
* @param $groupId
* @param $msg_type
* @param $msg
* @param $noEvent
* @param $noTg
* @param $extInfo
* @return array
* @throws Exception
*/
public function sendGroupMsg($from, $groupId, $msg_type, $msg, $noEvent = false, $noTg = false, $extInfo = []) {
$userMap = null;
$objGroupInfo = new GroupInfo();
if ($extInfo['event_type'] != 'leave_group' && !$this->objTable->getRow(['user_id' => $from, 'session_id' => $groupId])) {
// 聊天就自动加入群
// 检查私有群的权限
$objGroupInfo->checkPermission($groupId, $from);
// 第一次发言,需要返回用户信息
$objGroupInfo->joinGroup($from, $groupId);
$userMap = $this->getUserMap($from);
} else if ((new UserGroup())->isBlock($groupId, $from)) {
throw new Exception('Banned', CODE_NORMAL_ERROR);
}
$t = self::getMS();
0 == $msg_type && $msg = htmlentities($msg);
$lastNum = self::incrLastMsgNum($groupId);
$data = [
'group_id' => intval($groupId),
'from' => $from,
'msg_type' => $msg_type,
'msg' => $msg,
'create_time' => NOW,
'create_time_int' => $t,
'msg_num' => $lastNum,
];
$extInfo && $data['ext_info'] = json_encode($extInfo);
$data['hash'] = self::_genHash($data);
$objGroupMsg = new TableHelper('group_msg', 'dw_chat');
if (!$objGroupMsg->addObject($data)) {
throw new Exception('send message error', CODE_NORMAL_ERROR);
}
// 更新发送人已读序号
$this->updateState($groupId, ['read_num' => $lastNum], ['user_id' => $from]);
$content = self::_msgHandle($msg, $msg_type);
$name = GroupInfo::getGroupNameById($groupId);
$eventData = [
'type' => 'msg',
'msg_type' => $msg_type,
'from' => $from,
'name' => $name,
'nick_name' => User::getUserNameById($from),
'content' => $content,
'hash' => $data['hash'],
'timestamp' => $t,
'ext_info' => $extInfo,
];
!$noEvent && ThirdApi::pushGroupEvent($groupId, $eventData);
self::setLastMsg($groupId, $msg_type, $content, $from, $name, $extInfo);
$eventData['content'] = $msg;
$eventData['userMap'] = $userMap;
// 推送到Telegram
$group = $objGroupInfo->objTable->getRow(['group_id' => $groupId], ['_field' => 'group_name, tg_group_id']);
if ($group['tg_group_id'] && !$noTg && $msg_type != self::MSG_TYPE_REPEAL) {
// 特殊处理红包
if ($msg_type == self::MSG_TYPE_REDPACK) {
$url = 'https:' . URL_SELF . "/s/{$group['group_name']}";
$text = "
[收到MeeChat红包,请打开MeeChat查看]";
} else {
$text = Utils::decodeRC4($msg);
}
$text = "{$eventData['nick_name']}:
{$text}";
Telegram::pushMessageList(['chat_id' => $group['tg_group_id'], "text" => $text, 'parse_mode' => 'HTML']);
}
return $eventData;
}
private static function _genHash($data) {
return md5(json_encode($data));
}
public static function _msgHandle($content, $msg_type, $len = 16) {
if ($msg_type > 0) { // 只处理文本
return $content;
}
$source = Utils::decodeRC4($content);
!$source && $source = $content;
if (mb_strlen($source) > $len) {
$source = mb_substr($source, 0, $len);
}
return Utils::encodeRC4($source);
}
public static function getMS() {
return intval(microtime(true) * 1000);
}
/**
* 自增session num
* @author solu
* @param $sessionId
* @return int
*/
public static function incrLastMsgNum($sessionId) {
$objRedis = dwRedis::init(Eos::REDIS_SERV);
// 存在原子性问题
if ($objRedis->hExists(self::LAST_MSG_NUM_HASH, $sessionId)) {
return $objRedis->hIncrBy(self::LAST_MSG_NUM_HASH, $sessionId, 1);
}
if (is_numeric($sessionId)) { // 群组
$objGroupMsg = new GroupMsg();
$c = $objGroupMsg->objTable->getCount(['group_id' => $sessionId]);
} else {
$objPersonMsg = new PersonMsg();
$c = $objPersonMsg->objTable->getCount(['session_id' => $sessionId]);
}
$c += 1;
return $objRedis->hIncrBy(self::LAST_MSG_NUM_HASH, $sessionId, $c);
}
/**
* 获取session最新num
* @author solu
* @param $sessionId
* @param null $objRedis
* @return int
*/
public static function getLastMsgNum($sessionId, $objRedis = null) {
!$objRedis && $objRedis = dwRedis::init(Eos::REDIS_SERV);
return $objRedis->hGet(self::LAST_MSG_NUM_HASH, $sessionId) ?: 0;
}
public static function setLastMsg($sessionId, $msgType, $content, $from, $name, $extInfo = []) {
$objRedis = dwRedis::init(Eos::REDIS_SERV);
$msgType != self::MSG_TYPE_TEXT && $content = '';
$data = [
'msg_type' => $msgType,
'event_type' => $msgType == self::MSG_TYPE_EVENT ? $extInfo['event_type'] : '',
'content' => $content,
'from' => $from,
'name' => $name,
'nick_name' => User::getUserNameById($from),
'time' => self::getMS(),
];
$objRedis->hSet(self::LAST_MSG_HASH, $sessionId, json_encode($data));
}
public static function getLastMsg($sessionId, $objRedis = null) {
!$objRedis && $objRedis = dwRedis::init(Eos::REDIS_SERV);
if ($objRedis->hExists(self::LAST_MSG_HASH, $sessionId)) {
$json = $objRedis->hGet(self::LAST_MSG_HASH, $sessionId);
return json_decode($json, true);
}
$isGroup = is_numeric($sessionId);
if ($isGroup) { // 群组
$objGroupMsg = new GroupMsg();
$row = $objGroupMsg->objTable->getRow(['group_id' => $sessionId]);
} else {
$objPersonMsg = new PersonMsg();
$row = $objPersonMsg->objTable->getRow(['session_id' => $sessionId]);
}
$data = null;
if ($row) {
$msg_type = $row['msg_type'];
$content = '';
$from = $row['from'];
if ($msg_type == self::MSG_TYPE_TEXT) {
$content = self::_msgHandle($row['msg'], $msg_type);
}
$nick_name = User::getUserNameById($from);
$time = self::getMS();
$data = compact('msg_type', 'content', 'from', 'nick_name', 'time');
$objRedis->hSet(self::LAST_MSG_HASH, $sessionId, json_encode($data));
}
return $data;
}
public static function getToUser($from, $sessionId) {
$_tmp = explode('-', $sessionId);
foreach ($_tmp as $_uid) {
if ($_uid != $from) {
return $_uid;
}
}
return 0;
}
}