I tried Mastodon's Toot and Streaming API in Java

What I tried

--Mastodon seems to be able to Toot from his own code like Twitter --It seems that Python and Ruby have libraries, but I can't find Java. ――When I tried to beat it, I was able to stream Toot and Union TL

code

There seems to be an easy library to play with the REST API called Jersey, so I used it. To be honest, I tried to stick them together properly, so I'm messing around without knowing the details.

The connection instance is mstdn.jp, and the client id / secret and personal access token are prepared in advance with the help of Mastodon.py. (Since it was troublesome to write the authentication code ... I will try it someday) It seems that Streaming connection and Toot itself can be done with an access token.

import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;

import org.glassfish.jersey.media.sse.EventInput;
import org.glassfish.jersey.media.sse.InboundEvent;
import org.glassfish.jersey.media.sse.SseFeature;

public class MainWindow extends JFrame{
  private static final String APP_NAME = "TestMastodonClient";
  private static final int APP_WIDTH = 640;
  private static final int APP_HEIGHT = 480;

  //For the time being mstdn.I did it with jp, change it appropriately when doing it with other instances
  private static final String HOST_MASTODON = "https://mstdn.jp";
  
  //Client id in advance/Get secret and access token(I'm Mastodon.I did it with py)
  private static final String MASTODON_ACCESSTOKEN_TOKEN = "Put your own Access Token here";

  JComboBox<String> visibilityComboBox; //Scope of posting
  JTextField tootField;
  JButton tootButton;
  
  Client client;
  
  public MainWindow() {
    setTitle(APP_NAME);
    setSize(APP_WIDTH, APP_HEIGHT);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    // TLSv1.I couldn't connect to Streaming without using 2, so I changed it.
    System.out.println("HTTPS:" + System.getProperty("https.protocols"));
    System.setProperty("https.protocols", "TLSv1.2");
    System.out.println("HTTPS:" + System.getProperty("https.protocols"));
    
    client = ClientBuilder.newBuilder().register(SseFeature.class).build();
    
    Container container = getContentPane();
    JPanel parentPanel = new JPanel();
    container.add(parentPanel);

    visibilityComboBox = new JComboBox<String>();
    visibilityComboBox.addItem("public");  //Release(Come out in Union TL)
    visibilityComboBox.addItem("unlisted");//Release(Does not appear in Union TL)
    visibilityComboBox.addItem("private"); //private(I can only see myself and my followers)
    visibilityComboBox.addItem("direct");  //I do not understand(Is it like Twitter DM?)
    parentPanel.add(visibilityComboBox);
    
    tootField = new JTextField(10); //Defeat Toot For character string input
    parentPanel.add(tootField);
    
    tootButton = new JButton("Toot");
    tootButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        String msg = tootField.getText();
        System.out.println("Toot: " + msg);
        
        //It seems to make a header with Access Token
        MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
        headers.putSingle("Authorization", "Bearer " + MASTODON_ACCESSTOKEN_TOKEN);
        
        //Put the text in status and the disclosure range of posts in visibility
        Entity<Form> entity = Entity.entity(new Form().param("status", msg)
                                            .param("visibility", 
                                                    (String) visibilityComboBox.getSelectedItem()), 
                                                    MediaType.APPLICATION_FORM_URLENCODED_TYPE);

        //throw
        String result = client.target(HOST_MASTODON)
                              .path("/api/v1/statuses")
                              .request()
                              .headers(headers)
                              .post(entity, String.class);
        
        System.out.println("----------Execution result----------");
        System.out.println(result);
        
        //tootField.setText(""); //If you want to empty the input field after Toot, do it
      }
    });
    parentPanel.add(tootButton);
    
    //I don't know if this is okay, but for the time being, I picked up Streaming in another thread
    new Thread(new Runnable() {
      @Override
      public void run() {
        System.out.println("----------Streaming Thread----------");

        //Prepare Access Token
        MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
        headers.putSingle("Authorization", "Bearer " + MASTODON_ACCESSTOKEN_TOKEN);
        headers.putSingle("Content-Type", "application/json; charset=UTF-8");

        WebTarget target = client.target(HOST_MASTODON);

        //Connect to Union TL
        EventInput eventInput = target.path("/api/v1/streaming/public")
                                      .request()
                                      .headers(headers)
                                      .get(EventInput.class);
        
        //Just let the console keep receiving
        //JSON A decent string comes out so I have to parse it later
        while (!eventInput.isClosed()) {
          final InboundEvent inboundEvent = eventInput.read();
          if (inboundEvent == null) {
            // connection has been closed
            System.out.println("----------End of Streaming Thread----------");
            break;
          }
          System.out.println("----------Response----------");
          System.out.println(inboundEvent.getName() + "; ");
          System.out.println(inboundEvent.readData(String.class));
        }
      }
    }).start();
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override
      public void run() {
        new MainWindow().setVisible(true);
      }
    });
  }
}

