public function testAllInOne()
 {
     // ²âÊÔ´òÓ¡µ½ÆÁÄ»
     BigpipeLog::debug('[%s:%u][%s][debug]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::trace('[%s:%u][%s][trace]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::notice('[%s:%u][%s][notice]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::monitor('[%s:%u][%s][monitor]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::warning('[%s:%u][%s][warning]', __FILE__, __LINE__, __FUNCTION__);
     BigpipeLog::fatal('[%s:%u][%s][fatal]', __FILE__, __LINE__, __FUNCTION__);
     // ²âÊÔ²»Êä³ö´òÓ¡ÐÅÏ¢log configure
     $conf = new BigpipeLogConf();
     $conf->severity = BigpipeLogSeverity::FATAL;
     $conf->disable_ostream = true;
     $fatal_log = sprintf('[%s:%u][%s][fatal message]', __FILE__, __LINE__, __FUNCTION__);
     $warning_Log = sprintf('[%s:%u][%s][warning]', __FILE__, __LINE__, __FUNCTION__);
     $this->assertTrue(BigpipeLog::init($conf));
     BigpipeLog::fatal('%s', $fatal_log);
     $msg = BigpipeLog::get_last_error_message();
     BigpipeLog::warning('%s', $warning_Log);
     $this->assertEquals($msg, BigpipeLog::get_last_error_message());
     $new_fatal_log = sprintf('[%s:%u][%s][fatal new message]', __FILE__, __LINE__, __FUNCTION__);
     $this->assertTrue($msg == BigpipeLog::get_last_error_message());
     // ²âÊÔclose
     BigpipeLog::close();
 }
 /**
  * 生成unique id
  * @return string unique id
  */
 public static function get_session_id($pipe_name)
 {
     $hostip = '127.0.0.0';
     // default host ip
     ##$host = gethostname(); // can not be used before php 5.3
     $host = php_uname('n');
     if (false === $host) {
         BigpipeLog::warning('[%s:%u][%s][no host name. use default value: %s]', __FILE__, __LINE__, __FUNCTION__, $hostip);
     } else {
         $hostip = gethostbyname($host);
         if (false === $hostip) {
             BigpipeLog::warning('[%s:%u][%s][no ip on host use default local ip: 127.0.0.0][host name:%s]', __FILE__, __LINE__, __FUNCTION__, $host);
         }
     }
     // session格式为
     // hostip + 精确得到1天半的时间戳 + pid + pipe_name
     $timestamp = time() >> 17;
     // 精确到1天半的时间戳
     $uid = sprintf('%s-%u-%u-%s', $hostip, $timestamp, getmypid(), $pipe_name);
     return $uid;
 }
 /**
  * 将message package 写入buffer<p>
  * @param binary $buff: 传入一个buffer的引用
  * @return true on success or false on failure
  */
 public function store(&$buff)
 {
     if ($this->is_empty()) {
         BigpipeLog::warning('[store error][empty message package]');
         return false;
     }
     $buff .= pack("L1", $this->_count);
     $buff .= $this->_data;
     return true;
 }
 /**
  * 删除一个stop状态的queue
  * @param string $name        : name of the queue
  * @param string $token       : token of the queue
  * @param array  $meta_params : meta配置信息
  * @return boolean
  */
 public static function delete_queue($name, $token, $meta_params)
 {
     // 参数检查
     if (false === is_array($meta_params) || true === empty($name) || true === empty($token)) {
         BigpipeLog::fatal("[%s:%u][%s][invalid params]", __FILE__, __LINE__, __FUNCTION__);
         return false;
     }
     $meta = true === self::$unittest ? self::$stub_meta : self::_init_meta($meta_params);
     if (false === $meta) {
         BigpipeLog::fatal("[%s:%u][%s][fail to init meta]", __FILE__, __LINE__, __FUNCTION__);
         return false;
     }
     // 读取queue entry信息
     $full_entry = sprintf('queue/%s', $name);
     $stat = array('version' => 'for test');
     //仅在测试时有用
     $queue_info = $meta->get_entry($full_entry, $stat);
     if (false === $queue_info) {
         BigpipeLog::fatal("[%s:%u][%s][can not access to queue under /%s]", __FILE__, __LINE__, __FUNCTION__, $full_entry);
         return false;
     }
     if ($token != $queue_info['token']) {
         BigpipeLog::fatal("[%s:%u][%s][wrong token][entry:%s]", __FILE__, __LINE__, __FUNCTION__, $full_entry);
         return false;
     }
     $status = $queue_info['status'];
     if (BigpipeQueueStatus::STOPPED != $status) {
         // 只删除stop状态的queue node
         BigpipeLog::warning("[%s:%u][%s][please stop the queue before delete it][entry:%s][status:%s]", __FILE__, __LINE__, __FUNCTION__, $full_entry, BigpipeQueueStatus::to_string($status));
         return false;
     }
     $curr_version = $stat['version'];
     $queue_info['status'] = BigpipeQueueStatus::STOPPED;
     // change status of a queue
     $ret = $meta->delete_entry($full_entry);
     if (false === $ret) {
         BigpipeLog::fatal("[%s:%u][%s][fail to delete the queue][name:%s][ver:%u]", __FILE__, __LINE__, __FUNCTION__, $name, $curr_version);
         return false;
     }
     BigpipeLog::notice("[%s:%u][%s][queue is deleted][name:%s]", __FILE__, __LINE__, __FUNCTION__, $name);
     return true;
 }
 /**
  * 从zk中读取一个node并,反序列化node value数组
  * @return mixed value of a node. <p>
  *         return value converted into associative arrays on success. <p>
  *         return false on failure
  */
 public function deserialize($buff)
 {
     // unpack head
     $this->_content = $buff;
     $head_arr = unpack("C1ver/C1len/S1flags/L1bdlen", $this->_content);
     $this->_version = $head_arr['ver'];
     $this->_length = $head_arr['len'];
     $this->_flags = $head_arr['flags'];
     $this->_body_len = $head_arr['bdlen'];
     $obj = json_decode(substr($this->_content, $this->_length), true);
     if (null === $obj) {
         BigpipeLog::warning("[%s:%u][%s][fail to decode meta node][ver:%d][flags:%u][len:%u]", __FILE__, __LINE__, __FUNCTION__, $this->_version, $this->_flags, $this->_body_len);
         $obj = false;
     } else {
         BigpipeLog::notice("[%s:%u][%s][meta node header][ver:%d][flags:%u][len:%u]", __FILE__, __LINE__, __FUNCTION__, $this->_version, $this->_flags, $this->_body_len);
     }
     return $obj;
 }
 public static function get_private_method(&$obj, $method_name)
 {
     $ret = version_compare(PHP_VERSION, '5.3.0', '>=') ? true : false;
     if (true === $ret) {
         // 使用5.3.0的功能
         $method = new ReflectionMethod($obj, $method_name);
         $method->setAccessible(true);
         // >=php5.3可用
         return $method;
     } else {
         BigpipeLog::warning('unsported function in PHP < 5.3.0');
     }
     return $ret;
 }
 /**
  * 从config array中读取配置<p>
  * 不支持嵌套config array, 既config中嵌套config array
  * @param array $conf_arr
  * @return true on success or false on failure
  */
 protected static function _array_to_object($conf_arr, &$elem)
 {
     try {
         $obj = new ReflectionClass($elem);
         $fields = $obj->getProperties();
         foreach ($fields as $fld) {
             if (isset($conf_arr[$fld->name])) {
                 $val = $conf_arr[$fld->name];
                 if (true === is_array($val)) {
                     // 不允许用本函数给配置项赋一个array
                     BigpipeLog::warning('[%s:%u][%s][can set an array to the config element][name:%s]', __FILE__, __LINE__, __FUNCTION__, $fld->name);
                     return false;
                 } else {
                     $fld->setValue($elem, $val);
                 }
             } else {
                 // 检查是否有默认配置
                 $val = $fld->getValue($elem);
                 if (null === $val) {
                     // 配置没有默认值,必须在配置文件里给出
                     BigpipeLog::warning('[%s:%u][%s][missing configure item][name:%s]', __FILE__, __LINE__, __FUNCTION__, $fld->name);
                     return false;
                 }
             }
             // end of check defulat value
         }
         // end of traverse each fields of 'this' object
     } catch (Exception $e) {
         BigpipeLog::warning('[%s:%u][%s][fail to load configure][error message:%s]', __FILE__, __LINE__, __FUNCTION__, $e->getMessage());
         return false;
     }
     return true;
 }
 /**
  *  从传入buff中读取command type
  * @param binary string $buff:传入协议流
  * @return int32_t command type on success or UNKNOWN_TYPE on failure
  */
 public static function get_command_type($buff)
 {
     if (2 > strlen($buff)) {
         BigpipeLog::warning('[fail to get command type]');
         return MetaAgentFrameType::UNKNOWN_TYPE;
     }
     $ai = unpack("l1int", $buff);
     $type = $ai["int"];
     return $type;
 }
 /**
  * List the children of the given path, i.e. the name of the directories
  * within the current node, if any
  * @param string $path the path to the node
  * @return array the subpaths within the given node
  */
 public function get_children($path)
 {
     if (false === $this->_inited) {
         BigpipeLog::warning("[%s:%u][%s][uninited]", __FILE__, __LINE__, __FUNCTION__);
         return false;
     }
     if (strlen($path) > 1 && preg_match('@/$@', $path)) {
         // remove trailing /
         $path = substr($path, 0, -1);
     }
     return $this->_zk->getChildren($path);
 }
 /**
  * Uninitialize the meta on meta agent
  * @param $meta_name : string of meta name
  * @return void type
  */
 private function _uninit_meta($meta_name)
 {
     if (null == $this->meta_name) {
         return;
         // 不需要释放meta
     }
     // create uninit_meta_command
     $cmd = new UninitMetaFrame();
     $cmd->meta_name = $this->meta_name;
     // send
     $res_body = $this->_request($cmd);
     if (null === $res_body) {
         $this->meta_name = null;
         BigpipeLog::warning('[uninit_meta error][%s][%s]', $this->last_error_message, $cmd->last_error_message());
         $this->last_error_message = "_uninit_meta no ack";
         return;
     }
     // parse ack
     $ack = new UninitMetaAckFrame();
     if (!$ack->load($res_body)) {
         $this->last_error_message = '_uninit_meta error ack';
         $this->meta_name = null;
         BigpipeLog::warning('[%s:%u][%s][ack error][%s][%s]', __FILE__, __LINE__, __FUNCTION__, $this->last_error_message, $cmd->last_error_message());
         return;
     }
     $this->meta_name = null;
 }
 /**
  * Check if there is a frame to read
  * @param $timeo: 用户指定的超时等待值,如果无指定则读取配置(单位:毫秒)
  * @return number
  */
 public function is_readable($timeo_ms)
 {
     if (empty($timeo_ms) || $timeo_ms <= 0) {
         // 参数错误
         BigpipeLog::warning("[is_readable][invalid parameter]");
         return BigpipeErrorCode::INVALID_PARAM;
     }
     $timeo_s = floor($timeo_ms / 1000);
     $timeo_us = $timeo_ms % 1000 * 1000;
     $ret = $this->_socket->is_readable($timeo_s, $timeo_us);
     if (c_socket::ERROR == $ret) {
         $msg = $this->_socket->__get('socket_error');
         BigpipeLog::warning("[peek to read error][{$msg}]");
         $ret = BigpipeErrorCode::ERROR_CONNECTION;
     } else {
         if (c_socket::TIMEOUT == $ret) {
             BigpipeLog::warning("[peek to read time out]");
             $ret = BigpipeErrorCode::TIMEOUT;
         } else {
             $ret = BigpipeErrorCode::READABLE;
         }
     }
     return $ret;
 }
 /**
  * 接收返回消息, 判断发布是否成功
  * @return BigpipePubResult on success or false on failure
  */
 private function _check_ack($receipt_id, &$send_result)
 {
     // 接收CONNECTED
     $res_body = $this->_stomp_adapter->receive();
     if (null === $res_body) {
         return false;
     }
     // parse ACK
     $ack = new BStompAckFrame();
     if (!$ack->load($res_body)) {
         BigpipeLog::warning('[stomp parse ack frame error][cmd_type:%d][err_msg:]', $ack->command_type, $ack->last_error_message());
         return false;
     }
     if ($ack->session_message_id != $this->_session_msg_id) {
         BigpipeLog::warning('[check session message id error][send:%u][ack:%u]', $this->_session_msg_id, $ack->session_message_id);
         return false;
     }
     if ($ack->receipt_id != $receipt_id) {
         BigpipeLog::warning('[check receipt id error][send:%u][ack:%u]', $receipt_id, $ack->receipt_id);
         return false;
     }
     // 填充result
     $send_result = new BigpipePubResult();
     $send_result->error_no = $ack->status;
     $send_result->pipelet_id = $this->_pipelet_id;
     $send_result->pipelet_msg_id = $ack->topic_message_id;
     $send_result->session_msg_id = $ack->session_message_id;
     return $send_result;
 }
 /**
  * 从read buffer读取一个message package
  * @return false on failure or BigpageMessage on success
  */
 private function _receive()
 {
     $obj = false;
     do {
         $res_body = $this->_stomp_adapter->receive();
         if (null === $res_body) {
             continue;
             // 直接重订阅
         }
         // 接收成功,读取数据
         $msg = new BStompMessageFrame();
         if (!$msg->load($res_body)) {
             // message包问题
             BigpipeLog::warning('[%s:%u][%s][receive msg error][%s]', __FILE__, __LINE__, __FUNCTION__, $msg->last_error_message());
             continue;
         }
         // 读取msg包
         if (-1 != $this->_pipelet_msg_id && $msg->topic_message_id < $this->_pipelet_msg_id) {
             BigpipeLog::warning('[%s:%u][%s][received different start point error][recv: %u][req: %u]', __FILE__, __LINE__, __FUNCTION__, $msg->topic_message_id, $this->_pipelet_msg_id);
             continue;
         }
         $msg_body = $msg->message_body;
         if (empty($msg_body) || false === $msg_body) {
             continue;
             // 接收message失败,failover
         }
         // message 接收成功,返回ack
         if (BStompClientAckType::AUTO == $this->_client_ack_type) {
             // 发送ack包
             $ack = new BStompAckFrame();
             $ack->receipt_id = $msg->receipt_id;
             $ack->topic_message_id = $msg->topic_message_id;
             $ack->destination = $msg->destination;
             $ack->ack_type = BStompIdAckType::TOPIC_ID;
             if (!$this->_stomp_adapter->send($ack)) {
                 // message接收成功,但是ack发送失败,可以不用理会
                 // 因为下次receive时,会进入failover
                 BigpipeLog::warning('[%s:%u][%s][fail to ack message]', __FILE__, __LINE__, __FUNCTION__);
             }
         }
         // 处理message
         if ($this->_enable_checksum) {
             $sign = creat_sign_mds64($msg_body);
             if ($sign[2] != $msg->cur_checksum) {
                 // checksum校验失败, 进入failover
                 BigpipeLog::warning('[%s:%u][%s][message package checksum error][orig:%u][curr:%u][name:%s][msg_id:%u]', __FILE__, __LINE__, __FUNCTION__, $msg->cur_checksum, $sign[2], $this->_get_stripe_name(), $msg->topic_message_id);
                 continue;
             }
         }
         if (!$this->_package->load($msg_body, $msg->topic_message_id)) {
             // 接收的包有问题, 进入failover
             BigpipeLog::warning('[%s:%u][%s][message package error][name:%s][msg_id:%u]', __FILE__, __LINE__, __FUNCTION__, $this->_get_stripe_name(), $msg->topic_message_id);
             continue;
         }
         $obj = $this->_package->pop();
         // 必须能成功取一条message
         if (false === $obj) {
             // 包中的内容有问,进入failover
             BigpipeLog::warning('[%s:%u][%s][empty message package][name:%s][msg_id:%u]', __FILE__, __LINE__, __FUNCTION__, $this->_get_stripe_name(), $msg->topic_message_id);
             continue;
         }
         $this->_active();
         // 设置活跃状态
         $this->_pipelet_msg_id = $msg->topic_message_id + 1;
         if ($this->_get_end_pos() < $this->_pipelet_msg_id) {
             // 已接收到stripe末尾,更换新stripe
             // 主动更新订阅, 如果更新失败也没关系,下次receive时可以处理
             // 这里进入flush_subscribe不需要sleep
             $this->_fo_sleep_time = 0;
             if ($this->_flush_subscribe()) {
                 $this->_active();
                 //
             }
         }
         break;
         // 成功收到message 跳出循环
     } while ($this->_flush_subscribe());
     return $obj;
 }
 /**
  * 向终端发送CONNECT命令
  */
 private function _stomp_connect()
 {
     // 发送CONNECT
     $cmd = new BStompConnectFrame();
     $cmd->role = $this->role;
     $cmd->session_id = $this->session_id;
     $cmd->topic_name = $this->topic_name;
     if (!$this->send($cmd)) {
         BigpipeLog::warning("[stomp connect error]");
         return false;
     }
     // 接收CONNECTED
     $res_body = $this->receive();
     if (null === $res_body) {
         BigpipeLog::warning("[stomp receive connected error]");
         return false;
     }
     // parse CONNECTED
     $ack = new BStompConnectedFrame();
     if (!$ack->load($res_body)) {
         BigpipeLog::warning('[stomp parse connected frame error][cmd_type:' . $ack->command_type . '][msg:' . $ack->last_error_message() . ']');
         return false;
     }
     // 更新session id和session message id
     $this->session_id = $ack->session_id;
     $this->session_message_id = $ack->session_message_id + 1;
     return true;
 }
 /**
  * 检查路径下的node是否存在,如不存在打印错误日志
  * @param string $node_path : node path in meta
  * @return true on success or false on failure
  */
 private function _exists($node_path)
 {
     if (false === $this->_zk->exists($node_path)) {
         BigpipeLog::warning("[invalid meta node][%s]", $node_path);
         return false;
     }
     return true;
 }