{"id":22330646,"url":"https://github.com/backendstack21/realtime-pubsub-client-java","last_synced_at":"2025-03-26T07:09:53.066Z","repository":{"id":265542662,"uuid":"885907396","full_name":"BackendStack21/realtime-pubsub-client-java","owner":"BackendStack21","description":null,"archived":false,"fork":false,"pushed_at":"2024-12-21T08:34:05.000Z","size":177,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T08:33:15.255Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BackendStack21.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-09T17:51:59.000Z","updated_at":"2024-12-14T16:10:22.000Z","dependencies_parsed_at":"2025-01-31T08:30:18.758Z","dependency_job_id":"d6545d0c-11c4-4cdd-b6ff-f5ae8b117f88","html_url":"https://github.com/BackendStack21/realtime-pubsub-client-java","commit_stats":null,"previous_names":["backendstack21/realtime-pubsub-client-java"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BackendStack21%2Frealtime-pubsub-client-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BackendStack21","download_url":"https://codeload.github.com/BackendStack21/realtime-pubsub-client-java/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245605730,"owners_count":20643030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-04T04:07:27.399Z","updated_at":"2025-03-26T07:09:53.032Z","avatar_url":"https://github.com/BackendStack21.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Realtime Pub/Sub Client for Java\n\nThe `realtime-pubsub-client` is a Java client library for interacting with [Realtime Pub/Sub](https://realtime.21no.de) applications. It enables developers to manage real-time WebSocket connections, handle subscriptions, and process messages efficiently. The library provides a simple and flexible API to interact with realtime applications, supporting features like publishing/sending messages, subscribing to topics, handling acknowledgments, and waiting for replies with timeout support.\n\n## Features\n\n- **WebSocket Connection Management**: Seamlessly connect and disconnect from the Realtime Pub/Sub service with automatic reconnection support.\n- **Topic Subscription**: Subscribe and unsubscribe to topics for receiving messages.\n- **Topic Publishing**: [Publish](https://realtime.21no.de/documentation/#publishers) messages to specific topics with optional message types and compression.\n- **Message Sending**: [Send](https://realtime.21no.de/documentation/#websocket-inbound-messaging) messages to backend applications with optional message types and compression.\n- **Event Handling**: Handle incoming messages with custom event listeners.\n- **Acknowledgments and Replies**: Wait for gateway acknowledgments or replies to messages with timeout support.\n- **Error Handling**: Robust error handling and logging capabilities.\n- **Strongly Typed Classes**: Provides strongly typed classes for a better development experience.\n\n## Installation\n\nAdd the `realtime-pubsub-client` library to your project via Maven or Gradle:\n\n### Maven\n\nAdd the following dependency to your `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ede.backendstack21\u003c/groupId\u003e\n    \u003cartifactId\u003erealtime-pubsub\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\u003e Note: Use the version number that corresponds to the latest release.\n\n### Gradle\n\nAdd the following to your `build.gradle` dependencies:\n\n```kt\nimplementation 'de.backendstack21:realtime-pubsub:1.0.0'\n```\n\n**Dependencies**:\n\n- **Java WebSocket API**:\n\n  ```kt\n  dependencies {\n    // https://mvnrepository.com/artifact/jakarta.websocket/jakarta.websocket-api\n    compileOnly(\"jakarta.websocket:jakarta.websocket-api:2.2.0\")\n\n    // https://mvnrepository.com/artifact/org.glassfish.tyrus.bundles/tyrus-standalone-client\n    implementation(\"org.glassfish.tyrus.bundles:tyrus-standalone-client:2.2.0\")\n  }\n  ```\n\n- **Jackson JSON Processor**:\n\n  ```kt\n  dependencies { \n    // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core\n    implementation(\"com.fasterxml.jackson.core:jackson-core:2.18.1\")\n  }\n  ```\n\n- **Logging Framework**:\n\n  Use Java's built-in logging or include a logging framework of your choice.\n\n## Getting Started\n\n### Connecting to the Server\n\nFirst, import the `RealtimeClient` class and create a new instance with the required configuration:\n\n```java\nimport de.backendstack21.realtime.pubsub.RealtimeClient;\nimport de.backendstack21.realtime.pubsub.RealtimeClientConfig;\nimport de.backendstack21.realtime.pubsub.ConnectionInfo;\n\npublic class ClientDemo {\n    public static void main(String[] args) {\n        // Retrieve environment variables\n        String APP_ID = System.getenv(\"APP_ID\");\n        String ACCESS_TOKEN = System.getenv(\"ACCESS_TOKEN\");\n\n        if (APP_ID == null || ACCESS_TOKEN == null) {\n            System.err.println(\"APP_ID and ACCESS_TOKEN environment variables must be set.\");\n            return;\n        }\n\n        // Create the configuration\n        RealtimeClientConfig config = new RealtimeClientConfig(() -\u003e {\n            // Construct the WebSocket URL with the access token and app ID\n            return String.format(\"wss://genesis.r7.21no.de/apps/%s?access_token=%s\", APP_ID, ACCESS_TOKEN);\n        });\n\n        // Initialize the RealtimeClient with the configuration\n        RealtimeClient client = new RealtimeClient(config);\n\n        // Register event listener for session started\n        client.on(\"session.started\", (Object... eventArgs) -\u003e {\n            ConnectionInfo connectionInfo = (ConnectionInfo) eventArgs[0];\n            System.out.println(\"Connection ID: \" + connectionInfo.getId());\n\n            // Subscribe to topics here\n            try {\n                client.subscribeRemoteTopic(\"topic1\");\n                client.subscribeRemoteTopic(\"topic2\");\n                // ...\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        });\n\n        // Connect to the WebSocket server\n        client.connect();\n\n        // Wait for the session.started event\n        try {\n            client.waitFor(\"session.started\", 10).get();\n        } catch (InterruptedException | ExecutionException e) {\n            e.printStackTrace();\n        }\n    }\n}\n```\n\n### Subscribing to Incoming Messages\n\nYou can handle messages for specific topics and message types:\n\n\u003e **Note**: The topic and message type are concatenated with a dot (`.`) in the event name.\n\n```java\nclient.on(\"topic1.action1\", (Object... eventArgs) -\u003e {\n    IncomingMessage message = (IncomingMessage) eventArgs[0];\n    // Message handling logic here\n    System.out.println(\"Received message: \" + message.get(\"data\"));\n});\n```\n\nWildcard subscriptions are also supported:\n\n```java\nclient.on(\"topic1.*\", (Object... eventArgs) -\u003e {\n    // Handle all messages in topic1\n});\n```\n\n#### Concurrency Support \n\nThe underlying EventEmitter implementation uses a single thread for event handling. If you need to handle events concurrently, \nor block the active thread, DO use a thread pool or executor service to process events in a separate thread.\n\nFor example, you can access the client `ExecutorService` instance by calling the `getExecutorService()` method:\n\n```java\nclient.on(\"secure/inbound.gettime\", (Object... eventArgs) -\u003e {\n    var replyFn = (ReplyFunction) eventArgs[1];\n    logger.info(\"Responding to gettime request on a separate thread...\");\n\n    client.getExecutorService().submit(() -\u003e {\n        try {\n            var response = Map.of(\"time\", new Date());\n            // Send a reply and wait for acknowledgment\n            replyFn.reply(response, \"ok\", false).waitForAck().get();\n            logger.info(\"Response delivered!\");\n        } catch (Exception e) {\n            logger.log(Level.SEVERE, \"Failed to send reply\", e);\n        }\n    });\n});\n```\n\n### Publishing Messages\n\nPublish messages to a topic:\n\n```java\nclient.publish(\"topic1\", \"Hello, world!\", \"text-message\");\n```\n\n### Sending messages to your backend services:\n\n```java\nclient.send(Map.of(\"name\", \"Realtime Pub/Sub\", \"type\": \"saas\"), \"create\");\n```\n\n### Responding to Incoming Messages\n\nSet up event listeners to handle incoming messages and send replies:\n\n```java\nclient.on(\"topic1.text-message\", (Object... eventArgs) -\u003e {\n    IncomingMessage message = (IncomingMessage) eventArgs[0];\n    ReplyFunction replyFn = (ReplyFunction) eventArgs[1];\n\n    // Message handling logic here\n    System.out.println(\"Received message: \" + message.get(\"data\"));\n    \n    try {\n        replyFn.reply(\"Message received!\", \"ok\", false);\n    } catch (Exception e) {\n        e.printStackTrace();\n    }\n});\n```\n\n### Waiting for Acknowledgments and Replies\n\nYou can wait for acknowledgments or replies when publishing or sending messages.\n\n- **waitForAck(int timeoutSeconds)**: Waits for an acknowledgment of the message, with an optional timeout in seconds.\n- **waitForReply(int timeoutSeconds)**: Waits for a reply to the message, with an optional timeout in seconds.\n\nWait for the Realtime Gateway acknowledgment after publishing a message:\n\n```java\ntry {\n    WaitFor waitFor = client.publish(\"secure/peer-to-peer1\", \"Hi\", \"greeting\");\n    waitFor.waitForAck(5).get(); // Wait for up to 5 seconds\n} catch (Exception e) {\n    e.printStackTrace();\n}\n```\n\nWait for the Realtime Gateway acknowledgment after sending a message:\n\n```java\ntry {\n    WaitFor waitFor = client.send(\"Your Message\", \"create\");\n    waitFor.waitForAck(5).get();\n} catch (Exception e) {\n    e.printStackTrace();\n}\n```\n\nWait for a reply with a timeout:\n\n```java\ntry {\n    WaitFor waitFor = client.send(Map.of(\"name\", \"Realtime Pub/Sub\", \"type\": \"saas\"), \"create\");\n    ResponseMessage response = (ResponseMessage) waitFor.waitForReply(5).get()[0]; // Wait for up to 5 seconds\n    System.out.println(\"Received reply: \" + response);\n} catch (Exception e) {\n    e.printStackTrace();\n}\n```\n\n### Error Handling\n\nHandle errors and disconnections:\n\n```java\nclient.on(\"error\", (Object... eventArgs) -\u003e {\n    Exception error = (Exception) eventArgs[0];\n    System.err.println(\"WebSocket error: \" + error.getMessage());\n});\n\nclient.on(\"close\", (Object... eventArgs) -\u003e {\n    CloseReason closeReason = (CloseReason) eventArgs[0];\n    System.out.println(\"WebSocket closed: \" + closeReason.getReasonPhrase());\n});\n```\n\n## API Reference\n\n### RealtimeClient\n\n#### Constructor\n\n```java\npublic RealtimeClient(RealtimeClientConfig config);\n```\n\nCreates a new `RealtimeClient` instance.\n\n- **config**: Configuration options for the client encapsulated in `RealtimeClientConfig`.\n\n#### Methods\n\n- **getExecutorService()**: Returns the `ExecutorService` instance used by the client.\n\n  ```java\n  public ExecutorService getExecutorService();\n  ```\n\n- **connect()**: Connects the client to the WebSocket Messaging Gateway.\n\n  ```java\n  public void connect();\n  ```\n\n- **disconnect()**: Terminates the WebSocket connection.\n\n  ```java\n  public void disconnect();\n  ```\n\n- **subscribeRemoteTopic(String topic)**: [Subscribes](https://realtime.21no.de/documentation/#subscribers) the connection to a remote topic.\n\n  ```java\n  public void subscribeRemoteTopic(String topic) throws Exception;\n  ```\n\n- **unsubscribeRemoteTopic(String topic)**: [Unsubscribes](https://realtime.21no.de/documentation/#subscribers) the connection from a remote topic.\n\n  ```java\n  public void unsubscribeRemoteTopic(String topic) throws Exception;\n  ```\n\n- **publish(String topic, Object payload, String messageType, boolean compress, String messageId)**: Publishes a message to a topic.\n\n  ```java\n  public WaitFor publish(String topic, Object payload, String messageType, boolean compress, String messageId) throws Exception;\n  ```\n\n  Returns a `WaitFor` instance to wait for acknowledgments or replies.\n\n- **send(Object payload, String messageType, boolean compress, String messageId)**: Sends a message to the server.\n\n  ```java\n  public WaitFor send(Object payload, String messageType, boolean compress, String messageId) throws Exception;\n  ```\n\n  Returns a `WaitFor` instance to wait for acknowledgments or replies.\n\n- **waitFor(String eventName, int timeoutSeconds)**: Waits for a specific event to occur within a timeout period.\n\n  ```java\n  public CompletableFuture\u003cObject[]\u003e waitFor(String eventName, int timeoutSeconds);\n  ```\n\n  Returns a `CompletableFuture` that completes with the event data.\n\n#### Events\n\n- **`\"session.started\"`**: Emitted when the session starts.\n\n  ```java\n  client.on(\"session.started\", (Object... eventArgs) -\u003e {\n      ConnectionInfo connectionInfo = (ConnectionInfo) eventArgs[0];\n      // Handle session started\n  });\n  ```\n\n- **`\"error\"`**: Emitted on WebSocket errors.\n\n  ```java\n  client.on(\"error\", (Object... eventArgs) -\u003e {\n      Exception error = (Exception) eventArgs[0];\n      // Handle error\n  });\n  ```\n\n- **`\"close\"`**: Emitted when the WebSocket connection closes.\n\n  ```java\n  client.on(\"close\", (Object... eventArgs) -\u003e {\n      CloseReason closeReason = (CloseReason) eventArgs[0];\n      // Handle close\n  });\n  ```\n\n- **Custom Events**: Handle custom events based on topic and message type.\n\n  ```java\n  client.on(\"TOPIC_NAME.MESSAGE_TYPE\", (Object... eventArgs) -\u003e {\n      IncomingMessage message = (IncomingMessage) eventArgs[0];\n      ReplyFunction replyFn = (ReplyFunction) eventArgs[1];\n      // Handle message and possibly send a reply\n  });\n  ```\n\n  \u003e **Note**: Wildcard subscriptions are also supported.\n\n## License\n\nThis library is licensed under the MIT License.\n\n---\n\nFor more detailed examples and advanced configurations, please refer to the [documentation](https://realtime.21no.de/introduction/).\n\n## Notes\n\n- Ensure that you have an account and an app set up with [Realtime Pub/Sub](https://realtime.21no.de).\n- Customize the `WebSocketUrlProvider` function to retrieve the access token for connecting to your realtime application.\n- Implement any authentication mechanism as required by your application.\n- Optionally use a custom logger or integrate with your application's logging system.\n- Handle errors and disconnections gracefully to improve the robustness of your application.\n- Make sure to handle timeouts when waiting for replies to avoid hanging operations.\n- Include necessary dependencies in your project's build configuration.\n\n---\n\nFeel free to contribute to this project by submitting issues or pull requests on [GitHub](https://github.com/YourGithubUsername/realtime-pubsub-client-java).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackendstack21%2Frealtime-pubsub-client-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbackendstack21%2Frealtime-pubsub-client-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbackendstack21%2Frealtime-pubsub-client-java/lists"}