diff --git a/example/Bridge.java b/example/Bridge.java new file mode 100644 index 0000000..a7c721c --- /dev/null +++ b/example/Bridge.java @@ -0,0 +1,88 @@ +package com.leohabrom.discordrpc; + +import com.leohabrom.discord.DiscordActivity; +import com.leohabrom.discord.DiscordBridge; +import com.leohabrom.discord.DiscordBridgeAdapter; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + +public class Bridge implements DiscordBridgeAdapter { + private final DiscordBridge bridge; + private final BlockingQueue feedbackQueue = new ArrayBlockingQueue<>(1); + + // Scheduling tools + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + private final AtomicLong lastSendTime = new AtomicLong(0); + private final AtomicReference pendingActivity = new AtomicReference<>(); + private final AtomicReference> scheduledTask = new AtomicReference<>(); + + private DiscordActivity lastSentActivity = null; + + public Bridge(long appId) { + this.bridge = new DiscordBridge(); + this.bridge.init(appId); + this.bridge.setAdapter(this); + this.bridge.start(); + } + + /** + * Updates the activity. If called too fast, it buffers the latest + * request and sends it as soon as the rate limit allows. + */ + public void update(DiscordActivity activity) { + pendingActivity.set(activity); + + long now = System.currentTimeMillis(); + long timeSinceLastSend = now - lastSendTime.get(); + long delayNeeded = 1000 - timeSinceLastSend; + + if (delayNeeded <= 0) { + sendNow(); + } else { + // If a task is already scheduled, don't create another one. + // The scheduled task will naturally pick up the "latest" pendingActivity. + if (scheduledTask.get() == null || scheduledTask.get().isDone()) { + ScheduledFuture task = scheduler.schedule(this::sendNow, delayNeeded, TimeUnit.MILLISECONDS); + scheduledTask.set(task); + } + } + } + + private void sendNow() { + DiscordActivity activity = pendingActivity.getAndSet(null); + if (activity != null) { + if (activity.equals(lastSentActivity)) { + return; + } + lastSentActivity = activity; + lastSendTime.set(System.currentTimeMillis()); + bridge.update(activity); + } + } + + public boolean updateWithFeedback(DiscordActivity activity) { + feedbackQueue.clear(); + update(activity); + try { + // We wait a bit longer because the update might be delayed by the scheduler + Boolean result = feedbackQueue.poll(3, TimeUnit.SECONDS); + return result != null && result; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return false; + } + } + + @Override + public void onMessage(String message) { + if (message == null) return; + String msg = message.toLowerCase(); + if (msg.contains("sent") || msg.contains("success")) { + feedbackQueue.offer(true); + } else if (msg.contains("fail") || msg.contains("error")) { + feedbackQueue.offer(false); + } + } +} \ No newline at end of file diff --git a/example/Main.java b/example/Main.java new file mode 100644 index 0000000..9ebf193 --- /dev/null +++ b/example/Main.java @@ -0,0 +1,34 @@ +package com.leohabrom.discordrpc; + +import com.leohabrom.discord.DiscordActivity; +import com.leohabrom.discord.DiscordActivityBuilder; + +public class Main { + + public static void main(String[] args) { + + Bridge bridge = new Bridge(00000L); + + + System.out.println("Discord RPC Service Running..."); + long startTime = System.currentTimeMillis(); + + while (true) { + + + DiscordActivity activity = new DiscordActivityBuilder() + .name("My Test Activity") + .time(startTime) + .build; + + bridge.update(activity); + + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + break; + } + } + } +} \ No newline at end of file