]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/TwitterBridge/jsonstreamreader.php
ad8e2626ad15d48450ecbfe048968a1d7925ea06
[quix0rs-gnu-social.git] / plugins / TwitterBridge / jsonstreamreader.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * PHP version 5
6  *
7  * LICENCE: This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  * @category  Plugin
21  * @package   StatusNet
22  * @author    Brion Vibber <brion@status.net>
23  * @copyright 2010 StatusNet, Inc.
24  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
25  * @link      http://status.net/
26  */
27
28 class OAuthData
29 {
30     public $consumer_key, $consumer_secret, $token, $token_secret;
31 }
32
33 /**
34  *
35  */
36 abstract class JsonStreamReader
37 {
38     const CRLF = "\r\n";
39
40     public $id;
41     protected $socket = null;
42     protected $state = 'init'; // 'init', 'connecting', 'waiting', 'headers', 'active'
43
44     public function __construct()
45     {
46         $this->id = get_class($this) . '.' . substr(md5(mt_rand()), 0, 8);
47     }
48
49     /**
50      * Starts asynchronous connect operation...
51      *
52      * @param <type> $url
53      */
54     public function connect($url)
55     {
56         common_log(LOG_DEBUG, "$this->id opening connection to $url");
57
58         $scheme = parse_url($url, PHP_URL_SCHEME);
59         if ($scheme == 'http') {
60             $rawScheme = 'tcp';
61         } else if ($scheme == 'https') {
62             $rawScheme = 'ssl';
63         } else {
64             throw new ServerException('Invalid URL scheme for HTTP stream reader');
65         }
66
67         $host = parse_url($url, PHP_URL_HOST);
68         $port = parse_url($url, PHP_URL_PORT);
69         if (!$port) {
70             if ($scheme == 'https') {
71                 $port = 443;
72             } else {
73                 $port = 80;
74             }
75         }
76
77         $path = parse_url($url, PHP_URL_PATH);
78         $query = parse_url($url, PHP_URL_QUERY);
79         if ($query) {
80             $path .= '?' . $query;
81         }
82
83         $errno = $errstr = null;
84         $timeout = 5;
85         //$flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT;
86         $flags = STREAM_CLIENT_CONNECT;
87         // @fixme add SSL params
88         $this->socket = stream_socket_client("$rawScheme://$host:$port", $errno, $errstr, $timeout, $flags);
89
90         $this->send($this->httpOpen($host, $path));
91
92         stream_set_blocking($this->socket, false);
93         $this->state = 'waiting';
94     }
95
96     function send($buffer)
97     {
98         echo "Writing...\n";
99         var_dump($buffer);
100         fwrite($this->socket, $buffer);
101     }
102
103     function read()
104     {
105         echo "Reading...\n";
106         $buffer = fread($this->socket, 65536);
107         var_dump($buffer);
108         return $buffer;
109     }
110
111     protected function httpOpen($host, $path)
112     {
113         $lines = array(
114             "GET $path HTTP/1.1",
115             "Host: $host",
116             "User-Agent: StatusNet/" . STATUSNET_VERSION . " (TwitterBridgePlugin)",
117             "Connection: close",
118             "",
119             ""
120         );
121         return implode(self::CRLF, $lines);
122     }
123
124     /**
125      * Close the current connection, if open.
126      */
127     public function close()
128     {
129         if ($this->isConnected()) {
130             common_log(LOG_DEBUG, "$this->id closing connection.");
131             fclose($this->socket);
132             $this->socket = null;
133         }
134     }
135
136     /**
137      * Are we currently connected?
138      *
139      * @return boolean
140      */
141     public function isConnected()
142     {
143         return $this->socket !== null;
144     }
145
146     /**
147      * Send any sockets we're listening on to the IO manager
148      * to wait for input.
149      *
150      * @return array of resources
151      */
152     public function getSockets()
153     {
154         if ($this->isConnected()) {
155             return array($this->socket);
156         }
157         return array();
158     }
159
160     /**
161      * Take a chunk of input over the horn and go go go! :D
162      * @param string $buffer
163      */
164     function handleInput($socket)
165     {
166         if ($this->socket !== $socket) {
167             throw new Exception('Got input from unexpected socket!');
168         }
169
170         $buffer = $this->read();
171         switch ($this->state)
172         {
173             case 'waiting':
174                 $this->handleInputWaiting($buffer);
175                 break;
176             case 'headers':
177                 $this->handleInputHeaders($buffer);
178                 break;
179             case 'active':
180                 $this->handleInputActive($buffer);
181                 break;
182             default:
183                 throw new Exception('Invalid state in handleInput: ' . $this->state);
184         }
185     }
186
187     function handleInputWaiting($buffer)
188     {
189         common_log(LOG_DEBUG, "$this->id Does this happen? " . $buffer);
190         $this->state = 'headers';
191         $this->handleInputHeaders($buffer);
192     }
193
194     function handleInputHeaders($buffer)
195     {
196         $lines = explode(self::CRLF, $buffer);
197         foreach ($lines as $line) {
198             if ($line == '') {
199                 $this->state = 'active';
200                 common_log(LOG_DEBUG, "$this->id connection is active!");
201             } else {
202                 common_log(LOG_DEBUG, "$this->id read HTTP header: $line");
203                 $this->responseHeaders[] = $line;
204             }
205         }
206     }
207
208     function handleInputActive($buffer)
209     {
210         // One JSON object on each line...
211         // Will we always deliver on packet boundaries?
212         $lines = explode("\n", $buffer);
213         foreach ($lines as $line) {
214             $data = json_decode($line, true);
215             if ($data) {
216                 $this->handleJson($data);
217             } else {
218                 common_log(LOG_ERR, "$this->id received bogus JSON data: " . $line);
219             }
220         }
221     }
222
223     abstract function handleJson(array $data);
224 }