Ticket #8851: MythBackend-mod.php

File MythBackend-mod.php, 8.2 KB (added by anonymous, 14 years ago)

modified mythplugins/mythweb/classes/MythBackend.php file with improved message

Line 
1<?php
2/**
3 *
4 * @url         $URL$
5 * @date        $Date$
6 * @version     $Revision$
7 * @author      $Author$
8 * @license     GPL
9 *
10 * @package     MythTV
11 *
12/**/
13
14class MythBackend {
15
16// MYTH_PROTO_VERSION is defined in libmyth in mythtv/libs/libmyth/mythcontext.h
17// and should be the current MythTV protocol version.
18    static $protocol_version        = '59';
19
20// The character string used by the backend to separate records
21    static $backend_separator       = '[]:[]';
22
23// NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
24// the number of items in a ProgramInfo QStringList group used by
25// ProgramInfo::ToSringList and ProgramInfo::FromStringList.
26    static $program_line_number     = 41;
27
28    private $fp                     = null;
29    private $connected              = false;
30    private $host                   = '127.0.0.1';
31    private $ip                     = '127.0.0.1';
32    private $port                   = null;
33    private $port_http              = null;
34
35    static function find($host = null, $port = null) {
36        static $Backends = array();
37
38    // Looking for the master backend?
39        if (is_null($host)) {
40            $host = setting('MasterServerIP');
41            $port = setting('MasterServerPort');
42            if (!$host || !$port)
43                trigger_error("MasterServerIP or MasterServerPort not found! You may"
44                            ."need to check your mythweb.conf.* file, re-run mythtv-setup,"
45                            ."or insert rows into the MythTV database's 'settings' table defining"
46                            ."MasterServerIP and MasterServerPort for the NULL host."
47                            FATAL);
48        }
49
50        if (!isset($Backend[$host][$port]))
51            $Backend[$host][$port] = new MythBackend($host, $port);
52        return $Backend[$host][$port];
53    }
54
55    function __construct($host, $port = null) {
56        $this->host         = $host;
57        $this->ip           = _or(setting('BackendServerIP', $this->host), $host);
58        $this->port         = _or($port, _or(setting('BackendServerPort', $this->host), 6543));
59        $this->port_http    = _or(setting('BackendStatusPort', $this->host), _or(setting('BackendStatusPort'), 6544));
60    }
61
62    function __destruct() {
63        $this->disconnect();
64    }
65
66    private function connect() {
67        if ($this->fp)
68            return;
69        $this->fp = @fsockopen($this->ip, $this->port, $errno, $errstr, 25);
70        if (!$this->fp)
71            custom_error("Unable to connect to the master backend at {$this->ip}:{$this->port}".(($this->host == $this->ip)?'':" (hostname: {$this->host})").".\nIs it running?");
72        socket_set_timeout($this->fp, 30);
73        $this->checkProtocolVersion();
74        $this->announce();
75    }
76
77    private function disconnect() {
78        if (!$this->fp)
79            return;
80        $this->sendCommand('DONE');
81        fclose($this->fp);
82    }
83
84    private function checkProtocolVersion() {
85    // Allow overriding this check
86        if ($_SERVER['ignore_proto'] == true )
87            return true;
88
89        if (   time() - $_SESSION['backend'][$this->host]['proto_version']['last_check_time'] < 60*60*2
90            && $_SESSION['backend'][$this->host]['proto_version']['last_check_version'] == MythBackend::$protocol_version )
91            return true;
92
93        $response = $this->sendCommand('MYTH_PROTO_VERSION '.MythBackend::$protocol_version);
94        $_SESSION['backend'][$this->host]['proto_version']['last_check_version'] = @$response[1];
95
96        if ($response[0] == 'ACCEPT') {
97            $_SESSION['backend'][$this->host]['proto_version']['last_check_time'] = time();
98            return true;
99        }
100
101        if ($response[0] == 'REJECT')
102            trigger_error("Incompatible protocol version (mythweb=" . MythBackend::$protocol_version . ", backend=" . @$response[1] . ")");
103        else
104            trigger_error("Unexpected response to MYTH_PROTO_VERSION '".MythBackend::$protocol_version."': ".print_r($response, true));
105        return false;
106    }
107
108    private function announce() {
109        $response = $this->sendCommand('ANN Monitor '.hostname.' 2' );
110        if ($response == 'OK')
111            return true;
112        return false;
113    }
114
115    public function setTimezone() {
116        if (!is_string($_SESSION['backend']['timezone']['value']) || time() - $_SESSION['backend']['timezone']['last_check_time'] > 60*60*24) {
117            $response = $this->sendCommand('QUERY_TIME_ZONE');
118            $timezone = str_replace(' ', '_', $response[0]);
119            $_SESSION['backend']['timezone']['value']           = $timezone;
120            $_SESSION['backend']['timezone']['last_check_time'] = time();
121        }
122
123        if (!@date_default_timezone_set($_SESSION['backend']['timezone']['value'])) {
124            $attempted_value = $_SESSION['backend']['timezone']['value'];
125            unset($_SESSION['backend']['timezone']);
126            trigger_error('Failed to set php timezone to '.$attempted_value.(is_array($response) ? ' Response from backend was '.print_r($response, true) : ''));
127        }
128    }
129
130    public function sendCommand($command = null) {
131        $this->connect();
132    // The format should be <length + whitespace to 8 total bytes><data>
133        if (is_array($command))
134            $command = implode(MythBackend::$backend_separator, $command);
135        $command = strlen($command) . str_repeat(' ', 8 - strlen(strlen($command))) . $command;
136        fputs($this->fp, $command);
137        return $this->receiveData();
138    }
139
140    public function receiveData($timeout = 30) {
141        $this->connect();
142        stream_set_timeout($this->fp, $timeout);
143
144    // Read the response header to find out how much data we'll be grabbing
145        $length = rtrim(fread($this->fp, 8));
146
147    // Read and return any data that was returned
148        $response = '';
149        while ($length > 0) {
150            $data = fread($this->fp, min(8192, $length));
151            if (strlen($data) < 1)
152                break; // EOF
153            $response .= $data;
154            $length -= strlen($data);
155        }
156        $response = explode(MythBackend::$backend_separator, $response);
157        if (count($response) == 1)
158            return $response[0];
159        if (count($response) == 0)
160            return false;
161        return $response;
162    }
163
164    public function listenForEvent($event, $timeout = 120) {
165        $endtime = time() + $timeout;
166        do {
167            $response = $this->receiveData();
168        } while ($response[1] != $event && $endtime < time());
169        if ($response[1] == $event)
170            return $response;
171        return false;
172    }
173
174    public function queryProgramRows($query = null, $offset = 1) {
175        $records = $this->sendCommand($query);
176    // Parse the records, starting at the offset point
177        $row = 0;
178        $col = 0;
179        $count = count($records);
180        for($i = $offset; $i < $count; $i++) {
181            $rows[$row][$col] = $records[$i];
182        // Every $NUMPROGRAMLINES fields (0 through ($NUMPROGRAMLINES-1)) means
183        // a new row.  Please note that this changes between myth versions
184            if ($col == (MythBackend::$program_line_number - 1)) {
185                $col = 0;
186                $row++;
187            }
188        // Otherwise, just increment the column
189            else
190                $col++;
191        }
192    // Lastly, grab the offset data (if there is any)
193        for ($i=0; $i < $offset; $i++) {
194            $rows['offset'][$i] = $recs[$i];
195        }
196    // Return the data
197        return $rows;
198    }
199
200/**
201 * Tell the backend to reschedule a particular record entry.  If the change
202 * isn't specific to a single record entry (e.g. channel or record type
203 * priorities), then use 0.  I don't think mythweb should need it, but if you
204 * need to indicate every record rule is affected, then use -1.
205/**/
206    public function rescheduleRecording($recordid = -1) {
207        $this->sendCommand('RESCHEDULE_RECORDINGS '.$recordid);
208        Cache::clear();
209        if ($this->listenForEvent('SCHEDULE_CHANGE'))
210            return true;
211        return false;
212    }
213
214    public function httpRequest($path, $args = array()) {
215        $url = "http://{$this->ip}:{$this->port_http}/Myth/{$path}?";
216        foreach ($args as $key => $value)
217            $url .= $key.'='.urlencode($value).'&';
218        return @file_get_contents($url);
219    }
220}