PageRenderTime 125ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/build/cpf/amqphp/wire/Method.php

http://github.com/BraveSirRobin/amqphp
PHP | 2 lines | 2 code | 0 blank | 0 comment | 117 complexity | 11845de56d571bcc8f286d5291c566e1 MD5 | raw file
  1. <?php
  2. namespace amqphp\wire; use amqphp\protocol as proto; use amqphp\protocol\abstrakt; class Method implements \Serializable { const ST_METH_READ = 1; const ST_CHEAD_READ = 2; const ST_BODY_READ = 4; const PARTIAL_FRAME = 7; private static $PlainPFields = array('rcState', 'mode', 'fields', 'classFields', 'content', 'frameSize', 'wireChannel', 'isHb', 'wireMethodId', 'wireClassId', 'contentSize'); private $rcState = 0; private $methProto; private $classProto; private $mode; private $fields = array(); private $classFields = array(); private $content; private $frameSize; private $wireChannel = null; private $wireMethodId; private $wireClassId; private $contentSize; private $isHb = false; private $protoLoader; public $amqpClass; function serialize () { if ($this->mode != 'read') { trigger_error("Only read mode methods should be serialised", E_USER_WARNING); return null; } $ret = array(); $ret['plainFields'] = array(); foreach (self::$PlainPFields as $k) { $ret['plainFields'][$k] = $this->$k; } if ($this->methProto && $this->classProto) { $ret['protos'] = array(get_class($this->methProto), get_class($this->classProto)); } return serialize($ret); } function unserialize ($s) { $state = unserialize($s); foreach (self::$PlainPFields as $k) { $this->$k = $state['plainFields'][$k]; } if (array_key_exists('protos', $state)) { list($mc, $cc) = $state['protos']; $this->methProto = new $mc; $this->classProto = new $cc; $this->amqpClass = sprintf('%s.%s', $this->classProto->getSpecName(), $this->methProto->getSpecName()); } } function setProtocolLoader ($l) { $this->protoLoader = $l; } function __construct (abstrakt\XmlSpecMethod $src = null, $chan = 0) { if ($src instanceof abstrakt\XmlSpecMethod) { $this->methProto = $src; $this->classProto = $this->methProto->getClass(); $this->mode = 'write'; $this->wireChannel = $chan; $this->amqpClass = sprintf('%s.%s', $this->classProto->getSpecName(), $this->methProto->getSpecName()); } else { $this->mode = 'read'; } } function canReadFrom (Reader $src) { if (is_null($this->wireChannel)) { return true; } if (true === ($_fh = $this->extractFrameHeader($src))) { return false; } list($wireType, $wireChannel, $wireSize) = $_fh; $ret = ($wireChannel == $this->wireChannel); $src->rewind(7); return $ret; } function readConstruct (Reader $src, \Closure $protoLoader) { if ($this->mode == 'write') { trigger_error('Invalid read construct operation on a read mode method', E_USER_WARNING); return false; } $FRME = 206; $break = false; $ret = true; $this->protoLoader = $protoLoader; while (! $src->isSpent()) { if (true === ($_fh = $this->extractFrameHeader($src))) { $ret = self::PARTIAL_FRAME; break; } else { list($wireType, $wireChannel, $wireSize) = $_fh; } if (! $this->wireChannel) { $this->wireChannel = $wireChannel; } else if ($this->wireChannel != $wireChannel) { $src->rewind(7); return true; } if ($src->isSpent($wireSize + 1)) { $src->rewind(7); $ret = self::PARTIAL_FRAME; break; } switch ($wireType) { case 1: $this->readMethodContent($src, $wireSize); if (! $this->methProto->getSpecHasContent()) { $break = true; } break; case 2: $this->readContentHeaderContent($src, $wireSize); break; case 3: $this->readBodyContent($src, $wireSize); if ($this->readConstructComplete()) { $break = true; } break; case 8: $break = $ret = $this->isHb = true; break; default: throw new \Exception(sprintf("Unsupported frame type %d", $wireType), 8674); } if ($src->read('octet') != $FRME) { throw new \Exception(sprintf("Framing exception - missed frame end (%s) - (%d,%d,%d,%d) [%d, %d]", $this->amqpClass, $this->rcState, $break, $src->isSpent(), $this->readConstructComplete(), strlen($this->content), $this->contentSize ), 8763); } if ($break) { break; } } return $ret; } private function extractFrameHeader(Reader $src) { if ($src->isSpent(7)) { return true; } if (null === ($wireType = $src->read('octet'))) { throw new \Exception('Failed to read type from frame', 875); } else if (null === ($wireChannel = $src->read('short'))) { throw new \Exception('Failed to read channel from frame', 9874); } else if (null === ($wireSize = $src->read('long'))) { throw new \Exception('Failed to read size from frame', 8715); } return array($wireType, $wireChannel, $wireSize); } private function readMethodContent (Reader $src, $wireSize) { $st = $src->p; $this->wireClassId = $src->read('short'); $this->wireMethodId = $src->read('short'); $protoLoader = $this->protoLoader; if (! ($this->classProto = $protoLoader('ClassFactory', 'GetClassByIndex', array($this->wireClassId)))) { throw new \Exception(sprintf("Failed to construct class prototype for class ID %s", $this->wireClassId), 9875); } else if (! ($this->methProto = $this->classProto->getMethodByIndex($this->wireMethodId))) { throw new \Exception("Failed to construct method prototype", 5645); } $this->amqpClass = sprintf('%s.%s', $this->classProto->getSpecName(), $this->methProto->getSpecName()); foreach ($this->methProto->getFields() as $f) { $this->fields[$f->getSpecFieldName()] = $src->read($f->getSpecDomainType()); } $en = $src->p; if ($wireSize != ($en - $st)) { throw new \Exception("Invalid method frame size", 9845); } $this->rcState = $this->rcState | self::ST_METH_READ; } private function readContentHeaderContent (Reader $src, $wireSize) { $st = $src->p; $wireClassId = $src->read('short'); $src->read('short'); $this->contentSize = $src->read('longlong'); if ($wireClassId != $this->wireClassId) { throw new \Exception(sprintf("Unexpected class in content header (%d, %d) - read state %d", $wireClassId, $this->wireClassId, $this->rcState), 5434); } $binFlags = ''; while (true) { if (null === ($fBlock = $src->read('short'))) { throw new \Exception("Failed to read property flag block", 4548); } $binFlags .= str_pad(decbin($fBlock), 16, '0', STR_PAD_LEFT); if (0 !== (strlen($binFlags) % 16)) { throw new \Exception("Unexpected message property flags", 8740); } if (substr($binFlags, -1) == '1') { $binFlags = substr($binFlags, 0, -1); } else { break; } } foreach ($this->classProto->getFields() as $i => $f) { if ($f->getSpecFieldDomain() == 'bit') { $this->classFields[$f->getSpecFieldName()] = (boolean) substr($binFlags, $i, 1); } else if (substr($binFlags, $i, 1) == '1') { $this->classFields[$f->getSpecFieldName()] = $src->read($f->getSpecFieldDomain()); } else { $this->classFields[$f->getSpecFieldName()] = null; } } $en = $src->p; if ($wireSize != ($en - $st)) { throw new \Exception("Invalid content header frame size", 2546); } $this->rcState = $this->rcState | self::ST_CHEAD_READ; } private function readBodyContent (Reader $src, $wireSize) { $this->content .= $src->readN($wireSize); $this->rcState = $this->rcState | self::ST_BODY_READ; } function readConstructComplete () { if ($this->isHb) { return true; } else if (! $this->methProto) { return false; } else if (! $this->methProto->getSpecHasContent()) { return (boolean) $this->rcState & self::ST_METH_READ; } else { return ($this->rcState & self::ST_CHEAD_READ) && (strlen($this->content) >= $this->contentSize); } } function setField ($name, $val) { if ($this->mode == 'read') { trigger_error('Setting field value for read constructed method', E_USER_WARNING); } else if (in_array($name, $this->methProto->getSpecFields())) { $this->fields[$name] = $val; } else if (in_array($name, $this->classProto->getSpecFields())) { $this->classFields[$name] = $val; } else { $warns = sprintf("Field %s is invalid for Amqp message type %s", $name, $this->amqpClass); trigger_error($warns, E_USER_WARNING); } } function getField ($name) { if (array_key_exists($name, $this->fields)) { return $this->fields[$name]; } else if (array_key_exists($name, $this->classFields)) { return $this->classFields[$name]; } else if (! in_array($name, array_merge($this->classProto->getSpecFields(), $this->methProto->getSpecFields()))) { $warns = sprintf("Field %s is invalid for Amqp message type %s", $name, $this->amqpClass); trigger_error($warns, E_USER_WARNING); } } function getFields () { return array_merge($this->classFields, $this->fields); } function setContent ($content) { if ($this->mode == 'read') { trigger_error('Setting content value for read constructed method', E_USER_WARNING); } else if (strlen($content)) { if (! $this->methProto->getSpecHasContent()) { trigger_error('Setting content value for a method which doesn\'t take content', E_USER_WARNING); } $this->content = $content; } } function getContent () { if (! $this->methProto->getSpecHasContent()) { trigger_error('Invalid serialize operation on a method which doesn\'t take content', E_USER_WARNING); return ''; } return $this->content; } function getMethodProto () { return $this->methProto; } function getClassProto () { return $this->classProto; } function getWireChannel () { return $this->wireChannel; } function getWireSize () { return $this->wireSize; } function getWireClassId () { return $this->wireClassId; } function getWireMethodId () { return $this->wireMethodId; } function setMaxFrameSize ($max) { $this->frameSize = $max; } function setWireChannel ($chan) { $this->wireChannel = $chan; } function isHeartbeat () { return $this->isHb; } function toBin (\Closure $protoLoader) { if ($this->mode == 'read') { trigger_error('Invalid serialize operation on a read mode method', E_USER_WARNING); return ''; } $frme = $protoLoader('ProtoConsts', 'GetConstant', array('FRAME_END')); $w = new Writer; $tmp = $this->getMethodBin(); $w->write(1, 'octet'); $w->write($this->wireChannel, 'short'); $w->write(strlen($tmp), 'long'); $buff = $w->getBuffer() . $tmp . $frme; $ret = array($buff); if ($this->methProto->getSpecHasContent()) { $w = new Writer; $tmp = $this->getContentHeaderBin(); $w->write(2, 'octet'); $w->write($this->wireChannel, 'short'); $w->write(strlen($tmp), 'long'); $ret[] = $w->getBuffer() . $tmp . $frme; $tmp = (string) $this->content; $i = 0; $frameSize = $this->frameSize - 8; while (true) { $chunk = substr($tmp, ($i * $frameSize), $frameSize); if (strlen($chunk) == 0) { break; } $w = new Writer; $w->write(3, 'octet'); $w->write($this->wireChannel, 'short'); $w->write(strlen($chunk), 'long'); $ret[] = $w->getBuffer() . $chunk . $frme; $i++; } } return $ret; } private function getMethodBin () { if ($this->mode == 'read') { trigger_error('Invalid serialize operation on a read mode method', E_USER_WARNING); return ''; } $src = new Writer; $src->write($this->classProto->getSpecIndex(), 'short'); $src->write($this->methProto->getSpecIndex(), 'short'); foreach ($this->methProto->getFields() as $f) { $name = $f->getSpecFieldName(); $type = $f->getSpecDomainType(); $val = ''; if (array_key_exists($name, $this->fields)) { $val = $this->fields[$name]; if (! $f->validate($val)) { $warns = sprintf("Field %s of method %s failed validation by protocol binding class %s", $name, $this->amqpClass, get_class($f)); trigger_error($warns, E_USER_WARNING); } } $src->write($val, $type); } return $src->getBuffer(); } private function getContentHeaderBin () { if ($this->mode == 'read') { trigger_error('Invalid serialize operation on a read mode method', E_USER_WARNING); return ''; } else if (! $this->methProto->getSpecHasContent()) { trigger_error('Invalid serialize operation on a method which doesn\'t take content', E_USER_WARNING); return ''; } $src = new Writer; $src->write($this->classProto->getSpecIndex(), 'short'); $src->write(0, 'short'); $src->write(strlen($this->content), 'longlong'); $pFlags = ''; $pChunks = 0; $pList = ''; $src2 = new Writer; foreach ($this->classProto->getFields() as $i => $f) { if (($i % 15) == 0) { if ($i > 0) { $pFlags .= '1'; } $pChunks++; } $fName = $f->getSpecFieldName(); $dName = $f->getSpecFieldDomain(); if (array_key_exists($fName, $this->classFields) && ! ($dName == 'bit' && ! $this->classFields[$fName])) { $pFlags .= '1'; } else { $pFlags .= '0'; } if (array_key_exists($fName, $this->classFields) && $dName != 'bit') { if (! $f->validate($this->classFields[$fName])) { trigger_error("Field {$fName} of method {$this->amqpClass} is not valid", E_USER_WARNING); } $src2->write($this->classFields[$fName], $f->getSpecDomainType()); } } if ($pFlags && (strlen($pFlags) % 16) !== 0) { $pFlags .= str_repeat('0', 16 - (strlen($pFlags) % 16)); } $pBuff = ''; for ($i = 0; $i < $pChunks; $i++) { $pBuff .= pack('n', bindec(substr($pFlags, $i*16, 16))); } return $src->getBuffer() . $pBuff . $src2->getBuffer(); } function isResponse (Method $other) { if ($exp = $this->methProto->getSpecResponseMethods()) { if ($this->classProto->getSpecName() != $other->classProto->getSpecName() || $this->wireChannel != $other->wireChannel) { return false; } else { return in_array($other->methProto->getSpecName(), $exp); } } else { trigger_error("Method does not expect a response", E_USER_WARNING); return false; } } }