NotionCommotion Posted March 8, 2017 Share Posted March 8, 2017 I have a class for streaming text. My question has nothing to do with this particular, but how to modify an object. Originally, I had functionality to deal JSON, but decided to remove that functionality as I felt it didn't belong there. The class now looks like the following: <?php namespace Server; use Evenement\EventEmitterInterface; use Evenement\EventEmitterTrait; use React\Stream\DuplexStreamInterface; class LengthPrefixStream implements EventEmitterInterface { use EventEmitterTrait; private $socket=false, $buffer=''; public function __construct(DuplexStreamInterface $socket){ $this->socket = $socket; $this->socket->on('data', function($data){ $this->buffer .= $data; $this->parseBuffer(); }); } public function send($message){ //Still need to implement drain if($this->isConnected()) { $this->socket->write(pack("V", strlen($message)).$message); return true; } else { return false; } } private function parseBuffer(){ do { $checkAgain = false; $bufferLength = strlen($this->buffer); $length = unpack('Vlen', substr($this->buffer, 0, 4))['len']; if($bufferLength >= $length + 4){ $this->emit('data', [substr($this->buffer, 4, $length)]); $this->buffer = substr($this->buffer, $length+4); $checkAgain = strlen($this->buffer)>=4; } } while ($checkAgain); } public function isConnected() { return $this->socket?true:false; } public function close() { $this->socket->close(); } } I use it something like this: protected function sendCommand($text) { $data = false; $loop = new \React\EventLoop\StreamSelectLoop(); $socket = new \React\SocketClient\TimeoutConnector(new \React\SocketClient\TcpConnector($loop), 15, $loop); $socket->create($this->host['url'], $this->host['port'])->then(function($stream) use (&$data, $loop, $text){ $client = new \DataLogger\Server\LengthPrefixStream($stream); $client->on('data', function($data) use (&$data, $loop, $stream){ //Passed by reference $data will be set. Maybe need to use a separate variable? $stream->close(); $loop->stop(); }); $client->send($text); }); $loop->run(); return $data; //False on failure } But now I wish to send and return variables other than text, and will need to convert them to JSON. I still don't wish to put this functionality in the class. Furthermore, I use this class more than one place, so don't wish to duplicate the JSON conversion and checking that it is valid JSON each time. I am thinking I might be able to wrap the object in another method. //$client = new \DataLogger\Server\LengthPrefixStream($stream); $client = $this->wrapClient(new \DataLogger\Server\LengthPrefixStream($stream)); protected function wrapClient($client) { /* Turn messages sent into JSON and verify that it is valid. Turn responses received into JSON and verify that it is valid. */ } But I am kind of at a lose where to go next. Any suggestions? Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted March 8, 2017 Author Share Posted March 8, 2017 Or maybe I should be wrapping it not in a method, but another class? The send() method seems okay, but not the on() method. The reason I tried to get away from having the json scope in the LengthPrefixStream class is I wish to log json errors, and didn't want to pass a logger into a generic class. Guess I will need to do the same if I use this approach... $client = new wrapClient(new \DataLogger\Server\LengthPrefixStream($stream)); class wrapClient { public function __construct($client){ $this->client = $client; } public function send($msg) { $this->client->send(json_encode($msg)); } public function on($msg) { $o = json_decode($msg); if (json_last_error() != JSON_ERROR_NONE){ $rsp='ERROR: Invalid JSON provided'; } return o; } } Quote Link to comment Share on other sites More sharing options...
kicken Posted March 8, 2017 Share Posted March 8, 2017 You could try implementing a stream wrapper but not sure how well that'd work with react/json. Your wrapping class sounds more or less like my JSONStream class from an earlier example. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted March 8, 2017 Author Share Posted March 8, 2017 Your wrapping class sounds more or less like my JSONStream class from an earlier example. Almost... Yours worked! Maybe I put the on method in the constructor like you did. Or maybe I just go back to putting this json functionality in the class like you did, and pass back some message if json isn't valid. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted March 8, 2017 Author Share Posted March 8, 2017 Actually, what I will do is put the json scope in the class, but through an exception upon invalid json. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.