Commit 65fb54d2 by HanSon

开始消息模块

1 parent b29bc04a
...@@ -18,3 +18,8 @@ Robot->special ...@@ -18,3 +18,8 @@ Robot->special
Robot->contact Robot->contact
Robot->group Robot->group
# what can wx-robot do?
* 转发消息
* 记录特别消息
* 特别关注某人
\ No newline at end of file \ No newline at end of file
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "01d02b438cdd61b6f9c0202caaf088fb", "hash": "a651fd0a020b70751704aec9ca9217f9",
"content-hash": "524011ccf768eadbec9c686506e6057c", "content-hash": "524011ccf768eadbec9c686506e6057c",
"packages": [ "packages": [
{ {
...@@ -648,7 +648,7 @@ ...@@ -648,7 +648,7 @@
}, },
{ {
"name": "symfony/css-selector", "name": "symfony/css-selector",
"version": "v3.2.0", "version": "v3.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/css-selector.git", "url": "https://github.com/symfony/css-selector.git",
...@@ -701,16 +701,16 @@ ...@@ -701,16 +701,16 @@
}, },
{ {
"name": "symfony/dom-crawler", "name": "symfony/dom-crawler",
"version": "v3.2.0", "version": "v3.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/dom-crawler.git", "url": "https://github.com/symfony/dom-crawler.git",
"reference": "c6b6111f5aae7c58698cdc10220785627ac44a2c" "reference": "1638c7534a8a2fa0bf9e979f9aacb6d7e8e9e24e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://packagist.phpcomposer.com/files/symfony/dom-crawler/c6b6111f5aae7c58698cdc10220785627ac44a2c.zip", "url": "https://packagist.phpcomposer.com/files/symfony/dom-crawler/1638c7534a8a2fa0bf9e979f9aacb6d7e8e9e24e.zip",
"reference": "c6b6111f5aae7c58698cdc10220785627ac44a2c", "reference": "1638c7534a8a2fa0bf9e979f9aacb6d7e8e9e24e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
...@@ -753,11 +753,11 @@ ...@@ -753,11 +753,11 @@
], ],
"description": "Symfony DomCrawler Component", "description": "Symfony DomCrawler Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-11-25 12:32:42" "time": "2016-12-10 14:24:53"
}, },
{ {
"name": "symfony/options-resolver", "name": "symfony/options-resolver",
"version": "v3.2.0", "version": "v3.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/options-resolver.git", "url": "https://github.com/symfony/options-resolver.git",
......
...@@ -9,13 +9,46 @@ ...@@ -9,13 +9,46 @@
namespace Hanson\Robot\Core; namespace Hanson\Robot\Core;
use Closure; use Closure;
use Hanson\Robot\Message\Message;
use Hanson\Robot\Support\Log;
class MessageHandler class MessageHandler
{ {
protected $server;
private $syncHost;
private $handler; private $handler;
static $instance = null;
const MESSAGE_MAP = [
2 => 'text', // 新消息
3 => 'unknown', // 未知
4 => 'contactUpdate', // 通讯录更新
6 => 'money', // 可能是红包
7 => 'mobile' // 手机上操作了微信
];
public function __construct(Server $server)
{
$this->server = $server;
}
/**
* get a message handler single instance
*
* @param Server $server
* @return MessageHandler
*/
public static function getInstance($server = null)
{
if(static::$instance === null){
static::$instance = new MessageHandler($server);
}
return static::$instance;
}
public function setMessageHandler(Closure $closure) public function setMessageHandler(Closure $closure)
{ {
...@@ -26,9 +59,157 @@ class MessageHandler ...@@ -26,9 +59,157 @@ class MessageHandler
$this->handler = $closure; $this->handler = $closure;
} }
/**
* listen the chat api
*/
public function listen() public function listen()
{ {
call_user_func_array($this->handler, []); $this->preCheckSync();
while (true){
$time = time();
list($retCode, $selector) = $this->checkSync();
if(in_array($retCode, ['1100', '1101'])){ # 微信客户端上登出或者其他设备登录
break;
}elseif ($retCode == 0){
$this->handlerMessage($selector);
}else{
$this->debugMessage($retCode, $selector, 10);
}
$this->checkTime($time);
}
// call_user_func_array($this->handler, []);
}
private function handlerMessage($selector)
{
if($selector === 0){
return;
}
$message = $this->sync();
Message::make($selector, $message);
// print_r($message);
Log::echo(json_encode($message));
}
/**
* get a message code
*
* @return array
*/
private function checkSync()
{
$url = 'https://' . $this->syncHost . '/cgi-bin/mmwebwx-bin/synccheck?' . http_build_query([
'r' => time(),
'sid' => $this->server->sid,
'uin' => $this->server->uin,
'skey' => $this->server->skey,
'deviceid' => $this->server->deviceId,
'synckey' => $this->server->syncKeyStr,
'_' => time()
]);
try{
$content = $this->server->http->get($url);
preg_match('/window.synccheck=\{retcode:"(\d+)",selector:"(\d+)"\}/', $content, $matches);
return [$matches[1], $matches[2]];
}catch (\Exception $e){
return [-1, -1];
}
}
/**
* test a domain before sync
*
* @return bool
*/
private function preCheckSync()
{
foreach (['webpush.', 'webpush2.'] as $host) {
$this->syncHost = $host . Server::BASE_HOST;
list($retCode,) = $this->checkSync();
if($retCode == 0){
return true;
}
}
return false;
}
private function sync()
{
$url = sprintf(Server::BASE_URI . '/webwxsync?sid=%s&skey=%s&lang=en_US&pass_ticket=%s', $this->server->sid, $this->server->skey, $this->server->passTicket);
try{
$result = $this->server->http->json($url, [
'BaseRequest' => $this->server->baseRequest,
'SyncKey' => $this->server->syncKey,
'rr' => ~time()
], true);
if($result['BaseResponse']['Ret'] == 0){
$this->generateSyncKey($result);
}
return $result;
}catch (\Exception $e){
return null;
}
}
/**
* generate a sync key
*
* @param $result
*/
private function generateSyncKey($result)
{
$this->server->syncKey = $result['SyncKey'];
$syncKey = [];
foreach ($this->server->syncKey['List'] as $item) {
$syncKey[] = $item['Key'] . '_' . $item['Val'];
}
$this->server->syncKeyStr = implode('|', $syncKey);
}
/**
* check message time
*
* @param $time
*/
private function checkTime($time)
{
$checkTime = time() - $time;
if($checkTime < 0.8){
sleep(1 - $checkTime);
}
}
/**
* debug while the sync
*
* @param $retCode
* @param $selector
* @param null $sleep
*/
private function debugMessage($retCode, $selector, $sleep = null)
{
Log::echo('[DEBUG] retcode:' . $retCode . ' selector:' . $selector);
if($sleep){
sleep($sleep);
}
} }
} }
\ No newline at end of file \ No newline at end of file
...@@ -26,21 +26,21 @@ class Server ...@@ -26,21 +26,21 @@ class Server
public $skey; public $skey;
protected $sid; public $sid;
protected $uin; public $uin;
public $passTicket; public $passTicket;
protected $deviceId; public $deviceId;
public $baseRequest; public $baseRequest;
protected $syncKey; public $syncKey;
protected $myAccount; static $myAccount;
protected $syncKeyStr; public $syncKeyStr;
public $http; public $http;
...@@ -74,7 +74,7 @@ class Server ...@@ -74,7 +74,7 @@ class Server
$this->initContact(); $this->initContact();
Log::echo('[INFO] init contacts success!'); Log::echo('[INFO] init contacts success!');
MessageHandler::listen(); MessageHandler::getInstance()->listen();
} }
public function prepare() public function prepare()
...@@ -144,8 +144,6 @@ class Server ...@@ -144,8 +144,6 @@ class Server
$content = $this->http->get($url); $content = $this->http->get($url);
Log::echo($content);
preg_match('/window.code=(\d+);/', $content, $matches); preg_match('/window.code=(\d+);/', $content, $matches);
$code = $matches[1]; $code = $matches[1];
...@@ -219,7 +217,7 @@ class Server ...@@ -219,7 +217,7 @@ class Server
$result = json_decode($content, true); $result = json_decode($content, true);
$this->generateSyncKey($result); $this->generateSyncKey($result);
$this->myAccount = $result['User']; static::$myAccount = $result['User'];
if($result['BaseResponse']['Ret'] != 0){ if($result['BaseResponse']['Ret'] != 0){
throw new Exception('[ERROR] init fail!'); throw new Exception('[ERROR] init fail!');
...@@ -241,8 +239,8 @@ class Server ...@@ -241,8 +239,8 @@ class Server
$this->http->json($url, [ $this->http->json($url, [
'BaseRequest' => $this->baseRequest, 'BaseRequest' => $this->baseRequest,
'Code' => 3, 'Code' => 3,
'FromUserName' => $this->myAccount['UserName'], 'FromUserName' => static::$myAccount['UserName'],
'ToUserName' => $this->myAccount['UserName'], 'ToUserName' => static::$myAccount['UserName'],
'ClientMsgId' => time() 'ClientMsgId' => time()
]); ]);
} }
...@@ -260,6 +258,20 @@ class Server ...@@ -260,6 +258,20 @@ class Server
$this->syncKeyStr = implode('|', $syncKey); $this->syncKeyStr = implode('|', $syncKey);
} }
public static function isMyself($fromUserName)
{
return $fromUserName === static::$myAccount['UserName'];
}
public function setMessageHandler(\Closure $closure)
{
if(!is_callable($closure)){
throw new \Exception('[ERROR] message handler must be a closure!');
}
MessageHandler::getInstance($this)->setMessageHandler($closure);
}
public function debug($debug = true) public function debug($debug = true)
{ {
$this->debug = $debug; $this->debug = $debug;
......
...@@ -9,7 +9,46 @@ ...@@ -9,7 +9,46 @@
namespace Hanson\Robot\Message; namespace Hanson\Robot\Message;
use Hanson\Robot\Core\Server;
class Message class Message
{ {
public $sender;
public $receiver;
public $content;
public $time;
public $type;
static $message = [];
const USER_MAP = [
0 => 'Init',
1 => 'Self',
2 => 'FileHelper',
3 => 'Group',
4 => 'Contact',
5 => 'Public',
6 => 'Special',
99 => 'UnKnown',
];
public function make($selector, $message)
{
$msg = $message['AddMsgList'][0];
if($msg['MsgType'] == 51){
$this->sender->name = 'system';
$this->sender->type = 0;
}elseif ($msg['MsgType'] == 37){
$this->sender->type = 37;
}elseif (Server::isMyself($msg['FromUserName'])){
}
}
} }
\ No newline at end of file \ No newline at end of file
...@@ -15,7 +15,17 @@ $robot = new \Hanson\Robot\Robot([ ...@@ -15,7 +15,17 @@ $robot = new \Hanson\Robot\Robot([
'tuling_key' => '' 'tuling_key' => ''
]); ]);
//$robot->setMessageHandler(function($message){ //$robot->run();
$robot = new \Hanson\Robot\Foundation\Robot([
'tmp' => realpath('./tmp') . '/',
'debug' => true,
'tuling' => true,
'tuling_key' => ''
]);
$robot->server->setMessageHandler(function($message){
// if($message->type === 'text'){ // if($message->type === 'text'){
// //
// }elseif ($message->type === 'location'){ // }elseif ($message->type === 'location'){
...@@ -25,16 +35,6 @@ $robot = new \Hanson\Robot\Robot([ ...@@ -25,16 +35,6 @@ $robot = new \Hanson\Robot\Robot([
// if($message->FromUserName === ''){ // if($message->FromUserName === ''){
// # do something; // # do something;
// } // }
//
//});
//$robot->run();
$robot = new \Hanson\Robot\Foundation\Robot([
'tmp' => realpath('./tmp') . '/',
'debug' => true,
'tuling' => true,
'tuling_key' => ''
]);
});
$robot->server->run(); $robot->server->run();
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!