Recentemente eu me deparei a tarefa de implementar o Twitter de Streaming de APIs para o processo de Feeds do Twitter (Tweets) em tempo real. Mais especificamente, a aplicação para a construção teve de ser capaz de ouvir os tweets que vão desde vários tópicos e usuários (vamos nos referir a eles como faixas), e deve ter sido capaz de hot-swap estas faixas, quase que instantaneamente. Não muito tempo antes de trabalhar com este aplicativo, o que eu tinha para realizar a mesma tarefa no contexto do Facebook. Em oposição ao Twitter, que faz uso de suas APIs de Streaming para fornecer aplicações com atualizações em tempo real, Facebook em vez disso, usa de Webhooks. Webhooks, sendo um HTTP retorno de chamada, fornecer aos desenvolvedores com um nível de sofisticação que é muito mais fácil de lidar. O Streaming de APIs fornecidas pelo Twitter, no entanto, requer seu aplicativo para manter uma conexão HTTP persistente com um Twitter muitos streaming de pontos de extremidade. Escrever um aplicativo que se baseia em tal uma conexão persistente para ele está funcionando nos obriga a pensar sobre isso de uma forma ligeiramente diferente do que o que estamos supostamente usada enquanto a construção de uma tradicional aplicativo web. Todo o foco deste artigo será no desenvolvimento de um aplicativo. O Twitter APIs de Streaming Se você der uma olhada no Twitter da Documentação do Desenvolvedor, você vai ver que elas nos fornecem APIs de Streaming. Claro, eles também fornecer-nos com o REST e Anúncios de APIs bem, mas para os nossos propósitos, vamos apenas focar em suas APIs de Streaming. Então, o que exatamente são as APIs de Streaming? Para colocar isso em termos simples, usando as APIs de Streaming, seu aplicativo pode estabelecer uma baixa latência de conexão com o Twitter streaming de pontos de extremidade. Uma vez que uma conexão foi estabelecida com êxito, o Twitter vai enviar para a frente qualquer feed em tempo real seu aplicativo solicitou para esta conexão de tubagem quase instantaneamente. De acordo com o google docs: As APIs de Streaming dar aos desenvolvedores de baixa latência de acesso ao Twitter da transmissão global do Tweet de dados. Uma boa implementação de um streaming cliente serão enviadas mensagens indicando Tweets e outros eventos tenham ocorrido, sem a sobrecarga associada com as mesas de um REST de ponto de extremidade. As APIs de Streaming requer o disse conexão persistente (essencialmente, que nunca termina) na natureza. Em essência, é semelhante ao download de um infinitamente grande de arquivos — o sistema irá manter na recepção de dados, a menos que você manualmente encerrar a conexão. O tipo de feeds de seu aplicativo recebe dependerá do tipo de fluxos, você estará usando. As APIs de Streaming oferece aos desenvolvedores com três diferentes tipos de fluxos: Público Fluxos – os Fluxos de público dados que fluem através do Twitter. Adequada para os seguintes usuários específicos ou tópicos, e mineração de dados. Usuário transmite – usuário Único fluxos, contendo cerca de todos os dados correspondente, com um único ponto de vista do utilizador do Twitter. Site de Fluxos – A versão multi-usuário de usuário de fluxos. Site de fluxos são destinados para os servidores que devem se conectar ao Twitter em nome de muitos usuários. Como eu disse antes, a alimenta nós receber vai depender do tipo de fluxos de nós estará usando. Então, antes de irmos adiante, vamos dar uma olhada nas exigências da nossa aplicação, dependendo do que vamos usar, Públicas ou Sequências de Usuário Fluxos (Streams estão em um beta fechado). A nossa aplicação deve satisfazer os seguintes requisitos: Ouvir ao vivo tweets para as faixas que tenha solicitado Ser capaz de processar o recebeu tweets sem interromper a conexão com o fluxo de ponto de extremidade Ser capaz de mudar essas faixas como eles estão sendo alterados com o mínimo de interrupção para o dito de conexão Manter esses requisitos em mente, agora temos que resolver sobre os fluxos de nós estará usando. Usuário transmite, como dito anteriormente, fornece dados de um indivíduo, o ponto de vista de usuário. De acordo com a O Twitter é a documentação para o Utilizador Fluxos de: Usuário Fluxos de fornecer um fluxo de dados e eventos específicos para o usuário autenticado. Note que o Usuário Fluxos não são destinados para o servidor-para-servidor de conexões. Se você precisar fazer ligações em nome de vários usuários do mesmo computador, considere a utilização de site de fluxos. Minimizar o número de conexões que o aplicativo faz para Usuário transmite. Cada conta do Twitter é limitado a apenas algumas simultânea de Usuário Fluxos de conexões por OAuth aplicação, independentemente do IP. Uma vez por aplicativo limite é excedido, a mais antiga conexão será encerrada. Uma conta de logon em muitas instâncias do mesmo OAuth aplicação de um ciclo de ligações como as instâncias de aplicação de voltar a ligar e desligar o outro. Uma vez que estamos mais focados em ser capaz de receber os tweets de vários usuários, não é claro como o número de usuários que vai ser. Indo pelo google docs, o Usuário transmite não cortá-la para a nossa aplicação do caso de uso. Agora estamos a esquerda para tornar Pública Fluxos. Como oposição ao Usuário Fluxos, o que nos permite receber feeds no contexto limitado a usuários individuais, Públicas Fluxos de fornecer aplicativos com um fluxo de dados públicos que flui através do Twitter. Falando em contexto de tweets especificamente, se usamos pública fluxos de forma inteligente, nosso aplicativo de não ser vinculado ao escopo limitado de usuários individuais em contraste com o Usuário transmite. Já que não está necessariamente preocupado com particular fluxo de dados, podemos passar ao longo do Twitter Alças (@nome de usuário) correspondente ao indivíduo Usuários do Twitter, como faixas antes de estabelecer uma conexão com o público de transmissão de ponto de extremidade. Isto irá permitir que a nossa aplicação para ouvir ao vivo pública tweets de vários usuários. Uma rápida ponto a notar, antes de ir mais longe, como por Twitter Documentação para o Público Córregos, nossa aplicação só pode estabelecer uma conexão única com o público, fluxos, em qualquer dado momento. a Comunicação com a API de Streaming: Construir a nossa aplicação Agora que estamos a fazer com todos os introdutório bits, podemos começar a construir nossa aplicação. Eu vou estar a desenvolver a aplicação em PHP que roda em Linux, usando o popular Framework Symfony e Compositor como o gerenciador de pacotes. O que está sendo dito, você deve ser capaz de aplicar os conceitos fundamentais e implementar o projeto em qualquer idioma de sua escolha. eu vou, no entanto, estar usando Phirehose por Fennb, uma biblioteca de terceiros para facilitar o processo de comunicação com o Twitter APIs de Streaming. Se você está em desenvolvimento na plataforma diferente PHP, aqui está uma lista extensa de third-party libraries você pode fazer uso. Você pode adicionar Phirehose para o seu projecto através do Compositor usando o seguinte comando: php composer require “fennb/phirehose” Configuração de nossa aplicação: Criar um novo projeto Symfony (vamos chamá-lo de twitterFeeds), executando o seguinte comando: symfony novo twitterFeeds Antes de se mover junto com o artigo, certifique-se de que instalou a biblioteca de terceiros, como mencionado acima. Em seguida, crie um novo bundle (vamos chamar isso de TwitterBundle), executando o seguinte comando: php bin/console generate:bundle Siga junto com o que detalhes de configuração é perguntado de você. Em seguida, vá para o TwitterBundle diretório em seu projeto e crie um novo Serviços diretório. Nesse diretório, crie um novo arquivo chamado TwitterService.php que vamos usar. Certifique-se de registrar esse serviço para a sua aplicação. o Estabelecimento de uma conexão persistente: Como eu disse antes, escrever uma aplicação que se baseia em uma conexão persistente para ele está funcionando nos obriga a pensar sobre isso de uma forma ligeiramente diferente. Ao contrário, no caso do uso de APIs REST, onde podemos fazer chamadas de API, ou Webhooks, onde um retorno de chamada é feita para os nossos servidores, com a Transmissão de APIs, estamos estabelecendo uma conexão persistente com um streaming de ponto de extremidade que, em seguida, vivem para sempre (idealmente falando), e processar os dados que recebemos em nossos finais através deste meio. Encerramos esta conexão apenas em casos quando vamos precisar reiniciá-lo, a fim de atualizar as faixas. Então, como nós vamos sobre o estabelecimento de tais disse: conexão? Uma maneira é fazer uso de Processos De Plano De Fundo. Vamos dizer que temos para ouvir ao vivo, tweets, em seguida, precisamos estabelecer uma conexão persistente com o Twitter público de transmissão de pontos de extremidade. Para fazer isso, podemos executar um processo de plano de fundo através do terminal. Este processo de plano de fundo será executado como um processo individual, e vai estabelecer a referida ligação persistente nosso aplicativo requer. Podemos, então, controlar o ID de processo (PID) este pano de fundo do processo, se necessário alterá-lo de qualquer maneira. Para fazer o nosso processo de plano de fundo, vamos criar um comando de console que podemos, então, executar a partir do terminal, no diretório raiz do nosso projeto. Para tornar o nosso comando, podemos utilizar o Componente Console fornecida pelo Framework Symfony. Primeiro crie um Comandos diretório no seu TwitterBundle, e, em seguida, crie TwitterCommand.php arquivo nesse diretório. /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Command; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class TwitterCommand extends ContainerAwareCommand { protected function configure() { $this->setName('twitter:stream')->setDescription('Listen for Live Twitter Feeds.'); } protected function execute(InputInterface $input, OutputInterface $output) { $twitterTracks = ['#ReasonsToLoveMe']; // Define your tracks you wish to receive updates for $this->getContainer()->get('twitter.service')->listenForTweets($twitterTracks); // This will start the streaming process } } 12345678910111213141516171819202122232425262728293031 /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Command; use Symfony\Component\Console\Command\Command;use Symfony\Component\Console\Input\InputInterface;use Symfony\Component\Console\Output\OutputInterface;use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class TwitterCommand extends ContainerAwareCommand{ protected function configure() { $this->setName('twitter:stream')->setDescription('Listen for Live Twitter Feeds.'); } protected function execute(InputInterface $input, OutputInterface $output) { $twitterTracks = ['#ReasonsToLoveMe']; // Define your tracks you wish to receive updates for $this->getContainer()->get('twitter.service')->listenForTweets($twitterTracks); // This will start the streaming process }} A partir do directório raiz do nosso projeto, agora podemos executar o código escrito dentro do execute() função usando o seguinte comando no terminal: php bin/console twitter:stream Como podemos ver, o TwitterCommand::execute(), a função em vez de chamar o TwitterCommand::listenForTweets() função definida em <TwitterService, , que irá estabelecer uma nova conexão persistente com o Twitter streaming de ponto de extremidade. Então, vamos código este até a próxima. Em seu TwitterService.php que criamos anteriormente, /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Services; const CONSUMER_KEY = YOUR_APP_CONSUMER_KEY; const CONSUMER_SECRET = YOUR_APP_CONSUMER_SECRET; const APPLICATION_TOKEN = YOUR_APP_ACCESS_TOKEN; const APPLICATION_TOKEN_SECRET = YOUR_APP_ACCESS_TOKEN_SECRET; // Include the third-party library require_once __DIR__ . '/../../../vendor/fennb/phirehose/lib/OauthPhirehose.php'; class TwitterListener extends \OauthPhirehose { public function __construct() { parent::__construct(APPLICATION_TOKEN, APPLICATION_TOKEN_SECRET, \Phirehose::METHOD_FILTER); $this->consumerKey = CONSUMER_KEY; $this->consumerSecret = CONSUMER_SECRET; } public function enqueueStatus($status) { $twitterFeed = json_decode($status, true); if (is_array($twitterFeed) && isset($twitterFeed['user']['screen_name'])) { $twitterData = array('feed' => $twitterFeed); dump('New Feed Recieved'); dump($twitterData); } } } class TwitterService { /** * This function will establish a persistent connection with one of the twitter's streaming endpoint. * @param array $twitterTrackCollection Collection of tracks which we'll receive updates for */ public function listenForTweets(array $twitterTrackCollection = []) { // Terminate the process if there are no active tracks if (empty($twitterTrackCollection)) { echo 'No active tracks. Terminating Process...' . PHP_EOL . PHP_EOL; exit(0); } $twitterListener = new TwitterListener(); $twitterListener->setTrack($twitterTrackCollection); $twitterListener->consume(); } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Services; const CONSUMER_KEY = YOUR_APP_CONSUMER_KEY;const CONSUMER_SECRET = YOUR_APP_CONSUMER_SECRET;const APPLICATION_TOKEN = YOUR_APP_ACCESS_TOKEN;const APPLICATION_TOKEN_SECRET = YOUR_APP_ACCESS_TOKEN_SECRET; // Include the third-party libraryrequire_once __DIR__ . '/../../../vendor/fennb/phirehose/lib/OauthPhirehose.php'; class TwitterListener extends \OauthPhirehose{ public function __construct() { parent::__construct(APPLICATION_TOKEN, APPLICATION_TOKEN_SECRET, \Phirehose::METHOD_FILTER); $this->consumerKey = CONSUMER_KEY; $this->consumerSecret = CONSUMER_SECRET; } public function enqueueStatus($status) { $twitterFeed = json_decode($status, true); if (is_array($twitterFeed) && isset($twitterFeed['user']['screen_name'])) { $twitterData = array('feed' => $twitterFeed); dump('New Feed Recieved'); dump($twitterData); } }} class TwitterService{ /** * This function will establish a persistent connection with one of the twitter's streaming endpoint. * @param array $twitterTrackCollection Collection of tracks which we'll receive updates for */ public function listenForTweets(array $twitterTrackCollection = []) { // Terminate the process if there are no active tracks if (empty($twitterTrackCollection)) { echo 'No active tracks. Terminating Process...' . PHP_EOL . PHP_EOL; exit(0); } $twitterListener = new TwitterListener(); $twitterListener->setTrack($twitterTrackCollection); $twitterListener->consume(); }} Agora, se você executar o comando que acabamos de criar a partir do seu terminal, uma nova conexão com o Twitter API de Streaming será estabelecida e você vai começar a receber público tweets para as faixas que você tiver definido. No momento de escrever este artigo, “#ReasonsToLoveMe” foi trending então eu usei isso como uma faixa de exemplo. Agora, cada vez que um tweet que consiste em qualquer um dos nossos especificado faixas (neste caso, “#ReasonsToLoveMe”), que o tweet vai ser passados para baixo a ligação de tubagem. Este tweet, em seguida, irá ser repassados para o TwitterListener::enqueueStatus() função, onde você pode processar o recebeu de alimentação. No entanto, o você deve evitar fazer qualquer operação demorada neste ponto,. A razão é que se o seu aplicativo não é possível processar este fluxo de dados rápido o suficiente em contraste com a taxa que está a receber os feeds, você corre o risco de ter sua ligação finalizada, o que para a maioria de nós seria indesejável. Em Tempo Real No Twitter Feeds Até agora, temos sido iniciando manualmente a ligação por ir ao nosso terminal e executar o comando. Mas desde aplicações do mundo real são muito diferentes, vamos automatizar esse processo de iniciar e fechar a conexão. No nosso DefaultController, vamos escrever um manipulador de ação (vamos chamar isso de startStreamAction), que quando executado irá iniciar o nosso processo de fluxo contínuo. Certifique-se de que você tenha configurado a rota para este manipulador correspondente routing.yml ficheiro. DefaultController.php, /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class DefaultController extends Controller { // ..... /** * This handler will switch to the root directory and start a new background process */ public function startStreamAction(Request $request) { chdir('../'); $command = 'php bin/console twitter:listen'; exec($command); exit(0); } // ..... } 12345678910111213141516171819202122232425262728293031 /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class DefaultController extends Controller{ // ..... /** * This handler will switch to the root directory and start a new background process */ public function startStreamAction(Request $request) { chdir('../'); $command = 'php bin/console twitter:listen'; exec($command); exit(0); } // .....} Agora cada vez que visitar a rota para este processador, este comando deve ser executado separadamente em um novo segmento. Com Público Córregos, só recebe pública feeds para as faixas que definimos antes de estabelecer uma conexão persistente com o fluxo de ponto de extremidade. Então, se necessário, para atualização de nossa faixas, que vai precisar para terminar a ligação anterior, re-definir as nossas faixas e, em seguida, re-estabelecer uma nova conexão com o fluxo de ponto de extremidade. Este processo é muito crítico, pois podemos ter apenas uma conexão com a transmissão de ponto de extremidade de cada vez (corremos o risco de ter o nosso IP banido, com múltiplas conexões). Então, precisamos ter certeza de que antes de tentar criar uma nova conexão, todos previamente realizada conexões são fechadas. Para fechar uma conexão com o fluxo de ponto final, podemos terminar o processo de plano de fundo correspondente à conexão. Para matar o processo, podemos fazer uso de ID de processo (PID), ou procurá-la usando o nome e os argumentos do processo de plano de fundo. Usando o ID do processo, cada vez que estabelecer uma nova conexão, nós vamos precisar de registo de dados (banco de dados, arquivo de texto, etc…) a ID do processo correspondente a esse processo de plano de fundo. Usando este registo, em seguida, você pode encerrar qualquer anteriormente realizada processos de plano de fundo antes de iniciar um novo. Vamos atualizar o nosso startStreamAction processador para registrar a ID do processo a cada vez que uma conexão é feita, e em nosso DefaultController, crie um novo manipulador de ação (vamos chamar este stopStreamAction) para encerrar qualquer anteriormente realizada processos de plano de fundo. Podemos então chamar esta rotina de tratamento antes de iniciar um novo processo em segundo plano para garantir que apenas uma instância de uma conexão persistente com o fluxo de ponto de extremidade está activa de cada vez. /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class DefaultController extends Controller { // ...... /** * This handler will first terminate any previously held background process * by firing the stopStreamAction() handler. Then it'll create a new background * process which establish a new connection with a streaming endpoint. */ public function startStreamAction(Request $request) { // Execute the stopStreamAction() handler $curlHandler = curl_init(); $stopStreamPath = $this->generateUrl('twitter_stream_stop', array(), UrlGeneratorInterface::ABSOLUTE_URL); curl_setopt($curlHandler, CURLOPT_URL, $stopStreamPath); curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1); curl_exec($curlHandler); // Create a new background process chdir('../'); $output = array(); $command = 'nohup php bin/console twitter:listen > /dev/null 2>&1 & echo $!'; exec($command, $output); $processId = (int) $output[0]; // Process ID of the newly created background process. Log this. exit(0); } /** * This handler will fetch a log of Process IDs corresponding to any background * process and terminate them. */ public function stopStreamAction(Request $request) { $activeProcesses = ARRAY_COLLECTION_OF_PROCESS_IDS_TO_TERMINATE; if (!empty($activeProcesses)) { foreach ($activeProcesses as $processId) { $command = 'kill ' . $processId . ' 2>&1'; exec($command, $output); $this->get('logger')->info('Twitter Stream Process Terminated: ' . $processId); } } exit(0); } // ...... } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Controller; use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class DefaultController extends Controller{ // ...... /** * This handler will first terminate any previously held background process * by firing the stopStreamAction() handler. Then it'll create a new background * process which establish a new connection with a streaming endpoint. */ public function startStreamAction(Request $request) { // Execute the stopStreamAction() handler $curlHandler = curl_init(); $stopStreamPath = $this->generateUrl('twitter_stream_stop', array(), UrlGeneratorInterface::ABSOLUTE_URL); curl_setopt($curlHandler, CURLOPT_URL, $stopStreamPath); curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1); curl_exec($curlHandler); // Create a new background process chdir('../'); $output = array(); $command = 'nohup php bin/console twitter:listen > /dev/null 2>&1 & echo $!'; exec($command, $output); $processId = (int) $output[0]; // Process ID of the newly created background process. Log this. exit(0); } /** * This handler will fetch a log of Process IDs corresponding to any background * process and terminate them. */ public function stopStreamAction(Request $request) { $activeProcesses = ARRAY_COLLECTION_OF_PROCESS_IDS_TO_TERMINATE; if (!empty($activeProcesses)) { foreach ($activeProcesses as $processId) { $command = 'kill ' . $processId . ' 2>&1'; exec($command, $output); $this->get('logger')->info('Twitter Stream Process Terminated: ' . $processId); } } exit(0); } // ......} Se você olhar com cuidado, nós modificamos o comando que vamos executar a partir de um terminal, usando o exec() função. nohup php bin/console twitter:listen > /dev/null 2>&1 & echo $! Todos os bits extras e peças retornará o ID de processo do processo de plano de fundo criado através do exec() função. Agora, cada vez que um novo processo de plano de fundo é criado seguindo esta abordagem, todos os nossos anteriormente realizado processo de plano de fundo será interrompida (se houver). Isso deve ser mais do que suficiente para garantir que apenas uma está activa uma ligação de cada vez, desde que você efetuar corretamente o seu id de processo. Você pode melhorar esta funcionalidade de acordo com as suas necessidades. Tudo o que resta agora é processar o fluxo de dados que nós vamos estar recebendo através da conexão de tubagem. Para fazer isso, vamos fazer de melhoria para o nosso Twitter Serviço de (TwitterService.php) primeiro, e, em seguida, redirecionar todos os tweets que nosso aplicativo recebe um manipulador (vamos chamar este (processStreamAction) que vai nos processar esses tweets. Em seu TwitterService.php, /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Services; const CONSUMER_KEY = YOUR_APP_CONSUMER_KEY; const CONSUMER_SECRET = YOUR_APP_CONSUMER_SECRET; const APPLICATION_TOKEN = YOUR_APP_ACCESS_TOKEN; const APPLICATION_TOKEN_SECRET = YOUR_APP_ACCESS_TOKEN_SECRET; require_once __DIR__ . '/../../../vendor/fennb/phirehose/lib/OauthPhirehose.php'; class TwitterListener extends \OauthPhirehose { private $curlHandler = null; private $processStreamPath = null; public function __construct() { parent::__construct(APPLICATION_TOKEN, APPLICATION_TOKEN_SECRET, \Phirehose::METHOD_FILTER); $this->processStreamPath = URL_TO_PROCESS_STREAM_ACTION_HANDLER; $this->consumerKey = CONSUMER_KEY; $this->consumerSecret = CONSUMER_SECRET; $this->configureCURL(); } private function configureCURL() { $this->curlHandler = curl_init(); $headers = array('Content-type: multipart/form-data'); curl_setopt($this->curlHandler, CURLOPT_POST, true); curl_setopt($this->curlHandler, CURLOPT_URL, $this->processStreamPath); curl_setopt($this->curlHandler, CURLOPT_RETURNTRANSFER, 1); } public function enqueueStatus($status) { $twitterFeed = json_decode($status, true); if (is_array($twitterFeed) && isset($twitterFeed['user']['screen_name'])) { $twitterData = array('feed' => $twitterFeed); curl_setopt($this->curlHandler, CURLOPT_POSTFIELDS, http_build_query($twitterData)); curl_exec($this->curlHandler); } } } class TwitterService { /** * This function will establish a persistent connection with one of the twitter's streaming endpoint. * @param array $twitterTrackCollection Collection of tracks which we'll receive updates for */ public function listenForTweets(array $twitterTrackCollection = []) { // Terminate the process if there are no active tracks if (empty($twitterTrackCollection)) { echo 'No active tracks. Terminating Process...' . PHP_EOL . PHP_EOL; exit(0); } $twitterListener = new TwitterListener(); $twitterListener->setTrack($twitterTrackCollection); $twitterListener->consume(); } } 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Services; const CONSUMER_KEY = YOUR_APP_CONSUMER_KEY;const CONSUMER_SECRET = YOUR_APP_CONSUMER_SECRET;const APPLICATION_TOKEN = YOUR_APP_ACCESS_TOKEN;const APPLICATION_TOKEN_SECRET = YOUR_APP_ACCESS_TOKEN_SECRET; require_once __DIR__ . '/../../../vendor/fennb/phirehose/lib/OauthPhirehose.php'; class TwitterListener extends \OauthPhirehose{ private $curlHandler = null; private $processStreamPath = null; public function __construct() { parent::__construct(APPLICATION_TOKEN, APPLICATION_TOKEN_SECRET, \Phirehose::METHOD_FILTER); $this->processStreamPath = URL_TO_PROCESS_STREAM_ACTION_HANDLER; $this->consumerKey = CONSUMER_KEY; $this->consumerSecret = CONSUMER_SECRET; $this->configureCURL(); } private function configureCURL() { $this->curlHandler = curl_init(); $headers = array('Content-type: multipart/form-data'); curl_setopt($this->curlHandler, CURLOPT_POST, true); curl_setopt($this->curlHandler, CURLOPT_URL, $this->processStreamPath); curl_setopt($this->curlHandler, CURLOPT_RETURNTRANSFER, 1); } public function enqueueStatus($status) { $twitterFeed = json_decode($status, true); if (is_array($twitterFeed) && isset($twitterFeed['user']['screen_name'])) { $twitterData = array('feed' => $twitterFeed); curl_setopt($this->curlHandler, CURLOPT_POSTFIELDS, http_build_query($twitterData)); curl_exec($this->curlHandler); } }} class TwitterService{ /** * This function will establish a persistent connection with one of the twitter's streaming endpoint. * @param array $twitterTrackCollection Collection of tracks which we'll receive updates for */ public function listenForTweets(array $twitterTrackCollection = []) { // Terminate the process if there are no active tracks if (empty($twitterTrackCollection)) { echo 'No active tracks. Terminating Process...' . PHP_EOL . PHP_EOL; exit(0); } $twitterListener = new TwitterListener(); $twitterListener->setTrack($twitterTrackCollection); $twitterListener->consume(); }} Agora, cada vez que um feed do twitter é recebida, o TwitterListener::enqueueStatus() reencaminhar a alimentação para a rota que tiver especificado usando CURL por fazer uma solicitação POST. Em essência, esta é exatamente como um Webhook se você pensar sobre isso. Agora vamos escrever o processStreamAction() manipulador de nosso DefaultController. Em seu <DefaultController.php, /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class DefaultController extends Controller { /** * This handler will first terminate any previously held background process * by firing the stopStreamAction() handler. Then it'll create a new background * process which establishes a new connection with a streaming endpoint. */ public function startStreamAction(Request $request) { // Execute the stopStreamAction() handler $curlHandler = curl_init(); $stopStreamPath = $this->generateUrl('twitter_stream_stop', array(), UrlGeneratorInterface::ABSOLUTE_URL); curl_setopt($curlHandler, CURLOPT_URL, $stopStreamPath); curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1); curl_exec($curlHandler); // Create a new background process chdir('../'); $output = array(); $command = 'nohup php bin/console twitter:listen > /dev/null 2>&1 & echo $!'; exec($command, $output); $processId = (int) $output[0]; // Process ID of the newly created background process. Log this. exit(0); } /** * This handler will fetch a log of Process IDs corresponding to any background * process and terminate them. */ public function stopStreamAction(Request $request) { $activeProcesses = ARRAY_COLLECTION_OF_PROCESS_IDS_TO_TERMINATE; if (!empty($activeProcesses)) { foreach ($activeProcesses as $processId) { $command = 'kill ' . $processId . ' 2>&1'; exec($command, $output); $this->get('logger')->info('Twitter Stream Process Terminated: ' . $processId); } } exit(0); } /** * A POST request will be made to this handler whenever our application receives * a feed. You can write your implementation here. */ public function processStreamAction(Request $request) { if (isset($_POST)) { if (array_key_exists('feed', $_POST)) { // Real-time Twitter Feed. Write your own implementation over here. $streamContent = $_POST['feed']; } } else { // Request method not supported. } exit(0); } } 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 /** * Webkul Software. * * @category Webkul, Uvdesk * @package Webkul_UVDesk_TF * @author Akshay Kumar * @copyright Copyright (c) 2010-2016 Webkul Software Private Limited (https://webkul.com) * @license https://store.webkul.com/license.html */ namespace TwitterBundle\Controller; use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;use Symfony\Bundle\FrameworkBundle\Controller\Controller;use Symfony\Component\Routing\Generator\UrlGeneratorInterface; class DefaultController extends Controller{ /** * This handler will first terminate any previously held background process * by firing the stopStreamAction() handler. Then it'll create a new background * process which establishes a new connection with a streaming endpoint.*/public function startStreamAction(Request $request){// Execute the stopStreamAction() handler$curlHandler = curl_init();$stopStreamPath = $this->generateUrl('twitter_stream_stop', array(), UrlGeneratorInterface::ABSOLUTE_URL);curl_setopt($curlHandler, CURLOPT_URL, $stopStreamPath);curl_setopt($curlHandler, CURLOPT_RETURNTRANSFER, 1);curl_exec($curlHandler);// Create a new background processchdir('../');$output = array();$command = 'nohup php bin/console twitter:listen > /dev/null 2>&1 & echo $!';exec($command, $output);$processId = (int) $output[0]; // Process ID of the newly created background process. Log this.exit(0);} /** * This handler will fetch a log of Process IDs corresponding to any background * process and terminate them. */ public function stopStreamAction(Request $request){ $activeProcesses = ARRAY_COLLECTION_OF_PROCESS_IDS_TO_TERMINATE; if (!empty($activeProcesses)) { foreach ($activeProcesses as $processId) { $command = 'kill ' . $processId . ' 2>&1'; exec($command, $output); $this->get('logger')->info('Twitter Stream Process Terminated: ' . $processId);}} exit(0);} /** * A POST request will be made to this handler whenever our application receives * a feed. You can write your implementation here. */ public function processStreamAction(Request $request){ if (isset($_POST)) { if (array_key_exists('feed', $_POST)) { // Real-time Twitter Feed. Write your own implementation over here. $streamContent = $_POST['feed']; } } else { // Request method not supported.} exit(0);}} Não que você vá! Agora temos uma cozinha totalmente funcional do aplicativo, que não vai apenas ouvir ao vivo feeds do Twitter para o especificado faixas, mas também nos permite atualizar nossas faixas, quase que instantaneamente, enquanto certificando-se de que apenas uma conexão com a transmissão de ponto de extremidade está ativo no momento. Você pode estender esta aplicação para o seu gosto e torná-lo mais robusto e tolerante a falhas. Aqui no UVDesk, seguimos uma abordagem semelhante para fornecer aos nossos Usuários do Twitter com a melhor experiência de usuário e conectividade social. Tag(s) Background Process Facebook API Streaming API Twitter Category(s) uvdesk