/** * Sometimes ScratchLive doesn't supply the length, even when it knows the file. * Not sure why; perhaps files that have never been analysed. * * So, let's attempt to guess it by analysing the full file. */ protected function guessLengthFromFile() { $fullpath = $this->getFullpath(); if (strlen($fullpath) == 0) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Guessing MP3 length from file failed: full path was empty. Perhaps this entry was manually added?', array()); return "0:00"; } if (!$this->file_exists($fullpath)) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Guessing MP3 length from file failed: file not found (%s)', array($fullpath)); return "0:00"; } $external_factory = Inject::the(new ExternalRepo()); /* @var $external_factory ExternalFactory */ $getid3 = $external_factory->newGetID3(); /* @var $getid3 getid3 */ $getid3->option_tag_lyrics3 = false; $getid3->option_tag_apetag = false; $getid3->option_extra_info = true; $getid3->encoding = 'UTF-8'; try { $info = $getid3->Analyze($fullpath); $playtime = $info['playtime_seconds']; if ($playtime) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Guessed MP3 length %d seconds from file.', array($playtime)); $minutes = floor($playtime / 60); $seconds = $playtime % 60; return sprintf("%d:%02d", $minutes, $seconds); } L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Guessing MP3 length from file failed for an unknown reason. Hmmph.', array()); } catch (getid3_exception $e) { // MP3 couldn't be analyzed. L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Guessing MP3 length from file failed: %s', array($e->getMessage())); } return "0:00"; }
/** * @return Unpacker|NULL */ protected function loadCompiled($filename) { $basename = basename($filename, '.xoup'); $class = 'XOUP' . $basename . 'Unpacker'; if (!class_exists($class, false)) { $dirname = dirname($filename); $compiled_name = $dirname . '/' . $basename . '.php'; if (file_exists($dirname . '/' . $basename . '.php')) { $source_ts = filemtime($filename); $compiled_ts = filemtime($compiled_name); if ($compiled_ts < $source_ts) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'source modified since last compilation', array()); return null; } require_once $compiled_name; if (!class_exists($class)) { throw new RuntimeException("{$class} not present in {$compiled_name}"); } L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'loaded compiled XOUP class %s from file %s', array($class, $compiled_name)); } else { // no compiled file exists L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'compiled XOUP file %s does not (yet) exist', array($compiled_name)); return null; } } return new $class(); }
public function addPluginsTo(SSLPluggable $sslpluggable) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "yielding %d plugins", array(count($this->plugins))); foreach ($this->plugins as $plugin) { $sslpluggable->addPlugin($plugin); } }
protected function trackStopped(SSLTrack $track) { $stm = $this->factory->newScrobblerTrackModel($track); if ($stm->isScrobblable()) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'I reckon it\'s time to submit a scrobble for %s!', array($track->getFullTitle())); $this->notifyScrobbleObservers($track); } }
protected function handle($signal) { switch ($signal) { case SIGINT: L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'Caught SIGINT', array()); $this->should_exit = true; break; } }
public function getChunks() { $chunks = array(); do { $chunk = $this->readChunk(); if ($chunk !== false) { $chunks[] = $chunk; } } while ($chunk !== false); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Read %d chunks", array(count($chunks))); return $chunks; }
public function dump() { L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'reading structure of %s...', array($this->filename)); $tree = $this->read($this->filename); L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'asking structure DOM to parse %s...', array($this->filename)); // Without this line you'll just get hexdumps, which is not very exciting. $tree->getData(); L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'printing structure of %s...', array($this->filename)); // After the parsing has occurred, we get much more exciting debug output. $tree->display(); echo "Memory usage: " . number_format(memory_get_peak_usage()) . " bytes\n"; }
protected function checkForNewFilename() { if (isset($this->fns)) { $old_filename = $this->filename; $this->filename = $this->fns->getNewFilename(); $got_new_file = $this->filename != $old_filename; if ($got_new_file) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, "Changed to new file %s", array($this->filename)); } return $got_new_file; } return false; }
/** * Enable a plugin. * * HistoryReader calls this indirectly when it asks CLIPlugins to add their * SSLPlugins to the plugin chain. * * @param SSLPlugin $plugin */ public function addPlugin(SSLPlugin $plugin) { // onSetup for late added plugins if ($this->setup_done) { $plugin->onSetup(); } // onStart for late added plugins if ($this->clock_is_ticking) { $plugin->onStart(); } $this->plugin_wrapper->addPlugin($this->max_plugin_id, $plugin); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "added %s plugin with id %d", array(get_class($plugin), $this->max_plugin_id)); $this->max_plugin_id++; }
public function shorten($url) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, "Shortening %s", array($url)); $result = vgdShorten($url, null, true); // log stats if ($result['shortURL']) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, "Shortened to %s", array($result['shortURL'])); return $result['shortURL']; } L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Shorten failed: %s", array($result['errorMessage'])); // On failure we return empty rather than the original URL // on the assumption that it was too long in the first place //return $url; return ''; }
/** * @return array of SSLOtrkChunk */ public function getData() { $data = array(); $chunk_count = 0; foreach ($this as $chunk) { if ($chunk instanceof SSLOtrkChunk) { $data[] = $chunk->getDataInto(new SSLLibraryTrack()); } elseif ($chunk instanceof SSLVrsnChunk) { $data[] = $chunk->getDataInto(new SSLVersion()); } $chunk_count++; L::level(L::DEBUG) && !($chunk_count % 1000) && L::log(L::DEBUG, __CLASS__, "Parsed %d chunks...", array($chunk_count)); } return $data; }
public function notifyNowPlaying(SSLTrack $track = null) { if (!$track) { return; } $sock = fsockopen($this->host, $this->port, $errno, $errstr, $timeout = 1); if ($sock === false) { L::level(L::ERROR) && L::log(L::ERROR, __CLASS__, "couldn't connect to IRCCat: (%d) %s", array($errno, $errstr)); return; } $message = sprintf($this->config['message'], $track->getFullTitle()); L::level(L::INFO) && L::log(L::INFO, __CLASS__, "sending '%s' -> %s:%d#%s", array($message, $this->host, $this->port, $this->channel)); fwrite($sock, sprintf("%s %s", $this->channel, $message)); fclose($sock); }
public function notifyScrobble(SSLTrack $track) { $length = $track->getLengthInSeconds(SSLTrack::TRY_HARD); if ($length == 0) { // Perhaps this entry was added manually. L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Could not guess length. Last.fm will silently ignore the scrobble.', array()); } try { $this->scrobbler->add($track->getArtist(), $track->getTitle(), $track->getAlbum(), $length, $track->getStartTime()); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'Sending %d scrobble(s) to Last.fm', array($this->scrobbler->getQueueSize())); $this->scrobbler->submit(); // TODO: caching if scrobbling's down whilst playing. } catch (Exception $e) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Could not send %d scrobble(s) to Last.fm: %s', array($this->scrobbler->getQueueSize(), $e->getMessage())); } }
public function compile($filename) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'compiling %s', array($filename)); $class = $this->getClassName($filename); $output = "<?php\n\n"; $output .= "/* Autogenerated by XoupCompiler */\n\n"; $output .= "class {$class} extends Unpacker\n{\n\n"; $output .= " private \$out_buffer = '';\n"; $output .= " private \$context = array();\n"; if (!empty($this->data)) { $output .= " private \$data = array(\n"; foreach ($this->data as $k => $v) { $k = addslashes($k); $v = addslashes($v); $output .= " \"{$k}\" => \"{$v}\",\n"; } $output .= " );\n"; } $output .= "\n"; $output .= " public function unpack(\$bin)\n"; $output .= " {\n"; $output .= " \$binlen = strlen(\$bin);\n"; $output .= " \$acc = 0;\n"; $output .= " \$ptr = 0;\n"; $output .= " \$this->_main(\$bin, \$binlen, \$acc, \$ptr);\n"; $output .= " return \$this->context;\n"; $output .= " }\n\n"; $output .= " public function flushBuffer()\n"; $output .= " {\n"; $output .= " L::level(L::INFO) &&\n"; $output .= " L::log(L::INFO, __CLASS__, \$this->out_buffer,\n"; $output .= " array());\n"; $output .= " }\n\n"; foreach (array_keys($this->subs) as $sub) { $output .= $this->writeFunctionHeader($sub); $output .= $this->writeFunctionBody($sub); $output .= $this->writeFunctionFooter(); } $output .= $this->writeLUTFunctionHeader(); $output .= $this->writeLUTFunctionBody(array_keys($this->subs)); $output .= $this->writeFunctionFooter(); $output .= "}\n"; file_put_contents($this->getCompiledName($filename), $output); }
public function elapse($seconds) { $this->playtime += $seconds; $was_passed_now_playing_point = $this->passed_now_playing_point; $was_passed_scrobble_point = $this->passed_scrobble_point; $was_ended = $this->passed_end; $this->passed_now_playing_point = $this->playtime >= self::NOW_PLAYING_MIN; $this->passed_scrobble_point = $this->playtime >= $this->scrobble_point; $this->passed_end = $this->playtime >= $this->end_point; if ($this->passed_now_playing_point && !$was_passed_now_playing_point) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, '%s passed now playing point', array($this->track->getFullTitle())); } if ($this->passed_scrobble_point && !$was_passed_scrobble_point) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, '%s passed scrobble point', array($this->track->getFullTitle())); } if ($this->passed_end && !$was_ended) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, '%s passed end point', array($this->track->getFullTitle())); } }
public function parse($program) { $data = array(); // strip comments $stripped_program = preg_replace("/#[^\n]*\n/", ' ', $program); // tokenize $ops = preg_split("/\\s+/", $stripped_program); // trim $ops = array_map('trim', $ops); // remove empty tokens foreach ($ops as $k => $v) { if (empty($v)) { unset($ops[$k]); } } $subs = array(); $opdest = null; foreach ($ops as $k => $v) { if (preg_match('/^([a-zA-Z0-9]+):$/', $v, $matches)) { // it's a label $subs[$matches[1]] = array(); $opdest = $matches[1]; } elseif (preg_match('/^\\.[a-zA-Z0-9]+$/', $v, $matches)) { // we found our first piece of DATA. finish program parsing // and move to DATA parsing $data = $this->parseData($program); break; } else { // it's an op if (is_null($opdest)) { throw new RuntimeException("Parse error: op found out of sub scope"); } $subs[$opdest][] = $v; } } if (!in_array('main', array_keys($subs))) { throw new RuntimeException("Parse error: no 'main' sub found."); } L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'parsed %d subs and %d literals', array(count($subs), count($this->data))); return $subs; }
protected function getBeatportURL(SSLTrack $track) { $url = ''; $bp = $this->newBeatportAPIClient(); $artistName = $track->getArtist(); $trackName = $track->getTitle(); $bp_track = $bp->getTrackByArtist($artistName, $trackName); if ($bp_track) { $bp_artist_names = $bp_track->getArtistNames(); $bp_track_title = $bp_track->getName(); $bp_url = $bp_track->getURL(); $bp_track_string = implode(', ', $bp_artist_names) . ' - ' . $bp_track_title; $ssl_track_string = $track->getFullTitle(); L::level(L::INFO) && L::log(L::INFO, __CLASS__, "Found %s at %s", array($bp_track_string, $bp_url)); if ($this->checkMatch($ssl_track_string, $bp_track_string)) { $url = $bp_track->getURL(); } else { L::level(L::INFO) && L::log(L::INFO, __CLASS__, "Rejected %s as a match for %s", array($bp_track_string, $ssl_track_string)); } } else { L::level(L::INFO) && L::log(L::INFO, __CLASS__, "No track found.", array()); } return $url; }
protected function sendNowPlaying() { $track = $this->track_to_notify; $message = $this->msg_format; foreach ($this->message_filters as $mf) { /* @var $mf ITrackMessageFilter */ $message = $mf->apply($track, $message); } // Twitter max message length, minus the pre-processed message, // and give back 2 chars for '%s' $max_title_length = 160 - (mb_strlen($message) - 2); $title = $track->getFullTitle(); $title_length = mb_strlen($title); if ($title_length > $max_title_length) { $title = mb_substr($title, 0, $this->max_title_length - 1) . '…'; } $status = sprintf($message, $title); try { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'Sending Now Playing to Twitter', array()); $this->twitter->send($status); } catch (Exception $e) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Could not send Now Playing to Twitter: %s', array($e->getMessage())); } }
public function spinOff(ParallelTask $t, $task = 'task') { if (function_exists('pcntl_fork') && !defined('SINGLE_THREADED')) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Forking %s...", array($task)); $pid = pcntl_fork(); if ($pid) { // parent if ($pid == -1) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Fork failed! Running %s single-threaded...", array($task)); $t->run(); return false; } return $pid; } else { // child $t->run(); exit; } } else { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "PCNTL not supported. Running %s single-threaded. If %s is slow, it will block the app until it is finished.", array($task, $task)); $t->run(); } return false; }
protected function handleRequest($conn) { socket_set_block($conn); $request = ''; $bytes = socket_recv($conn, $request, 16384, 0); if ($bytes === false) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Problem reading from socket: %s", array(socket_last_error($conn))); return; } $request = explode("\n", $request); $get_line = explode(' ', $request[0]); if (preg_match('#^/nowplaying\\.json(?:\\?.*|$)#', $get_line[1])) { $data = array(); if (isset($this->most_recent_track)) { $track = $this->most_recent_track; $data = array('artist' => $track->getArtist(), 'title' => $track->getTitle(), 'album' => $track->getAlbum(), 'length' => $track->getLengthInSeconds()); } $body = json_encode($data); $len = strlen($body); $lines = array('HTTP/1.0 200 OK', 'Date: ' . date('r'), 'Content-Type: application/json', 'Content-Length: ' . $len, 'Server: ScratchLive! Scrobbler', 'Connection: close', '', $body); socket_write($conn, implode("\n", $lines)); socket_close($conn); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Finished handling request.", array()); } else { $body = '<html><head><title>404 Not Found</title></head><body>No Dice.</body></html>'; $len = strlen($body); $lines = array('HTTP/1.0 404 Not Found', 'Date: ' . date('r'), 'Content-Type: text/html', 'Content-Length: ' . $len, 'Server: ScratchLive! Scrobbler', 'Connection: close', '', $body); socket_write($conn, implode("\n", $lines)); socket_close($conn); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Handled unknown request.", array()); } }
protected function getMixesForTrack($key) { $search = $this->doMixcloudCall('mixes', 'http://api.mixcloud.com%spopular/?limit=%d', array($key, 20)); if (isset($search['error'])) { throw new Exception('Error from Mixcloud: ' . $search['error']['message']); } $cloudcasts = array(); foreach ($search['data'] as $result) { $cloudcasts[] = $result; } L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'Found %d mixes for track %s', array(count($cloudcasts), $key)); return $cloudcasts; }
public function parseFromFile($fp) { $header_bin = fread($fp, 8); $length_read = strlen($header_bin); if ($length_read == 0) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Reached EOF; no more to read", array()); return false; // if we read an exact chunk, it's not an 'eof'. } if ($length_read < 8) { throw new OutOfBoundsException("No more data (read {$length_read} bytes)"); } if ($header_bin === false) { throw new RuntimeException("Read error; failed to read 8 bytes of chunk header"); } list($chunk_type, $chunk_size) = $this->parseHeader($header_bin); if ($chunk_size > 1048576) { // a chunk larger than 1Mb!? $chunk_size = number_format($chunk_size / 1024 / 1024, 2); throw new RuntimeException("Found chunk claiming to be enormous ({$chunk_size} MiB); are you reading the right file?"); } $body_bin = fread($fp, $chunk_size); $chunk = $this->chunk_factory->newChunk($chunk_type, $body_bin); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Read %s chunk from file", array($chunk_type)); return $chunk; }
public function notifyExit() { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "Exit caught.", array()); $this->exit_notified = true; }
/** * Converts an SSL signed binary string into a PHP integer */ protected function unpacksint($datum, $intmax = PHP_INT_MAX) { $width = strlen($datum); switch ($intmax) { case 0x7fffffff: // 32-bit mode switch ($width) { case 8: // Seems that ScratchLive 2.0 uses 64-bit timestamps. oh shi-- $vals = unpack('Nupper/Nlower', $datum); if ($vals['upper'] != 4294967295.0 && $vals['upper'] != 0 || $vals['upper'] == 4294967295.0 && $vals['lower'] & 2147483648.0 == 0 || $vals['upper'] == 0 && $vals['lower'] & 2147483648.0 == 2147483648.0) { L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, "Encountered signed 64-bit integer > PHP_INT_MAX on a 32-bit PHP. Throwing away upper bytes. Original value was 0x%08X%08X", array(dechex($vals['upper']), dechex($vals['lower']))); } // 32-bit range -ve vals will already be in the right sign. All bets are already off for other vals. if ($vals['upper'] > 0) { $vals['val'] = PHP_INT_MAX; } elseif ($vals['upper'] < -1) { $vals['val'] = -PHP_INT_MAX - 1; } else { $vals['val'] = $vals['lower']; if ($vals['upper'] < 0) { // -ve sign bit $vals['val'] |= 2147483648.0; } } break; case 4: // this will be signed on a 32-bit machine $vals = unpack('Nval', $datum); // unsigned long (always 32 bit, big endian byte order) break; case 2: $vals = unpack('nval', $datum); // unsigned short (always 16 bit, big endian byte order) if ($vals['val'] & 0x8000) { $vals['val'] |= 4294901760.0; // extend sign } break; case 1: $vals = unpack('cval', $datum); // char if ($vals['val'] & 0x80) { $vals['val'] |= 4294967040.0; // extend sign } break; default: throw new InvalidArgumentException('Cannot unpack an odd-sized int of width ' . $width); } return $vals['val']; case 9.223372036854776E+18: // 64-bit mode switch ($width) { case 8: // Seems that ScratchLive 2.0 uses 64-bit timestamps. oh shi-- $vals = unpack('Nupper/Nlower', $datum); // this will be signed on a 64-bit machine. $vals['val'] = $vals['upper'] << 32 | $vals['lower']; break; case 4: $vals = unpack('Nval', $datum); // unsigned long (always 32 bit, big endian byte order) if ($vals['val'] & 2147483648.0) { $vals['val'] |= 1.8446744069414584E+19; // extend sign } break; case 2: $vals = unpack('nval', $datum); // unsigned short (always 16 bit, big endian byte order) if ($vals['val'] & 0x8000) { $vals['val'] |= 1.8446744073709486E+19; // extend sign } break; case 1: $vals = unpack('cval', $datum); // char if ($vals['val'] & 0x80) { $vals['val'] |= 1.8446744073709552E+19; // extend sign } break; default: throw new InvalidArgumentException('Cannot unpack an odd-sized int of width ' . $width); } return $vals['val']; default: throw new RuntimeException('Unsupported architecture (neither 32-bit or 64-bit)'); } }
public function transitionTo(SSLTrack $track) { $from = $this->getStatus(); $to = $track->getStatus(); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "deck %d transitioned from %s to %s with track %s", array($this->deck_number, $from, $to, $track->getTitle())); switch ($from) { case 'EMPTY': $this->transitionFromEmptyTo($track); break; case 'SKIPPED': $this->transitionFromSkippedTo($track); break; case 'PLAYED': $this->transitionFromPlayedTo($track); break; case 'NEW': $this->transitionFromNewTo($track); break; case 'PLAYING': $this->transitionFromPlayingTo($track); break; default: throw new InvalidArgumentException('Unknown FROM state "' . $from . '"'); } }
protected function addAllObserversFromPlugins() { foreach ($this->plugins as $id => $plugin) { $observers = $plugin->getObservers(); $oc = 0; // observer count foreach ($observers as $o) { // we wrap every observer in a 'WithId' version // of the same observer which we can later use // to selectively pull matching observers back // out of the list. if ($o instanceof TickObserver) { $this->addTickObserver(new TickObserverWithId($o, $id)); $oc++; } if ($o instanceof SSLDiffObserver) { $this->addDiffObserver(new SSLDiffObserverWithId($o, $id)); $oc++; } if ($o instanceof TrackChangeObserver) { $this->addTrackChangeObserver(new TrackChangeObserverWithId($o, $id)); $oc++; } if ($o instanceof NowPlayingObserver) { $this->addNowPlayingObserver(new NowPlayingObserverWithId($o, $id)); $oc++; } if ($o instanceof ScrobbleObserver) { $this->addScrobbleObserver(new ScrobbleObserverWithId($o, $id)); $oc++; } } L::level(L::INFO) && L::log(L::INFO, __CLASS__, "%d: %s installed", array($id, get_class($plugin))); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "%s brought %d observers to the table", array(get_class($plugin), $oc)); } }
protected function flushBuffer() { L::level(L::INFO) && L::log(L::INFO, __CLASS__, $this->out_buffer, array()); $this->out_buffer = ''; }
/** * Update model information based on changes to the SSL History. * * @param SSLHistoryDiffDom $diff */ public function notifyDiff(SSLHistoryDiffDom $diff) { foreach ($diff->getTracks() as $track) { /* @var $track SSLTrack */ // create track deck on demand $this->getDeck($track->getDeck()); } $events = array(); foreach ($this->decks as $deck_number => $deck) { /* @var $deck SSLRealtimeModelDeck */ $deck->notify($diff); $stopped_track = $deck->trackStopped(); if ($stopped_track) { $events[] = $this->factory->newTrackStoppedEvent($stopped_track); } $started_track = $deck->trackStarted(); if ($started_track) { $events[] = $this->factory->newTrackStartedEvent($started_track); } $updated_track = $deck->trackUpdated(); if ($updated_track) { $events[] = $this->factory->newTrackUpdatedEvent($updated_track); } } if (count($events)) { $events = $this->factory->newTrackChangeEventList($events); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, "notifying %s", array($events)); $this->notifyTrackChangeObservers($events); } }
protected function executeWithRetries(array $placeholders, $retry_count = 0) { if ($retry_count > self::RETRY_LIMIT) { L::level(L::ERROR) && L::log(L::ERROR, __CLASS__, 'Failed to execute database statement; tried %d times', array(self::RETRY_LIMIT + 1)); return; // fail } if ($retry_count > 0) { L::level(L::INFO) && L::log(L::INFO, __CLASS__, 'Retrying database statement. Attempt number %d', array($retry_count + 1)); } try { if (!isset($this->dbh)) { $this->connect(); } $this->sth->execute($placeholders); } catch (Exception $e) { $this->close(); L::level(L::WARNING) && L::log(L::WARNING, __CLASS__, 'Statement failed: %s', array($e->getMessage())); // retry $this->executeWithRetries($placeholders, $retry_count + 1); } }
protected function groupByTimestamp(array $tracks) { $last_updated_at = 0; $group = array(); L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'Found %d tracks in file', array(count($tracks))); //usort($tracks, array($this, 'timestampSort')); foreach ($tracks as $track) { /* @var $track SSLTrack */ if ($track->getUpdatedAt() != $last_updated_at) { if (!empty($group)) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'Entries found at %s', array(date('Y-m-d H:i:s', $last_updated_at))); $this->payloads[] = new SSLHistoryDiffDom($group); } $last_updated_at = $track->getUpdatedAt(); $group = array(); } $group[] = $track; } if (!empty($group)) { L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'Entries found at %s', array(date('Y-m-d H:i:s', $last_updated_at))); $this->payloads[$last_updated_at] = new SSLHistoryDiffDom($group); } L::level(L::DEBUG) && L::log(L::DEBUG, __CLASS__, 'Divided tracks in %d groups', array(count($this->payloads))); }