import java.util.List; import java.util.ArrayList; import java.io.IOException; import cafe.biskuteri.hinoki.Tree; class TimelineWindowUpdater { private JKomasto primaire; private MastodonApi api; // - -%- - private List updatees; private StringBuilder event, data; // - -%- - private Thread federated, local, home; // ---%-@-%--- public void addWindow(TimelineWindow updatee) { updatees.add(updatee); Connection c = new Connection(); c.type = updatee.getTimelineType(); Thread t = new Thread(c); switch (c.type) { case FEDERATED: if (federated != null) return; federated = t; break; case LOCAL: if (local != null) return; local = t; break; case HOME: if (home != null) return; home = t; break; default: return; } t.start(); } public void removeWindow(TimelineWindow updatee) { updatees.remove(updatee); } // - -%- - private void handle(TimelineType type, String event, String data) { assert !data.isEmpty(); if (event.isEmpty()) return; boolean newPost = event.equals("update"); boolean newNotif = event.equals("notification"); if (!(newPost || newNotif)) return; for (TimelineWindow updatee: filter(type)) { updatee.showLatestPage(); } } private List filter(TimelineType type) { List returnee = new ArrayList<>(); for (TimelineWindow updatee: updatees) if (updatee.getTimelineType() == type) returnee.add(updatee); return returnee; } // ---%-@-%--- private class Connection implements Runnable, ServerSideEventsListener { private TimelineType type; // -=- private StringBuilder event, data; // -=%=- public void run() { event = new StringBuilder(); data = new StringBuilder(); api.monitorTimeline(type, this); // monitorTimeline should not return // until the connection is closed. } public void lineReceived(String line) { if (line.startsWith(":")) return; if (line.isEmpty()) { handle(type, event.toString(), data.toString()); event.delete(0, event.length()); data.delete(0, event.length()); } if (line.startsWith("data: ")) data.append(line.substring("data: ".length())); if (line.startsWith("event: ")) event.append(line.substring("event: ".length())); /* * Note that I utterly ignore https://html.spec.whatwg.org * /multipage/server-sent-events.html#dispatchMessage. * That is because I am not a browser. */ } public void connectionFailed(IOException eIo) { // sais pas dois-je faire.. eIo.printStackTrace(); } public void requestFailed(int httpCode, Tree json) { // mo shiranu System.err.println(httpCode + ", " + json.get("error").value); } } // ---%-@-%--- TimelineWindowUpdater(JKomasto primaire) { this.primaire = primaire; this.api = primaire.getMastodonApi(); this.updatees = new ArrayList<>(); } }