package com.twasyl.slideshowfx.server.service; import com.twasyl.slideshowfx.server.SlideshowFXServer; import com.twasyl.slideshowfx.server.beans.chat.ChatMessage; import com.twasyl.slideshowfx.server.beans.chat.ChatMessageSource; import com.twasyl.slideshowfx.server.beans.chat.ChatMessageStatus; import io.vertx.core.json.JsonObject; import javafx.application.Platform; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.concurrent.Worker; import javafx.scene.Scene; import javafx.scene.web.WebView; import javafx.stage.Stage; import twitter4j.*; import twitter4j.auth.AccessToken; import twitter4j.auth.RequestToken; import twitter4j.conf.Configuration; import twitter4j.conf.ConfigurationBuilder; import twitter4j.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; /** * This class allow to use Twitter in the chat. * * @author Thierry Wasylczenko * @version 1.0 * @since SlideshowFX 1.0 */ public class TwitterService extends AbstractSlideshowFXService { private static final Logger LOGGER = Logger.getLogger(TwitterService.class.getName()); private Configuration twitterConfiguration; private Twitter twitter = null; private TwitterStream twitterStream = null; private final ObjectProperty<RequestToken> requestToken = new SimpleObjectProperty<>(); private final ObjectProperty<AccessToken> accessToken = new SimpleObjectProperty<>(); @Override public void start() { final String hashtag = SlideshowFXServer.getSingleton().getTwitterHashtag(); this.twitterConfiguration = new ConfigurationBuilder() .setOAuthConsumerKey("5luxVGxswd42RgTfbF02g") .setOAuthConsumerSecret("winWDhMbeJZ4m66gABqpohkclLDixnyeOINuVtPWs") .build(); this.accessToken.addListener((value, oldValue, newValue) -> { this.launchTwitter(); }); if(hashtag != null && !hashtag.isEmpty()) { if(this.accessToken.get() == null) this.connect(); else this.launchTwitter(); } } @Override public void stop() { try { super.stop(); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Can not stop the TwitterService properly", e); } if(this.twitterStream != null) { try { new Thread(() -> { this.twitterStream.shutdown(); }).start(); } catch(Exception e) { LOGGER.log(Level.SEVERE, "Can not stop the Twitter stream", e); } } } /** * Connect to the Twitter service by asking the user to log in. Once the connection is successful, the {@link #accessToken} * is udpated. */ private void connect() { this.twitter = TwitterFactory.getSingleton(); try { this.twitter.setOAuthConsumer(this.twitterConfiguration.getOAuthConsumerKey(), this.twitterConfiguration.getOAuthConsumerSecret()); } catch(IllegalStateException e) { LOGGER.fine("Consumer keys already set up"); } try { this.requestToken.set(this.twitter.getOAuthRequestToken()); final String authUrl = this.requestToken.get().getAuthorizationURL(); Platform.runLater(() -> { final WebView twitterBrowser = new WebView(); final Scene scene = new Scene(twitterBrowser); final Stage stage = new Stage(); twitterBrowser.getEngine().load(authUrl); twitterBrowser.getEngine().getLoadWorker().stateProperty().addListener((observableValue, oldState, newState) -> { if (newState == Worker.State.SUCCEEDED) { if (twitterBrowser.getEngine().getDocument().getDocumentURI().equals("https://api.twitter.com/oauth/authorize")) { String pinCode = twitterBrowser.getEngine().getDocument().getElementsByTagName("kbd").item(0).getTextContent(); try { TwitterService.this.accessToken.set(twitter.getOAuthAccessToken(requestToken.get(), pinCode)); twitter.verifyCredentials(); } catch (TwitterException e) { LOGGER.log(Level.SEVERE, "Error while connecting to Twitter", e); } stage.close(); } } }); stage.setScene(scene); stage.show(); }); } catch (TwitterException | IllegalStateException e) { LOGGER.fine("Seems to be already connected to Twitter"); try { this.accessToken.set(this.twitter.getOAuthAccessToken()); } catch (TwitterException e1) { LOGGER.log(Level.SEVERE, "Can not connect to Twitter", e1); } } } /** * Start the {@link TwitterStream}. */ private void launchTwitter() { if(this.accessToken.get() != null) { final FilterQuery query = new FilterQuery(); query.track(new String[]{SlideshowFXServer.getSingleton().getTwitterHashtag()}); this.twitterStream = new TwitterStreamFactory(this.twitterConfiguration).getInstance(this.accessToken.get()); this.twitterStream.onStatus(this.buildTwitterStatusConsumer()); this.twitterStream.filter(query); } } private Consumer<Status> buildTwitterStatusConsumer() { final Consumer<Status> statusConsumer = status -> { final ChatMessage chatMessage = new ChatMessage(); chatMessage.setId(System.currentTimeMillis() + ""); chatMessage.setSource(ChatMessageSource.TWITTER); chatMessage.setStatus(ChatMessageStatus.NEW); chatMessage.setAuthor("@" + status.getUser().getScreenName()); chatMessage.setContent(status.getText()); final JsonObject jsonTweet = chatMessage.toJSON(); System.out.println(jsonTweet.toString()); TwitterService.this.vertx.eventBus().publish(SERVICE_CHAT_ATTENDEE_MESSAGE_ADD, jsonTweet); TwitterService.this.vertx.eventBus().publish(SERVICE_CHAT_PRESENTER_MESSAGE_ADD, jsonTweet); }; return statusConsumer; } }