diff --git a/eng/ignore-links.txt b/eng/ignore-links.txt index b283f02db590..c2c3251950eb 100644 --- a/eng/ignore-links.txt +++ b/eng/ignore-links.txt @@ -5,3 +5,9 @@ http://localhost:9021/ http://localhost:9000/ http://localhost:9001/ http://localhost:9004/ + +# Web PubSub Chat links will become available after the package is merged and released. +https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/webpubsub/azure-messaging-webpubsub-chat/src +https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples +https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/webpubsub/azure-messaging-webpubsub-chat/CHANGELOG.md +https://central.sonatype.com/artifact/com.azure/azure-messaging-webpubsub-chat diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt index 5bef20bd1c1f..f7dbdc0b22fc 100644 --- a/eng/versioning/version_client.txt +++ b/eng/versioning/version_client.txt @@ -167,6 +167,7 @@ com.azure:azure-messaging-servicebus;7.17.20;7.18.0-beta.4 com.azure:azure-messaging-servicebus-stress;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-messaging-servicebus-track2-perf;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-messaging-webpubsub;1.5.7;1.6.0-beta.1 +com.azure:azure-messaging-webpubsub-chat;1.0.0-beta.1;1.0.0-beta.1 com.azure:azure-messaging-webpubsub-client;1.1.10;1.2.0-beta.1 com.azure:azure-monitor-opentelemetry-exporter;1.0.0-beta.32;1.0.0-beta.33 com.azure:azure-monitor-opentelemetry-autoconfigure;1.6.0;1.7.0-beta.1 diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/CHANGELOG.md b/sdk/webpubsub/azure-messaging-webpubsub-chat/CHANGELOG.md new file mode 100644 index 000000000000..15b61aa59e2f --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/CHANGELOG.md @@ -0,0 +1,18 @@ +# Release History + +## 1.0.0-beta.1 (Unreleased) + +- Azure WebPubSubChat client library for Java. This package contains Microsoft Azure WebPubSubChat client library. + +### Features Added + +- Added synchronous and asynchronous clients for managing Chat users, rooms, room members, roles, and message history. +- Added connection string, access key, and Microsoft Entra ID authentication. +- Added client access token generation with local access-key signing and service delegation for Microsoft Entra ID. +- Added reverse proxy support and built-in Chat role and permission values. + +### Breaking Changes + +### Bugs Fixed + +### Other Changes diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/README.md b/sdk/webpubsub/azure-messaging-webpubsub-chat/README.md new file mode 100644 index 000000000000..3ffe57c22a48 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/README.md @@ -0,0 +1,251 @@ +# Azure Web PubSub Chat service client library for Java + +[Azure Web PubSub Chat][product_documentation] is a managed chat capability built on [Azure Web PubSub][webpubsub_documentation]. It provides purpose-built client and server APIs for chat scenarios. Applications use the SDKs to work with chat-native concepts such as rooms, messages, members, and users. The service handles real-time message delivery and ordering, fan-out across a user's devices and browser tabs, room membership, and message persistence and retrieval. + +Use this client library in an application server to: + +- Create and manage Chat roles and permissions. +- Create users, rooms, and room memberships. +- Get room conversations and query persisted message history. +- Update and delete persisted messages. +- Generate client access credentials for Chat WebSocket clients. + +[Source code][source_code] | [Package][package] | [API reference documentation][docs] | [Product documentation][product_documentation] | [Samples][samples] | [Changelog][changelog] + +## Getting started + +### Prerequisites + +- A [Java Development Kit (JDK)][jdk] with version 8 or later. +- An [Azure subscription][azure_subscription]. +- An [Azure Web PubSub resource][create_instance]. +- A Web PubSub hub with [Chat enabled][enable_chat]. + +### 1. Add the package to your project + +[//]: # ({x-version-update-start;com.azure:azure-messaging-webpubsub-chat;current}) +```xml + + com.azure + azure-messaging-webpubsub-chat + 1.0.0-beta.1 + +``` +[//]: # ({x-version-update-end}) + +### 2. Create and authenticate a `WebPubSubChatServiceClient` + +The client supports a connection string, an `AzureKeyCredential`, or a Microsoft Entra ID token credential. The hub passed to the client must have Chat enabled. + +#### Use a connection string + +Get the connection string from the Azure portal or Azure CLI, and store it securely. See [Web PubSub authorization][connection_string] for details. + +```java readme-sample-createChatClientWithConnectionString +WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .connectionString("") + .hub("chat") + .buildClient(); +``` + +#### Use an access key + +```java readme-sample-createChatClientWithKey +WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .endpoint("https://.webpubsub.azure.com") + .hub("chat") + .credential(new AzureKeyCredential("")) + .buildClient(); +``` + +#### Use Microsoft Entra ID + +For recommended passwordless authentication, add the [Azure Identity][azure_identity] package, assign an appropriate Web PubSub data-plane role to the principal, and authenticate with a token credential. The following example uses `DefaultAzureCredential`: + +```java readme-sample-createChatClientWithEntraId +WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .endpoint("https://.webpubsub.azure.com") + .hub("chat") + .credential(new DefaultAzureCredentialBuilder().build()) + .buildClient(); +``` + +For more information, see [Authenticate Azure-hosted Java applications][azure_identity_auth] and [Microsoft Entra authorization for Azure Web PubSub][entra_authorization]. + +## Key concepts + +### Client + +`WebPubSubChatServiceClient` is the entry point for managing Chat resources in one Web PubSub hub. Create one client for each endpoint and hub combination, and reuse the client for multiple operations. For nonblocking operations, use `WebPubSubChatServiceAsyncClient`, which is created by calling `buildAsyncClient` on the same builder. + +### Hub + +A hub is a logical collection of WebSocket connections. A standard hub offers event-based real-time messaging through the Web PubSub subprotocol or a custom subprotocol. A chat hub adds built-in rooms, member management, message persistence, and chat-specific APIs. + +This SDK applies only to chat hubs. Chat must be enabled on the target hub before the SDK can manage roles, users, rooms, members, conversations, or messages. + +### Role and permission + +A role is a named collection of Chat permissions. User role names start with `user.`, and room role names start with `room.`. Do not combine user and room permissions in one role. + +User roles control operations such as creating rooms. Room roles control what a member can do in a particular room, such as publishing messages or reading message history. `BuiltInChatRoles` provides role names for common scenarios, and `ChatPermission` provides the permissions used to define custom roles. + +### User + +A user represents an application identity that can send and receive messages. A user is identified by a user ID and assigned a user role. A human user also has a nickname. Client access credentials associate WebSocket connections with a user ID. + +### Room + +A room groups users together and is the primary organizational unit for chat interactions. Every room has an automatically created default conversation. + +### Room member + +A room member represents a user added to a room. Membership controls which users can receive and send messages in the room. Each room member is assigned a room role. + +### Conversation and message history + +A conversation is a message thread that belongs to a room. Every room has a default conversation and can contain multiple conversations. + +Messages sent to a conversation are delivered in real time to the room's connected members. The Chat service manages ordering and persistence, allowing members to load message history after reconnecting or joining later. The service client can list, update, and delete persisted messages. + +### Client access credentials + +`getClientAccessToken` returns a token and WebSocket connection URL. Clients configured with a connection string or access key sign the token locally. Clients configured with Microsoft Entra ID request the token from the Web PubSub service. + +## Examples + +### Generate a client access token + +```java readme-sample-getChatClientAccessToken +WebPubSubClientAccessToken accessToken = client.getClientAccessToken( + new GetClientAccessTokenOptions().setUserId("alice").setExpiresAfter(Duration.ofHours(1))); +String clientConnectionUrl = accessToken.getUrl(); +``` + +The returned URL contains an access token. Send it only to the intended client, and do not log or persist it in production. + +### Work with built-in values + +```java readme-sample-chatBuiltInValues +String memberRole = BuiltInChatRoles.ROOM_MEMBER; +ChatPermission publishPermission = ChatPermission.ROOM_PUBLISH_MESSAGE; +``` + +### Create and list a custom role + +```java readme-sample-manageChatRoles +ChatRole moderator = new ChatRole(Arrays.asList(ChatPermission.ROOM_HISTORY, + ChatPermission.ROOM_REMOVE_USER, ChatPermission.ROOM_PUBLISH_MESSAGE)); +client.createOrReplaceRole("room.moderator", moderator); + +client.listRoles().forEach(role -> System.out.println(role.getName())); +client.deleteRole("room.moderator"); +``` + +### Create a user, room, and room membership + +```java readme-sample-manageChatRooms +client.createOrReplaceRole("user.room_creator", + new ChatRole(Arrays.asList(ChatPermission.USER_CREATE_ROOM))); +client.createOrReplaceRole("room.contributor", + new ChatRole(Arrays.asList(ChatPermission.ROOM_PUBLISH_MESSAGE))); +client.createOrReplaceUser("alice", new HumanChatUser("Alice", "user.room_creator")); + +ChatRoom room = client.createOrReplaceRoom("general", new ChatRoom("General")); +ChatRoomMember member = client.createOrReplaceRoomMember( + room.getId(), "alice", new ChatRoomMember("room.contributor")); +System.out.printf("%s: %s%n", member.getUserId(), member.getRoleName()); + +client.deleteRoom(room.getId()); +client.deleteUser("alice"); +client.deleteRole("room.contributor"); +client.deleteRole("user.room_creator"); +``` + +Delete dependent resources in reverse order when they are no longer needed: room, user, and then roles. + +### List persisted messages + +```java readme-sample-listChatMessages +ChatRoom room = client.getRoom("general"); +client.listMessages(room.getDefaultConversation()).forEach(message -> + System.out.printf("%s: %s%n", message.getCreatedBy(), message.getContent().getText())); +``` + +### Use the asynchronous client + +```java readme-sample-createAsyncChatClient +WebPubSubChatServiceAsyncClient asyncClient = new WebPubSubChatServiceClientBuilder() + .connectionString("") + .hub("chat") + .buildAsyncClient(); + +asyncClient.listRoles().subscribe(role -> System.out.println(role.getName())); +``` + +### Service API versions + +The client library targets the latest service API version by default. To use another supported version, pass a `WebPubSubChatServiceVersion` to the builder's `serviceVersion` method. Verify that the selected version supports the operations and models used by your application. + +## Troubleshooting + +### Handle service errors + +Service operations throw `HttpResponseException` or a more specific subclass when a request fails. Inspect the status code and response body before retrying an operation. For example, a missing resource results in a `ResourceNotFoundException`, while a failed ETag condition can result in a `ResourceModifiedException`. + +### Logging + +Enable SDK logging by setting the `AZURE_LOG_LEVEL` environment variable. See [Azure SDK logging][logging] for the supported levels and logging configuration. HTTP logs can contain sensitive information. Do not enable detailed logging in production without reviewing how logs are collected and protected, and never log connection strings, access keys, bearer tokens, or generated client access tokens. + +### Authentication and authorization + +- Confirm that the endpoint and hub name identify the Web PubSub resource and Chat-enabled hub you intend to use. +- For Microsoft Entra ID, confirm that the principal has an appropriate Web PubSub data-plane role and that role assignment propagation has completed. +- Connection-string and access-key authentication are unavailable when local authentication is disabled on the Web PubSub resource. + + +## Next steps + +Explore the [complete package samples][samples] to learn how to: + +- Authenticate with a connection string, access key, or Microsoft Entra ID. +- Manage roles, permissions, users, rooms, and room members. +- Generate client access credentials. +- Query, update, and delete message history. +- Use synchronous and asynchronous clients. + +## Additional resources + +- [Azure Web PubSub documentation][webpubsub_documentation] +- [Web PubSub Chat documentation][product_documentation] +- [Web PubSub Chat REST API][rest_api] +- [Azure SDK for Java design guidelines][design_guidelines] + +## Contributing + +This project welcomes contributions and suggestions. See the [contributing guide][contributing] for instructions on building, testing, and submitting changes. + +This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information, see the [Code of Conduct FAQ][code_of_conduct_faq] or contact opencode@microsoft.com with questions or comments. + + +[source_code]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/webpubsub/azure-messaging-webpubsub-chat/src +[package]: https://central.sonatype.com/artifact/com.azure/azure-messaging-webpubsub-chat +[docs]: https://azure.github.io/azure-sdk-for-java/ +[product_documentation]: https://learn.microsoft.com/azure/azure-web-pubsub/chat-overview +[samples]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples +[changelog]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/webpubsub/azure-messaging-webpubsub-chat/CHANGELOG.md +[jdk]: https://learn.microsoft.com/java/azure/jdk/ +[azure_subscription]: https://azure.microsoft.com/free +[webpubsub_documentation]: https://learn.microsoft.com/azure/azure-web-pubsub/ +[create_instance]: https://learn.microsoft.com/azure/azure-web-pubsub/howto-develop-create-instance +[enable_chat]: https://learn.microsoft.com/azure/azure-web-pubsub/chat-howto-enable-chat +[connection_string]: https://learn.microsoft.com/azure/azure-web-pubsub/howto-websocket-connect#authorization +[azure_identity]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/identity/azure-identity +[azure_identity_auth]: https://learn.microsoft.com/azure/developer/java/sdk/authentication/overview +[entra_authorization]: https://learn.microsoft.com/azure/azure-web-pubsub/concept-azure-ad-authorization +[logging]: https://learn.microsoft.com/azure/developer/java/sdk/logging-overview +[rest_api]: https://learn.microsoft.com/rest/api/webpubsub/dataplane/webpubsubchat/web-pub-sub-chat-service +[design_guidelines]: https://azure.github.io/azure-sdk/java_introduction.html +[contributing]: https://github.com/Azure/azure-sdk-for-java/blob/main/CONTRIBUTING.md +[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ +[code_of_conduct_faq]: https://opensource.microsoft.com/codeofconduct/faq/ diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/assets.json b/sdk/webpubsub/azure-messaging-webpubsub-chat/assets.json new file mode 100644 index 000000000000..946f2266fe20 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/assets.json @@ -0,0 +1 @@ +{"AssetsRepo":"Azure/azure-sdk-assets","AssetsRepoPrefixPath":"java","TagPrefix":"java/webpubsub/azure-messaging-webpubsub-chat","Tag": "java/webpubsub/azure-messaging-webpubsub-chat_395861d3d4"} \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/checkstyle-suppressions.xml b/sdk/webpubsub/azure-messaging-webpubsub-chat/checkstyle-suppressions.xml new file mode 100644 index 000000000000..11568686ab19 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/checkstyle-suppressions.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/customization.md b/sdk/webpubsub/azure-messaging-webpubsub-chat/customization.md new file mode 100644 index 000000000000..83e9d0168a86 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/customization.md @@ -0,0 +1,372 @@ +# Web PubSub Chat SDK post-generation customization + +Use this instruction after generating a Web PubSub Chat service SDK from the +TypeSpec project. Apply it in each language repository using that repository's +Azure SDK naming, API, testing, and pipeline conventions. + +The generated REST operations and models remain generator-owned. Put the work +described here in customization, handwritten, or protocol-policy files. Do not +edit generated files unless the language generator explicitly requires a +checked-in generated output update. Regenerate before final validation and +verify that regeneration preserves the custom behavior. + +The existing Web PubSub **service** SDK for the target language is the source of +truth for connection-string parsing, access-key authentication, reverse proxy +behavior, and client access token generation. Reuse or share its implementation +instead of creating a second incompatible implementation in the Chat SDK. + +## 1. Establish the public client surface + +Keep the generated Microsoft Entra ID credential support. Follow the same +language's existing Web PubSub service SDK convention for client creation, +including constructor or builder shape, overload ordering, credential names, +options placement, defaults, validation, and sync/async client organization. +Do not copy the .NET constructor shape into a language that uses a different +idiom. Add that language's conventional equivalents of these inputs: + +- endpoint, hub, key credential +- endpoint, hub, key credential, client options +- connection string, hub +- connection string, hub, client options + +Use the same public key credential type and connection-string entry point as the +same language's Web PubSub service SDK. Parse a connection string with the same +parser and rules as that SDK. At minimum, read `Endpoint` and `AccessKey`, honor +supported optional fields such as `Port`, and construct the key credential from +the parsed access key. Do not log or retain the original connection string after +parsing. + +Validate endpoint, hub, credential, connection string, and options consistently +with the language's Azure SDK guidelines. Reject a null or empty hub. Options +omitted by the caller must receive the normal default instance. + +The client must retain enough state to create an internal Web PubSub service +client with the same endpoint, hub, credential, and relevant options. This +internal client owns client access token generation described below. + +## 2. Apply key credential authentication + +Follow the target language's Web PubSub service SDK convention exactly. Prefer +sharing the service SDK policy or helper. If that is not possible because it is +internal, move the implementation to a shared source/module owned by the Web +PubSub service SDK, or port it without changing behavior. + +For every Chat service REST request authenticated by key credential: + +1. Create a short-lived JWT signed with the UTF-8 bytes of the current key. +2. Use the same signing algorithm and JWT builder as the Web PubSub service SDK. +3. Set `nbf`, `iat`, `exp`, and `aud` claims. The policy token lifetime is five + minutes. +4. Set `Authorization: Bearer `. +5. Read the key for every token creation, or invalidate cached key bytes when + the credential is updated. Key rotation must work without recreating the + client. + +The `aud` claim is the complete original request URI, including scheme, +authority, path, and query string. It is not the reverse proxy URI. + +Place the authentication policy at the same pipeline position as the Web PubSub +service SDK. Ensure any reverse proxy rewrite records the original audience +before authentication creates the JWT. + +Microsoft Entra ID authentication continues to use the language's standard +bearer token policy and the scopes emitted for the Chat service. + +## 3. Add reverse proxy support + +Add the target language's conventional `reverseProxyEndpoint` client option. +The option must be set before client construction. + +When configured, install one per-call policy that: + +1. Captures the original request URI for authentication. +2. Replaces the request scheme and authority with the reverse proxy endpoint. +3. Preserves the original path and query without double escaping. +4. Sends the request to the rewritten URI. + +Do not add duplicate policies when an option is assigned more than once. A +request through the proxy must still have an access-key JWT whose audience is +the original Web PubSub URI. Entra ID requests must use the proxy while retaining +their normal bearer token. + +Copy the reverse proxy endpoint into the options used to construct the internal +Web PubSub service client. This propagation is required because Entra ID client +access token generation calls the service through that client. Do not silently +copy service name, API version, or other package-specific settings. Propagate +additional common options only when the target language can do so without +changing the inner client's service identity or duplicating policies. + +## 4. Generate client access credentials by delegation + +Expose the target language's idiomatic sync and async client access generation +API. Follow the Web PubSub service SDK's naming and result shape. For example, +some languages return a token response while the .NET Chat SDK exposes +`GetClientAccessUri` and returns a WebSocket URI containing `access_token`. + +Provide an options type with: + +- optional user ID +- token lifetime, defaulting to one hour + +Delegate to the internal Web PubSub service client. Do not duplicate its token +generation or service call in the Chat SDK. Pass the caller's user ID and token +lifetime, no initial groups, the default Web PubSub client protocol, and these +two fixed Web PubSub data roles: + +```text +webpubsub.getGroupState +webpubsub.setGroupState +``` + +These roles are service roles needed by a connected Chat client. They are not +Chat role names and are not caller-configurable. + +With a connection string or key credential, the Web PubSub service SDK normally +signs the client token locally. With Microsoft Entra ID, it normally calls the +service's generate-client-token operation. Preserve those service SDK semantics, +including cancellation, errors, endpoint conversion from HTTP(S) to WS(S), and +reverse proxy routing for the service call. + +## 5. Add built-in Chat constants + +Expose constants using the target language's normal constant container or enum +pattern. Use these exact wire values. + +Built-in roles: + +| Name | Value | +| --- | --- | +| User normal | `user.normal` | +| Room member | `room.member` | +| Room operator | `room.operator` | + +User permissions: + +| Name | Value | +| --- | --- | +| Create room | `user.create_room` | +| Fetch all rooms | `user.fetch_all_rooms` | + +Room permissions: + +| Name | Value | +| --- | --- | +| Invite user | `room.invite` | +| Remove user | `room.remove_user` | +| Read history | `room.history` | +| Publish message | `room.publish_message` | + +Do not expose planned permissions until the service supports them. In +particular, do not copy constants from an old API listing without checking the +handwritten source and current service behavior. Regenerate or update the +language's API surface artifact after adding these constants and verify that it +contains only supported values. + +## 6. Unit test the customization + +Add tests using the target language's Azure SDK test framework and mock +transport. Cover at least: + +- null and empty validation for every new constructor or builder path +- connection-string parsing, including endpoint/port handling +- key credential requests contain a five-minute signed bearer JWT +- JWT `aud` equals the full original request URI +- updating the key credential changes subsequently generated JWTs +- reverse proxy requests use the proxy authority and preserve path and query +- reverse proxy plus key credential keeps the original URI as JWT audience +- reverse proxy plus Entra ID sends the normal bearer token to the proxy +- client access generation forwards user ID, expiration, no groups, and exactly + the two required Web PubSub roles +- default client access lifetime is one hour +- sync and async client access APIs have equivalent behavior, where applicable +- key/connection-string access generation produces a WS(S) connection URL or + the language-standard equivalent result +- Entra ID access generation delegates to the service operation and honors the + reverse proxy endpoint +- every public role and permission constant has the exact expected wire value + +Decode JWTs in tests and assert claims rather than checking only that a token is +present. Use fake credentials and endpoints in unit tests. + +## 7. Add live and playback tests + +Create a test project/suite that participates in the language repository's +record/playback framework. Provision an Azure Web PubSub resource with a system +identity and persistent storage suitable for Chat message history. Export the +endpoint and connection string under stable test environment variable names. +For consistency with the .NET reference, use: + +```text +WPS_CHAT_ENDPOINT +WPS_CHAT_CONNECTION_STRING +``` + +Register the connection string as a secret and sanitize at least its +`AccessKey` value as Base64 secret data. Never commit a populated `.env` file, +credentials, deployed resource names tied to a developer, or raw access tokens. + +Exercise both async and sync clients when the language supports both. Live tests +must cover: + +- create, get, list, paginate, and delete roles +- create, get, and delete rooms +- get a room conversation and list messages +- empty message and member pages +- create, list, and delete room members +- create, get, and delete users +- generate a client access credential and verify its connection URL/result +- message send, list, update, and delete when the service and language client + support creating a message + +Use unique recorded IDs for mutable resources and clean up in `finally` or the +language equivalent. Cleanup must tolerate a resource that was not created or +was already deleted. Do not make a permanently skipped message test the only +coverage for message update/delete behavior; document the service limitation +and enable the scenario as soon as message creation is available. + +If a WebSocket helper is needed, connect with subprotocol +`json.webpubsub.azure.v1` and send the room message as a `sendToGroup` request: + +```json +{ + "type": "sendToGroup", + "group": "", + "dataType": "json", + "data": { + "type": "text", + "content": "" + } +} +``` + +Use a bounded timeout and wait for the service to persist the message before +asserting history. A test-only Chat client from another language may seed the +message when WebSocket handling is not practical, but pin its dependencies and +automate its invocation instead of requiring an undocumented manual step. + +## 8. Record and upload test assets + +Follow the target language repository's test-proxy setup. The required flow is: + +1. Create the package's `assets.json` using that repository's language prefix + and package path. +2. Deploy the test resources and set secret environment variables locally. +3. Run the complete live suite in record mode. +4. Inspect every recording for connection strings, access keys, bearer tokens, + user data, and unstable values. Add sanitizers and record again if any secret + remains. +5. Run the suite in playback mode without Azure credentials and verify that it + passes. +6. Upload the recordings with the repository-supported test-proxy executable: + + ```text + test-proxy push -a /assets.json + ``` + +7. Commit the updated `assets.json` tag. Do not commit the local `.assets` + checkout or populated secret files. +8. Restore the new tag in a clean checkout and run playback once more. + +Do not reuse the .NET assets tag in another language. Each language package owns +its own prefix, tag, recordings, and sanitizer configuration. + +## 9. Write samples and README + +Add executable, tested samples using the language repository's snippet system. +Include: + +- connection string, key credential, and Microsoft Entra ID authentication +- client access credential generation +- creating a room and user, adding and listing a room member, and cleanup +- listing built-in roles and permissions +- creating, assigning, listing, and deleting a custom role +- reading paged message history +- updating and deleting a message when supported +- handling the language's standard Azure service exception + +The package README must contain installation, prerequisites, authentication, +key concepts, short runnable examples, troubleshooting, and links to the package +samples. State clearly that the service client manages server-side Chat +resources while connected clients send real-time messages over WebSockets. + +Before merging, validate every README link: + +- Link only to package-manager pages that exist for the actual package name. +- Link only to identity packages and API references used by the sample code. +- Use relative sample links with exact path and filename casing. +- Use an official Azure Web PubSub documentation URL that resolves. +- Remove template links, placeholders, and references to samples or APIs that + are not included in the package. +- Run the language repository's link checker when one is available. + +Update the changelog/release notes with the added authentication methods, +resource operations, access generation, and built-in constants. + +## 10. Configure build and live-test pipelines + +Add the Chat package to the service area's package build/CI artifact list. Add a +live-test pipeline entry using the language repository's standard SDK test +template and configure: + +- service directory `webpubsub` +- the Chat package/test project +- Public Azure cloud support unless another cloud is verified +- the package directory as a test-resource directory +- the Chat test resource template. The C# reference is located at + `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/test-resources.bicep`; place the + target language's copy at the equivalent package test-resource location + expected by that repository's pipeline template +- secure injection of the endpoint and connection string +- test-proxy restore and playback in normal CI +- resource deployment, live execution, recording support, and cleanup in the + live-test pipeline + +Ensure service-level project discovery includes the Chat tests. If the service +repository supports conditional test exclusion, add a Chat-specific exclusion +property without excluding the tests by default. + +## 11. C# reference map + +Use these files in the .NET repository to compare behavior. Translate their +intent into the target language's conventions; do not translate C# mechanics +such as partial classes, linked compile items, or NUnit attributes literally. + +| Concern | C# reference | +| --- | --- | +| Client constructors, inner service client, access URI delegation | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/src/WebPubSubChatServiceClient.cs` | +| Reverse proxy option | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/src/WebPubSubChatServiceClientOptions.cs` | +| Access options | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/src/GetClientAccessTokenOptions.cs` | +| Built-in constants | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/src/ChatRoles.cs`, `RoomPermissions.cs`, and `UserPermissions.cs` | +| Shared key authentication and proxy behavior | `sdk/webpubsub/Azure.Messaging.WebPubSub/src/Shared/` | +| Client project dependencies/shared source | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/src/Azure.Messaging.WebPubSub.Chat.csproj` | +| Unit tests | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/tests/WebPubSubChatServiceClientTests.cs` and `ChatRolesAndPermissionsTests.cs` | +| Live tests and test environment | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/tests/WebPubSubChatServiceClientLiveTests.cs` and `WebPubSubChatTestEnvironment.cs` | +| WebSocket/test-client helpers | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/tests/ChatWebSocketHelper.cs` and `tests/tools/` | +| Samples | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/tests/Samples/` | +| Resource deployment and recordings | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/test-resources.bicep` and `assets.json` | +| Package live-test pipeline | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/tests.yml` | +| Service build and test discovery | `sdk/webpubsub/ci.yml`, `sdk/webpubsub/tests.yml`, and `sdk/webpubsub/service.projects` | +| Package documentation and release notes | `sdk/webpubsub/Azure.Messaging.WebPubSub.Chat/README.md` and `CHANGELOG.md` | + +The C# working tree may contain work in progress. Treat handwritten source and +passing behavioral tests as authoritative. Do not copy stale API listings, +local `.env` content, ignored test behavior, or editor files. + +## 12. Completion checks + +The customization is complete only when all of the following pass: + +- regenerate the SDK and confirm handwritten customizations remain intact +- format, lint, build, and run the package's unit tests +- run recorded tests in playback mode from a clean environment +- run the live suite against a deployed resource +- push recordings and verify the new assets tag restores +- regenerate and review the public API surface +- build every README and sample snippet +- validate README and sample links +- run the language repository's package checks and API compatibility checks +- run or queue both package CI and the Web PubSub Chat live-test pipeline + +Review the final diff and confirm it contains no generated-file hand edits, +secrets, local `.env` values, `.assets` content, editor state, or unrelated +service changes. \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/customization/pom.xml b/sdk/webpubsub/azure-messaging-webpubsub-chat/customization/pom.xml new file mode 100644 index 000000000000..8e39dd92de4e --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/customization/pom.xml @@ -0,0 +1,21 @@ + + + 4.0.0 + + + com.azure + azure-code-customization-parent + 1.0.0-beta.1 + ../../../parents/azure-code-customization-parent + + + com.azure.tools + azure-messaging-webpubsub-chat-customization + 1.0.0-beta.1 + jar + + Microsoft Azure Web PubSub Chat client customization for Java + This package contains client customization for Microsoft Azure Web PubSub Chat. + \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/customization/src/main/java/WebPubSubChatCustomization.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/customization/src/main/java/WebPubSubChatCustomization.java new file mode 100644 index 000000000000..c622472de368 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/customization/src/main/java/WebPubSubChatCustomization.java @@ -0,0 +1,265 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import com.azure.autorest.customization.Customization; +import com.azure.autorest.customization.LibraryCustomization; +import com.azure.autorest.customization.PackageCustomization; +import com.github.javaparser.ast.Modifier; +import org.slf4j.Logger; + +import static com.github.javaparser.StaticJavaParser.parseBlock; +import static com.github.javaparser.javadoc.description.JavadocDescription.parseText; + +/** Customizes the generated Azure Web PubSub Chat client library. */ +public final class WebPubSubChatCustomization extends Customization { + private static final String PACKAGE_NAME = "com.azure.messaging.webpubsub.chat"; + + @Override + public void customize(LibraryCustomization libraryCustomization, Logger logger) { + PackageCustomization chatPackage = libraryCustomization.getPackage(PACKAGE_NAME); + + chatPackage.getClass("WebPubSubChatServiceClientBuilder").customizeAst(ast -> { + ast.addImport("com.azure.core.client.traits.AzureKeyCredentialTrait"); + ast.addImport("com.azure.core.client.traits.ConnectionStringTrait"); + ast.addImport("com.azure.core.credential.AzureKeyCredential"); + ast.addImport("com.azure.core.util.UrlBuilder"); + ast.addImport("java.net.MalformedURLException"); + ast.addImport("java.net.URL"); + ast.addImport("java.util.HashMap"); + ast.addImport("java.util.Locale"); + + ast.getClassByName("WebPubSubChatServiceClientBuilder").ifPresent(builder -> { + if (builder.getImplementedTypes() + .stream() + .noneMatch(type -> type.getNameAsString().equals("AzureKeyCredentialTrait"))) { + builder.addImplementedType("AzureKeyCredentialTrait"); + } + if (builder.getImplementedTypes() + .stream() + .noneMatch(type -> type.getNameAsString().equals("ConnectionStringTrait"))) { + builder.addImplementedType("ConnectionStringTrait"); + } + + builder.addField("AzureKeyCredential", "keyCredential", Modifier.Keyword.PRIVATE); + builder.addField("String", "reverseProxyEndpoint", Modifier.Keyword.PRIVATE); + + builder.addMethod("credential", Modifier.Keyword.PUBLIC) + .addMarkerAnnotation("Override") + .addParameter("AzureKeyCredential", "credential") + .setType("WebPubSubChatServiceClientBuilder") + .setBody(parseBlock("{" + + "this.keyCredential = Objects.requireNonNull(credential, \"'credential' cannot be null.\");" + + "return this;" + + "}")) + .setJavadocComment(new com.github.javaparser.javadoc.Javadoc(parseText( + "Sets the Azure key credential used to authenticate requests.")) + .addBlockTag("param", "credential", "The Azure key credential.") + .addBlockTag("return", "The updated builder.")); + + builder.addMethod("connectionString", Modifier.Keyword.PUBLIC) + .addMarkerAnnotation("Override") + .addParameter("String", "connectionString") + .setType("WebPubSubChatServiceClientBuilder") + .setBody(parseBlock("{" + + "Objects.requireNonNull(connectionString, \"'connectionString' cannot be null.\");" + + "Map connectionStringParams = parseConnectionString(connectionString);" + + "if (!connectionStringParams.containsKey(\"endpoint\") " + + "|| !connectionStringParams.containsKey(\"accesskey\")) {" + + "throw LOGGER.logExceptionAsError(new IllegalArgumentException(" + + "\"Connection string does not contain required 'endpoint' and 'accesskey' values\"));" + + "}" + + "this.keyCredential = new AzureKeyCredential(connectionStringParams.get(\"accesskey\"));" + + "String connectionStringEndpoint = connectionStringParams.get(\"endpoint\");" + + "URL url;" + + "try {" + + "url = new URL(connectionStringEndpoint);" + + "this.endpoint = connectionStringEndpoint;" + + "} catch (MalformedURLException exception) {" + + "throw LOGGER.logExceptionAsWarning(new IllegalArgumentException(" + + "\"Connection string contains invalid endpoint\", exception));" + + "}" + + "String port = connectionStringParams.get(\"port\");" + + "if (!CoreUtils.isNullOrEmpty(port)) {" + + "this.endpoint = UrlBuilder.parse(url).setPort(port).toString();" + + "}" + + "return this;" + + "}")) + .setJavadocComment(new com.github.javaparser.javadoc.Javadoc(parseText( + "Sets the Web PubSub connection string used to configure the endpoint and access key.")) + .addBlockTag("param", "connectionString", "The Web PubSub connection string.") + .addBlockTag("return", "The updated builder.")); + + builder.addMethod("reverseProxyEndpoint", Modifier.Keyword.PUBLIC) + .addParameter("String", "reverseProxyEndpoint") + .setType("WebPubSubChatServiceClientBuilder") + .setBody(parseBlock("{" + + "this.reverseProxyEndpoint = reverseProxyEndpoint;" + + "return this;" + + "}")) + .setJavadocComment(new com.github.javaparser.javadoc.Javadoc(parseText( + "Sets the reverse proxy endpoint.")) + .addBlockTag("param", "reverseProxyEndpoint", "The reverse proxy endpoint.") + .addBlockTag("return", "The updated builder.")); + + builder.addMethod("parseConnectionString", Modifier.Keyword.PRIVATE) + .addParameter("String", "connectionString") + .setType("Map") + .setBody(parseBlock("{" + + "String[] parameters = connectionString.split(\";\");" + + "Map connectionStringParams = new HashMap<>();" + + "for (String parameter : parameters) {" + + "String[] parameterParts = parameter.split(\"=\", 2);" + + "if (parameterParts.length != 2) { continue; }" + + "String key = parameterParts[0].trim().toLowerCase(Locale.ROOT);" + + "if (connectionStringParams.containsKey(key)) {" + + "throw LOGGER.logExceptionAsError(new IllegalArgumentException(" + + "\"Duplicate connection string key parameter provided for key '\" + key + \"'\"));" + + "}" + + "connectionStringParams.put(key, parameterParts[1].trim());" + + "}" + + "return connectionStringParams;" + + "}")); + + builder.getMethodsByName("validateClient").forEach(method -> method.setBody(parseBlock("{" + + "Objects.requireNonNull(endpoint, \"'endpoint' cannot be null.\");" + + "if (hub == null || hub.isEmpty()) {" + + "throw LOGGER.logExceptionAsError(new IllegalStateException(" + + "\"hub is not valid - it must be non-null and non-empty.\"));" + + "}" + + "}"))); + + builder.getMethodsByName("createHttpPipeline").forEach(method -> method.setBody(parseBlock("{" + + "Configuration buildConfiguration = (configuration == null) " + + "? Configuration.getGlobalConfiguration() : configuration;" + + "HttpLogOptions localHttpLogOptions = this.httpLogOptions == null " + + "? new HttpLogOptions() : this.httpLogOptions;" + + "ClientOptions localClientOptions = this.clientOptions == null " + + "? new ClientOptions() : this.clientOptions;" + + "List policies = new ArrayList<>();" + + "String clientName = PROPERTIES.getOrDefault(SDK_NAME, \"UnknownName\");" + + "String clientVersion = PROPERTIES.getOrDefault(SDK_VERSION, \"UnknownVersion\");" + + "String applicationId = CoreUtils.getApplicationId(localClientOptions, localHttpLogOptions);" + + "policies.add(new UserAgentPolicy(applicationId, clientName, clientVersion, buildConfiguration));" + + "policies.add(new RequestIdPolicy());" + + "policies.add(new AddHeadersFromContextPolicy());" + + "HttpHeaders headers = CoreUtils.createHttpHeadersFromClientOptions(localClientOptions);" + + "if (headers != null) { policies.add(new AddHeadersPolicy(headers)); }" + + "this.pipelinePolicies.stream()" + + ".filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_CALL)" + + ".forEach(policies::add);" + + "HttpPolicyProviders.addBeforeRetryPolicies(policies);" + + "policies.add(ClientBuilderUtil.validateAndGetRetryPolicy(" + + "retryPolicy, retryOptions, new RetryPolicy()));" + + "policies.add(new AddDatePolicy());" + + "if (keyCredential != null) {" + + "policies.add(new WebPubSubAuthenticationPolicy(keyCredential));" + + "} else if (tokenCredential != null) {" + + "policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, DEFAULT_SCOPES));" + + "} else {" + + "throw LOGGER.logExceptionAsError(new IllegalStateException(" + + "\"No credential available to create the client.\"));" + + "}" + + "if (!CoreUtils.isNullOrEmpty(reverseProxyEndpoint)) {" + + "policies.add(new ReverseProxyPolicy(reverseProxyEndpoint));" + + "}" + + "this.pipelinePolicies.stream()" + + ".filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_RETRY)" + + ".forEach(policies::add);" + + "HttpPolicyProviders.addAfterRetryPolicies(policies);" + + "policies.add(new HttpLoggingPolicy(localHttpLogOptions));" + + "return new HttpPipelineBuilder().policies(policies.toArray(new HttpPipelinePolicy[0]))" + + ".httpClient(httpClient).clientOptions(localClientOptions).build();" + + "}"))); + + builder.getMethodsByName("buildAsyncClient").forEach(method -> method.setBody(parseBlock("{" + + "return new WebPubSubChatServiceAsyncClient(buildInnerClient(), keyCredential);" + + "}"))); + builder.getMethodsByName("buildClient").forEach(method -> method.setBody(parseBlock("{" + + "return new WebPubSubChatServiceClient(buildInnerClient(), keyCredential);" + + "}"))); + }); + }); + + customizeTokenClient(chatPackage, "WebPubSubChatServiceClient", false); + customizeTokenClient(chatPackage, "WebPubSubChatServiceAsyncClient", true); + + addNimbusModuleRequirement(libraryCustomization); + fixGeneratedPagingCalls(libraryCustomization); + removeTrailingJavadocWhitespace(libraryCustomization); + } + + private static void customizeTokenClient(PackageCustomization chatPackage, String className, boolean async) { + chatPackage.getClass(className).customizeAst(ast -> { + ast.getImports() + .removeIf(importDeclaration -> importDeclaration.getNameAsString() + .equals("com.azure.messaging.webpubsub.chat.implementation.models.GenerateClientTokenResponse")); + ast.addImport("com.azure.core.credential.AzureKeyCredential"); + ast.addImport("com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions"); + ast.addImport("com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken"); + if (async) { + ast.addImport("reactor.core.publisher.Mono"); + } + + ast.getClassByName(className).ifPresent(client -> { + client.getMethodsByName("generateClientToken").forEach(method -> method.remove()); + client.getMethodsByName("generateClientTokenWithResponse").forEach(method -> method.remove()); + client.addField("AzureKeyCredential", "keyCredential", Modifier.Keyword.PRIVATE, + Modifier.Keyword.FINAL); + client.getConstructors().forEach(constructor -> { + constructor.addParameter("AzureKeyCredential", "keyCredential"); + constructor.getBody().addStatement("this.keyCredential = keyCredential;"); + }); + + client.addMethod("getClientAccessToken", Modifier.Keyword.PUBLIC) + .addParameter("GetClientAccessTokenOptions", "options") + .setType(async ? "Mono" : "WebPubSubClientAccessToken") + .setBody(parseBlock(async + ? "{ return WebPubSubClientAccessTokenFactory.createAsync(serviceClient, keyCredential, options); }" + : "{ return WebPubSubClientAccessTokenFactory.create(serviceClient, keyCredential, options); }")) + .setJavadocComment(new com.github.javaparser.javadoc.Javadoc(parseText( + "Creates a client access token for connecting to Azure Web PubSub Chat.")) + .addBlockTag("param", "options", "Options for creating the client access token.") + .addBlockTag("return", async + ? "A publisher containing the client access token." + : "The client access token.")); + }); + }); + } + + private static void addNimbusModuleRequirement(LibraryCustomization libraryCustomization) { + String path = "src/main/java/module-info.java"; + String moduleInfo = libraryCustomization.getRawEditor().getFileContent(path); + if (!moduleInfo.contains("requires com.nimbusds.jose.jwt;")) { + libraryCustomization.getRawEditor() + .replaceFile(path, moduleInfo.replace(" requires transitive com.azure.core;", + " requires transitive com.azure.core;\n requires com.nimbusds.jose.jwt;")); + } + } + + private static void fixGeneratedPagingCalls(LibraryCustomization libraryCustomization) { + replaceInGeneratedFiles(libraryCustomization, "listMessages(\"c.room1.abcd1234\", null, null, 10)", + "listMessages(\"c.room1.abcd1234\")", "ListMessages.java", "ListMessagesTests.java"); + replaceInGeneratedFiles(libraryCustomization, "listRoles(10, null)", "listRoles()", "ListRoles.java", + "ListRolesTests.java"); + replaceInGeneratedFiles(libraryCustomization, "listRoomMembers(\"room1\", 10, null)", + "listRoomMembers(\"room1\")", "ListRoomMembers.java", "ListRoomMembersTests.java"); + } + + private static void replaceInGeneratedFiles(LibraryCustomization libraryCustomization, String oldValue, + String newValue, String sampleFile, String testFile) { + String samplePath = "src/samples/java/com/azure/messaging/webpubsub/chat/generated/" + sampleFile; + String testPath = "src/test/java/com/azure/messaging/webpubsub/chat/generated/" + testFile; + String sample = libraryCustomization.getRawEditor().getFileContent(samplePath); + String test = libraryCustomization.getRawEditor().getFileContent(testPath); + libraryCustomization.getRawEditor().replaceFile(samplePath, sample.replace(oldValue, newValue)); + libraryCustomization.getRawEditor().replaceFile(testPath, test.replace(oldValue, newValue)); + } + + private static void removeTrailingJavadocWhitespace(LibraryCustomization libraryCustomization) { + String path + = "src/main/java/com/azure/messaging/webpubsub/chat/implementation/WebPubSubChatServiceClientImpl.java"; + String implementation = libraryCustomization.getRawEditor().getFileContent(path); + libraryCustomization.getRawEditor() + .replaceFile(path, implementation.replace("* \r\n", "*\r\n").replace("* \n", "*\n")); + } +} \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/pom.xml b/sdk/webpubsub/azure-messaging-webpubsub-chat/pom.xml new file mode 100644 index 000000000000..f3c296ded33a --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + + com.azure + azure-client-sdk-parent + 1.7.0 + ../../parents/azure-client-sdk-parent + + + com.azure + azure-messaging-webpubsub-chat + 1.0.0-beta.1 + jar + + Microsoft Azure SDK for WebPubSubChat + This package contains Microsoft Azure WebPubSubChat client library. + https://github.com/Azure/azure-sdk-for-java + + + + The MIT License (MIT) + http://opensource.org/licenses/MIT + repo + + + + + https://github.com/Azure/azure-sdk-for-java + scm:git:git@github.com:Azure/azure-sdk-for-java.git + scm:git:git@github.com:Azure/azure-sdk-for-java.git + HEAD + + + + microsoft + Microsoft + + + + UTF-8 + + + + com.azure + azure-core + 1.59.1 + + + com.azure + azure-core-http-netty + 1.16.7 + + + com.nimbusds + nimbus-jose-jwt + 9.37.3 + + + com.azure + azure-core-test + 1.27.0-beta.18 + test + + + com.azure + azure-identity + 1.18.5 + test + + + io.projectreactor.netty + reactor-netty-http + 1.2.18 + test + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.6.3 + + + + + com.nimbusds:nimbus-jose-jwt:[9.37.3] + io.projectreactor.netty:reactor-netty-http:[1.2.18] + + + + + + + + diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/ReverseProxyPolicy.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/ReverseProxyPolicy.java new file mode 100644 index 000000000000..a1381cf51c76 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/ReverseProxyPolicy.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpRequest; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.util.CoreUtils; +import reactor.core.publisher.Mono; + +import java.net.URL; + +/** + * Routes requests through a reverse proxy using the Web PubSub service SDK convention. + */ +final class ReverseProxyPolicy implements HttpPipelinePolicy { + private final String reverseProxyEndpoint; + + ReverseProxyPolicy(String reverseProxyEndpoint) { + this.reverseProxyEndpoint = reverseProxyEndpoint; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + URL url = context.getHttpRequest().getUrl(); + String reverseProxyUrl = reverseProxyEndpoint; + String path = url.getPath(); + if (!CoreUtils.isNullOrEmpty(path)) { + reverseProxyUrl += path; + } + String query = url.getQuery(); + if (!CoreUtils.isNullOrEmpty(query)) { + reverseProxyUrl += "?" + query; + } + + HttpRequest requestCopy = context.getHttpRequest().copy(); + context.setHttpRequest(requestCopy.setUrl(reverseProxyUrl)); + return next.clone().process(); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubAuthenticationPolicy.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubAuthenticationPolicy.java new file mode 100644 index 000000000000..f02b1f892e17 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubAuthenticationPolicy.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.HttpPipelineCallContext; +import com.azure.core.http.HttpPipelineNextPolicy; +import com.azure.core.http.HttpResponse; +import com.azure.core.http.policy.HttpPipelinePolicy; +import reactor.core.publisher.Mono; + +import java.time.Duration; + +/** + * An {@link HttpPipelinePolicy} for authenticating requests to the Azure Web PubSub Chat service. + */ +public final class WebPubSubAuthenticationPolicy implements HttpPipelinePolicy { + private static final Duration DEFAULT_EXPIRATION = Duration.ofHours(1); + + private final AzureKeyCredential credential; + + /** + * Creates a policy that authenticates requests using the supplied credential. + * + * @param credential The credential used to authenticate outgoing requests. + */ + public WebPubSubAuthenticationPolicy(AzureKeyCredential credential) { + this.credential = credential; + } + + @Override + public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) { + return Mono.fromRunnable(() -> { + String audience = context.getHttpRequest().getUrl().toString(); + String token = WebPubSubTokenGenerator.generateToken(audience, null, null, DEFAULT_EXPIRATION, credential); + if (token != null) { + context.getHttpRequest().setHeader(HttpHeaderName.AUTHORIZATION, "Bearer " + token); + } + }).then(next.process()); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceAsyncClient.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceAsyncClient.java new file mode 100644 index 000000000000..031e4a98cc52 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceAsyncClient.java @@ -0,0 +1,1621 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.MatchConditions; +import com.azure.core.http.rest.PagedFlux; +import com.azure.core.http.rest.PagedResponse; +import com.azure.core.http.rest.PagedResponseBase; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import com.azure.core.util.FluxUtil; +import com.azure.messaging.webpubsub.chat.implementation.JsonMergePatchHelper; +import com.azure.messaging.webpubsub.chat.implementation.WebPubSubChatServiceClientImpl; +import com.azure.messaging.webpubsub.chat.models.ChatConversation; +import com.azure.messaging.webpubsub.chat.models.ChatMessage; +import com.azure.messaging.webpubsub.chat.models.ChatRole; +import com.azure.messaging.webpubsub.chat.models.ChatRoom; +import com.azure.messaging.webpubsub.chat.models.ChatRoomMember; +import com.azure.messaging.webpubsub.chat.models.ChatUser; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; +import java.util.stream.Collectors; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * Initializes a new instance of the asynchronous WebPubSubChatServiceClient type. + */ +@ServiceClient(builder = WebPubSubChatServiceClientBuilder.class, isAsync = true) +public final class WebPubSubChatServiceAsyncClient { + + @Generated + private final WebPubSubChatServiceClientImpl serviceClient; + + /** + * Initializes an instance of WebPubSubChatServiceAsyncClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + WebPubSubChatServiceAsyncClient(WebPubSubChatServiceClientImpl serviceClient, AzureKeyCredential keyCredential) { + this.serviceClient = serviceClient; + this.keyCredential = keyCredential; + } + + /** + * Get conversation information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     parentRoom: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return conversation information along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getConversationWithResponse(String conversationId, + RequestOptions requestOptions) { + return this.serviceClient.getConversationWithResponseAsync(conversationId, requestOptions); + } + + /** + * Query messages in a conversation from latest to earliest. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
latestMessageIdStringNoLatest message ID (exclusive) for pagination.
earliestMessageIdStringNoEarliest message ID (exclusive) for + * pagination.
maxpagesizeIntegerNoThe maximum number of result items per page.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listMessages(String conversationId, RequestOptions requestOptions) { + return this.serviceClient.listMessagesAsync(conversationId, requestOptions); + } + + /** + * Delete a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteMessageWithResponse(String conversationId, String messageId, + RequestOptions requestOptions) { + return this.serviceClient.deleteMessageWithResponseAsync(conversationId, messageId, requestOptions); + } + + /** + * Update a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat message along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> updateMessageWithResponse(String conversationId, String messageId, + BinaryData resource, RequestOptions requestOptions) { + return this.serviceClient.updateMessageWithResponseAsync(conversationId, messageId, resource, requestOptions); + } + + /** + * Query roles in a hub. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoles(RequestOptions requestOptions) { + return this.serviceClient.listRolesAsync(requestOptions); + } + + /** + * Get role information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return role information along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRoleWithResponse(String roleName, RequestOptions requestOptions) { + return this.serviceClient.getRoleWithResponseAsync(roleName, requestOptions); + } + + /** + * Create or replace a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both along with {@link Response} on + * successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceRoleWithResponse(String roleName, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceRoleWithResponseAsync(roleName, resource, requestOptions); + } + + /** + * Delete a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRoleWithResponse(String roleName, RequestOptions requestOptions) { + return this.serviceClient.deleteRoleWithResponseAsync(roleName, requestOptions); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat room along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceRoomWithResponse(String roomId, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceRoomWithResponseAsync(roomId, resource, requestOptions); + } + + /** + * Get room information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room information along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRoomWithResponse(String roomId, RequestOptions requestOptions) { + return this.serviceClient.getRoomWithResponseAsync(roomId, requestOptions); + } + + /** + * Delete a room. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRoomWithResponse(String roomId, RequestOptions requestOptions) { + return this.serviceClient.deleteRoomWithResponseAsync(roomId, requestOptions); + } + + /** + * Get room members. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoomMembers(String roomId, RequestOptions requestOptions) { + return this.serviceClient.listRoomMembersAsync(roomId, requestOptions); + } + + /** + * Create or replace a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a room member along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceRoomMemberWithResponse(String roomId, String userId, + BinaryData resource, RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceRoomMemberWithResponseAsync(roomId, userId, resource, requestOptions); + } + + /** + * Delete a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRoomMemberWithResponse(String roomId, String userId, + RequestOptions requestOptions) { + return this.serviceClient.deleteRoomMemberWithResponseAsync(roomId, userId, requestOptions); + } + + /** + * Get a user's profile. + * + * Get a user's profile. The response is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the `kind` + * discriminator. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return a user's profile. + * + * Get a user's profile along with {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getUserWithResponse(String userId, RequestOptions requestOptions) { + return this.serviceClient.getUserWithResponseAsync(userId, requestOptions); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param userId User identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a user profile in the chat system along with {@link Response} on successful completion of + * {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceUserWithResponse(String userId, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceUserWithResponseAsync(userId, resource, requestOptions); + } + + /** + * Delete a user. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteUserWithResponse(String userId, RequestOptions requestOptions) { + return this.serviceClient.deleteUserWithResponseAsync(userId, requestOptions); + } + + /** + * Get conversation information. + * + * @param conversationId Conversation identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return conversation information on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getConversation(String conversationId) { + // Generated convenience method for getConversationWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getConversationWithResponse(conversationId, requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatConversation.class)); + } + + /** + * Query messages in a conversation from latest to earliest. + * + * @param conversationId Conversation identifier. + * @param latestMessageId Latest message ID (exclusive) for pagination. + * @param earliestMessageId Earliest message ID (exclusive) for pagination. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatMessage items as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listMessages(String conversationId, String latestMessageId, + String earliestMessageId) { + // Generated convenience method for listMessages + RequestOptions requestOptions = new RequestOptions(); + if (latestMessageId != null) { + requestOptions.addQueryParam("latestMessageId", latestMessageId, false); + } + if (earliestMessageId != null) { + requestOptions.addQueryParam("earliestMessageId", earliestMessageId, false); + } + PagedFlux pagedFluxResponse = listMessages(conversationId, requestOptions); + return PagedFlux.create(() -> (continuationTokenParam, pageSizeParam) -> { + Flux> flux = (continuationTokenParam == null) + ? pagedFluxResponse.byPage().take(1) + : pagedFluxResponse.byPage(continuationTokenParam).take(1); + return flux.map(pagedResponse -> new PagedResponseBase(pagedResponse.getRequest(), + pagedResponse.getStatusCode(), pagedResponse.getHeaders(), + pagedResponse.getValue() + .stream() + .map(protocolMethodData -> protocolMethodData.toObject(ChatMessage.class)) + .collect(Collectors.toList()), + pagedResponse.getContinuationToken(), null)); + }); + } + + /** + * Query messages in a conversation from latest to earliest. + * + * @param conversationId Conversation identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatMessage items as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listMessages(String conversationId) { + // Generated convenience method for listMessages + RequestOptions requestOptions = new RequestOptions(); + PagedFlux pagedFluxResponse = listMessages(conversationId, requestOptions); + return PagedFlux.create(() -> (continuationTokenParam, pageSizeParam) -> { + Flux> flux = (continuationTokenParam == null) + ? pagedFluxResponse.byPage().take(1) + : pagedFluxResponse.byPage(continuationTokenParam).take(1); + return flux.map(pagedResponse -> new PagedResponseBase(pagedResponse.getRequest(), + pagedResponse.getStatusCode(), pagedResponse.getHeaders(), + pagedResponse.getValue() + .stream() + .map(protocolMethodData -> protocolMethodData.toObject(ChatMessage.class)) + .collect(Collectors.toList()), + pagedResponse.getContinuationToken(), null)); + }); + } + + /** + * Delete a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteMessage(String conversationId, String messageId, MatchConditions matchConditions) { + // Generated convenience method for deleteMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return deleteMessageWithResponse(conversationId, messageId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Delete a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteMessage(String conversationId, String messageId) { + // Generated convenience method for deleteMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + return deleteMessageWithResponse(conversationId, messageId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Update a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat message on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono updateMessage(String conversationId, String messageId, ChatMessage resource, + MatchConditions matchConditions) { + // Generated convenience method for updateMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, true); + BinaryData resourceInBinaryData = BinaryData.fromObject(resource); + // BinaryData.fromObject() will not fire serialization, use getLength() to fire serialization. + resourceInBinaryData.getLength(); + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, false); + return updateMessageWithResponse(conversationId, messageId, resourceInBinaryData, requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatMessage.class)); + } + + /** + * Update a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat message on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono updateMessage(String conversationId, String messageId, ChatMessage resource) { + // Generated convenience method for updateMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, true); + BinaryData resourceInBinaryData = BinaryData.fromObject(resource); + // BinaryData.fromObject() will not fire serialization, use getLength() to fire serialization. + resourceInBinaryData.getLength(); + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, false); + return updateMessageWithResponse(conversationId, messageId, resourceInBinaryData, requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatMessage.class)); + } + + /** + * Query roles in a hub. + * + * @param continuationToken Continuation token for pagination. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatRole items as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoles(String continuationToken) { + // Generated convenience method for listRoles + RequestOptions requestOptions = new RequestOptions(); + if (continuationToken != null) { + requestOptions.addQueryParam("continuationToken", continuationToken, false); + } + PagedFlux pagedFluxResponse = listRoles(requestOptions); + return PagedFlux.create(() -> (continuationTokenParam, pageSizeParam) -> { + Flux> flux = (continuationTokenParam == null) + ? pagedFluxResponse.byPage().take(1) + : pagedFluxResponse.byPage(continuationTokenParam).take(1); + return flux.map(pagedResponse -> new PagedResponseBase(pagedResponse.getRequest(), + pagedResponse.getStatusCode(), pagedResponse.getHeaders(), + pagedResponse.getValue() + .stream() + .map(protocolMethodData -> protocolMethodData.toObject(ChatRole.class)) + .collect(Collectors.toList()), + pagedResponse.getContinuationToken(), null)); + }); + } + + /** + * Query roles in a hub. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatRole items as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoles() { + // Generated convenience method for listRoles + RequestOptions requestOptions = new RequestOptions(); + PagedFlux pagedFluxResponse = listRoles(requestOptions); + return PagedFlux.create(() -> (continuationTokenParam, pageSizeParam) -> { + Flux> flux = (continuationTokenParam == null) + ? pagedFluxResponse.byPage().take(1) + : pagedFluxResponse.byPage(continuationTokenParam).take(1); + return flux.map(pagedResponse -> new PagedResponseBase(pagedResponse.getRequest(), + pagedResponse.getStatusCode(), pagedResponse.getHeaders(), + pagedResponse.getValue() + .stream() + .map(protocolMethodData -> protocolMethodData.toObject(ChatRole.class)) + .collect(Collectors.toList()), + pagedResponse.getContinuationToken(), null)); + }); + } + + /** + * Get role information. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return role information on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getRole(String roleName) { + // Generated convenience method for getRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getRoleWithResponse(roleName, requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRole.class)); + } + + /** + * Create or replace a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both on successful completion of + * {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceRole(String roleName, ChatRole resource, MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceRoleWithResponse(roleName, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRole.class)); + } + + /** + * Create or replace a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both on successful completion of + * {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceRole(String roleName, ChatRole resource) { + // Generated convenience method for createOrReplaceRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceRoleWithResponse(roleName, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRole.class)); + } + + /** + * Delete a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRole(String roleName, MatchConditions matchConditions) { + // Generated convenience method for deleteRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return deleteRoleWithResponse(roleName, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Delete a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRole(String roleName) { + // Generated convenience method for deleteRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + return deleteRoleWithResponse(roleName, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + * + * @param roomId Room identifier. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat room on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceRoom(String roomId, ChatRoom resource, MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceRoomWithResponse(roomId, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoom.class)); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + * + * @param roomId Room identifier. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat room on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceRoom(String roomId, ChatRoom resource) { + // Generated convenience method for createOrReplaceRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceRoomWithResponse(roomId, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoom.class)); + } + + /** + * Get room information. + * + * @param roomId Room identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return room information on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getRoom(String roomId) { + // Generated convenience method for getRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getRoomWithResponse(roomId, requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoom.class)); + } + + /** + * Delete a room. + * + * @param roomId Room identifier. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRoom(String roomId, MatchConditions matchConditions) { + // Generated convenience method for deleteRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return deleteRoomWithResponse(roomId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Delete a room. + * + * @param roomId Room identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRoom(String roomId) { + // Generated convenience method for deleteRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + return deleteRoomWithResponse(roomId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Get room members. + * + * @param roomId Room identifier. + * @param continuationToken Continuation token for pagination. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return room members as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoomMembers(String roomId, String continuationToken) { + // Generated convenience method for listRoomMembers + RequestOptions requestOptions = new RequestOptions(); + if (continuationToken != null) { + requestOptions.addQueryParam("continuationToken", continuationToken, false); + } + PagedFlux pagedFluxResponse = listRoomMembers(roomId, requestOptions); + return PagedFlux.create(() -> (continuationTokenParam, pageSizeParam) -> { + Flux> flux = (continuationTokenParam == null) + ? pagedFluxResponse.byPage().take(1) + : pagedFluxResponse.byPage(continuationTokenParam).take(1); + return flux.map(pagedResponse -> new PagedResponseBase(pagedResponse.getRequest(), + pagedResponse.getStatusCode(), pagedResponse.getHeaders(), + pagedResponse.getValue() + .stream() + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoomMember.class)) + .collect(Collectors.toList()), + pagedResponse.getContinuationToken(), null)); + }); + } + + /** + * Get room members. + * + * @param roomId Room identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return room members as paginated response with {@link PagedFlux}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoomMembers(String roomId) { + // Generated convenience method for listRoomMembers + RequestOptions requestOptions = new RequestOptions(); + PagedFlux pagedFluxResponse = listRoomMembers(roomId, requestOptions); + return PagedFlux.create(() -> (continuationTokenParam, pageSizeParam) -> { + Flux> flux = (continuationTokenParam == null) + ? pagedFluxResponse.byPage().take(1) + : pagedFluxResponse.byPage(continuationTokenParam).take(1); + return flux.map(pagedResponse -> new PagedResponseBase(pagedResponse.getRequest(), + pagedResponse.getStatusCode(), pagedResponse.getHeaders(), + pagedResponse.getValue() + .stream() + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoomMember.class)) + .collect(Collectors.toList()), + pagedResponse.getContinuationToken(), null)); + }); + } + + /** + * Create or replace a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a room member on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceRoomMember(String roomId, String userId, ChatRoomMember resource, + MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceRoomMemberWithResponse(roomId, userId, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoomMember.class)); + } + + /** + * Create or replace a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a room member on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceRoomMember(String roomId, String userId, ChatRoomMember resource) { + // Generated convenience method for createOrReplaceRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceRoomMemberWithResponse(roomId, userId, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatRoomMember.class)); + } + + /** + * Delete a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRoomMember(String roomId, String userId, MatchConditions matchConditions) { + // Generated convenience method for deleteRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return deleteRoomMemberWithResponse(roomId, userId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Delete a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteRoomMember(String roomId, String userId) { + // Generated convenience method for deleteRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + return deleteRoomMemberWithResponse(roomId, userId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Get a user's profile. + * + * Get a user's profile. The response is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the `kind` + * discriminator. + * + * @param userId User identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return a user's profile. + * + * Get a user's profile on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono getUser(String userId) { + // Generated convenience method for getUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getUserWithResponse(userId, requestOptions).flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatUser.class)); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + * + * @param userId User identifier. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a user profile in the chat system on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceUser(String userId, ChatUser resource, MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceUserWithResponse(userId, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatUser.class)); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + * + * @param userId User identifier. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a user profile in the chat system on successful completion of {@link Mono}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono createOrReplaceUser(String userId, ChatUser resource) { + // Generated convenience method for createOrReplaceUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceUserWithResponse(userId, BinaryData.fromObject(resource), requestOptions) + .flatMap(FluxUtil::toMono) + .map(protocolMethodData -> protocolMethodData.toObject(ChatUser.class)); + } + + /** + * Delete a user. + * + * @param userId User identifier. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteUser(String userId, MatchConditions matchConditions) { + // Generated convenience method for deleteUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return deleteUserWithResponse(userId, requestOptions).flatMap(FluxUtil::toMono); + } + + /** + * Delete a user. + * + * @param userId User identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return A {@link Mono} that completes when a successful response is received. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono deleteUser(String userId) { + // Generated convenience method for deleteUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + return deleteUserWithResponse(userId, requestOptions).flatMap(FluxUtil::toMono); + } + + private final AzureKeyCredential keyCredential; + + /** + * Creates a client access token for connecting to Azure Web PubSub Chat. + * + * @param options Options for creating the client access token. + * @return A publisher containing the client access token. + */ + public Mono getClientAccessToken(GetClientAccessTokenOptions options) { + return WebPubSubClientAccessTokenFactory.createAsync(serviceClient, keyCredential, options); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClient.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClient.java new file mode 100644 index 000000000000..b22459607eac --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClient.java @@ -0,0 +1,1519 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceClient; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.MatchConditions; +import com.azure.core.http.rest.PagedIterable; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.util.BinaryData; +import com.azure.messaging.webpubsub.chat.implementation.JsonMergePatchHelper; +import com.azure.messaging.webpubsub.chat.implementation.WebPubSubChatServiceClientImpl; +import com.azure.messaging.webpubsub.chat.models.ChatConversation; +import com.azure.messaging.webpubsub.chat.models.ChatMessage; +import com.azure.messaging.webpubsub.chat.models.ChatRole; +import com.azure.messaging.webpubsub.chat.models.ChatRoom; +import com.azure.messaging.webpubsub.chat.models.ChatRoomMember; +import com.azure.messaging.webpubsub.chat.models.ChatUser; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; + +/** + * Initializes a new instance of the synchronous WebPubSubChatServiceClient type. + */ +@ServiceClient(builder = WebPubSubChatServiceClientBuilder.class) +public final class WebPubSubChatServiceClient { + + @Generated + private final WebPubSubChatServiceClientImpl serviceClient; + + /** + * Initializes an instance of WebPubSubChatServiceClient class. + * + * @param serviceClient the service client implementation. + */ + @Generated + WebPubSubChatServiceClient(WebPubSubChatServiceClientImpl serviceClient, AzureKeyCredential keyCredential) { + this.serviceClient = serviceClient; + this.keyCredential = keyCredential; + } + + /** + * Get conversation information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     parentRoom: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return conversation information along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getConversationWithResponse(String conversationId, RequestOptions requestOptions) { + return this.serviceClient.getConversationWithResponse(conversationId, requestOptions); + } + + /** + * Query messages in a conversation from latest to earliest. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
latestMessageIdStringNoLatest message ID (exclusive) for pagination.
earliestMessageIdStringNoEarliest message ID (exclusive) for + * pagination.
maxpagesizeIntegerNoThe maximum number of result items per page.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listMessages(String conversationId, RequestOptions requestOptions) { + return this.serviceClient.listMessages(conversationId, requestOptions); + } + + /** + * Delete a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteMessageWithResponse(String conversationId, String messageId, + RequestOptions requestOptions) { + return this.serviceClient.deleteMessageWithResponse(conversationId, messageId, requestOptions); + } + + /** + * Update a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat message along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response updateMessageWithResponse(String conversationId, String messageId, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.updateMessageWithResponse(conversationId, messageId, resource, requestOptions); + } + + /** + * Query roles in a hub. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoles(RequestOptions requestOptions) { + return this.serviceClient.listRoles(requestOptions); + } + + /** + * Get role information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return role information along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getRoleWithResponse(String roleName, RequestOptions requestOptions) { + return this.serviceClient.getRoleWithResponse(roleName, requestOptions); + } + + /** + * Create or replace a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceRoleWithResponse(String roleName, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceRoleWithResponse(roleName, resource, requestOptions); + } + + /** + * Delete a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRoleWithResponse(String roleName, RequestOptions requestOptions) { + return this.serviceClient.deleteRoleWithResponse(roleName, requestOptions); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat room along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceRoomWithResponse(String roomId, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceRoomWithResponse(roomId, resource, requestOptions); + } + + /** + * Get room information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room information along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getRoomWithResponse(String roomId, RequestOptions requestOptions) { + return this.serviceClient.getRoomWithResponse(roomId, requestOptions); + } + + /** + * Delete a room. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRoomWithResponse(String roomId, RequestOptions requestOptions) { + return this.serviceClient.deleteRoomWithResponse(roomId, requestOptions); + } + + /** + * Get room members. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoomMembers(String roomId, RequestOptions requestOptions) { + return this.serviceClient.listRoomMembers(roomId, requestOptions); + } + + /** + * Create or replace a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a room member along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceRoomMemberWithResponse(String roomId, String userId, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceRoomMemberWithResponse(roomId, userId, resource, requestOptions); + } + + /** + * Delete a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRoomMemberWithResponse(String roomId, String userId, RequestOptions requestOptions) { + return this.serviceClient.deleteRoomMemberWithResponse(roomId, userId, requestOptions); + } + + /** + * Get a user's profile. + * + * Get a user's profile. The response is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the `kind` + * discriminator. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return a user's profile. + * + * Get a user's profile along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getUserWithResponse(String userId, RequestOptions requestOptions) { + return this.serviceClient.getUserWithResponse(userId, requestOptions); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param userId User identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a user profile in the chat system along with {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceUserWithResponse(String userId, BinaryData resource, + RequestOptions requestOptions) { + return this.serviceClient.createOrReplaceUserWithResponse(userId, resource, requestOptions); + } + + /** + * Delete a user. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteUserWithResponse(String userId, RequestOptions requestOptions) { + return this.serviceClient.deleteUserWithResponse(userId, requestOptions); + } + + /** + * Get conversation information. + * + * @param conversationId Conversation identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return conversation information. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatConversation getConversation(String conversationId) { + // Generated convenience method for getConversationWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getConversationWithResponse(conversationId, requestOptions).getValue().toObject(ChatConversation.class); + } + + /** + * Query messages in a conversation from latest to earliest. + * + * @param conversationId Conversation identifier. + * @param latestMessageId Latest message ID (exclusive) for pagination. + * @param earliestMessageId Earliest message ID (exclusive) for pagination. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatMessage items as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listMessages(String conversationId, String latestMessageId, + String earliestMessageId) { + // Generated convenience method for listMessages + RequestOptions requestOptions = new RequestOptions(); + if (latestMessageId != null) { + requestOptions.addQueryParam("latestMessageId", latestMessageId, false); + } + if (earliestMessageId != null) { + requestOptions.addQueryParam("earliestMessageId", earliestMessageId, false); + } + return serviceClient.listMessages(conversationId, requestOptions) + .mapPage(bodyItemValue -> bodyItemValue.toObject(ChatMessage.class)); + } + + /** + * Query messages in a conversation from latest to earliest. + * + * @param conversationId Conversation identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatMessage items as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listMessages(String conversationId) { + // Generated convenience method for listMessages + RequestOptions requestOptions = new RequestOptions(); + return serviceClient.listMessages(conversationId, requestOptions) + .mapPage(bodyItemValue -> bodyItemValue.toObject(ChatMessage.class)); + } + + /** + * Delete a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteMessage(String conversationId, String messageId, MatchConditions matchConditions) { + // Generated convenience method for deleteMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + deleteMessageWithResponse(conversationId, messageId, requestOptions).getValue(); + } + + /** + * Delete a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteMessage(String conversationId, String messageId) { + // Generated convenience method for deleteMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + deleteMessageWithResponse(conversationId, messageId, requestOptions).getValue(); + } + + /** + * Update a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat message. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatMessage updateMessage(String conversationId, String messageId, ChatMessage resource, + MatchConditions matchConditions) { + // Generated convenience method for updateMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, true); + BinaryData resourceInBinaryData = BinaryData.fromObject(resource); + // BinaryData.fromObject() will not fire serialization, use getLength() to fire serialization. + resourceInBinaryData.getLength(); + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, false); + return updateMessageWithResponse(conversationId, messageId, resourceInBinaryData, requestOptions).getValue() + .toObject(ChatMessage.class); + } + + /** + * Update a message. + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat message. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatMessage updateMessage(String conversationId, String messageId, ChatMessage resource) { + // Generated convenience method for updateMessageWithResponse + RequestOptions requestOptions = new RequestOptions(); + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, true); + BinaryData resourceInBinaryData = BinaryData.fromObject(resource); + // BinaryData.fromObject() will not fire serialization, use getLength() to fire serialization. + resourceInBinaryData.getLength(); + JsonMergePatchHelper.getChatMessageAccessor().prepareModelForJsonMergePatch(resource, false); + return updateMessageWithResponse(conversationId, messageId, resourceInBinaryData, requestOptions).getValue() + .toObject(ChatMessage.class); + } + + /** + * Query roles in a hub. + * + * @param continuationToken Continuation token for pagination. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatRole items as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoles(String continuationToken) { + // Generated convenience method for listRoles + RequestOptions requestOptions = new RequestOptions(); + if (continuationToken != null) { + requestOptions.addQueryParam("continuationToken", continuationToken, false); + } + return serviceClient.listRoles(requestOptions).mapPage(bodyItemValue -> bodyItemValue.toObject(ChatRole.class)); + } + + /** + * Query roles in a hub. + * + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return paged collection of ChatRole items as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoles() { + // Generated convenience method for listRoles + RequestOptions requestOptions = new RequestOptions(); + return serviceClient.listRoles(requestOptions).mapPage(bodyItemValue -> bodyItemValue.toObject(ChatRole.class)); + } + + /** + * Get role information. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return role information. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRole getRole(String roleName) { + // Generated convenience method for getRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getRoleWithResponse(roleName, requestOptions).getValue().toObject(ChatRole.class); + } + + /** + * Create or replace a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRole createOrReplaceRole(String roleName, ChatRole resource, MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceRoleWithResponse(roleName, BinaryData.fromObject(resource), requestOptions).getValue() + .toObject(ChatRole.class); + } + + /** + * Create or replace a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRole createOrReplaceRole(String roleName, ChatRole resource) { + // Generated convenience method for createOrReplaceRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceRoleWithResponse(roleName, BinaryData.fromObject(resource), requestOptions).getValue() + .toObject(ChatRole.class); + } + + /** + * Delete a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRole(String roleName, MatchConditions matchConditions) { + // Generated convenience method for deleteRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + deleteRoleWithResponse(roleName, requestOptions).getValue(); + } + + /** + * Delete a role. + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRole(String roleName) { + // Generated convenience method for deleteRoleWithResponse + RequestOptions requestOptions = new RequestOptions(); + deleteRoleWithResponse(roleName, requestOptions).getValue(); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + * + * @param roomId Room identifier. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat room. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRoom createOrReplaceRoom(String roomId, ChatRoom resource, MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceRoomWithResponse(roomId, BinaryData.fromObject(resource), requestOptions).getValue() + .toObject(ChatRoom.class); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + * + * @param roomId Room identifier. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a chat room. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRoom createOrReplaceRoom(String roomId, ChatRoom resource) { + // Generated convenience method for createOrReplaceRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceRoomWithResponse(roomId, BinaryData.fromObject(resource), requestOptions).getValue() + .toObject(ChatRoom.class); + } + + /** + * Get room information. + * + * @param roomId Room identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return room information. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRoom getRoom(String roomId) { + // Generated convenience method for getRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getRoomWithResponse(roomId, requestOptions).getValue().toObject(ChatRoom.class); + } + + /** + * Delete a room. + * + * @param roomId Room identifier. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRoom(String roomId, MatchConditions matchConditions) { + // Generated convenience method for deleteRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + deleteRoomWithResponse(roomId, requestOptions).getValue(); + } + + /** + * Delete a room. + * + * @param roomId Room identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRoom(String roomId) { + // Generated convenience method for deleteRoomWithResponse + RequestOptions requestOptions = new RequestOptions(); + deleteRoomWithResponse(roomId, requestOptions).getValue(); + } + + /** + * Get room members. + * + * @param roomId Room identifier. + * @param continuationToken Continuation token for pagination. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return room members as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoomMembers(String roomId, String continuationToken) { + // Generated convenience method for listRoomMembers + RequestOptions requestOptions = new RequestOptions(); + if (continuationToken != null) { + requestOptions.addQueryParam("continuationToken", continuationToken, false); + } + return serviceClient.listRoomMembers(roomId, requestOptions) + .mapPage(bodyItemValue -> bodyItemValue.toObject(ChatRoomMember.class)); + } + + /** + * Get room members. + * + * @param roomId Room identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return room members as paginated response with {@link PagedIterable}. + */ + @Generated + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoomMembers(String roomId) { + // Generated convenience method for listRoomMembers + RequestOptions requestOptions = new RequestOptions(); + return serviceClient.listRoomMembers(roomId, requestOptions) + .mapPage(bodyItemValue -> bodyItemValue.toObject(ChatRoomMember.class)); + } + + /** + * Create or replace a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a room member. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRoomMember createOrReplaceRoomMember(String roomId, String userId, ChatRoomMember resource, + MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceRoomMemberWithResponse(roomId, userId, BinaryData.fromObject(resource), requestOptions) + .getValue() + .toObject(ChatRoomMember.class); + } + + /** + * Create or replace a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a room member. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatRoomMember createOrReplaceRoomMember(String roomId, String userId, ChatRoomMember resource) { + // Generated convenience method for createOrReplaceRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceRoomMemberWithResponse(roomId, userId, BinaryData.fromObject(resource), requestOptions) + .getValue() + .toObject(ChatRoomMember.class); + } + + /** + * Delete a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRoomMember(String roomId, String userId, MatchConditions matchConditions) { + // Generated convenience method for deleteRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + deleteRoomMemberWithResponse(roomId, userId, requestOptions).getValue(); + } + + /** + * Delete a room member. + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteRoomMember(String roomId, String userId) { + // Generated convenience method for deleteRoomMemberWithResponse + RequestOptions requestOptions = new RequestOptions(); + deleteRoomMemberWithResponse(roomId, userId, requestOptions).getValue(); + } + + /** + * Get a user's profile. + * + * Get a user's profile. The response is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the `kind` + * discriminator. + * + * @param userId User identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return a user's profile. + * + * Get a user's profile. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatUser getUser(String userId) { + // Generated convenience method for getUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + return getUserWithResponse(userId, requestOptions).getValue().toObject(ChatUser.class); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + * + * @param userId User identifier. + * @param resource The resource instance. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a user profile in the chat system. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatUser createOrReplaceUser(String userId, ChatUser resource, MatchConditions matchConditions) { + // Generated convenience method for createOrReplaceUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + return createOrReplaceUserWithResponse(userId, BinaryData.fromObject(resource), requestOptions).getValue() + .toObject(ChatUser.class); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + * + * @param userId User identifier. + * @param resource The resource instance. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + * @return represents a user profile in the chat system. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public ChatUser createOrReplaceUser(String userId, ChatUser resource) { + // Generated convenience method for createOrReplaceUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + return createOrReplaceUserWithResponse(userId, BinaryData.fromObject(resource), requestOptions).getValue() + .toObject(ChatUser.class); + } + + /** + * Delete a user. + * + * @param userId User identifier. + * @param matchConditions Specifies HTTP options for conditional requests. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteUser(String userId, MatchConditions matchConditions) { + // Generated convenience method for deleteUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + String ifMatch = matchConditions == null ? null : matchConditions.getIfMatch(); + String ifNoneMatch = matchConditions == null ? null : matchConditions.getIfNoneMatch(); + if (ifMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_MATCH, ifMatch); + } + if (ifNoneMatch != null) { + requestOptions.setHeader(HttpHeaderName.IF_NONE_MATCH, ifNoneMatch); + } + deleteUserWithResponse(userId, requestOptions).getValue(); + } + + /** + * Delete a user. + * + * @param userId User identifier. + * @throws IllegalArgumentException thrown if parameters fail the validation. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent. + */ + @Generated + @ServiceMethod(returns = ReturnType.SINGLE) + public void deleteUser(String userId) { + // Generated convenience method for deleteUserWithResponse + RequestOptions requestOptions = new RequestOptions(); + deleteUserWithResponse(userId, requestOptions).getValue(); + } + + private final AzureKeyCredential keyCredential; + + /** + * Creates a client access token for connecting to Azure Web PubSub Chat. + * + * @param options Options for creating the client access token. + * @return The client access token. + */ + public WebPubSubClientAccessToken getClientAccessToken(GetClientAccessTokenOptions options) { + return WebPubSubClientAccessTokenFactory.create(serviceClient, keyCredential, options); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilder.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilder.java new file mode 100644 index 000000000000..08375acb3bfb --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilder.java @@ -0,0 +1,448 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.ServiceClientBuilder; +import com.azure.core.client.traits.AzureKeyCredentialTrait; +import com.azure.core.client.traits.ConfigurationTrait; +import com.azure.core.client.traits.ConnectionStringTrait; +import com.azure.core.client.traits.EndpointTrait; +import com.azure.core.client.traits.HttpTrait; +import com.azure.core.client.traits.TokenCredentialTrait; +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.HttpClient; +import com.azure.core.http.HttpHeaders; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.HttpPipelinePosition; +import com.azure.core.http.policy.AddDatePolicy; +import com.azure.core.http.policy.AddHeadersFromContextPolicy; +import com.azure.core.http.policy.AddHeadersPolicy; +import com.azure.core.http.policy.BearerTokenAuthenticationPolicy; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.http.policy.HttpLoggingPolicy; +import com.azure.core.http.policy.HttpPipelinePolicy; +import com.azure.core.http.policy.HttpPolicyProviders; +import com.azure.core.http.policy.RequestIdPolicy; +import com.azure.core.http.policy.RetryOptions; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.util.ClientOptions; +import com.azure.core.util.Configuration; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.UrlBuilder; +import com.azure.core.util.builder.ClientBuilderUtil; +import com.azure.core.util.logging.ClientLogger; +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.messaging.webpubsub.chat.implementation.WebPubSubChatServiceClientImpl; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * A builder for creating a new instance of the WebPubSubChatServiceClient type. + */ +@ServiceClientBuilder(serviceClients = { WebPubSubChatServiceClient.class, WebPubSubChatServiceAsyncClient.class }) +public final class WebPubSubChatServiceClientBuilder implements HttpTrait, + ConfigurationTrait, TokenCredentialTrait, + EndpointTrait, AzureKeyCredentialTrait, + ConnectionStringTrait { + + @Generated + private static final String SDK_NAME = "name"; + + @Generated + private static final String SDK_VERSION = "version"; + + @Generated + private static final String[] DEFAULT_SCOPES = new String[] { "https://webpubsub.azure.com/.default" }; + + @Generated + private static final Map PROPERTIES + = CoreUtils.getProperties("azure-messaging-webpubsub-chat.properties"); + + @Generated + private final List pipelinePolicies; + + /** + * Create an instance of the WebPubSubChatServiceClientBuilder. + */ + @Generated + public WebPubSubChatServiceClientBuilder() { + this.pipelinePolicies = new ArrayList<>(); + } + + /* + * The HTTP client used to send the request. + */ + @Generated + private HttpClient httpClient; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder httpClient(HttpClient httpClient) { + this.httpClient = httpClient; + return this; + } + + /* + * The HTTP pipeline to send requests through. + */ + @Generated + private HttpPipeline pipeline; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder pipeline(HttpPipeline pipeline) { + if (this.pipeline != null && pipeline == null) { + LOGGER.atInfo().log("HttpPipeline is being set to 'null' when it was previously configured."); + } + this.pipeline = pipeline; + return this; + } + + /* + * The logging configuration for HTTP requests and responses. + */ + @Generated + private HttpLogOptions httpLogOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder httpLogOptions(HttpLogOptions httpLogOptions) { + this.httpLogOptions = httpLogOptions; + return this; + } + + /* + * The client options such as application ID and custom headers to set on a request. + */ + @Generated + private ClientOptions clientOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder clientOptions(ClientOptions clientOptions) { + this.clientOptions = clientOptions; + return this; + } + + /* + * The retry options to configure retry policy for failed requests. + */ + @Generated + private RetryOptions retryOptions; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder retryOptions(RetryOptions retryOptions) { + this.retryOptions = retryOptions; + return this; + } + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder addPolicy(HttpPipelinePolicy customPolicy) { + Objects.requireNonNull(customPolicy, "'customPolicy' cannot be null."); + pipelinePolicies.add(customPolicy); + return this; + } + + /* + * The configuration store that is used during construction of the service client. + */ + @Generated + private Configuration configuration; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder configuration(Configuration configuration) { + this.configuration = configuration; + return this; + } + + /* + * The TokenCredential used for authentication. + */ + @Generated + private TokenCredential tokenCredential; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder credential(TokenCredential tokenCredential) { + this.tokenCredential = tokenCredential; + return this; + } + + /* + * The service endpoint + */ + @Generated + private String endpoint; + + /** + * {@inheritDoc}. + */ + @Generated + @Override + public WebPubSubChatServiceClientBuilder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + /* + * Target hub name, which should start with alphabetic characters and only contain alpha-numeric characters or + * underscore. + */ + @Generated + private String hub; + + /** + * Sets Target hub name, which should start with alphabetic characters and only contain alpha-numeric characters or + * underscore. + * + * @param hub the hub value. + * @return the WebPubSubChatServiceClientBuilder. + */ + @Generated + public WebPubSubChatServiceClientBuilder hub(String hub) { + this.hub = hub; + return this; + } + + /* + * Service version + */ + @Generated + private WebPubSubChatServiceVersion serviceVersion; + + /** + * Sets Service version. + * + * @param serviceVersion the serviceVersion value. + * @return the WebPubSubChatServiceClientBuilder. + */ + @Generated + public WebPubSubChatServiceClientBuilder serviceVersion(WebPubSubChatServiceVersion serviceVersion) { + this.serviceVersion = serviceVersion; + return this; + } + + /* + * The retry policy that will attempt to retry failed requests, if applicable. + */ + @Generated + private RetryPolicy retryPolicy; + + /** + * Sets The retry policy that will attempt to retry failed requests, if applicable. + * + * @param retryPolicy the retryPolicy value. + * @return the WebPubSubChatServiceClientBuilder. + */ + @Generated + public WebPubSubChatServiceClientBuilder retryPolicy(RetryPolicy retryPolicy) { + this.retryPolicy = retryPolicy; + return this; + } + + /** + * Builds an instance of WebPubSubChatServiceClientImpl with the provided parameters. + * + * @return an instance of WebPubSubChatServiceClientImpl. + */ + @Generated + private WebPubSubChatServiceClientImpl buildInnerClient() { + this.validateClient(); + HttpPipeline localPipeline = (pipeline != null) ? pipeline : createHttpPipeline(); + WebPubSubChatServiceVersion localServiceVersion + = (serviceVersion != null) ? serviceVersion : WebPubSubChatServiceVersion.getLatest(); + WebPubSubChatServiceClientImpl client = new WebPubSubChatServiceClientImpl(localPipeline, + JacksonAdapter.createDefaultSerializerAdapter(), this.endpoint, this.hub, localServiceVersion); + return client; + } + + @Generated + private void validateClient() { + Objects.requireNonNull(endpoint, "'endpoint' cannot be null."); + if (hub == null || hub.isEmpty()) { + throw LOGGER.logExceptionAsError( + new IllegalStateException("hub is not valid - it must be non-null and non-empty.")); + } + } + + @Generated + private HttpPipeline createHttpPipeline() { + Configuration buildConfiguration + = (configuration == null) ? Configuration.getGlobalConfiguration() : configuration; + HttpLogOptions localHttpLogOptions = this.httpLogOptions == null ? new HttpLogOptions() : this.httpLogOptions; + ClientOptions localClientOptions = this.clientOptions == null ? new ClientOptions() : this.clientOptions; + List policies = new ArrayList<>(); + String clientName = PROPERTIES.getOrDefault(SDK_NAME, "UnknownName"); + String clientVersion = PROPERTIES.getOrDefault(SDK_VERSION, "UnknownVersion"); + String applicationId = CoreUtils.getApplicationId(localClientOptions, localHttpLogOptions); + policies.add(new UserAgentPolicy(applicationId, clientName, clientVersion, buildConfiguration)); + policies.add(new RequestIdPolicy()); + policies.add(new AddHeadersFromContextPolicy()); + HttpHeaders headers = CoreUtils.createHttpHeadersFromClientOptions(localClientOptions); + if (headers != null) { + policies.add(new AddHeadersPolicy(headers)); + } + this.pipelinePolicies.stream() + .filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_CALL) + .forEach(policies::add); + HttpPolicyProviders.addBeforeRetryPolicies(policies); + policies.add(ClientBuilderUtil.validateAndGetRetryPolicy(retryPolicy, retryOptions, new RetryPolicy())); + policies.add(new AddDatePolicy()); + if (keyCredential != null) { + policies.add(new WebPubSubAuthenticationPolicy(keyCredential)); + } else if (tokenCredential != null) { + policies.add(new BearerTokenAuthenticationPolicy(tokenCredential, DEFAULT_SCOPES)); + } else { + throw LOGGER + .logExceptionAsError(new IllegalStateException("No credential available to create the client.")); + } + if (!CoreUtils.isNullOrEmpty(reverseProxyEndpoint)) { + policies.add(new ReverseProxyPolicy(reverseProxyEndpoint)); + } + this.pipelinePolicies.stream() + .filter(p -> p.getPipelinePosition() == HttpPipelinePosition.PER_RETRY) + .forEach(policies::add); + HttpPolicyProviders.addAfterRetryPolicies(policies); + policies.add(new HttpLoggingPolicy(localHttpLogOptions)); + return new HttpPipelineBuilder().policies(policies.toArray(new HttpPipelinePolicy[0])) + .httpClient(httpClient) + .clientOptions(localClientOptions) + .build(); + } + + /** + * Builds an instance of WebPubSubChatServiceAsyncClient class. + * + * @return an instance of WebPubSubChatServiceAsyncClient. + */ + @Generated + public WebPubSubChatServiceAsyncClient buildAsyncClient() { + return new WebPubSubChatServiceAsyncClient(buildInnerClient(), keyCredential); + } + + /** + * Builds an instance of WebPubSubChatServiceClient class. + * + * @return an instance of WebPubSubChatServiceClient. + */ + @Generated + public WebPubSubChatServiceClient buildClient() { + return new WebPubSubChatServiceClient(buildInnerClient(), keyCredential); + } + + private static final ClientLogger LOGGER = new ClientLogger(WebPubSubChatServiceClientBuilder.class); + + private AzureKeyCredential keyCredential; + + private String reverseProxyEndpoint; + + /** + * Sets the Azure key credential used to authenticate requests. + * + * @param credential The Azure key credential. + * @return The updated builder. + */ + @Override + public WebPubSubChatServiceClientBuilder credential(AzureKeyCredential credential) { + this.keyCredential = Objects.requireNonNull(credential, "'credential' cannot be null."); + return this; + } + + /** + * Sets the Web PubSub connection string used to configure the endpoint and access key. + * + * @param connectionString The Web PubSub connection string. + * @return The updated builder. + */ + @Override + public WebPubSubChatServiceClientBuilder connectionString(String connectionString) { + Objects.requireNonNull(connectionString, "'connectionString' cannot be null."); + Map connectionStringParams = parseConnectionString(connectionString); + if (!connectionStringParams.containsKey("endpoint") || !connectionStringParams.containsKey("accesskey")) { + throw LOGGER.logExceptionAsError(new IllegalArgumentException( + "Connection string does not contain required 'endpoint' and 'accesskey' values")); + } + this.keyCredential = new AzureKeyCredential(connectionStringParams.get("accesskey")); + String connectionStringEndpoint = connectionStringParams.get("endpoint"); + URL url; + try { + url = new URL(connectionStringEndpoint); + this.endpoint = connectionStringEndpoint; + } catch (MalformedURLException exception) { + throw LOGGER.logExceptionAsWarning( + new IllegalArgumentException("Connection string contains invalid endpoint", exception)); + } + String port = connectionStringParams.get("port"); + if (!CoreUtils.isNullOrEmpty(port)) { + this.endpoint = UrlBuilder.parse(url).setPort(port).toString(); + } + return this; + } + + /** + * Sets the reverse proxy endpoint. + * + * @param reverseProxyEndpoint The reverse proxy endpoint. + * @return The updated builder. + */ + public WebPubSubChatServiceClientBuilder reverseProxyEndpoint(String reverseProxyEndpoint) { + this.reverseProxyEndpoint = reverseProxyEndpoint; + return this; + } + + private Map parseConnectionString(String connectionString) { + String[] parameters = connectionString.split(";"); + Map connectionStringParams = new HashMap<>(); + for (String parameter : parameters) { + String[] parameterParts = parameter.split("=", 2); + if (parameterParts.length != 2) { + continue; + } + String key = parameterParts[0].trim().toLowerCase(Locale.ROOT); + if (connectionStringParams.containsKey(key)) { + throw LOGGER.logExceptionAsError(new IllegalArgumentException( + "Duplicate connection string key parameter provided for key '" + key + "'")); + } + connectionStringParams.put(key, parameterParts[1].trim()); + } + return connectionStringParams; + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceVersion.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceVersion.java new file mode 100644 index 000000000000..e91eac676d04 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceVersion.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.util.ServiceVersion; + +/** + * Service version of WebPubSubChatClient. + */ +public enum WebPubSubChatServiceVersion implements ServiceVersion { + /** + * Enum value 2026-02-01-preview. + */ + V2026_02_01_PREVIEW("2026-02-01-preview"); + + private final String version; + + WebPubSubChatServiceVersion(String version) { + this.version = version; + } + + /** + * {@inheritDoc} + */ + @Override + public String getVersion() { + return this.version; + } + + /** + * Gets the latest service version supported by this client library. + * + * @return The latest {@link WebPubSubChatServiceVersion}. + */ + public static WebPubSubChatServiceVersion getLatest() { + return V2026_02_01_PREVIEW; + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubClientAccessTokenFactory.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubClientAccessTokenFactory.java new file mode 100644 index 000000000000..9a73bff61309 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubClientAccessTokenFactory.java @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.rest.RequestOptions; +import com.azure.messaging.webpubsub.chat.implementation.WebPubSubChatServiceClientImpl; +import com.azure.messaging.webpubsub.chat.implementation.models.GenerateClientTokenResponse; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +final class WebPubSubClientAccessTokenFactory { + private static final List CHAT_ROLES = Arrays.asList("webpubsub.getGroupState", "webpubsub.setGroupState"); + + static WebPubSubClientAccessToken create(WebPubSubChatServiceClientImpl serviceClient, + AzureKeyCredential keyCredential, GetClientAccessTokenOptions options) { + Objects.requireNonNull(options, "'options' cannot be null."); + Duration expiresAfter = validateExpiresAfter(options.getExpiresAfter()); + String token; + if (keyCredential == null) { + token = serviceClient + .generateClientTokenWithResponse(serviceClient.getHub(), createRequestOptions(options, expiresAfter)) + .getValue() + .toObject(GenerateClientTokenResponse.class) + .getToken(); + } else { + token = WebPubSubTokenGenerator.generateToken(createAudience(serviceClient), options.getUserId(), + CHAT_ROLES, expiresAfter, keyCredential); + } + return createResult(token, serviceClient); + } + + static Mono createAsync(WebPubSubChatServiceClientImpl serviceClient, + AzureKeyCredential keyCredential, GetClientAccessTokenOptions options) { + Objects.requireNonNull(options, "'options' cannot be null."); + Duration expiresAfter = validateExpiresAfter(options.getExpiresAfter()); + if (keyCredential == null) { + return serviceClient + .generateClientTokenWithResponseAsync(serviceClient.getHub(), + createRequestOptions(options, expiresAfter)) + .map(response -> response.getValue().toObject(GenerateClientTokenResponse.class).getToken()) + .map(token -> createResult(token, serviceClient)); + } + return Mono.fromCallable(() -> create(serviceClient, keyCredential, options)); + } + + private static RequestOptions createRequestOptions(GetClientAccessTokenOptions options, Duration expiresAfter) { + RequestOptions requestOptions = new RequestOptions(); + if (options.getUserId() != null) { + requestOptions.addQueryParam("userId", options.getUserId()); + } + requestOptions.addQueryParam("minutesToExpire", String.valueOf(expiresAfter.toMinutes())); + CHAT_ROLES.forEach(role -> requestOptions.addQueryParam("role", role)); + return requestOptions; + } + + private static Duration validateExpiresAfter(Duration expiresAfter) { + Objects.requireNonNull(expiresAfter, "'expiresAfter' cannot be null."); + long minutes = expiresAfter.toMinutes(); + if (minutes < 1 || minutes > Integer.MAX_VALUE) { + throw new IllegalArgumentException( + "'expiresAfter' must be between 1 minute and " + Integer.MAX_VALUE + " minutes."); + } + return expiresAfter; + } + + private static String createAudience(WebPubSubChatServiceClientImpl serviceClient) { + String endpoint = serviceClient.getEndpoint(); + return endpoint + (endpoint.endsWith("/") ? "" : "/") + "client/hubs/" + serviceClient.getHub(); + } + + private static WebPubSubClientAccessToken createResult(String token, WebPubSubChatServiceClientImpl serviceClient) { + String clientUrl = createAudience(serviceClient).replaceFirst("http", "ws"); + return new WebPubSubClientAccessToken(token, clientUrl + "?access_token=" + token); + } + + private WebPubSubClientAccessTokenFactory() { + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubTokenGenerator.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubTokenGenerator.java new file mode 100644 index 000000000000..fd0327dcb5f0 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubTokenGenerator.java @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.util.CoreUtils; +import com.azure.core.util.logging.ClientLogger; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.crypto.MACSigner; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.ZoneId; +import java.util.Date; +import java.util.List; + +import static java.time.LocalDateTime.now; + +final class WebPubSubTokenGenerator { + private static final ClientLogger LOGGER = new ClientLogger(WebPubSubTokenGenerator.class); + + static String generateToken(String audience, String userId, List roles, Duration expiresAfter, + AzureKeyCredential credential) { + try { + JWTClaimsSet.Builder claimsBuilder = new JWTClaimsSet.Builder().audience(audience) + .expirationTime(Date.from(now().plus(expiresAfter).atZone(ZoneId.systemDefault()).toInstant())); + if (!CoreUtils.isNullOrEmpty(userId)) { + claimsBuilder.subject(userId); + } + if (!CoreUtils.isNullOrEmpty(roles)) { + claimsBuilder.claim("role", roles); + } + + JWSSigner signer = new MACSigner(credential.getKey().getBytes(StandardCharsets.UTF_8)); + SignedJWT signedJwt = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsBuilder.build()); + signedJwt.sign(signer); + return signedJwt.serialize(); + } catch (JOSEException exception) { + LOGGER.logThrowableAsError(exception); + return null; + } + } + + private WebPubSubTokenGenerator() { + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/JsonMergePatchHelper.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/JsonMergePatchHelper.java new file mode 100644 index 000000000000..011cf2116990 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/JsonMergePatchHelper.java @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.implementation; + +import com.azure.messaging.webpubsub.chat.models.ChatMessage; +import com.azure.messaging.webpubsub.chat.models.MessageContent; + +/** + * This is the Helper class to enable json merge patch serialization for a model. + */ +public class JsonMergePatchHelper { + private static ChatMessageAccessor chatMessageAccessor; + + public interface ChatMessageAccessor { + ChatMessage prepareModelForJsonMergePatch(ChatMessage chatMessage, boolean jsonMergePatchEnabled); + + boolean isJsonMergePatch(ChatMessage chatMessage); + } + + public static void setChatMessageAccessor(ChatMessageAccessor accessor) { + chatMessageAccessor = accessor; + } + + public static ChatMessageAccessor getChatMessageAccessor() { + return chatMessageAccessor; + } + + private static MessageContentAccessor messageContentAccessor; + + public interface MessageContentAccessor { + MessageContent prepareModelForJsonMergePatch(MessageContent messageContent, boolean jsonMergePatchEnabled); + + boolean isJsonMergePatch(MessageContent messageContent); + } + + public static void setMessageContentAccessor(MessageContentAccessor accessor) { + messageContentAccessor = accessor; + } + + public static MessageContentAccessor getMessageContentAccessor() { + return messageContentAccessor; + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/WebPubSubChatServiceClientImpl.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/WebPubSubChatServiceClientImpl.java new file mode 100644 index 000000000000..022b743906ab --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/WebPubSubChatServiceClientImpl.java @@ -0,0 +1,2796 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.implementation; + +import com.azure.core.annotation.BodyParam; +import com.azure.core.annotation.Delete; +import com.azure.core.annotation.ExpectedResponses; +import com.azure.core.annotation.Get; +import com.azure.core.annotation.HeaderParam; +import com.azure.core.annotation.Host; +import com.azure.core.annotation.HostParam; +import com.azure.core.annotation.Patch; +import com.azure.core.annotation.PathParam; +import com.azure.core.annotation.Post; +import com.azure.core.annotation.Put; +import com.azure.core.annotation.QueryParam; +import com.azure.core.annotation.ReturnType; +import com.azure.core.annotation.ServiceInterface; +import com.azure.core.annotation.ServiceMethod; +import com.azure.core.annotation.UnexpectedResponseExceptionType; +import com.azure.core.exception.ClientAuthenticationException; +import com.azure.core.exception.HttpResponseException; +import com.azure.core.exception.ResourceModifiedException; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.HttpPipeline; +import com.azure.core.http.HttpPipelineBuilder; +import com.azure.core.http.policy.RetryPolicy; +import com.azure.core.http.policy.UserAgentPolicy; +import com.azure.core.http.rest.PagedFlux; +import com.azure.core.http.rest.PagedIterable; +import com.azure.core.http.rest.PagedResponse; +import com.azure.core.http.rest.PagedResponseBase; +import com.azure.core.http.rest.RequestOptions; +import com.azure.core.http.rest.Response; +import com.azure.core.http.rest.RestProxy; +import com.azure.core.util.BinaryData; +import com.azure.core.util.Context; +import com.azure.core.util.FluxUtil; +import com.azure.core.util.UrlBuilder; +import com.azure.core.util.serializer.JacksonAdapter; +import com.azure.core.util.serializer.SerializerAdapter; +import com.azure.messaging.webpubsub.chat.WebPubSubChatServiceVersion; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import reactor.core.publisher.Mono; + +/** + * Initializes a new instance of the WebPubSubChatServiceClient type. + */ +public final class WebPubSubChatServiceClientImpl { + /** + * The proxy service used to perform REST calls. + */ + private final WebPubSubChatServiceClientService service; + + /** + * HTTP or HTTPS endpoint for the Web PubSub service instance. + */ + private final String endpoint; + + /** + * Gets HTTP or HTTPS endpoint for the Web PubSub service instance. + * + * @return the endpoint value. + */ + public String getEndpoint() { + return this.endpoint; + } + + /** + * Target hub name, which should start with alphabetic characters and only contain alpha-numeric characters or + * underscore. + */ + private final String hub; + + /** + * Gets Target hub name, which should start with alphabetic characters and only contain alpha-numeric characters or + * underscore. + * + * @return the hub value. + */ + public String getHub() { + return this.hub; + } + + /** + * Service version. + */ + private final WebPubSubChatServiceVersion serviceVersion; + + /** + * Gets Service version. + * + * @return the serviceVersion value. + */ + public WebPubSubChatServiceVersion getServiceVersion() { + return this.serviceVersion; + } + + /** + * The HTTP pipeline to send requests through. + */ + private final HttpPipeline httpPipeline; + + /** + * Gets The HTTP pipeline to send requests through. + * + * @return the httpPipeline value. + */ + public HttpPipeline getHttpPipeline() { + return this.httpPipeline; + } + + /** + * The serializer to serialize an object into a string. + */ + private final SerializerAdapter serializerAdapter; + + /** + * Gets The serializer to serialize an object into a string. + * + * @return the serializerAdapter value. + */ + public SerializerAdapter getSerializerAdapter() { + return this.serializerAdapter; + } + + /** + * Initializes an instance of WebPubSubChatServiceClient client. + * + * @param endpoint HTTP or HTTPS endpoint for the Web PubSub service instance. + * @param hub Target hub name, which should start with alphabetic characters and only contain alpha-numeric + * characters or underscore. + * @param serviceVersion Service version. + */ + public WebPubSubChatServiceClientImpl(String endpoint, String hub, WebPubSubChatServiceVersion serviceVersion) { + this(new HttpPipelineBuilder().policies(new UserAgentPolicy(), new RetryPolicy()).build(), + JacksonAdapter.createDefaultSerializerAdapter(), endpoint, hub, serviceVersion); + } + + /** + * Initializes an instance of WebPubSubChatServiceClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param endpoint HTTP or HTTPS endpoint for the Web PubSub service instance. + * @param hub Target hub name, which should start with alphabetic characters and only contain alpha-numeric + * characters or underscore. + * @param serviceVersion Service version. + */ + public WebPubSubChatServiceClientImpl(HttpPipeline httpPipeline, String endpoint, String hub, + WebPubSubChatServiceVersion serviceVersion) { + this(httpPipeline, JacksonAdapter.createDefaultSerializerAdapter(), endpoint, hub, serviceVersion); + } + + /** + * Initializes an instance of WebPubSubChatServiceClient client. + * + * @param httpPipeline The HTTP pipeline to send requests through. + * @param serializerAdapter The serializer to serialize an object into a string. + * @param endpoint HTTP or HTTPS endpoint for the Web PubSub service instance. + * @param hub Target hub name, which should start with alphabetic characters and only contain alpha-numeric + * characters or underscore. + * @param serviceVersion Service version. + */ + public WebPubSubChatServiceClientImpl(HttpPipeline httpPipeline, SerializerAdapter serializerAdapter, + String endpoint, String hub, WebPubSubChatServiceVersion serviceVersion) { + this.httpPipeline = httpPipeline; + this.serializerAdapter = serializerAdapter; + this.endpoint = endpoint; + this.hub = hub; + this.serviceVersion = serviceVersion; + this.service + = RestProxy.create(WebPubSubChatServiceClientService.class, this.httpPipeline, this.getSerializerAdapter()); + } + + /** + * The interface defining all the services for WebPubSubChatServiceClient to be used by the proxy service to perform + * REST calls. + */ + @Host("{endpoint}") + @ServiceInterface(name = "WebPubSubChatServiceClient") + public interface WebPubSubChatServiceClientService { + @Get("/api/hubs/{hub}/chat/conversations/{conversationId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getConversation(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @HeaderParam("Accept") String accept, + RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/conversations/{conversationId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response getConversationSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @HeaderParam("Accept") String accept, + RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/conversations/{conversationId}/messages") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> listMessages(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @HeaderParam("Accept") String accept, + RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/conversations/{conversationId}/messages") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response listMessagesSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @HeaderParam("Accept") String accept, + RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/conversations/{conversationId}/messages/{messageId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteMessage(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @PathParam("messageId") String messageId, + RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/conversations/{conversationId}/messages/{messageId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response deleteMessageSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @PathParam("messageId") String messageId, + RequestOptions requestOptions, Context context); + + @Patch("/api/hubs/{hub}/chat/conversations/{conversationId}/messages/{messageId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> updateMessage(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @PathParam("messageId") String messageId, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/merge-patch+json") BinaryData resource, RequestOptions requestOptions, + Context context); + + @Patch("/api/hubs/{hub}/chat/conversations/{conversationId}/messages/{messageId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response updateMessageSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("conversationId") String conversationId, @PathParam("messageId") String messageId, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/merge-patch+json") BinaryData resource, RequestOptions requestOptions, + Context context); + + @Get("/api/hubs/{hub}/chat/roles") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> listRoles(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @HeaderParam("Accept") String accept, RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/roles") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response listRolesSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @HeaderParam("Accept") String accept, RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/roles/{roleName}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getRole(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roleName") String roleName, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("/api/hubs/{hub}/chat/roles/{roleName}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response getRoleSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roleName") String roleName, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Put("/api/hubs/{hub}/chat/roles/{roleName}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> createOrReplaceRole(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roleName") String roleName, @HeaderParam("Content-Type") String contentType, + @HeaderParam("Accept") String accept, @BodyParam("application/json") BinaryData resource, + RequestOptions requestOptions, Context context); + + @Put("/api/hubs/{hub}/chat/roles/{roleName}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response createOrReplaceRoleSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roleName") String roleName, @HeaderParam("Content-Type") String contentType, + @HeaderParam("Accept") String accept, @BodyParam("application/json") BinaryData resource, + RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/roles/{roleName}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteRole(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roleName") String roleName, RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/roles/{roleName}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response deleteRoleSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roleName") String roleName, RequestOptions requestOptions, Context context); + + @Put("/api/hubs/{hub}/chat/rooms/{roomId}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> createOrReplaceRoom(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @HeaderParam("Content-Type") String contentType, + @HeaderParam("Accept") String accept, @BodyParam("application/json") BinaryData resource, + RequestOptions requestOptions, Context context); + + @Put("/api/hubs/{hub}/chat/rooms/{roomId}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response createOrReplaceRoomSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @HeaderParam("Content-Type") String contentType, + @HeaderParam("Accept") String accept, @BodyParam("application/json") BinaryData resource, + RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/rooms/{roomId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getRoom(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("/api/hubs/{hub}/chat/rooms/{roomId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response getRoomSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Delete("/api/hubs/{hub}/chat/rooms/{roomId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteRoom(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/rooms/{roomId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response deleteRoomSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, RequestOptions requestOptions, Context context); + + @Get("/api/hubs/{hub}/chat/rooms/{roomId}/members") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> listRoomMembers(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("/api/hubs/{hub}/chat/rooms/{roomId}/members") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response listRoomMembersSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Put("/api/hubs/{hub}/chat/rooms/{roomId}/members/{userId}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> createOrReplaceRoomMember(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @PathParam("userId") String userId, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData resource, RequestOptions requestOptions, Context context); + + @Put("/api/hubs/{hub}/chat/rooms/{roomId}/members/{userId}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response createOrReplaceRoomMemberSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @PathParam("userId") String userId, + @HeaderParam("Content-Type") String contentType, @HeaderParam("Accept") String accept, + @BodyParam("application/json") BinaryData resource, RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/rooms/{roomId}/members/{userId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteRoomMember(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @PathParam("userId") String userId, RequestOptions requestOptions, + Context context); + + @Delete("/api/hubs/{hub}/chat/rooms/{roomId}/members/{userId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response deleteRoomMemberSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("roomId") String roomId, @PathParam("userId") String userId, RequestOptions requestOptions, + Context context); + + @Get("/api/hubs/{hub}/chat/users/{userId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> getUser(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("userId") String userId, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("/api/hubs/{hub}/chat/users/{userId}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response getUserSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("userId") String userId, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Put("/api/hubs/{hub}/chat/users/{userId}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> createOrReplaceUser(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("userId") String userId, @HeaderParam("Content-Type") String contentType, + @HeaderParam("Accept") String accept, @BodyParam("application/json") BinaryData resource, + RequestOptions requestOptions, Context context); + + @Put("/api/hubs/{hub}/chat/users/{userId}") + @ExpectedResponses({ 200, 201 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response createOrReplaceUserSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("userId") String userId, @HeaderParam("Content-Type") String contentType, + @HeaderParam("Accept") String accept, @BodyParam("application/json") BinaryData resource, + RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/users/{userId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> deleteUser(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("userId") String userId, RequestOptions requestOptions, Context context); + + @Delete("/api/hubs/{hub}/chat/users/{userId}") + @ExpectedResponses({ 204 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response deleteUserSync(@HostParam("endpoint") String endpoint, + @QueryParam("api-version") String apiVersion, @PathParam("hub") String hub, + @PathParam("userId") String userId, RequestOptions requestOptions, Context context); + + @Post("/api/hubs/{hub}/:generateToken") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> generateClientToken(@HostParam("endpoint") String endpoint, + @PathParam("hub") String hub, @QueryParam("api-version") String apiVersion, + @QueryParam("clientType") String clientType, @HeaderParam("Accept") String accept, + RequestOptions requestOptions, Context context); + + @Post("/api/hubs/{hub}/:generateToken") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response generateClientTokenSync(@HostParam("endpoint") String endpoint, + @PathParam("hub") String hub, @QueryParam("api-version") String apiVersion, + @QueryParam("clientType") String clientType, @HeaderParam("Accept") String accept, + RequestOptions requestOptions, Context context); + + @Get("{nextLink}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> listMessagesNext(@PathParam(value = "nextLink", encoded = true) String nextLink, + @HostParam("endpoint") String endpoint, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("{nextLink}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response listMessagesNextSync(@PathParam(value = "nextLink", encoded = true) String nextLink, + @HostParam("endpoint") String endpoint, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("{nextLink}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> listRolesNext(@PathParam(value = "nextLink", encoded = true) String nextLink, + @HostParam("endpoint") String endpoint, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("{nextLink}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response listRolesNextSync(@PathParam(value = "nextLink", encoded = true) String nextLink, + @HostParam("endpoint") String endpoint, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("{nextLink}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Mono> listRoomMembersNext(@PathParam(value = "nextLink", encoded = true) String nextLink, + @HostParam("endpoint") String endpoint, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + + @Get("{nextLink}") + @ExpectedResponses({ 200 }) + @UnexpectedResponseExceptionType(value = ClientAuthenticationException.class, code = { 401 }) + @UnexpectedResponseExceptionType(value = ResourceNotFoundException.class, code = { 404 }) + @UnexpectedResponseExceptionType(value = ResourceModifiedException.class, code = { 409 }) + @UnexpectedResponseExceptionType(HttpResponseException.class) + Response listRoomMembersNextSync(@PathParam(value = "nextLink", encoded = true) String nextLink, + @HostParam("endpoint") String endpoint, @HeaderParam("Accept") String accept, RequestOptions requestOptions, + Context context); + } + + /** + * Get conversation information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     parentRoom: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return conversation information along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getConversationWithResponseAsync(String conversationId, + RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.getConversation(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), conversationId, accept, requestOptions, context)); + } + + /** + * Get conversation information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     parentRoom: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return conversation information along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getConversationWithResponse(String conversationId, RequestOptions requestOptions) { + final String accept = "application/json"; + return service.getConversationSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + conversationId, accept, requestOptions, Context.NONE); + } + + /** + * Query messages in a conversation from latest to earliest. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
latestMessageIdStringNoLatest message ID (exclusive) for pagination.
earliestMessageIdStringNoEarliest message ID (exclusive) for + * pagination.
maxpagesizeIntegerNoThe maximum number of result items per page.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items along with {@link PagedResponse} on successful completion of + * {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> listMessagesSinglePageAsync(String conversationId, + RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil + .withContext(context -> service.listMessages(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), conversationId, accept, requestOptions, context)) + .map(res -> new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null)); + } + + /** + * Query messages in a conversation from latest to earliest. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
latestMessageIdStringNoLatest message ID (exclusive) for pagination.
earliestMessageIdStringNoEarliest message ID (exclusive) for + * pagination.
maxpagesizeIntegerNoThe maximum number of result items per page.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items as paginated response with {@link PagedFlux}. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listMessagesAsync(String conversationId, RequestOptions requestOptions) { + RequestOptions requestOptionsForNextPage = new RequestOptions(); + requestOptionsForNextPage.setContext( + requestOptions != null && requestOptions.getContext() != null ? requestOptions.getContext() : Context.NONE); + return new PagedFlux<>((pageSize) -> { + RequestOptions requestOptionsLocal = requestOptions == null ? new RequestOptions() : requestOptions; + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listMessagesSinglePageAsync(conversationId, requestOptionsLocal); + }, (nextLink, pageSize) -> { + RequestOptions requestOptionsLocal = new RequestOptions(); + requestOptionsLocal.setContext(requestOptionsForNextPage.getContext()); + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listMessagesNextSinglePageAsync(nextLink, requestOptionsLocal); + }); + } + + /** + * Query messages in a conversation from latest to earliest. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
latestMessageIdStringNoLatest message ID (exclusive) for pagination.
earliestMessageIdStringNoEarliest message ID (exclusive) for + * pagination.
maxpagesizeIntegerNoThe maximum number of result items per page.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items along with {@link PagedResponse}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private PagedResponse listMessagesSinglePage(String conversationId, RequestOptions requestOptions) { + final String accept = "application/json"; + Response res = service.listMessagesSync(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), conversationId, accept, requestOptions, Context.NONE); + return new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null); + } + + /** + * Query messages in a conversation from latest to earliest. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
latestMessageIdStringNoLatest message ID (exclusive) for pagination.
earliestMessageIdStringNoEarliest message ID (exclusive) for + * pagination.
maxpagesizeIntegerNoThe maximum number of result items per page.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param conversationId Conversation identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items as paginated response with {@link PagedIterable}. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listMessages(String conversationId, RequestOptions requestOptions) { + RequestOptions requestOptionsForNextPage = new RequestOptions(); + requestOptionsForNextPage.setContext( + requestOptions != null && requestOptions.getContext() != null ? requestOptions.getContext() : Context.NONE); + return new PagedIterable<>((pageSize) -> { + RequestOptions requestOptionsLocal = requestOptions == null ? new RequestOptions() : requestOptions; + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listMessagesSinglePage(conversationId, requestOptionsLocal); + }, (nextLink, pageSize) -> { + RequestOptions requestOptionsLocal = new RequestOptions(); + requestOptionsLocal.setContext(requestOptionsForNextPage.getContext()); + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listMessagesNextSinglePage(nextLink, requestOptionsLocal); + }); + } + + /** + * Delete a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteMessageWithResponseAsync(String conversationId, String messageId, + RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.deleteMessage(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), conversationId, messageId, requestOptions, context)); + } + + /** + * Delete a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteMessageWithResponse(String conversationId, String messageId, + RequestOptions requestOptions) { + return service.deleteMessageSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + conversationId, messageId, requestOptions, Context.NONE); + } + + /** + * Update a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat message along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> updateMessageWithResponseAsync(String conversationId, String messageId, + BinaryData resource, RequestOptions requestOptions) { + final String contentType = "application/merge-patch+json"; + final String accept = "application/json"; + return FluxUtil + .withContext(context -> service.updateMessage(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), conversationId, messageId, contentType, accept, resource, requestOptions, context)); + } + + /** + * Update a message. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param conversationId Conversation identifier. + * @param messageId Message identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat message along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response updateMessageWithResponse(String conversationId, String messageId, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/merge-patch+json"; + final String accept = "application/json"; + return service.updateMessageSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + conversationId, messageId, contentType, accept, resource, requestOptions, Context.NONE); + } + + /** + * Query roles in a hub. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items along with {@link PagedResponse} on successful completion of + * {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> listRolesSinglePageAsync(RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil + .withContext(context -> service.listRoles(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), accept, requestOptions, context)) + .map(res -> new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null)); + } + + /** + * Query roles in a hub. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items as paginated response with {@link PagedFlux}. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRolesAsync(RequestOptions requestOptions) { + RequestOptions requestOptionsForNextPage = new RequestOptions(); + requestOptionsForNextPage.setContext( + requestOptions != null && requestOptions.getContext() != null ? requestOptions.getContext() : Context.NONE); + return new PagedFlux<>((pageSize) -> { + RequestOptions requestOptionsLocal = requestOptions == null ? new RequestOptions() : requestOptions; + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRolesSinglePageAsync(requestOptionsLocal); + }, (nextLink, pageSize) -> { + RequestOptions requestOptionsLocal = new RequestOptions(); + requestOptionsLocal.setContext(requestOptionsForNextPage.getContext()); + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRolesNextSinglePageAsync(nextLink, requestOptionsLocal); + }); + } + + /** + * Query roles in a hub. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items along with {@link PagedResponse}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private PagedResponse listRolesSinglePage(RequestOptions requestOptions) { + final String accept = "application/json"; + Response res = service.listRolesSync(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), accept, requestOptions, Context.NONE); + return new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null); + } + + /** + * Query roles in a hub. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items as paginated response with {@link PagedIterable}. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoles(RequestOptions requestOptions) { + RequestOptions requestOptionsForNextPage = new RequestOptions(); + requestOptionsForNextPage.setContext( + requestOptions != null && requestOptions.getContext() != null ? requestOptions.getContext() : Context.NONE); + return new PagedIterable<>((pageSize) -> { + RequestOptions requestOptionsLocal = requestOptions == null ? new RequestOptions() : requestOptions; + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRolesSinglePage(requestOptionsLocal); + }, (nextLink, pageSize) -> { + RequestOptions requestOptionsLocal = new RequestOptions(); + requestOptionsLocal.setContext(requestOptionsForNextPage.getContext()); + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRolesNextSinglePage(nextLink, requestOptionsLocal); + }); + } + + /** + * Get role information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return role information along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRoleWithResponseAsync(String roleName, RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.getRole(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), roleName, accept, requestOptions, context)); + } + + /** + * Get role information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return role information along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getRoleWithResponse(String roleName, RequestOptions requestOptions) { + final String accept = "application/json"; + return service.getRoleSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), roleName, + accept, requestOptions, Context.NONE); + } + + /** + * Create or replace a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both along with {@link Response} on + * successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceRoleWithResponseAsync(String roleName, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext( + context -> service.createOrReplaceRole(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), roleName, contentType, accept, resource, requestOptions, context)); + } + + /** + * Create or replace a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceRoleWithResponse(String roleName, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.createOrReplaceRoleSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + roleName, contentType, accept, resource, requestOptions, Context.NONE); + } + + /** + * Delete a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRoleWithResponseAsync(String roleName, RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.deleteRole(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), roleName, requestOptions, context)); + } + + /** + * Delete a role. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roleName Role name. Must start with 'user.' or 'room.' prefix. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRoleWithResponse(String roleName, RequestOptions requestOptions) { + return service.deleteRoleSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + roleName, requestOptions, Context.NONE); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat room along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceRoomWithResponseAsync(String roomId, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext( + context -> service.createOrReplaceRoom(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), roomId, contentType, accept, resource, requestOptions, context)); + } + + /** + * Create or replace a room. + * + * Create or replace a room with a client-specified ID. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a chat room along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceRoomWithResponse(String roomId, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.createOrReplaceRoomSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + roomId, contentType, accept, resource, requestOptions, Context.NONE); + } + + /** + * Get room information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room information along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getRoomWithResponseAsync(String roomId, RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.getRoom(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), roomId, accept, requestOptions, context)); + } + + /** + * Get room information. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     title: String (Required)
+     *     defaultConversation: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room information along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getRoomWithResponse(String roomId, RequestOptions requestOptions) { + final String accept = "application/json"; + return service.getRoomSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), roomId, + accept, requestOptions, Context.NONE); + } + + /** + * Delete a room. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRoomWithResponseAsync(String roomId, RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.deleteRoom(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), roomId, requestOptions, context)); + } + + /** + * Delete a room. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRoomWithResponse(String roomId, RequestOptions requestOptions) { + return service.deleteRoomSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), roomId, + requestOptions, Context.NONE); + } + + /** + * Get room members. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members along with {@link PagedResponse} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> listRoomMembersSinglePageAsync(String roomId, + RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil + .withContext(context -> service.listRoomMembers(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), roomId, accept, requestOptions, context)) + .map(res -> new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null)); + } + + /** + * Get room members. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members as paginated response with {@link PagedFlux}. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedFlux listRoomMembersAsync(String roomId, RequestOptions requestOptions) { + RequestOptions requestOptionsForNextPage = new RequestOptions(); + requestOptionsForNextPage.setContext( + requestOptions != null && requestOptions.getContext() != null ? requestOptions.getContext() : Context.NONE); + return new PagedFlux<>((pageSize) -> { + RequestOptions requestOptionsLocal = requestOptions == null ? new RequestOptions() : requestOptions; + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRoomMembersSinglePageAsync(roomId, requestOptionsLocal); + }, (nextLink, pageSize) -> { + RequestOptions requestOptionsLocal = new RequestOptions(); + requestOptionsLocal.setContext(requestOptionsForNextPage.getContext()); + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRoomMembersNextSinglePageAsync(nextLink, requestOptionsLocal); + }); + } + + /** + * Get room members. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members along with {@link PagedResponse}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private PagedResponse listRoomMembersSinglePage(String roomId, RequestOptions requestOptions) { + final String accept = "application/json"; + Response res = service.listRoomMembersSync(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), roomId, accept, requestOptions, Context.NONE); + return new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null); + } + + /** + * Get room members. + *

Query Parameters

+ * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
maxpagesizeIntegerNoThe maximum number of result items per page.
continuationTokenStringNoContinuation token for pagination.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param roomId Room identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members as paginated response with {@link PagedIterable}. + */ + @ServiceMethod(returns = ReturnType.COLLECTION) + public PagedIterable listRoomMembers(String roomId, RequestOptions requestOptions) { + RequestOptions requestOptionsForNextPage = new RequestOptions(); + requestOptionsForNextPage.setContext( + requestOptions != null && requestOptions.getContext() != null ? requestOptions.getContext() : Context.NONE); + return new PagedIterable<>((pageSize) -> { + RequestOptions requestOptionsLocal = requestOptions == null ? new RequestOptions() : requestOptions; + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRoomMembersSinglePage(roomId, requestOptionsLocal); + }, (nextLink, pageSize) -> { + RequestOptions requestOptionsLocal = new RequestOptions(); + requestOptionsLocal.setContext(requestOptionsForNextPage.getContext()); + if (pageSize != null) { + requestOptionsLocal.addRequestCallback(requestLocal -> { + UrlBuilder urlBuilder = UrlBuilder.parse(requestLocal.getUrl()); + urlBuilder.setQueryParameter("maxpagesize", String.valueOf(pageSize)); + requestLocal.setUrl(urlBuilder.toString()); + }); + } + return listRoomMembersNextSinglePage(nextLink, requestOptionsLocal); + }); + } + + /** + * Create or replace a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a room member along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceRoomMemberWithResponseAsync(String roomId, String userId, + BinaryData resource, RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext( + context -> service.createOrReplaceRoomMember(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), roomId, userId, contentType, accept, resource, requestOptions, context)); + } + + /** + * Create or replace a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a room member along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceRoomMemberWithResponse(String roomId, String userId, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.createOrReplaceRoomMemberSync(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), roomId, userId, contentType, accept, resource, requestOptions, Context.NONE); + } + + /** + * Delete a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteRoomMemberWithResponseAsync(String roomId, String userId, + RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.deleteRoomMember(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), roomId, userId, requestOptions, context)); + } + + /** + * Delete a room member. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param roomId Room identifier. + * @param userId User ID of the member. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteRoomMemberWithResponse(String roomId, String userId, RequestOptions requestOptions) { + return service.deleteRoomMemberSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + roomId, userId, requestOptions, Context.NONE); + } + + /** + * Get a user's profile. + * + * Get a user's profile. The response is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the `kind` + * discriminator. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return a user's profile. + * + * Get a user's profile along with {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> getUserWithResponseAsync(String userId, RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.getUser(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), userId, accept, requestOptions, context)); + } + + /** + * Get a user's profile. + * + * Get a user's profile. The response is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the `kind` + * discriminator. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return a user's profile. + * + * Get a user's profile along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response getUserWithResponse(String userId, RequestOptions requestOptions) { + final String accept = "application/json"; + return service.getUserSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), userId, + accept, requestOptions, Context.NONE); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param userId User identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a user profile in the chat system along with {@link Response} on successful completion of + * {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> createOrReplaceUserWithResponseAsync(String userId, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return FluxUtil.withContext( + context -> service.createOrReplaceUser(this.getEndpoint(), this.getServiceVersion().getVersion(), + this.getHub(), userId, contentType, accept, resource, requestOptions, context)); + } + + /** + * Create or replace a user. + * + * Create or replace a user. The request body is a polymorphic `ChatUser` (e.g. `HumanChatUser`) selected by the + * `kind` discriminator. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + *

Request Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     kind: String(Human) (Required)
+     *     id: String (Required)
+     *     nickname: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + *

Response Headers

+ * + * + * + * + *
Response Headers
NameTypeDescription
ETagStringThe entity tag for the response.
+ * + * @param userId User identifier. + * @param resource The resource instance. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return represents a user profile in the chat system along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response createOrReplaceUserWithResponse(String userId, BinaryData resource, + RequestOptions requestOptions) { + final String contentType = "application/json"; + final String accept = "application/json"; + return service.createOrReplaceUserSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), + userId, contentType, accept, resource, requestOptions, Context.NONE); + } + + /** + * Delete a user. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> deleteUserWithResponseAsync(String userId, RequestOptions requestOptions) { + return FluxUtil.withContext(context -> service.deleteUser(this.getEndpoint(), + this.getServiceVersion().getVersion(), this.getHub(), userId, requestOptions, context)); + } + + /** + * Delete a user. + *

Header Parameters

+ * + * + * + * + * + *
Header Parameters
NameTypeRequiredDescription
If-MatchStringNoThe request should only proceed if an entity matches this + * string.
If-None-MatchStringNoThe request should only proceed if no entity matches this + * string.
+ * You can add these to a request with {@link RequestOptions#addHeader} + * + * @param userId User identifier. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return the {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response deleteUserWithResponse(String userId, RequestOptions requestOptions) { + return service.deleteUserSync(this.getEndpoint(), this.getServiceVersion().getVersion(), this.getHub(), userId, + requestOptions, Context.NONE); + } + + /** + * Generate a token for connecting a client to Azure Web PubSub. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
userIdStringNoUser identifier for the client connection.
roleList<String>NoRoles granted to the client connection. Call + * {@link RequestOptions#addQueryParam} to add string to array.
minutesToExpireIntegerNoLifetime of the generated token, in minutes.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     token: String (Required)
+     * }
+     * }
+     * 
+ * + * @param hub Target hub name. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return response containing a Web PubSub client access token along with {@link Response} on successful completion + * of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Mono> generateClientTokenWithResponseAsync(String hub, RequestOptions requestOptions) { + final String apiVersion = "2024-12-01"; + final String clientType = "default"; + final String accept = "application/json"; + return FluxUtil.withContext(context -> service.generateClientToken(this.getEndpoint(), hub, apiVersion, + clientType, accept, requestOptions, context)); + } + + /** + * Generate a token for connecting a client to Azure Web PubSub. + *

Query Parameters

+ * + * + * + * + * + * + *
Query Parameters
NameTypeRequiredDescription
userIdStringNoUser identifier for the client connection.
roleList<String>NoRoles granted to the client connection. Call + * {@link RequestOptions#addQueryParam} to add string to array.
minutesToExpireIntegerNoLifetime of the generated token, in minutes.
+ * You can add these to a request with {@link RequestOptions#addQueryParam} + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     token: String (Required)
+     * }
+     * }
+     * 
+ * + * @param hub Target hub name. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return response containing a Web PubSub client access token along with {@link Response}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + public Response generateClientTokenWithResponse(String hub, RequestOptions requestOptions) { + final String apiVersion = "2024-12-01"; + final String clientType = "default"; + final String accept = "application/json"; + return service.generateClientTokenSync(this.getEndpoint(), hub, apiVersion, clientType, accept, requestOptions, + Context.NONE); + } + + /** + * Query messages in a conversation from latest to earliest. + * + * Get the next page of items. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param nextLink The URL to get the next list of items. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items along with {@link PagedResponse} on successful completion of + * {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> listMessagesNextSinglePageAsync(String nextLink, + RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil + .withContext( + context -> service.listMessagesNext(nextLink, this.getEndpoint(), accept, requestOptions, context)) + .map(res -> new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null)); + } + + /** + * Query messages in a conversation from latest to earliest. + * + * Get the next page of items. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     id: String (Required)
+     *     createdBy: String (Optional, Required on create)
+     *     content (Optional, Required on create): {
+     *         text: String (Optional)
+     *         binary: byte[] (Optional)
+     *     }
+     *     createdAt: OffsetDateTime (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param nextLink The URL to get the next list of items. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatMessage items along with {@link PagedResponse}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private PagedResponse listMessagesNextSinglePage(String nextLink, RequestOptions requestOptions) { + final String accept = "application/json"; + Response res + = service.listMessagesNextSync(nextLink, this.getEndpoint(), accept, requestOptions, Context.NONE); + return new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null); + } + + /** + * Query roles in a hub. + * + * Get the next page of items. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param nextLink The URL to get the next list of items. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items along with {@link PagedResponse} on successful completion of + * {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> listRolesNextSinglePageAsync(String nextLink, + RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil + .withContext( + context -> service.listRolesNext(nextLink, this.getEndpoint(), accept, requestOptions, context)) + .map(res -> new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null)); + } + + /** + * Query roles in a hub. + * + * Get the next page of items. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     name: String (Required)
+     *     permissions (Required): [
+     *         String(user.create_room/user.fetch_all_rooms/room.publish_message/room.history/room.invite/room.remove_user) (Required)
+     *     ]
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param nextLink The URL to get the next list of items. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return paged collection of ChatRole items along with {@link PagedResponse}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private PagedResponse listRolesNextSinglePage(String nextLink, RequestOptions requestOptions) { + final String accept = "application/json"; + Response res + = service.listRolesNextSync(nextLink, this.getEndpoint(), accept, requestOptions, Context.NONE); + return new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null); + } + + /** + * Get room members. + * + * Get the next page of items. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param nextLink The URL to get the next list of items. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members along with {@link PagedResponse} on successful completion of {@link Mono}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private Mono> listRoomMembersNextSinglePageAsync(String nextLink, + RequestOptions requestOptions) { + final String accept = "application/json"; + return FluxUtil + .withContext( + context -> service.listRoomMembersNext(nextLink, this.getEndpoint(), accept, requestOptions, context)) + .map(res -> new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null)); + } + + /** + * Get room members. + * + * Get the next page of items. + *

Response Body Schema

+ * + *
+     * {@code
+     * {
+     *     userId: String (Required)
+     *     roleName: String (Required)
+     *     etag: String (Required)
+     * }
+     * }
+     * 
+ * + * @param nextLink The URL to get the next list of items. + * @param requestOptions The options to configure the HTTP request before HTTP client sends it. + * @throws HttpResponseException thrown if the request is rejected by server. + * @throws ClientAuthenticationException thrown if the request is rejected by server on status code 401. + * @throws ResourceNotFoundException thrown if the request is rejected by server on status code 404. + * @throws ResourceModifiedException thrown if the request is rejected by server on status code 409. + * @return room members along with {@link PagedResponse}. + */ + @ServiceMethod(returns = ReturnType.SINGLE) + private PagedResponse listRoomMembersNextSinglePage(String nextLink, RequestOptions requestOptions) { + final String accept = "application/json"; + Response res + = service.listRoomMembersNextSync(nextLink, this.getEndpoint(), accept, requestOptions, Context.NONE); + return new PagedResponseBase<>(res.getRequest(), res.getStatusCode(), res.getHeaders(), + getValues(res.getValue(), "value"), getNextLink(res.getValue(), "nextLink"), null); + } + + private List getValues(BinaryData binaryData, String... path) { + try { + Object value = binaryData.toObject(Map.class); + for (String segment : path) { + value = ((Map) value).get(segment); + } + List values = (List) value; + return values.stream().map(BinaryData::fromObject).collect(Collectors.toList()); + } catch (RuntimeException e) { + return null; + } + } + + private String getNextLink(BinaryData binaryData, String... path) { + try { + Object value = binaryData.toObject(Map.class); + for (String segment : path) { + value = ((Map) value).get(segment); + } + return (String) value; + } catch (RuntimeException e) { + return null; + } + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/GenerateClientTokenResponse.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/GenerateClientTokenResponse.java new file mode 100644 index 000000000000..30823f37f57b --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/GenerateClientTokenResponse.java @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.implementation.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * Response containing a Web PubSub client access token. + */ +@Immutable +public final class GenerateClientTokenResponse implements JsonSerializable { + /* + * Access token used to connect to Azure Web PubSub. + */ + @Generated + private final String token; + + /** + * Creates an instance of GenerateClientTokenResponse class. + * + * @param token the token value to set. + */ + @Generated + private GenerateClientTokenResponse(String token) { + this.token = token; + } + + /** + * Get the token property: Access token used to connect to Azure Web PubSub. + * + * @return the token value. + */ + @Generated + public String getToken() { + return this.token; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("token", this.token); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of GenerateClientTokenResponse from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of GenerateClientTokenResponse if the JsonReader was pointing to an instance of it, or null + * if it was pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the GenerateClientTokenResponse. + */ + @Generated + public static GenerateClientTokenResponse fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String token = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("token".equals(fieldName)) { + token = reader.getString(); + } else { + reader.skipChildren(); + } + } + return new GenerateClientTokenResponse(token); + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/package-info.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/package-info.java new file mode 100644 index 000000000000..11d0f7b14661 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * Package containing the data models for WebPubSubChat. + * Azure Web PubSub Chat REST API. + */ +package com.azure.messaging.webpubsub.chat.implementation.models; diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/package-info.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/package-info.java new file mode 100644 index 000000000000..6a4093ea8eb0 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/implementation/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * Package containing the implementations for WebPubSubChat. + * Azure Web PubSub Chat REST API. + */ +package com.azure.messaging.webpubsub.chat.implementation; diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/BuiltInChatRoles.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/BuiltInChatRoles.java new file mode 100644 index 000000000000..86d14144da18 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/BuiltInChatRoles.java @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat.models; + +/** Built-in roles supported by Azure Web PubSub Chat. */ +public final class BuiltInChatRoles { + /** The normal user role. */ + public static final String USER_NORMAL = "user.normal"; + + /** The room member role. */ + public static final String ROOM_MEMBER = "room.member"; + + /** The room operator role. */ + public static final String ROOM_OPERATOR = "room.operator"; + + private BuiltInChatRoles() { + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatConversation.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatConversation.java new file mode 100644 index 000000000000..00a529508967 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatConversation.java @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * Represents a chat conversation. + */ +@Immutable +public final class ChatConversation implements JsonSerializable { + /* + * Conversation identifier. + */ + @Generated + private String id; + + /* + * Parent room identifier. + */ + @Generated + private final String parentRoom; + + /* + * The entity tag for this resource. + */ + @Generated + private String etag; + + /** + * Creates an instance of ChatConversation class. + * + * @param parentRoom the parentRoom value to set. + */ + @Generated + private ChatConversation(String parentRoom) { + this.parentRoom = parentRoom; + } + + /** + * Get the id property: Conversation identifier. + * + * @return the id value. + */ + @Generated + public String getId() { + return this.id; + } + + /** + * Get the parentRoom property: Parent room identifier. + * + * @return the parentRoom value. + */ + @Generated + public String getParentRoom() { + return this.parentRoom; + } + + /** + * Get the etag property: The entity tag for this resource. + * + * @return the etag value. + */ + @Generated + public String getEtag() { + return this.etag; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("parentRoom", this.parentRoom); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ChatConversation from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ChatConversation if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ChatConversation. + */ + @Generated + public static ChatConversation fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String id = null; + String parentRoom = null; + String etag = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + id = reader.getString(); + } else if ("parentRoom".equals(fieldName)) { + parentRoom = reader.getString(); + } else if ("etag".equals(fieldName)) { + etag = reader.getString(); + } else { + reader.skipChildren(); + } + } + ChatConversation deserializedChatConversation = new ChatConversation(parentRoom); + deserializedChatConversation.id = id; + deserializedChatConversation.etag = etag; + + return deserializedChatConversation; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatMessage.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatMessage.java new file mode 100644 index 000000000000..ef21b96f8a29 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatMessage.java @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.core.util.CoreUtils; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import com.azure.messaging.webpubsub.chat.implementation.JsonMergePatchHelper; +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.HashSet; +import java.util.Set; + +/** + * Represents a chat message. + */ +@Fluent +public final class ChatMessage implements JsonSerializable { + /* + * Message identifier. + */ + @Generated + private String id; + + /* + * User who created the message. + */ + @Generated + private String createdBy; + + /* + * Message content. + */ + @Generated + private MessageContent content; + + /* + * Timestamp when the message was created. + */ + @Generated + private OffsetDateTime createdAt; + + /* + * The entity tag for this resource. + */ + @Generated + private String etag; + + /** + * Stores updated model property, the value is property name, not serialized name. + */ + @Generated + private final Set updatedProperties = new HashSet<>(); + + @Generated + private boolean jsonMergePatch; + + @Generated + private void serializeAsJsonMergePatch(boolean jsonMergePatch) { + this.jsonMergePatch = jsonMergePatch; + } + + static { + JsonMergePatchHelper.setChatMessageAccessor(new JsonMergePatchHelper.ChatMessageAccessor() { + @Override + public ChatMessage prepareModelForJsonMergePatch(ChatMessage model, boolean jsonMergePatchEnabled) { + model.serializeAsJsonMergePatch(jsonMergePatchEnabled); + return model; + } + + @Override + public boolean isJsonMergePatch(ChatMessage model) { + return model.jsonMergePatch; + } + }); + } + + /** + * Creates an instance of ChatMessage class. + */ + @Generated + public ChatMessage() { + } + + /** + * Get the id property: Message identifier. + * + * @return the id value. + */ + @Generated + public String getId() { + return this.id; + } + + /** + * Get the createdBy property: User who created the message. + * + * @return the createdBy value. + */ + @Generated + public String getCreatedBy() { + return this.createdBy; + } + + /** + * Set the createdBy property: User who created the message. + *

Required when create the resource.

+ * + * @param createdBy the createdBy value to set. + * @return the ChatMessage object itself. + */ + @Generated + public ChatMessage setCreatedBy(String createdBy) { + this.createdBy = createdBy; + this.updatedProperties.add("createdBy"); + return this; + } + + /** + * Get the content property: Message content. + * + * @return the content value. + */ + @Generated + public MessageContent getContent() { + return this.content; + } + + /** + * Set the content property: Message content. + *

Required when create the resource.

+ * + * @param content the content value to set. + * @return the ChatMessage object itself. + */ + @Generated + public ChatMessage setContent(MessageContent content) { + this.content = content; + this.updatedProperties.add("content"); + return this; + } + + /** + * Get the createdAt property: Timestamp when the message was created. + * + * @return the createdAt value. + */ + @Generated + public OffsetDateTime getCreatedAt() { + return this.createdAt; + } + + /** + * Get the etag property: The entity tag for this resource. + * + * @return the etag value. + */ + @Generated + public String getEtag() { + return this.etag; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + if (jsonMergePatch) { + return toJsonMergePatch(jsonWriter); + } else { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("createdBy", this.createdBy); + jsonWriter.writeJsonField("content", this.content); + return jsonWriter.writeEndObject(); + } + } + + @Generated + private JsonWriter toJsonMergePatch(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (updatedProperties.contains("createdBy")) { + if (this.createdBy == null) { + jsonWriter.writeNullField("createdBy"); + } else { + jsonWriter.writeStringField("createdBy", this.createdBy); + } + } + if (updatedProperties.contains("content")) { + if (this.content == null) { + jsonWriter.writeNullField("content"); + } else { + JsonMergePatchHelper.getMessageContentAccessor().prepareModelForJsonMergePatch(this.content, true); + jsonWriter.writeJsonField("content", this.content); + JsonMergePatchHelper.getMessageContentAccessor().prepareModelForJsonMergePatch(this.content, false); + } + } + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ChatMessage from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ChatMessage if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ChatMessage. + */ + @Generated + public static ChatMessage fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + ChatMessage deserializedChatMessage = new ChatMessage(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + deserializedChatMessage.id = reader.getString(); + } else if ("createdAt".equals(fieldName)) { + deserializedChatMessage.createdAt = reader + .getNullable(nonNullReader -> CoreUtils.parseBestOffsetDateTime(nonNullReader.getString())); + } else if ("etag".equals(fieldName)) { + deserializedChatMessage.etag = reader.getString(); + } else if ("createdBy".equals(fieldName)) { + deserializedChatMessage.createdBy = reader.getString(); + } else if ("content".equals(fieldName)) { + deserializedChatMessage.content = MessageContent.fromJson(reader); + } else { + reader.skipChildren(); + } + } + + return deserializedChatMessage; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatPermission.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatPermission.java new file mode 100644 index 000000000000..4732786864e0 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatPermission.java @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** + * A permission that can be assigned to a chat role. + */ +public final class ChatPermission extends ExpandableStringEnum { + /** + * Allows a user to create chat rooms. + */ + @Generated + public static final ChatPermission USER_CREATE_ROOM = fromString("user.create_room"); + + /** + * Allows a user to list the rooms they belong to. + */ + @Generated + public static final ChatPermission USER_FETCH_ALL_ROOMS = fromString("user.fetch_all_rooms"); + + /** + * Allows a room member to publish messages. + */ + @Generated + public static final ChatPermission ROOM_PUBLISH_MESSAGE = fromString("room.publish_message"); + + /** + * Allows a room member to read message history. + */ + @Generated + public static final ChatPermission ROOM_HISTORY = fromString("room.history"); + + /** + * Allows a room member to add users to a room. + */ + @Generated + public static final ChatPermission ROOM_INVITE = fromString("room.invite"); + + /** + * Allows a room operator to remove users from a room. + */ + @Generated + public static final ChatPermission ROOM_REMOVE_USER = fromString("room.remove_user"); + + /** + * Creates a new instance of ChatPermission value. + * + * @deprecated Use the {@link #fromString(String)} factory method. + */ + @Generated + @Deprecated + public ChatPermission() { + } + + /** + * Creates or finds a ChatPermission from its string representation. + * + * @param name a name to look for. + * @return the corresponding ChatPermission. + */ + @Generated + public static ChatPermission fromString(String name) { + return fromString(name, ChatPermission.class); + } + + /** + * Gets known ChatPermission values. + * + * @return known ChatPermission values. + */ + @Generated + public static Collection values() { + return values(ChatPermission.class); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRole.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRole.java new file mode 100644 index 000000000000..331ebeb217e7 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRole.java @@ -0,0 +1,130 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; +import java.util.List; + +/** + * Represents a chat role. + * A role name must start with 'user.' or 'room.' prefix. + * A role must contain either user permissions or room permissions, but not both. + */ +@Immutable +public final class ChatRole implements JsonSerializable { + /* + * Role name. Must start with 'user.' or 'room.' prefix. + */ + @Generated + private String name; + + /* + * Permissions associated with the role. Do not mix user permissions and room permissions in one role. + */ + @Generated + private final List permissions; + + /* + * The entity tag for this resource. + */ + @Generated + private String etag; + + /** + * Creates an instance of ChatRole class. + * + * @param permissions the permissions value to set. + */ + @Generated + public ChatRole(List permissions) { + this.permissions = permissions; + } + + /** + * Get the name property: Role name. Must start with 'user.' or 'room.' prefix. + * + * @return the name value. + */ + @Generated + public String getName() { + return this.name; + } + + /** + * Get the permissions property: Permissions associated with the role. Do not mix user permissions and room + * permissions in one role. + * + * @return the permissions value. + */ + @Generated + public List getPermissions() { + return this.permissions; + } + + /** + * Get the etag property: The entity tag for this resource. + * + * @return the etag value. + */ + @Generated + public String getEtag() { + return this.etag; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeArrayField("permissions", this.permissions, + (writer, element) -> writer.writeString(element == null ? null : element.toString())); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ChatRole from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ChatRole if the JsonReader was pointing to an instance of it, or null if it was pointing + * to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ChatRole. + */ + @Generated + public static ChatRole fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String name = null; + List permissions = null; + String etag = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("name".equals(fieldName)) { + name = reader.getString(); + } else if ("permissions".equals(fieldName)) { + permissions = reader.readArray(reader1 -> ChatPermission.fromString(reader1.getString())); + } else if ("etag".equals(fieldName)) { + etag = reader.getString(); + } else { + reader.skipChildren(); + } + } + ChatRole deserializedChatRole = new ChatRole(permissions); + deserializedChatRole.name = name; + deserializedChatRole.etag = etag; + + return deserializedChatRole; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoom.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoom.java new file mode 100644 index 000000000000..896f9919363f --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoom.java @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * Represents a chat room. + */ +@Immutable +public final class ChatRoom implements JsonSerializable { + /* + * Room identifier. + */ + @Generated + private String id; + + /* + * Room title. + */ + @Generated + private final String title; + + /* + * Default conversation ID for this room. + */ + @Generated + private String defaultConversation; + + /* + * The entity tag for this resource. + */ + @Generated + private String etag; + + /** + * Creates an instance of ChatRoom class. + * + * @param title the title value to set. + */ + @Generated + public ChatRoom(String title) { + this.title = title; + } + + /** + * Get the id property: Room identifier. + * + * @return the id value. + */ + @Generated + public String getId() { + return this.id; + } + + /** + * Get the title property: Room title. + * + * @return the title value. + */ + @Generated + public String getTitle() { + return this.title; + } + + /** + * Get the defaultConversation property: Default conversation ID for this room. + * + * @return the defaultConversation value. + */ + @Generated + public String getDefaultConversation() { + return this.defaultConversation; + } + + /** + * Get the etag property: The entity tag for this resource. + * + * @return the etag value. + */ + @Generated + public String getEtag() { + return this.etag; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("title", this.title); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ChatRoom from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ChatRoom if the JsonReader was pointing to an instance of it, or null if it was pointing + * to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ChatRoom. + */ + @Generated + public static ChatRoom fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String id = null; + String title = null; + String defaultConversation = null; + String etag = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + id = reader.getString(); + } else if ("title".equals(fieldName)) { + title = reader.getString(); + } else if ("defaultConversation".equals(fieldName)) { + defaultConversation = reader.getString(); + } else if ("etag".equals(fieldName)) { + etag = reader.getString(); + } else { + reader.skipChildren(); + } + } + ChatRoom deserializedChatRoom = new ChatRoom(title); + deserializedChatRoom.id = id; + deserializedChatRoom.defaultConversation = defaultConversation; + deserializedChatRoom.etag = etag; + + return deserializedChatRoom; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoomMember.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoomMember.java new file mode 100644 index 000000000000..14ac4bac134b --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoomMember.java @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * Represents a room member. + */ +@Immutable +public final class ChatRoomMember implements JsonSerializable { + /* + * User ID of the member. + */ + @Generated + private String userId; + + /* + * Room role assigned to the user within this room. + */ + @Generated + private final String roleName; + + /* + * The entity tag for this resource. + */ + @Generated + private String etag; + + /** + * Creates an instance of ChatRoomMember class. + * + * @param roleName the roleName value to set. + */ + @Generated + public ChatRoomMember(String roleName) { + this.roleName = roleName; + } + + /** + * Get the userId property: User ID of the member. + * + * @return the userId value. + */ + @Generated + public String getUserId() { + return this.userId; + } + + /** + * Get the roleName property: Room role assigned to the user within this room. + * + * @return the roleName value. + */ + @Generated + public String getRoleName() { + return this.roleName; + } + + /** + * Get the etag property: The entity tag for this resource. + * + * @return the etag value. + */ + @Generated + public String getEtag() { + return this.etag; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("roleName", this.roleName); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ChatRoomMember from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ChatRoomMember if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ChatRoomMember. + */ + @Generated + public static ChatRoomMember fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String userId = null; + String roleName = null; + String etag = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("userId".equals(fieldName)) { + userId = reader.getString(); + } else if ("roleName".equals(fieldName)) { + roleName = reader.getString(); + } else if ("etag".equals(fieldName)) { + etag = reader.getString(); + } else { + reader.skipChildren(); + } + } + ChatRoomMember deserializedChatRoomMember = new ChatRoomMember(roleName); + deserializedChatRoomMember.userId = userId; + deserializedChatRoomMember.etag = etag; + + return deserializedChatRoomMember; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUser.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUser.java new file mode 100644 index 000000000000..0e7efcbd33d8 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUser.java @@ -0,0 +1,197 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * Represents a user profile in the chat system. This is a discriminated base type; + * concrete payloads are selected by the `kind` field (e.g. `HumanChatUser`). + */ +@Immutable +public class ChatUser implements JsonSerializable { + /* + * The kind of user. + */ + @Generated + private ChatUserKind kind = ChatUserKind.fromString("ChatUser"); + + /* + * User identifier. + */ + @Generated + private String id; + + /* + * User's display nickname. + */ + @Generated + private final String nickname; + + /* + * The entity tag for this resource. + */ + @Generated + private String etag; + + /** + * Creates an instance of ChatUser class. + * + * @param nickname the nickname value to set. + */ + @Generated + public ChatUser(String nickname) { + this.nickname = nickname; + } + + /** + * Get the kind property: The kind of user. + * + * @return the kind value. + */ + @Generated + public ChatUserKind getKind() { + return this.kind; + } + + /** + * Get the id property: User identifier. + * + * @return the id value. + */ + @Generated + public String getId() { + return this.id; + } + + /** + * Set the id property: User identifier. + * + * @param id the id value to set. + * @return the ChatUser object itself. + */ + @Generated + ChatUser setId(String id) { + this.id = id; + return this; + } + + /** + * Get the nickname property: User's display nickname. + * + * @return the nickname value. + */ + @Generated + public String getNickname() { + return this.nickname; + } + + /** + * Get the etag property: The entity tag for this resource. + * + * @return the etag value. + */ + @Generated + public String getEtag() { + return this.etag; + } + + /** + * Set the etag property: The entity tag for this resource. + * + * @param etag the etag value to set. + * @return the ChatUser object itself. + */ + @Generated + ChatUser setEtag(String etag) { + this.etag = etag; + return this; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("nickname", this.nickname); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of ChatUser from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of ChatUser if the JsonReader was pointing to an instance of it, or null if it was pointing + * to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the ChatUser. + */ + @Generated + public static ChatUser fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String discriminatorValue = null; + try (JsonReader readerToUse = reader.bufferObject()) { + readerToUse.nextToken(); // Prepare for reading + while (readerToUse.nextToken() != JsonToken.END_OBJECT) { + String fieldName = readerToUse.getFieldName(); + readerToUse.nextToken(); + if ("kind".equals(fieldName)) { + discriminatorValue = readerToUse.getString(); + break; + } else { + readerToUse.skipChildren(); + } + } + // Use the discriminator value to determine which subtype should be deserialized. + if ("Human".equals(discriminatorValue)) { + return HumanChatUser.fromJson(readerToUse.reset()); + } else { + return fromJsonKnownDiscriminator(readerToUse.reset()); + } + } + }); + } + + @Generated + static ChatUser fromJsonKnownDiscriminator(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String id = null; + String nickname = null; + String etag = null; + ChatUserKind kind = null; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + id = reader.getString(); + } else if ("nickname".equals(fieldName)) { + nickname = reader.getString(); + } else if ("etag".equals(fieldName)) { + etag = reader.getString(); + } else if ("kind".equals(fieldName)) { + kind = ChatUserKind.fromString(reader.getString()); + } else { + reader.skipChildren(); + } + } + ChatUser deserializedChatUser = new ChatUser(nickname); + deserializedChatUser.id = id; + deserializedChatUser.etag = etag; + deserializedChatUser.kind = kind; + + return deserializedChatUser; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUserKind.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUserKind.java new file mode 100644 index 000000000000..88375ec718cf --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUserKind.java @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.util.ExpandableStringEnum; +import java.util.Collection; + +/** + * Discriminator for the kind of chat user. + */ +public final class ChatUserKind extends ExpandableStringEnum { + /** + * A human end-user. + */ + @Generated + public static final ChatUserKind HUMAN = fromString("Human"); + + /** + * Creates a new instance of ChatUserKind value. + * + * @deprecated Use the {@link #fromString(String)} factory method. + */ + @Generated + @Deprecated + public ChatUserKind() { + } + + /** + * Creates or finds a ChatUserKind from its string representation. + * + * @param name a name to look for. + * @return the corresponding ChatUserKind. + */ + @Generated + public static ChatUserKind fromString(String name) { + return fromString(name, ChatUserKind.class); + } + + /** + * Gets known ChatUserKind values. + * + * @return known ChatUserKind values. + */ + @Generated + public static Collection values() { + return values(ChatUserKind.class); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/GetClientAccessTokenOptions.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/GetClientAccessTokenOptions.java new file mode 100644 index 000000000000..d09f7873b8e1 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/GetClientAccessTokenOptions.java @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat.models; + +import java.time.Duration; + +/** Options for creating a Web PubSub client access token for Chat. */ +public final class GetClientAccessTokenOptions { + private Duration expiresAfter = Duration.ofHours(1); + private String userId; + + /** Creates an instance of {@link GetClientAccessTokenOptions}. */ + public GetClientAccessTokenOptions() { + } + + /** + * Sets the duration after which the client access token expires. + * + * @param expiresAfter The token lifetime. + * @return The updated options. + */ + public GetClientAccessTokenOptions setExpiresAfter(Duration expiresAfter) { + this.expiresAfter = expiresAfter; + return this; + } + + /** + * Gets the duration after which the client access token expires. + * + * @return The token lifetime. + */ + public Duration getExpiresAfter() { + return expiresAfter; + } + + /** + * Sets the user ID included in the client access token. + * + * @param userId The user ID. + * @return The updated options. + */ + public GetClientAccessTokenOptions setUserId(String userId) { + this.userId = userId; + return this; + } + + /** + * Gets the user ID included in the client access token. + * + * @return The user ID. + */ + public String getUserId() { + return userId; + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/HumanChatUser.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/HumanChatUser.java new file mode 100644 index 000000000000..553fc3083c34 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/HumanChatUser.java @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Generated; +import com.azure.core.annotation.Immutable; +import com.azure.json.JsonReader; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import java.io.IOException; + +/** + * A human end-user, identified by a user role. + */ +@Immutable +public final class HumanChatUser extends ChatUser { + /* + * The kind of user. + */ + @Generated + private ChatUserKind kind = ChatUserKind.HUMAN; + + /* + * Global user role assigned to the user. Must start with `user.`. + */ + @Generated + private final String roleName; + + /** + * Creates an instance of HumanChatUser class. + * + * @param nickname the nickname value to set. + * @param roleName the roleName value to set. + */ + @Generated + public HumanChatUser(String nickname, String roleName) { + super(nickname); + this.roleName = roleName; + } + + /** + * Get the kind property: The kind of user. + * + * @return the kind value. + */ + @Generated + @Override + public ChatUserKind getKind() { + return this.kind; + } + + /** + * Get the roleName property: Global user role assigned to the user. Must start with `user.`. + * + * @return the roleName value. + */ + @Generated + public String getRoleName() { + return this.roleName; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("nickname", getNickname()); + jsonWriter.writeStringField("roleName", this.roleName); + jsonWriter.writeStringField("kind", this.kind == null ? null : this.kind.toString()); + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of HumanChatUser from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of HumanChatUser if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IllegalStateException If the deserialized JSON object was missing any required properties. + * @throws IOException If an error occurs while reading the HumanChatUser. + */ + @Generated + public static HumanChatUser fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + String id = null; + String nickname = null; + String etag = null; + String roleName = null; + ChatUserKind kind = ChatUserKind.HUMAN; + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("id".equals(fieldName)) { + id = reader.getString(); + } else if ("nickname".equals(fieldName)) { + nickname = reader.getString(); + } else if ("etag".equals(fieldName)) { + etag = reader.getString(); + } else if ("roleName".equals(fieldName)) { + roleName = reader.getString(); + } else if ("kind".equals(fieldName)) { + kind = ChatUserKind.fromString(reader.getString()); + } else { + reader.skipChildren(); + } + } + HumanChatUser deserializedHumanChatUser = new HumanChatUser(nickname, roleName); + deserializedHumanChatUser.setId(id); + deserializedHumanChatUser.setEtag(etag); + deserializedHumanChatUser.kind = kind; + + return deserializedHumanChatUser; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/MessageContent.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/MessageContent.java new file mode 100644 index 000000000000..2affaccea8c2 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/MessageContent.java @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat.models; + +import com.azure.core.annotation.Fluent; +import com.azure.core.annotation.Generated; +import com.azure.core.util.CoreUtils; +import com.azure.json.JsonReader; +import com.azure.json.JsonSerializable; +import com.azure.json.JsonToken; +import com.azure.json.JsonWriter; +import com.azure.messaging.webpubsub.chat.implementation.JsonMergePatchHelper; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +/** + * Message content body. + */ +@Fluent +public final class MessageContent implements JsonSerializable { + /* + * Text content. + */ + @Generated + private String text; + + /* + * Binary content (base64 encoded). + */ + @Generated + private byte[] binary; + + /** + * Stores updated model property, the value is property name, not serialized name. + */ + @Generated + private final Set updatedProperties = new HashSet<>(); + + @Generated + private boolean jsonMergePatch; + + @Generated + private void serializeAsJsonMergePatch(boolean jsonMergePatch) { + this.jsonMergePatch = jsonMergePatch; + } + + static { + JsonMergePatchHelper.setMessageContentAccessor(new JsonMergePatchHelper.MessageContentAccessor() { + @Override + public MessageContent prepareModelForJsonMergePatch(MessageContent model, boolean jsonMergePatchEnabled) { + model.serializeAsJsonMergePatch(jsonMergePatchEnabled); + return model; + } + + @Override + public boolean isJsonMergePatch(MessageContent model) { + return model.jsonMergePatch; + } + }); + } + + /** + * Creates an instance of MessageContent class. + */ + @Generated + public MessageContent() { + } + + /** + * Get the text property: Text content. + * + * @return the text value. + */ + @Generated + public String getText() { + return this.text; + } + + /** + * Set the text property: Text content. + * + * @param text the text value to set. + * @return the MessageContent object itself. + */ + @Generated + public MessageContent setText(String text) { + this.text = text; + this.updatedProperties.add("text"); + return this; + } + + /** + * Get the binary property: Binary content (base64 encoded). + * + * @return the binary value. + */ + @Generated + public byte[] getBinary() { + return CoreUtils.clone(this.binary); + } + + /** + * Set the binary property: Binary content (base64 encoded). + * + * @param binary the binary value to set. + * @return the MessageContent object itself. + */ + @Generated + public MessageContent setBinary(byte[] binary) { + this.binary = CoreUtils.clone(binary); + this.updatedProperties.add("binary"); + return this; + } + + /** + * {@inheritDoc} + */ + @Generated + @Override + public JsonWriter toJson(JsonWriter jsonWriter) throws IOException { + if (jsonMergePatch) { + return toJsonMergePatch(jsonWriter); + } else { + jsonWriter.writeStartObject(); + jsonWriter.writeStringField("text", this.text); + jsonWriter.writeBinaryField("binary", this.binary); + return jsonWriter.writeEndObject(); + } + } + + @Generated + private JsonWriter toJsonMergePatch(JsonWriter jsonWriter) throws IOException { + jsonWriter.writeStartObject(); + if (updatedProperties.contains("text")) { + if (this.text == null) { + jsonWriter.writeNullField("text"); + } else { + jsonWriter.writeStringField("text", this.text); + } + } + if (updatedProperties.contains("binary")) { + if (this.binary == null) { + jsonWriter.writeNullField("binary"); + } else { + jsonWriter.writeBinaryField("binary", this.binary); + } + } + return jsonWriter.writeEndObject(); + } + + /** + * Reads an instance of MessageContent from the JsonReader. + * + * @param jsonReader The JsonReader being read. + * @return An instance of MessageContent if the JsonReader was pointing to an instance of it, or null if it was + * pointing to JSON null. + * @throws IOException If an error occurs while reading the MessageContent. + */ + @Generated + public static MessageContent fromJson(JsonReader jsonReader) throws IOException { + return jsonReader.readObject(reader -> { + MessageContent deserializedMessageContent = new MessageContent(); + while (reader.nextToken() != JsonToken.END_OBJECT) { + String fieldName = reader.getFieldName(); + reader.nextToken(); + + if ("text".equals(fieldName)) { + deserializedMessageContent.text = reader.getString(); + } else if ("binary".equals(fieldName)) { + deserializedMessageContent.binary = reader.getBinary(); + } else { + reader.skipChildren(); + } + } + + return deserializedMessageContent; + }); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/WebPubSubClientAccessToken.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/WebPubSubClientAccessToken.java new file mode 100644 index 000000000000..9ad5b69adf94 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/WebPubSubClientAccessToken.java @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat.models; + +/** A client access token and URL for connecting to Azure Web PubSub. */ +public final class WebPubSubClientAccessToken { + private final String token; + private final String url; + + /** + * Creates a Web PubSub client access token result. + * + * @param token The client access token. + * @param url The client connection URL. + */ + public WebPubSubClientAccessToken(String token, String url) { + this.token = token; + this.url = url; + } + + /** + * Gets the client access token. + * + * @return The client access token. + */ + public String getToken() { + return token; + } + + /** + * Gets the client connection URL. + * + * @return The client connection URL. + */ + public String getUrl() { + return url; + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/package-info.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/package-info.java new file mode 100644 index 000000000000..9b14e91a9d23 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/models/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * Package containing the data models for WebPubSubChat. + * Azure Web PubSub Chat REST API. + */ +package com.azure.messaging.webpubsub.chat.models; diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/package-info.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/package-info.java new file mode 100644 index 000000000000..440b0226e10d --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/com/azure/messaging/webpubsub/chat/package-info.java @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +/** + * Package containing the classes for WebPubSubChat. + * Azure Web PubSub Chat REST API. + */ +package com.azure.messaging.webpubsub.chat; diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/module-info.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/module-info.java new file mode 100644 index 000000000000..e28a66920bd9 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/java/module-info.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +module com.azure.messaging.webpubsub.chat { + requires transitive com.azure.core; + requires com.nimbusds.jose.jwt; + + exports com.azure.messaging.webpubsub.chat; + exports com.azure.messaging.webpubsub.chat.models; + + opens com.azure.messaging.webpubsub.chat.models to com.azure.core; + opens com.azure.messaging.webpubsub.chat.implementation.models to com.azure.core; +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/resources/META-INF/azure-messaging-webpubsub-chat_metadata.json b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/resources/META-INF/azure-messaging-webpubsub-chat_metadata.json new file mode 100644 index 000000000000..12444820d741 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/resources/META-INF/azure-messaging-webpubsub-chat_metadata.json @@ -0,0 +1 @@ +{"flavor":"azure","apiVersions":{"WebPubSubChat":"2026-02-01-preview"},"crossLanguagePackageId":"WebPubSubChat","crossLanguageVersion":"c36110faca71","crossLanguageDefinitions":{"com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient":"Customizations.WebPubSubChatServiceClient","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceRole":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceRoleWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceRoom":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceRoomMember":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceRoomMemberWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceRoomWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceUser":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.createOrReplaceUserWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteMessage":"WebPubSubChat.WebPubSubChatServiceClient.deleteMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteMessageWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteRole":"WebPubSubChat.WebPubSubChatServiceClient.deleteRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteRoleWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteRoom":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteRoomMember":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteRoomMemberWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteRoomWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteUser":"WebPubSubChat.WebPubSubChatServiceClient.deleteUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.deleteUserWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.generateClientToken":"Customizations.WebPubSubChatServiceClient.generateClientToken","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.generateClientTokenWithResponse":"Customizations.WebPubSubChatServiceClient.generateClientToken","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getConversation":"WebPubSubChat.WebPubSubChatServiceClient.getConversation","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getConversationWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getConversation","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getRole":"WebPubSubChat.WebPubSubChatServiceClient.getRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getRoleWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getRoom":"WebPubSubChat.WebPubSubChatServiceClient.getRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getRoomWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getUser":"WebPubSubChat.WebPubSubChatServiceClient.getUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.getUserWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.listMessages":"WebPubSubChat.WebPubSubChatServiceClient.listMessages","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.listRoles":"WebPubSubChat.WebPubSubChatServiceClient.listRoles","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.listRoomMembers":"WebPubSubChat.WebPubSubChatServiceClient.listRoomMembers","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.updateMessage":"WebPubSubChat.WebPubSubChatServiceClient.updateMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceAsyncClient.updateMessageWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.updateMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient":"Customizations.WebPubSubChatServiceClient","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceRole":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceRoleWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceRoom":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceRoomMember":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceRoomMemberWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceRoomWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceUser":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.createOrReplaceUserWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.createOrReplaceUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteMessage":"WebPubSubChat.WebPubSubChatServiceClient.deleteMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteMessageWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteRole":"WebPubSubChat.WebPubSubChatServiceClient.deleteRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteRoleWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteRoom":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteRoomMember":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteRoomMemberWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoomMember","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteRoomWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteUser":"WebPubSubChat.WebPubSubChatServiceClient.deleteUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.deleteUserWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.deleteUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.generateClientToken":"Customizations.WebPubSubChatServiceClient.generateClientToken","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.generateClientTokenWithResponse":"Customizations.WebPubSubChatServiceClient.generateClientToken","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getConversation":"WebPubSubChat.WebPubSubChatServiceClient.getConversation","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getConversationWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getConversation","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getRole":"WebPubSubChat.WebPubSubChatServiceClient.getRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getRoleWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getRole","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getRoom":"WebPubSubChat.WebPubSubChatServiceClient.getRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getRoomWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getRoom","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getUser":"WebPubSubChat.WebPubSubChatServiceClient.getUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.getUserWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.getUser","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.listMessages":"WebPubSubChat.WebPubSubChatServiceClient.listMessages","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.listRoles":"WebPubSubChat.WebPubSubChatServiceClient.listRoles","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.listRoomMembers":"WebPubSubChat.WebPubSubChatServiceClient.listRoomMembers","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.updateMessage":"WebPubSubChat.WebPubSubChatServiceClient.updateMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClient.updateMessageWithResponse":"WebPubSubChat.WebPubSubChatServiceClient.updateMessage","com.azure.messaging.webpubsub.chat.WebPubSubChatServiceClientBuilder":"Customizations.WebPubSubChatServiceClient","com.azure.messaging.webpubsub.chat.implementation.models.GenerateClientTokenResponse":"Customizations.GenerateClientTokenResponse","com.azure.messaging.webpubsub.chat.models.ChatConversation":"WebPubSubChat.ChatConversation","com.azure.messaging.webpubsub.chat.models.ChatMessage":"WebPubSubChat.ChatMessage","com.azure.messaging.webpubsub.chat.models.ChatPermission":"WebPubSubChat.ChatPermission","com.azure.messaging.webpubsub.chat.models.ChatRole":"WebPubSubChat.ChatRole","com.azure.messaging.webpubsub.chat.models.ChatRoom":"WebPubSubChat.ChatRoom","com.azure.messaging.webpubsub.chat.models.ChatRoomMember":"WebPubSubChat.ChatRoomMember","com.azure.messaging.webpubsub.chat.models.ChatUser":"WebPubSubChat.ChatUser","com.azure.messaging.webpubsub.chat.models.ChatUserKind":"WebPubSubChat.ChatUserKind","com.azure.messaging.webpubsub.chat.models.HumanChatUser":"WebPubSubChat.HumanChatUser","com.azure.messaging.webpubsub.chat.models.MessageContent":"WebPubSubChat.MessageContent"},"generatedFiles":["src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceAsyncClient.java","src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClient.java","src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilder.java","src/main/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceVersion.java","src/main/java/com/azure/messaging/webpubsub/chat/implementation/JsonMergePatchHelper.java","src/main/java/com/azure/messaging/webpubsub/chat/implementation/WebPubSubChatServiceClientImpl.java","src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/GenerateClientTokenResponse.java","src/main/java/com/azure/messaging/webpubsub/chat/implementation/models/package-info.java","src/main/java/com/azure/messaging/webpubsub/chat/implementation/package-info.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatConversation.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatMessage.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatPermission.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRole.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoom.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatRoomMember.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUser.java","src/main/java/com/azure/messaging/webpubsub/chat/models/ChatUserKind.java","src/main/java/com/azure/messaging/webpubsub/chat/models/HumanChatUser.java","src/main/java/com/azure/messaging/webpubsub/chat/models/MessageContent.java","src/main/java/com/azure/messaging/webpubsub/chat/models/package-info.java","src/main/java/com/azure/messaging/webpubsub/chat/package-info.java","src/main/java/module-info.java"]} \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/resources/azure-messaging-webpubsub-chat.properties b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/resources/azure-messaging-webpubsub-chat.properties new file mode 100644 index 000000000000..ca812989b4f2 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/main/resources/azure-messaging-webpubsub-chat.properties @@ -0,0 +1,2 @@ +name=${project.artifactId} +version=${project.version} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples/java/com/azure/messaging/webpubsub/chat/ReadmeSamples.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples/java/com/azure/messaging/webpubsub/chat/ReadmeSamples.java new file mode 100644 index 000000000000..ef5d31b99fc8 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples/java/com/azure/messaging/webpubsub/chat/ReadmeSamples.java @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// Code generated by Microsoft (R) TypeSpec Code Generator. + +package com.azure.messaging.webpubsub.chat; + +public final class ReadmeSamples { + public void readmeSamples() { + // BEGIN: com.azure.messaging.webpubsub.chat.readme + // END: com.azure.messaging.webpubsub.chat.readme + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples/java/com/azure/messaging/webpubsub/chat/WebPubSubChatSamples.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples/java/com/azure/messaging/webpubsub/chat/WebPubSubChatSamples.java new file mode 100644 index 000000000000..bcb50ea90d32 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/samples/java/com/azure/messaging/webpubsub/chat/WebPubSubChatSamples.java @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.identity.DefaultAzureCredentialBuilder; +import com.azure.messaging.webpubsub.chat.models.BuiltInChatRoles; +import com.azure.messaging.webpubsub.chat.models.ChatPermission; +import com.azure.messaging.webpubsub.chat.models.ChatRole; +import com.azure.messaging.webpubsub.chat.models.ChatRoom; +import com.azure.messaging.webpubsub.chat.models.ChatRoomMember; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.HumanChatUser; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; + +import java.time.Duration; +import java.util.Arrays; + +/** Code snippets used by the package README. */ +public final class WebPubSubChatSamples { + /** Creates a client from a connection string. */ + public void createClientWithConnectionString() { + // BEGIN: readme-sample-createChatClientWithConnectionString + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .connectionString("") + .hub("chat") + .buildClient(); + // END: readme-sample-createChatClientWithConnectionString + } + + /** Creates a client from an endpoint and access key. */ + public void createClientWithKey() { + // BEGIN: readme-sample-createChatClientWithKey + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .endpoint("https://.webpubsub.azure.com") + .hub("chat") + .credential(new AzureKeyCredential("")) + .buildClient(); + // END: readme-sample-createChatClientWithKey + } + + /** Creates a client using Microsoft Entra ID. */ + public void createClientWithEntraId() { + // BEGIN: readme-sample-createChatClientWithEntraId + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .endpoint("https://.webpubsub.azure.com") + .hub("chat") + .credential(new DefaultAzureCredentialBuilder().build()) + .buildClient(); + // END: readme-sample-createChatClientWithEntraId + } + + /** Generates a token for a Chat client connection. */ + public void getClientAccessToken() { + WebPubSubChatServiceClient client = createClient(); + + // BEGIN: readme-sample-getChatClientAccessToken + WebPubSubClientAccessToken accessToken = client.getClientAccessToken( + new GetClientAccessTokenOptions().setUserId("alice").setExpiresAfter(Duration.ofHours(1))); + String clientConnectionUrl = accessToken.getUrl(); + // END: readme-sample-getChatClientAccessToken + } + + /** Creates and lists a custom Chat role. */ + public void manageRoles() { + WebPubSubChatServiceClient client = createClient(); + + // BEGIN: readme-sample-manageChatRoles + ChatRole moderator = new ChatRole(Arrays.asList(ChatPermission.ROOM_HISTORY, + ChatPermission.ROOM_REMOVE_USER, ChatPermission.ROOM_PUBLISH_MESSAGE)); + client.createOrReplaceRole("room.moderator", moderator); + + client.listRoles().forEach(role -> System.out.println(role.getName())); + client.deleteRole("room.moderator"); + // END: readme-sample-manageChatRoles + } + + /** Creates a room and assigns a member. */ + public void manageRooms() { + WebPubSubChatServiceClient client = createClient(); + + // BEGIN: readme-sample-manageChatRooms + client.createOrReplaceRole("user.room_creator", + new ChatRole(Arrays.asList(ChatPermission.USER_CREATE_ROOM))); + client.createOrReplaceRole("room.contributor", + new ChatRole(Arrays.asList(ChatPermission.ROOM_PUBLISH_MESSAGE))); + client.createOrReplaceUser("alice", new HumanChatUser("Alice", "user.room_creator")); + + ChatRoom room = client.createOrReplaceRoom("general", new ChatRoom("General")); + ChatRoomMember member = client.createOrReplaceRoomMember( + room.getId(), "alice", new ChatRoomMember("room.contributor")); + System.out.printf("%s: %s%n", member.getUserId(), member.getRoleName()); + + client.deleteRoom(room.getId()); + client.deleteUser("alice"); + client.deleteRole("room.contributor"); + client.deleteRole("user.room_creator"); + // END: readme-sample-manageChatRooms + } + + /** Lists persisted messages in a room's default conversation. */ + public void listMessages() { + WebPubSubChatServiceClient client = createClient(); + + // BEGIN: readme-sample-listChatMessages + ChatRoom room = client.getRoom("general"); + client.listMessages(room.getDefaultConversation()).forEach(message -> + System.out.printf("%s: %s%n", message.getCreatedBy(), message.getContent().getText())); + // END: readme-sample-listChatMessages + } + + /** Creates an asynchronous client and lists roles. */ + public void createAsyncClient() { + // BEGIN: readme-sample-createAsyncChatClient + WebPubSubChatServiceAsyncClient asyncClient = new WebPubSubChatServiceClientBuilder() + .connectionString("") + .hub("chat") + .buildAsyncClient(); + + asyncClient.listRoles().subscribe(role -> System.out.println(role.getName())); + // END: readme-sample-createAsyncChatClient + } + + /** Reads the built-in role and permission values. */ + public void builtInValues() { + // BEGIN: readme-sample-chatBuiltInValues + String memberRole = BuiltInChatRoles.ROOM_MEMBER; + ChatPermission publishPermission = ChatPermission.ROOM_PUBLISH_MESSAGE; + // END: readme-sample-chatBuiltInValues + } + + private static WebPubSubChatServiceClient createClient() { + return new WebPubSubChatServiceClientBuilder().connectionString("") + .hub("chat") + .buildClient(); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatMessageSeeder.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatMessageSeeder.java new file mode 100644 index 000000000000..7b777ebcb07f --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatMessageSeeder.java @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import reactor.core.publisher.Mono; +import reactor.core.publisher.Sinks; +import reactor.netty.http.client.HttpClient; +import reactor.netty.http.client.WebsocketClientSpec; + +import java.time.Duration; +import java.util.UUID; + +final class ChatMessageSeeder { + private static final Duration TIMEOUT = Duration.ofSeconds(30); + + private ChatMessageSeeder() { + } + + static void sendTextMessage(String clientAccessUrl, String conversationId, String content) { + String loginInvocationId = UUID.randomUUID().toString(); + String sendInvocationId = UUID.randomUUID().toString(); + String loginFrame = "{\"type\":\"invoke\",\"invocationId\":\"" + loginInvocationId + + "\",\"target\":\"event\",\"event\":\"chat.login\",\"dataType\":\"text\",\"data\":\"\"}"; + String sendFrame = "{\"type\":\"invoke\",\"invocationId\":\"" + sendInvocationId + + "\",\"target\":\"event\",\"event\":\"chat.sendTextMessage\",\"dataType\":\"json\"," + + "\"data\":{\"conversation\":{\"conversationId\":\"" + escape(conversationId) + "\"},\"content\":\"" + + escape(content) + "\"}}"; + Sinks.Many outboundFrames = Sinks.many().unicast().onBackpressureBuffer(); + + HttpClient.create() + .websocket(WebsocketClientSpec.builder().protocols("json.webpubsub.azure.v1").build()) + .uri(clientAccessUrl) + .handle((inbound, outbound) -> Mono.when(outbound.sendString(outboundFrames.asFlux()).then(), + inbound.receive().asString().handle((message, sink) -> { + if (message.contains("\"type\":\"system\"") && message.contains("\"event\":\"connected\"")) { + outboundFrames.tryEmitNext(loginFrame); + } else if (message.contains("\"invocationId\":\"" + loginInvocationId + "\"")) { + if (message.contains("\"success\":true")) { + outboundFrames.tryEmitNext(sendFrame); + } else { + outboundFrames.tryEmitComplete(); + sink.error(new IllegalStateException("Chat login invocation failed: " + message)); + } + } else if (message.contains("\"invocationId\":\"" + sendInvocationId + "\"")) { + outboundFrames.tryEmitComplete(); + if (message.contains("\"success\":true")) { + sink.complete(); + } else { + sink.error(new IllegalStateException("Chat message invocation failed: " + message)); + } + } + }).then())) + .then() + .block(TIMEOUT); + } + + private static String escape(String value) { + return value.replace("\\", "\\\\").replace("\"", "\\\""); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceAsyncClientLiveTests.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceAsyncClientLiveTests.java new file mode 100644 index 000000000000..385c261f0a98 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceAsyncClientLiveTests.java @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.http.rest.PagedResponse; +import com.azure.core.test.TestMode; +import com.azure.messaging.webpubsub.chat.models.BuiltInChatRoles; +import com.azure.messaging.webpubsub.chat.models.ChatConversation; +import com.azure.messaging.webpubsub.chat.models.ChatMessage; +import com.azure.messaging.webpubsub.chat.models.ChatPermission; +import com.azure.messaging.webpubsub.chat.models.ChatRole; +import com.azure.messaging.webpubsub.chat.models.ChatRoom; +import com.azure.messaging.webpubsub.chat.models.ChatRoomMember; +import com.azure.messaging.webpubsub.chat.models.ChatUser; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.HumanChatUser; +import com.azure.messaging.webpubsub.chat.models.MessageContent; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ChatServiceAsyncClientLiveTests extends ChatServiceClientTestBase { + @Test + public void canManageRolesAndPagination() { + String firstRoleName = testResourceNamer.randomName("user.java-async-test-", 55); + String secondRoleName = testResourceNamer.randomName("room.java-async-test-", 55); + + try { + ChatRole createdRole + = asyncClient + .createOrReplaceRole(firstRoleName, + new ChatRole(Collections.singletonList(ChatPermission.USER_CREATE_ROOM))) + .block(); + assertEquals(firstRoleName, createdRole.getName()); + assertEquals(firstRoleName, asyncClient.getRole(firstRoleName).block().getName()); + + asyncClient + .createOrReplaceRole(secondRoleName, + new ChatRole(Collections.singletonList(ChatPermission.ROOM_PUBLISH_MESSAGE))) + .block(); + List roles = asyncClient.listRoles().collectList().block(); + assertTrue(roles.stream().anyMatch(role -> firstRoleName.equals(role.getName()))); + + List> pages = asyncClient.listRoles().byPage(1).take(2).collectList().block(); + assertFalse(pages.isEmpty()); + PagedResponse firstPage = pages.get(0); + assertFalse(firstPage.getValue().isEmpty()); + if (firstPage.getContinuationToken() != null) { + assertEquals(2, pages.size()); + PagedResponse secondPage = pages.get(1); + assertFalse(secondPage.getValue().isEmpty()); + assertFalse(firstPage.getValue().get(0).getName().equals(secondPage.getValue().get(0).getName())); + } + } finally { + cleanup(() -> asyncClient.deleteRole(firstRoleName).block()); + cleanup(() -> asyncClient.deleteRole(secondRoleName).block()); + } + } + + @Test + public void canManageRoomsAndReadEmptyConversation() { + String roomId = testResourceNamer.randomName("java-async-test-room-", 55); + + try { + ChatRoom createdRoom + = asyncClient.createOrReplaceRoom(roomId, new ChatRoom("Java async test room")).block(); + assertEquals(roomId, createdRoom.getId()); + assertEquals("Java async test room", asyncClient.getRoom(roomId).block().getTitle()); + + ChatConversation conversation = asyncClient.getConversation(createdRoom.getDefaultConversation()).block(); + assertEquals(createdRoom.getDefaultConversation(), conversation.getId()); + assertEquals(roomId, conversation.getParentRoom()); + assertTrue(asyncClient.listMessages(conversation.getId()).collectList().block().isEmpty()); + assertTrue(asyncClient.listRoomMembers(roomId).collectList().block().isEmpty()); + } finally { + cleanup(() -> asyncClient.deleteRoom(roomId).block()); + } + } + + @Test + public void canManageUserRoomAndMember() { + String suffix = testResourceNamer.randomName("java", 20); + String userId = "java-async-test-user-" + suffix; + String roomId = "java-async-test-room-" + suffix; + + try { + ChatUser user = asyncClient + .createOrReplaceUser(userId, new HumanChatUser("Java test user", BuiltInChatRoles.USER_NORMAL)) + .block(); + assertEquals(userId, user.getId()); + assertEquals(userId, asyncClient.getUser(userId).block().getId()); + + ChatRoom room = asyncClient.createOrReplaceRoom(roomId, new ChatRoom("Java test room")).block(); + assertEquals(roomId, room.getId()); + + ChatRoomMember member = asyncClient + .createOrReplaceRoomMember(roomId, userId, new ChatRoomMember(BuiltInChatRoles.ROOM_MEMBER)) + .block(); + assertEquals(userId, member.getUserId()); + assertEquals(BuiltInChatRoles.ROOM_MEMBER, member.getRoleName()); + assertTrue(asyncClient.listRoomMembers(roomId) + .collectList() + .block() + .stream() + .anyMatch(item -> userId.equals(item.getUserId()))); + asyncClient.deleteRoomMember(roomId, userId).block(); + } finally { + cleanup(() -> asyncClient.deleteRoomMember(roomId, userId).block()); + cleanup(() -> asyncClient.deleteRoom(roomId).block()); + cleanup(() -> asyncClient.deleteUser(userId).block()); + } + } + + @Test + public void canListUpdateAndDeleteMessages() { + String suffix = testResourceNamer.randomName("java", 20); + String userId = "java-async-message-user-" + suffix; + String roomId = "java-async-message-room-" + suffix; + String messageText = "Java async live test message " + suffix; + String conversationId = null; + String messageId = null; + + try { + asyncClient + .createOrReplaceUser(userId, + new HumanChatUser("Java async message test user", BuiltInChatRoles.USER_NORMAL)) + .block(); + ChatRoom room + = asyncClient.createOrReplaceRoom(roomId, new ChatRoom("Java async message test room")).block(); + conversationId = room.getDefaultConversation(); + asyncClient.createOrReplaceRoomMember(roomId, userId, new ChatRoomMember(BuiltInChatRoles.ROOM_MEMBER)) + .block(); + + WebPubSubClientAccessToken accessToken + = entraAsyncClient.getClientAccessToken(new GetClientAccessTokenOptions().setUserId(userId)).block(); + assertNotNull(accessToken.getToken()); + assertNotNull(accessToken.getUrl()); + if (getTestMode() != TestMode.PLAYBACK) { + ChatMessageSeeder.sendTextMessage(accessToken.getUrl(), conversationId, messageText); + } + + ChatMessage createdMessage = asyncClient.listMessages(conversationId) + .filter(message -> userId.equals(message.getCreatedBy()) + && messageText.equals(message.getContent().getText())) + .blockFirst(); + assertNotNull(createdMessage); + messageId = createdMessage.getId(); + + ChatMessage updatedText + = asyncClient + .updateMessage(conversationId, messageId, + new ChatMessage().setCreatedBy(userId) + .setContent(new MessageContent().setText(messageText + " updated"))) + .block(); + assertEquals(messageText + " updated", updatedText.getContent().getText()); + + byte[] binary = new byte[] { 0, 1, 2, (byte) 254, (byte) 255 }; + ChatMessage updatedBinary + = asyncClient + .updateMessage(conversationId, messageId, + new ChatMessage().setCreatedBy(userId).setContent(new MessageContent().setBinary(binary))) + .block(); + assertArrayEquals(binary, updatedBinary.getContent().getBinary()); + asyncClient.deleteMessage(conversationId, messageId).block(); + } finally { + String finalConversationId = conversationId; + String finalMessageId = messageId; + if (finalConversationId != null && finalMessageId != null) { + cleanup(() -> asyncClient.deleteMessage(finalConversationId, finalMessageId).block()); + } + cleanup(() -> asyncClient.deleteRoomMember(roomId, userId).block()); + cleanup(() -> asyncClient.deleteRoom(roomId).block()); + cleanup(() -> asyncClient.deleteUser(userId).block()); + } + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceClientLiveTests.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceClientLiveTests.java new file mode 100644 index 000000000000..960bd7a5ef75 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceClientLiveTests.java @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.exception.HttpResponseException; +import com.azure.core.http.MatchConditions; +import com.azure.core.http.rest.PagedResponse; +import com.azure.core.test.TestMode; +import com.azure.messaging.webpubsub.chat.models.BuiltInChatRoles; +import com.azure.messaging.webpubsub.chat.models.ChatConversation; +import com.azure.messaging.webpubsub.chat.models.ChatMessage; +import com.azure.messaging.webpubsub.chat.models.ChatPermission; +import com.azure.messaging.webpubsub.chat.models.ChatRole; +import com.azure.messaging.webpubsub.chat.models.ChatRoom; +import com.azure.messaging.webpubsub.chat.models.ChatRoomMember; +import com.azure.messaging.webpubsub.chat.models.ChatUser; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.HumanChatUser; +import com.azure.messaging.webpubsub.chat.models.MessageContent; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ChatServiceClientLiveTests extends ChatServiceClientTestBase { + @Test + public void canManageRolesWithConditionsAndPagination() { + String firstRoleName = testResourceNamer.randomName("user.java-test-", 50); + String secondRoleName = testResourceNamer.randomName("room.java-test-", 50); + + try { + ChatRole createdRole = client.createOrReplaceRole(firstRoleName, + new ChatRole(Collections.singletonList(ChatPermission.USER_CREATE_ROOM))); + assertEquals(firstRoleName, createdRole.getName()); + assertEquals(ChatPermission.USER_CREATE_ROOM, client.getRole(firstRoleName).getPermissions().get(0)); + + ChatRole replacedRole = client.createOrReplaceRole(firstRoleName, + new ChatRole(Arrays.asList(ChatPermission.USER_CREATE_ROOM, ChatPermission.USER_FETCH_ALL_ROOMS)), + new MatchConditions().setIfMatch(createdRole.getEtag())); + assertFalse(createdRole.getEtag().equals(replacedRole.getEtag())); + HttpResponseException staleEtag = assertThrows(HttpResponseException.class, + () -> client.createOrReplaceRole(firstRoleName, + new ChatRole(Collections.singletonList(ChatPermission.USER_CREATE_ROOM)), + new MatchConditions().setIfMatch(createdRole.getEtag()))); + assertEquals(412, staleEtag.getResponse().getStatusCode()); + + client.createOrReplaceRole(secondRoleName, + new ChatRole(Collections.singletonList(ChatPermission.ROOM_PUBLISH_MESSAGE)), + new MatchConditions().setIfNoneMatch("*")); + HttpResponseException alreadyExists = assertThrows(HttpResponseException.class, + () -> client.createOrReplaceRole(secondRoleName, + new ChatRole(Collections.singletonList(ChatPermission.ROOM_HISTORY)), + new MatchConditions().setIfNoneMatch("*"))); + assertEquals(412, alreadyExists.getResponse().getStatusCode()); + + assertTrue(client.listRoles().stream().anyMatch(role -> firstRoleName.equals(role.getName()))); + Iterator> pages = client.listRoles().iterableByPage(1).iterator(); + PagedResponse firstPage = pages.next(); + assertFalse(firstPage.getValue().isEmpty()); + if (firstPage.getContinuationToken() != null) { + assertTrue(pages.hasNext()); + PagedResponse secondPage = pages.next(); + assertFalse(secondPage.getValue().isEmpty()); + assertFalse(firstPage.getValue().get(0).getName().equals(secondPage.getValue().get(0).getName())); + } + } finally { + cleanup(() -> client.deleteRole(firstRoleName)); + cleanup(() -> client.deleteRole(secondRoleName)); + } + } + + @Test + public void canManageRoomsAndReadEmptyConversation() { + String roomId = testResourceNamer.randomName("java-test-room-", 50); + + try { + ChatRoom createdRoom = client.createOrReplaceRoom(roomId, new ChatRoom("Java test room")); + assertEquals(roomId, createdRoom.getId()); + assertEquals("Java test room", client.getRoom(roomId).getTitle()); + + ChatConversation conversation = client.getConversation(createdRoom.getDefaultConversation()); + assertEquals(createdRoom.getDefaultConversation(), conversation.getId()); + assertEquals(roomId, conversation.getParentRoom()); + assertFalse(client.listMessages(conversation.getId()).stream().findAny().isPresent()); + assertFalse(client.listRoomMembers(roomId).stream().findAny().isPresent()); + } finally { + cleanup(() -> client.deleteRoom(roomId)); + } + } + + @Test + public void canManageUsersAndRoomMembers() { + String suffix = testResourceNamer.randomName("java", 20); + String userId = "java-test-user-" + suffix; + String roomId = "java-test-room-" + suffix; + + try { + ChatUser createdUser + = client.createOrReplaceUser(userId, new HumanChatUser("Java test user", BuiltInChatRoles.USER_NORMAL)); + assertEquals(userId, createdUser.getId()); + assertEquals(userId, client.getUser(userId).getId()); + + client.createOrReplaceRoom(roomId, new ChatRoom("Java member test room")); + ChatRoomMember member + = client.createOrReplaceRoomMember(roomId, userId, new ChatRoomMember(BuiltInChatRoles.ROOM_MEMBER)); + assertEquals(userId, member.getUserId()); + assertTrue(client.listRoomMembers(roomId).stream().anyMatch(item -> userId.equals(item.getUserId()))); + client.deleteRoomMember(roomId, userId); + } finally { + cleanup(() -> client.deleteRoomMember(roomId, userId)); + cleanup(() -> client.deleteRoom(roomId)); + cleanup(() -> client.deleteUser(userId)); + } + } + + @Test + public void canListUpdateAndDeleteMessages() { + String suffix = testResourceNamer.randomName("java", 20); + String userId = "java-test-message-user-" + suffix; + String roomId = "java-test-message-room-" + suffix; + String messageText = "Java live test message " + suffix; + String conversationId = null; + String messageId = null; + + try { + client.createOrReplaceUser(userId, + new HumanChatUser("Java message test user", BuiltInChatRoles.USER_NORMAL)); + ChatRoom room = client.createOrReplaceRoom(roomId, new ChatRoom("Java message test room")); + conversationId = room.getDefaultConversation(); + client.createOrReplaceRoomMember(roomId, userId, new ChatRoomMember(BuiltInChatRoles.ROOM_MEMBER)); + + WebPubSubClientAccessToken accessToken + = entraClient.getClientAccessToken(new GetClientAccessTokenOptions().setUserId(userId)); + assertNotNull(accessToken.getToken()); + assertNotNull(accessToken.getUrl()); + + if (getTestMode() != TestMode.PLAYBACK) { + ChatMessageSeeder.sendTextMessage(accessToken.getUrl(), conversationId, messageText); + } + ChatMessage createdMessage = client.listMessages(conversationId) + .stream() + .filter(message -> userId.equals(message.getCreatedBy()) + && messageText.equals(message.getContent().getText())) + .findFirst() + .orElseThrow(() -> new AssertionError("The seeded Chat message was not found.")); + messageId = createdMessage.getId(); + + ChatMessage updatedText + = client.updateMessage(conversationId, messageId, new ChatMessage().setCreatedBy(userId) + .setContent(new MessageContent().setText(messageText + " updated"))); + assertEquals(messageText + " updated", updatedText.getContent().getText()); + + byte[] binary = new byte[] { 0, 1, 2, (byte) 254, (byte) 255 }; + ChatMessage updatedBinary = client.updateMessage(conversationId, messageId, + new ChatMessage().setCreatedBy(userId).setContent(new MessageContent().setBinary(binary))); + assertArrayEquals(binary, updatedBinary.getContent().getBinary()); + client.deleteMessage(conversationId, messageId); + } finally { + String finalConversationId = conversationId; + String finalMessageId = messageId; + if (finalConversationId != null && finalMessageId != null) { + cleanup(() -> client.deleteMessage(finalConversationId, finalMessageId)); + } + cleanup(() -> client.deleteRoomMember(roomId, userId)); + cleanup(() -> client.deleteRoom(roomId)); + cleanup(() -> client.deleteUser(userId)); + } + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceClientTestBase.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceClientTestBase.java new file mode 100644 index 000000000000..ab8ddc7a6ff0 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/ChatServiceClientTestBase.java @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.http.HttpClient; +import com.azure.core.test.TestMode; +import com.azure.core.test.TestProxyTestBase; +import com.azure.core.test.models.TestProxySanitizer; +import com.azure.core.test.models.TestProxySanitizerType; +import com.azure.core.test.utils.MockTokenCredential; +import com.azure.core.util.Configuration; +import com.azure.identity.DefaultAzureCredentialBuilder; + +import java.util.Collections; + +abstract class ChatServiceClientTestBase extends TestProxyTestBase { + private static final String CONNECTION_STRING = Configuration.getGlobalConfiguration() + .get("WPS_CHAT_CONNECTION_STRING", + "Endpoint=https://testendpoint.webpubsubdev.azure.com;AccessKey=LoremIpsumDolorSitAmetConsectetur;Version=1.0;"); + private static final String ENDPOINT = Configuration.getGlobalConfiguration() + .get("WPS_CHAT_ENDPOINT", "https://testendpoint.webpubsubdev.azure.com"); + private static final String HUB = "chat"; + + protected WebPubSubChatServiceClient client; + protected WebPubSubChatServiceAsyncClient asyncClient; + protected WebPubSubChatServiceClient entraClient; + protected WebPubSubChatServiceAsyncClient entraAsyncClient; + + @Override + protected void beforeTest() { + if (getTestMode() != TestMode.LIVE) { + // These values are generated by testResourceNamer and are needed to correlate playback requests. + interceptorManager.removeSanitizers("AZSDK3430", "AZSDK3433", "AZSDK3442", "AZSDK3490", "AZSDK3493"); + interceptorManager.addSanitizers( + Collections.singletonList(new TestProxySanitizer("https://(?[^/]+[.]webpubsub[.]azure[.]com)", + "REDACTED", TestProxySanitizerType.BODY_REGEX).setGroupForReplace("host"))); + } + + HttpClient httpClient + = getHttpClientOrUsePlayback(getHttpClients().findFirst().orElse(HttpClient.createDefault())); + WebPubSubChatServiceClientBuilder builder + = new WebPubSubChatServiceClientBuilder().connectionString(CONNECTION_STRING) + .hub(HUB) + .httpClient(httpClient); + + if (getTestMode() == TestMode.RECORD) { + builder.addPolicy(interceptorManager.getRecordPolicy()); + } + + client = builder.buildClient(); + asyncClient = builder.buildAsyncClient(); + + WebPubSubChatServiceClientBuilder entraBuilder = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .credential(getTestMode() == TestMode.PLAYBACK + ? new MockTokenCredential() + : new DefaultAzureCredentialBuilder().build()) + .hub(HUB) + .httpClient(httpClient); + if (getTestMode() == TestMode.RECORD) { + entraBuilder.addPolicy(interceptorManager.getRecordPolicy()); + } + entraClient = entraBuilder.buildClient(); + entraAsyncClient = entraBuilder.buildAsyncClient(); + } + + protected static void cleanup(Runnable cleanup) { + try { + cleanup.run(); + } catch (RuntimeException ignored) { + // Preserve the original test failure while making a best effort to remove live resources. + } + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/WebPubSubChatClientAccessTokenTests.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/WebPubSubChatClientAccessTokenTests.java new file mode 100644 index 000000000000..3526f81a2f3d --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/WebPubSubChatClientAccessTokenTests.java @@ -0,0 +1,186 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.HttpRequest; +import com.azure.core.test.http.MockHttpResponse; +import com.azure.core.test.utils.MockTokenCredential; +import com.azure.messaging.webpubsub.chat.models.GetClientAccessTokenOptions; +import com.azure.messaging.webpubsub.chat.models.WebPubSubClientAccessToken; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class WebPubSubChatClientAccessTokenTests { + private static final String ENDPOINT = "https://example.webpubsub.azure.com"; + private static final String KEY = "01234567890123456789012345678901"; + + @Test + public void keyCredentialGeneratesChatTokenLocally() throws ParseException { + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new AzureKeyCredential(KEY)) + .httpClient(request -> Mono.error(new AssertionError("Local token generation must not send a request."))) + .buildClient(); + + Instant before = Instant.now(); + WebPubSubClientAccessToken token + = client.getClientAccessToken(new GetClientAccessTokenOptions().setUserId("alice")); + + assertNotNull(token.getToken()); + assertEquals("wss://example.webpubsub.azure.com/client/hubs/chat?access_token=" + token.getToken(), + token.getUrl()); + JWTClaimsSet claims = SignedJWT.parse(token.getToken()).getJWTClaimsSet(); + assertEquals("alice", claims.getSubject()); + assertEquals(Arrays.asList("webpubsub.getGroupState", "webpubsub.setGroupState"), claims.getClaim("role")); + assertEquals(ENDPOINT + "/client/hubs/chat", claims.getAudience().get(0)); + assertTrue(claims.getExpirationTime().toInstant().isAfter(before.plus(Duration.ofMinutes(59)))); + assertTrue(claims.getExpirationTime().toInstant().isBefore(before.plus(Duration.ofMinutes(61)))); + } + + @Test + public void asyncKeyCredentialUsesSameTokenSemantics() throws ParseException { + WebPubSubChatServiceAsyncClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new AzureKeyCredential(KEY)) + .httpClient(request -> Mono.error(new AssertionError("Local token generation must not send a request."))) + .buildAsyncClient(); + + WebPubSubClientAccessToken token + = client.getClientAccessToken(new GetClientAccessTokenOptions().setUserId("alice")).block(); + + assertNotNull(token); + JWTClaimsSet claims = SignedJWT.parse(token.getToken()).getJWTClaimsSet(); + assertEquals("alice", claims.getSubject()); + assertEquals(Arrays.asList("webpubsub.getGroupState", "webpubsub.setGroupState"), claims.getClaim("role")); + } + + @Test + public void connectionStringGeneratesTokenLocally() { + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .connectionString("Endpoint=https://example.webpubsub.azure.com;AccessKey=" + KEY + ";Port=8443") + .hub("chat") + .httpClient(request -> Mono.error(new AssertionError("Local token generation must not send a request."))) + .buildClient(); + + WebPubSubClientAccessToken token = client.getClientAccessToken(new GetClientAccessTokenOptions()); + + assertTrue(token.getUrl().startsWith("wss://example.webpubsub.azure.com:8443/client/hubs/chat?access_token=")); + } + + @Test + public void signingFailureReturnsNullToken() { + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new AzureKeyCredential("short-key")) + .buildClient(); + + WebPubSubClientAccessToken token = client.getClientAccessToken(new GetClientAccessTokenOptions()); + + assertNull(token.getToken()); + assertEquals("wss://example.webpubsub.azure.com/client/hubs/chat?access_token=null", token.getUrl()); + } + + @Test + public void tokenCredentialCallsGenerateTokenOperation() { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = createTokenCredentialClient(sentRequest, null); + + WebPubSubClientAccessToken token = client.getClientAccessToken( + new GetClientAccessTokenOptions().setUserId("alice").setExpiresAfter(Duration.ofMinutes(30))); + + assertEquals("server-token", token.getToken()); + assertEquals("wss://example.webpubsub.azure.com/client/hubs/chat?access_token=server-token", token.getUrl()); + assertEquals("/api/hubs/chat/:generateToken", sentRequest.get().getUrl().getPath()); + String query = sentRequest.get().getUrl().getQuery(); + assertTrue(query.contains("userId=alice")); + assertTrue(query.contains("minutesToExpire=30")); + assertTrue(query.contains("role=webpubsub.getGroupState")); + assertTrue(query.contains("role=webpubsub.setGroupState")); + assertTrue(query.contains("api-version=2024-12-01")); + assertTrue(query.contains("clientType=default")); + assertEquals("Bearer mockToken", sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION)); + } + + @Test + public void asyncTokenCredentialCallsGenerateTokenOperation() { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceAsyncClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new MockTokenCredential()) + .httpClient(request -> Mono.defer(() -> { + sentRequest.set(request); + byte[] body = "{\"token\":\"server-token\"}".getBytes(StandardCharsets.UTF_8); + return Mono.just(new MockHttpResponse(request, 200, body)); + })) + .buildAsyncClient(); + + WebPubSubClientAccessToken token + = client.getClientAccessToken(new GetClientAccessTokenOptions().setUserId("alice")).block(); + + assertNotNull(token); + assertEquals("server-token", token.getToken()); + assertEquals("/api/hubs/chat/:generateToken", sentRequest.get().getUrl().getPath()); + assertTrue(sentRequest.get().getUrl().getQuery().contains("userId=alice")); + assertTrue(sentRequest.get().getUrl().getQuery().contains("minutesToExpire=60")); + } + + @Test + public void tokenCredentialUsesReverseProxyForGenerateTokenOperation() { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = createTokenCredentialClient(sentRequest, "https://proxy.example/gateway"); + + client.getClientAccessToken(new GetClientAccessTokenOptions()); + + assertEquals("proxy.example", sentRequest.get().getUrl().getHost()); + assertEquals("/gateway/api/hubs/chat/:generateToken", sentRequest.get().getUrl().getPath()); + assertEquals("Bearer mockToken", sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION)); + } + + @Test + public void validatesTokenOptions() { + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new AzureKeyCredential(KEY)) + .buildClient(); + + assertThrows(NullPointerException.class, () -> client.getClientAccessToken(null)); + assertThrows(NullPointerException.class, + () -> client.getClientAccessToken(new GetClientAccessTokenOptions().setExpiresAfter(null))); + assertThrows(IllegalArgumentException.class, () -> client + .getClientAccessToken(new GetClientAccessTokenOptions().setExpiresAfter(Duration.ofSeconds(59)))); + } + + private static WebPubSubChatServiceClient createTokenCredentialClient(AtomicReference sentRequest, + String reverseProxyEndpoint) { + WebPubSubChatServiceClientBuilder builder = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new MockTokenCredential()) + .httpClient(request -> Mono.defer(() -> { + sentRequest.set(request); + byte[] body = "{\"token\":\"server-token\"}".getBytes(StandardCharsets.UTF_8); + return Mono.just(new MockHttpResponse(request, 200, body)); + })); + if (reverseProxyEndpoint != null) { + builder.reverseProxyEndpoint(reverseProxyEndpoint); + } + return builder.buildClient(); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilderTests.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilderTests.java new file mode 100644 index 000000000000..77eca61933e1 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/WebPubSubChatServiceClientBuilderTests.java @@ -0,0 +1,171 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat; + +import com.azure.core.credential.AzureKeyCredential; +import com.azure.core.exception.ResourceNotFoundException; +import com.azure.core.http.HttpHeaderName; +import com.azure.core.http.HttpRequest; +import com.azure.core.test.http.MockHttpResponse; +import com.azure.core.test.utils.MockTokenCredential; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; + +import java.text.ParseException; +import java.time.Instant; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class WebPubSubChatServiceClientBuilderTests { + private static final String ENDPOINT = "https://example.webpubsub.azure.com"; + private static final String FIRST_KEY = "01234567890123456789012345678901"; + private static final String SECOND_KEY = "abcdefghijklmnopqrstuvwxyzABCDEF"; + + @Test + public void keyCredentialAuthenticatesChatRequest() throws ParseException { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = createClient(new AzureKeyCredential(FIRST_KEY), sentRequest); + + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + + String authorization = sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION); + assertNotNull(authorization); + assertTrue(authorization.startsWith("Bearer ")); + JWTClaimsSet claims = SignedJWT.parse(authorization.substring("Bearer ".length())).getJWTClaimsSet(); + assertEquals(sentRequest.get().getUrl().toString(), claims.getAudience().get(0)); + assertTrue(claims.getExpirationTime().toInstant().isAfter(Instant.now())); + } + + @Test + public void keyCredentialUpdateChangesSubsequentTokens() { + AzureKeyCredential credential = new AzureKeyCredential(FIRST_KEY); + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = createClient(credential, sentRequest); + + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + String firstAuthorization = sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION); + credential.update(SECOND_KEY); + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + + assertNotEquals(firstAuthorization, sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION)); + } + + @Test + public void signingFailureOmitsAuthorizationHeader() { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = createClient(new AzureKeyCredential("short-key"), sentRequest); + + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + + assertNull(sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION)); + } + + @Test + public void tokenCredentialAuthenticationIsPreserved() { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new MockTokenCredential()) + .httpClient(request -> Mono.defer(() -> { + sentRequest.set(request); + return Mono.just(new MockHttpResponse(request, 404)); + })) + .buildClient(); + + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + + assertEquals("Bearer mockToken", sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION)); + } + + @Test + public void connectionStringConfiguresEndpointPortAndCredential() throws ParseException { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder() + .connectionString("Endpoint=https://example.webpubsub.azure.com;AccessKey=" + FIRST_KEY + ";Port=8443") + .hub("chat") + .httpClient(request -> Mono.defer(() -> { + sentRequest.set(request); + return Mono.just(new MockHttpResponse(request, 404)); + })) + .buildClient(); + + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + + assertEquals(8443, sentRequest.get().getUrl().getPort()); + String authorization = sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION); + JWTClaimsSet claims = SignedJWT.parse(authorization.substring("Bearer ".length())).getJWTClaimsSet(); + assertEquals(sentRequest.get().getUrl().toString(), claims.getAudience().get(0)); + } + + @Test + public void connectionStringRejectsDuplicateKeys() { + assertThrows(IllegalArgumentException.class, () -> new WebPubSubChatServiceClientBuilder() + .connectionString("Endpoint=" + ENDPOINT + ";endpoint=" + ENDPOINT + ";AccessKey=" + FIRST_KEY)); + } + + @Test + public void connectionStringRejectsMissingRequiredKeys() { + assertThrows(IllegalArgumentException.class, + () -> new WebPubSubChatServiceClientBuilder().connectionString("Endpoint=" + ENDPOINT)); + assertThrows(IllegalArgumentException.class, + () -> new WebPubSubChatServiceClientBuilder().connectionString("AccessKey=" + FIRST_KEY)); + } + + @Test + public void reverseProxyPreservesJavaServiceBehavior() throws ParseException { + AtomicReference sentRequest = new AtomicReference<>(); + WebPubSubChatServiceClient client = new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(new AzureKeyCredential(FIRST_KEY)) + .reverseProxyEndpoint("https://proxy.example/gateway") + .httpClient(request -> Mono.defer(() -> { + sentRequest.set(request); + return Mono.just(new MockHttpResponse(request, 404)); + })) + .buildClient(); + + assertThrows(ResourceNotFoundException.class, () -> client.getRole("room.reader")); + + assertEquals("proxy.example", sentRequest.get().getUrl().getHost()); + assertTrue(sentRequest.get().getUrl().getPath().startsWith("/gateway/api/hubs/chat/chat/roles/")); + assertEquals("api-version=2026-02-01-preview", sentRequest.get().getUrl().getQuery()); + String authorization = sentRequest.get().getHeaders().getValue(HttpHeaderName.AUTHORIZATION); + JWTClaimsSet claims = SignedJWT.parse(authorization.substring("Bearer ".length())).getJWTClaimsSet(); + assertEquals(ENDPOINT + "/api/hubs/chat/chat/roles/room.reader?api-version=2026-02-01-preview", + claims.getAudience().get(0)); + } + + @Test + public void validatesBuilderInputs() { + assertThrows(NullPointerException.class, + () -> new WebPubSubChatServiceClientBuilder().credential((AzureKeyCredential) null)); + assertThrows(IllegalStateException.class, + () -> new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("") + .credential(new AzureKeyCredential(FIRST_KEY)) + .buildClient()); + assertThrows(IllegalStateException.class, + () -> new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT).hub("chat").buildClient()); + } + + private static WebPubSubChatServiceClient createClient(AzureKeyCredential credential, + AtomicReference sentRequest) { + return new WebPubSubChatServiceClientBuilder().endpoint(ENDPOINT) + .hub("chat") + .credential(credential) + .httpClient(request -> Mono.defer(() -> { + sentRequest.set(request); + return Mono.just(new MockHttpResponse(request, 404)); + })) + .buildClient(); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/models/ChatRolesAndPermissionsTests.java b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/models/ChatRolesAndPermissionsTests.java new file mode 100644 index 000000000000..60a373159790 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/src/test/java/com/azure/messaging/webpubsub/chat/models/ChatRolesAndPermissionsTests.java @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.messaging.webpubsub.chat.models; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ChatRolesAndPermissionsTests { + @Test + public void chatRolesHaveExpectedValues() { + assertEquals("user.normal", BuiltInChatRoles.USER_NORMAL); + assertEquals("room.member", BuiltInChatRoles.ROOM_MEMBER); + assertEquals("room.operator", BuiltInChatRoles.ROOM_OPERATOR); + } + + @Test + public void userPermissionsHaveExpectedValues() { + assertEquals("user.create_room", ChatPermission.USER_CREATE_ROOM.toString()); + assertEquals("user.fetch_all_rooms", ChatPermission.USER_FETCH_ALL_ROOMS.toString()); + } + + @Test + public void roomPermissionsHaveExpectedValues() { + assertEquals("room.invite", ChatPermission.ROOM_INVITE.toString()); + assertEquals("room.remove_user", ChatPermission.ROOM_REMOVE_USER.toString()); + assertEquals("room.history", ChatPermission.ROOM_HISTORY.toString()); + assertEquals("room.publish_message", ChatPermission.ROOM_PUBLISH_MESSAGE.toString()); + } +} diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/test-resources.bicep b/sdk/webpubsub/azure-messaging-webpubsub-chat/test-resources.bicep new file mode 100644 index 000000000000..28932f949d41 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/test-resources.bicep @@ -0,0 +1,141 @@ +@description('The base resource name.') +param baseName string = resourceGroup().name + +@description('This is the object id of the service principal used to run tests.') +param testApplicationOid string + +@description('Location of the resource.') +param location string = resourceGroup().location + +var webPubSubName = '${baseName}-chat-e2e' +var chatStorageAccountName = toLower('wpsChat${uniqueString(resourceGroup().id)}') +var webPubSubOwnerRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12cf5a90-567b-43ae-8102-96cf46c7d9b4') +var webPubSubOperatorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') +var blobDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe') +var tableDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3') +var queueDataContributorRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '974c5e8b-45b9-4653-ba55-5f855dd0fb88') + +resource webPubSub 'Microsoft.SignalRService/webPubSub@2025-12-01-preview' = { + name: webPubSubName + location: location + kind: 'WebPubSub' + sku: { + name: 'Standard_S1' + tier: 'Standard' + capacity: 1 + } + identity: { + type: 'SystemAssigned' + } + properties: { + tls: { + clientCertEnabled: false + } + networkACLs: { + defaultAction: 'Deny' + publicNetwork: { + allow: [ 'ServerConnection', 'ClientConnection', 'RESTAPI', 'Trace' ] + } + privateEndpoints: [] + } + publicNetworkAccess: 'Enabled' + disableLocalAuth: false + disableAadAuth: false + } +} + +resource chatStorageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = { + name: chatStorageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + allowBlobPublicAccess: false + allowSharedKeyAccess: false + minimumTlsVersion: 'TLS1_2' + supportsHttpsTrafficOnly: true + } +} + +resource chatBlobDataContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(webPubSub.id, chatStorageAccount.id, blobDataContributorRoleId) + scope: chatStorageAccount + properties: { + roleDefinitionId: blobDataContributorRoleId + principalId: webPubSub.identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource chatTableDataContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(webPubSub.id, chatStorageAccount.id, tableDataContributorRoleId) + scope: chatStorageAccount + properties: { + roleDefinitionId: tableDataContributorRoleId + principalId: webPubSub.identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource chatQueueDataContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(webPubSub.id, chatStorageAccount.id, queueDataContributorRoleId) + scope: chatStorageAccount + properties: { + roleDefinitionId: queueDataContributorRoleId + principalId: webPubSub.identity.principalId + principalType: 'ServicePrincipal' + } +} + +resource chatPersistentStorage 'Microsoft.SignalRService/webPubSub/persistentStorages@2025-12-01-preview' = { + name: 'chatstorage' + parent: webPubSub + properties: { + storageAccount: { + id: chatStorageAccount.id + } + } + dependsOn: [ + chatBlobDataContributorRoleAssignment + chatTableDataContributorRoleAssignment + chatQueueDataContributorRoleAssignment + ] +} + +resource chatHub 'Microsoft.SignalRService/webPubSub/hubs@2025-12-01-preview' = { + name: 'chat' + parent: webPubSub + properties: { + chat: { + mode: 'Enabled' + persistentStorage: { + id: chatPersistentStorage.id + } + } + } +} + +resource webPubSubOwnerRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('owner', webPubSub.id, testApplicationOid) + scope: webPubSub + properties: { + roleDefinitionId: webPubSubOwnerRoleId + principalId: testApplicationOid + principalType: 'ServicePrincipal' + } +} + +resource webPubSubOperatorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('operator', webPubSub.id, testApplicationOid) + scope: webPubSub + properties: { + roleDefinitionId: webPubSubOperatorRoleId + principalId: testApplicationOid + principalType: 'ServicePrincipal' + } +} + +output WPS_CHAT_CONNECTION_STRING string = webPubSub.listKeys().primaryConnectionString +output WPS_CHAT_ENDPOINT string = 'https://${webPubSub.properties.hostName}' \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/tests.yml b/sdk/webpubsub/azure-messaging-webpubsub-chat/tests.yml new file mode 100644 index 000000000000..135d4e52ace4 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/tests.yml @@ -0,0 +1,13 @@ +trigger: none + +extends: + template: /eng/pipelines/templates/stages/archetype-sdk-tests.yml + parameters: + ServiceDirectory: webpubsub/azure-messaging-webpubsub-chat + Artifacts: + - name: azure-messaging-webpubsub-chat + groupId: com.azure + safeName: azuremessagingwebpubsubchat + TimeoutInMinutes: 60 + EnvVars: + AZURE_LOG_LEVEL: 2 \ No newline at end of file diff --git a/sdk/webpubsub/azure-messaging-webpubsub-chat/tsp-location.yaml b/sdk/webpubsub/azure-messaging-webpubsub-chat/tsp-location.yaml new file mode 100644 index 000000000000..6a9e19265df8 --- /dev/null +++ b/sdk/webpubsub/azure-messaging-webpubsub-chat/tsp-location.yaml @@ -0,0 +1,4 @@ +directory: specification/webpubsub/data-plane/WebPubSubChat +commit: c89aaf41901a10fbc0ba6ff25a5f5778cf2c245a +repo: Azure/azure-rest-api-specs +additionalDirectories: diff --git a/sdk/webpubsub/ci.yml b/sdk/webpubsub/ci.yml index c474a94aa867..a20a88f1464f 100644 --- a/sdk/webpubsub/ci.yml +++ b/sdk/webpubsub/ci.yml @@ -40,6 +40,10 @@ parameters: displayName: 'azure-messaging-webpubsub-client' type: boolean default: false +- name: release_azuremessagingwebpubsubchat + displayName: 'azure-messaging-webpubsub-chat' + type: boolean + default: false - name: release_azureresourcemanagerwebpubsub displayName: 'azure-resourcemanager-webpubsub' type: boolean @@ -58,6 +62,10 @@ extends: groupId: com.azure safeName: azuremessagingwebpubsubclient releaseInBatch: ${{ parameters.release_azuremessagingwebpubsubclient }} + - name: azure-messaging-webpubsub-chat + groupId: com.azure + safeName: azuremessagingwebpubsubchat + releaseInBatch: ${{ parameters.release_azuremessagingwebpubsubchat }} - name: azure-resourcemanager-webpubsub groupId: com.azure.resourcemanager safeName: azureresourcemanagerwebpubsub diff --git a/sdk/webpubsub/pom.xml b/sdk/webpubsub/pom.xml index 1e3d7a66f852..9310561e10f9 100644 --- a/sdk/webpubsub/pom.xml +++ b/sdk/webpubsub/pom.xml @@ -10,6 +10,7 @@ 1.0.0 azure-messaging-webpubsub + azure-messaging-webpubsub-chat azure-messaging-webpubsub-client azure-resourcemanager-webpubsub