When you receive the Union TL, it will flow at a tremendous momentum, so it may be easier to confirm if you try it with Home TL. Addendum: ~~ While continuing to pick up Streaming JSON in Thread at the end of the above code, [15.5.2. Asynchronous SSE processing with EventSource](https://jersey.java.net/documentation/latest/ As shown in sse.html # d0e12060), it seems that it can be defined as onEvent, so that seems to be better ~~ As a result of searching variously, EventSource seems to be unable to connect with a request header so far, so either write the code to generate an event from the above While, or write the code to put the header with AccessToken in EventSource somehow. It seems that it will correspond

Recommended Posts

I tried Mastodon's Toot and Streaming API in Java
I tried metaprogramming in Java
I tried using Google Cloud Vision API in Java
I tried using Java8 Stream API
I tried using JWT in Java
I tried the new era in Java
I tried to implement deep learning in Java
I tried to output multiplication table in Java
I tried to create Alexa skill in Java
Zabbix API in Java
I tried to implement Firebase push notification in Java
# 2 [Note] I tried to calculate multiplication tables in Java.
I tried to create a Clova skill in Java
I tried to make a login function in Java
[Java] I tried to implement Yahoo API product search
I tried using an extended for statement in Java
I tried passing Java Silver in 2 weeks without knowing Java
I tried to implement the Euclidean algorithm in Java
~ I tried to learn functional programming in Java now ~
I tried to find out what changed in Java 9
I made roulette in Java.
Java Stream API in 5 minutes
I tried Drools (Java, InputStream)
I tried using Java REPL
I tried to summarize the basics of kotlin and java
Object-oriented child !? I tried Deep Learning in Java (trial edition)
What I learned in Java (Part 4) Conditional branching and repetition
I tried to make Java Optional and guard clause coexist
How to call and use API in Java (Spring Boot)
[Java] I tried access modifier public and unspecified field access [Eclipse]
I tried to convert a string to a LocalDate type in Java
I tried using Dapr in Java to facilitate microservice development
Tips for using Salesforce SOAP and Bulk API in Java
I tried to make a client of RESAS-API in Java
Generate AWS Signature V4 in Java and request an API
I sent an email in Java
I compared PHP and Java constructors
What I have learned in Java (Part 1) Java development flow and overview
I created a PDF in Java.
Encoding and Decoding example in Java
I tried setting Java beginners to use shortcut keys in eclipse
I tried to interact with Java
I tried UDP communication with Java
Generate CloudStack API URL in Java
I wrote Goldbach's theorem in java
I tried putting Domino11 in CentOS7
StringBuffer and StringBuilder Class in Java
I tried the Java framework "Quarkus"
Hit Zaim's API (OAuth 1.0) in Java
Parsing the COTOHA API in Java
Understanding equals and hashCode in Java
I made an annotation in Java.
I tried to summarize the methods of Java String and StringBuilder
I tried to summarize Java learning (1)
I tried to summarize Java 8 now
JPA (Java Persistence API) in Eclipse
I tried using Java memo LocalDate
I compared Java and Ruby's FizzBuzz.
Hello world in Java and Gradle
I tried using GoogleHttpClient of Java
I called the COTOHA API parser 100 times in Java to measure performance.