From bcd26168efc88f77b36dbd2a2456622383640838 Mon Sep 17 00:00:00 2001 From: Vadym Yaroshchuk Date: Tue, 19 Dec 2023 17:51:58 +0100 Subject: [PATCH] feat(#43): rsocket transport * feat(#43): rsocket transport * feat: `files` api * refactor: `grpc-engine` removal * feat: factory function for RSocket transport engine * fix: build * docs: removal of grpc-engine notes, adding `RSocketTimeMatesRequestsEngine` * fix: run tests * fix: names * fix: workflow * fix: websockets should be installed before rsocket * refactor: move to `rsocket` * fix: build, missing requests * fix & userId in auth model --- .github/workflows/publish-release-version.yml | 2 +- .github/workflows/run-tests.yml | 2 +- README.md | 15 +- gradle/libs.versions.toml | 11 +- gradle/wrapper/gradle-wrapper.properties | 2 +- grpc-engine/android/build.gradle.kts | 48 -- .../android/grpc/AndroidGrpcEngineBuilder.kt | 15 - grpc-engine/build.gradle.kts | 72 --- .../api/grpc/GrpcTimeMatesRequestsEngine.kt | 429 ------------------ .../grpc/factory/DefaultGrpcEngineBuilder.kt | 12 - .../api/grpc/factory/GrpcEngineBuilder.kt | 7 - .../timemates/api/grpc/internal/ResultExt.kt | 16 - .../api/grpc/mappers/AuthorizationsMapper.kt | 39 -- .../timemates/api/grpc/mappers/FilesMapper.kt | 13 - .../api/grpc/mappers/TimersMapper.kt | 116 ----- .../timemates/api/grpc/mappers/UsersMapper.kt | 23 - .../io/timemates/api/files/FilesService.proto | 23 - .../files/requests/GetFileBytesRequest.proto | 14 - .../files/requests/UploadFileRequest.proto | 31 -- .../GetUserCurrentSessionRequest.proto | 11 - .../io/timemates/api/users/UsersService.proto | 32 -- .../api/users/requests/EditUserRequest.proto | 22 - .../io/timemates/api/users/types/User.proto | 39 -- rsocket-engine/build.gradle.kts | 60 +++ .../io/timemates/api/rsocket/ApiContainer.kt | 13 + .../timemates/api/rsocket/CommandsRegistry.kt | 18 + .../rsocket/RSocketTimeMatesRequestsEngine.kt | 113 +++++ .../api/rsocket/authorizations/AuthMappers.kt | 42 ++ .../commands/AuthorizationCommandsRegistry.kt | 23 + .../commands/ConfigureNewAccountCommand.kt | 23 + .../commands/ConfirmAuthorizationCommand.kt | 22 + .../GetAuthorizationSessionsCommand.kt | 28 ++ .../commands/RenewAuthorizationCommand.kt | 21 + .../commands/StartAuthorizationCommand.kt | 31 ++ .../TerminateCurrentAuthorizationCommand.kt | 17 + .../rsocket/common/commands/RSocketCommand.kt | 26 ++ .../common/commands/RSocketCommands.kt | 39 ++ .../commands/RSocketCommandsBuilderScope.kt | 37 ++ .../api/rsocket/timers/TimerMappers.kt | 89 ++++ .../timers/commands/CreateTimerCommand.kt | 25 + .../timers/commands/EditTimerCommand.kt | 20 + .../timers/commands/GetTimerCommand.kt | 21 + .../timers/commands/GetUserTimersCommand.kt | 30 ++ .../timers/commands/RemoveTimerCommand.kt | 17 + .../timers/commands/TimersCommandsRegistry.kt | 24 + .../commands/GetTimerMembersCommand.kt | 31 ++ .../commands/KickTimerMemberCommand.kt | 17 + .../commands/TimerMembersCommandsRegistry.kt | 20 + .../invites/commands/CreateInviteCommand.kt | 23 + .../invites/commands/GetInvitesCommand.kt | 31 ++ .../commands/JoinTimerByCodeCommand.kt | 23 + .../invites/commands/RemoveInviteCommand.kt | 20 + .../commands/TimerMembersCommandsRegistry.kt | 17 + .../commands/ConfirmSessionCommand.kt | 17 + .../commands/GetCurrentSessionCommand.kt | 18 + .../sessions/commands/GetTimerStateCommand.kt | 20 + .../sessions/commands/JoinSessionCommand.kt | 19 + .../sessions/commands/LeaveSessionCommand.kt | 17 + .../sessions/commands/PingSessionCommand.kt | 17 + .../sessions/commands/StartSessionCommand.kt | 19 + .../sessions/commands/StopSessionCommand.kt | 19 + .../commands/TimerSessionsCommandsRegistry.kt | 25 + .../api/rsocket/users/UsersMapper.kt | 20 + .../users/commands/EditEmailCommand.kt | 19 + .../users/commands/EditProfileCommand.kt | 22 + .../rsocket/users/commands/GetUsersCommand.kt | 17 + .../users/commands/UsersCommandsRegistry.kt | 17 + .../authorizations/AuthorizationService.proto | 13 + .../options/OmitAuthorizationOption.proto | 0 .../ConfirmAuthorizationRequest.proto | 0 .../requests/CreateProfileRequest.proto | 0 .../requests/GetAuthorizationsRequest.proto | 0 .../requests/RenewAuthorizationRequest.proto | 13 + .../requests/StartAuthorizationRequest.proto | 5 + .../authorizations/types/Authorization.proto | 13 +- .../api/authorizations/types/Metadata.proto | 8 + .../timemates/api/timers/TimersService.proto | 6 + .../requests/CreateInviteRequest.proto | 0 .../invites/requests/GetInvitesRequest.proto | 0 .../JoinTimerByInviteCodeRequest.proto | 13 + .../requests/RemoveInviteRequest.proto | 0 .../timers/members/invites/types/Invite.proto | 0 .../members/requests/GetMembersRequest.proto | 0 .../members/requests/KickMemberRequest.proto | 0 .../timers/requests/CreateTimerRequest.proto | 7 +- .../requests/EditTimerInfoRequest.proto | 0 .../api/timers/requests/GetTimerRequest.proto | 0 .../timers/requests/GetTimersRequest.proto | 0 .../timers/requests/RemoveTimerRequest.proto | 0 .../sessions/TimerSessionsService.proto | 6 +- .../requests/ConfirmTimerSessionRequest.proto | 0 .../GetCurrentTimerSessionRequest.proto | 11 + .../requests/GetTimerStateRequest.proto | 0 .../requests/JoinTimerSessionRequest.proto | 0 .../requests/StartTimerSessionRequest.proto | 0 .../requests/StopTimerSessionRequest.proto | 0 .../timers/sessions/types/TimerState.proto | 0 .../io/timemates/api/timers/types/Timer.proto | 0 .../io/timemates/api/users/UsersService.proto | 32 ++ .../api/users/requests/EditEmailRequest.proto | 0 .../api/users/requests/EditUserRequest.proto | 19 + .../api/users/requests/GetUsersRequest.proto | 0 .../io/timemates/api/users/types/User.proto | 32 ++ sdk/build.gradle.kts | 4 + .../email/EmailAuthorizationApi.kt | 11 +- .../requests/ConfigureNewAccountRequest.kt | 7 +- .../requests/ConfirmAuthorizationRequest.kt | 11 +- .../requests/StartAuthorizationRequest.kt | 10 +- .../sessions/AuthorizedSessionsApi.kt | 4 +- .../GetAuthorizationSessionsRequest.kt | 11 +- .../requests/RenewAuthorizationRequest.kt | 23 + ...inateCurrentAuthorizationSessionRequest.kt | 9 +- .../sessions/types/Authorization.kt | 8 +- .../sessions/types/value/ApplicationName.kt | 12 + .../sessions/types/value/ClientName.kt | 12 - .../sessions/types/value/ClientVersion.kt | 6 +- ...ntalApi.kt => ExperimentalTimeMatesApi.kt} | 2 +- .../exceptions/handler/SafeExceptionResult.kt | 221 --------- .../sdk/common/pagination/PagesIterator.kt | 8 +- .../common/providers/AccessHashProvider.kt | 2 +- .../types/AuthorizedTimeMatesRequest.kt | 18 + .../sdk/common/types/TimeMatesRequest.kt | 13 +- .../sdk/files/requests/GetFileBytesRequest.kt | 6 + .../sdk/files/requests/UploadFileRequest.kt | 9 +- .../io/timemates/sdk/files/types/FileType.kt | 2 - .../invites/requests/CreateInviteRequest.kt | 10 +- .../invites/requests/GetInvitesRequest.kt | 10 +- .../requests/JoinTimerByCodeRequest.kt | 19 + .../invites/requests/RemoveInviteRequest.kt | 9 +- .../members/requests/GetMembersRequest.kt | 10 +- .../members/requests/KickMemberRequest.kt | 6 +- .../sdk/timers/requests/CreateTimerRequest.kt | 9 +- .../sdk/timers/requests/EditTimerRequest.kt | 9 +- .../sdk/timers/requests/GetTimerRequest.kt | 9 +- .../timers/requests/GetUserTimersRequest.kt | 9 +- .../sdk/timers/requests/RemoveTimerRequest.kt | 6 +- .../requests/ConfirmTimerRoundRequest.kt | 10 +- .../sessions/requests/GetTimerStateRequest.kt | 10 +- .../requests/GetUserCurrentSessionRequest.kt | 10 +- .../requests/JoinTimerSessionRequest.kt | 9 +- .../requests/LeaveTimerSessionRequest.kt | 10 +- .../sessions/requests/PingSessionRequest.kt | 10 +- .../sessions/requests/StartTimerRequest.kt | 9 +- .../sessions/requests/StopTimerRequest.kt | 9 +- .../kotlin/io/timemates/sdk/users/UserApi.kt | 3 +- .../timemates/sdk/users/profile/ProfileApi.kt | 3 +- .../profile/requests/EditProfileRequest.kt | 12 +- .../users/profile/requests/GetUsersRequest.kt | 4 + .../sdk/users/profile/types/Avatar.kt | 12 - .../timemates/sdk/users/profile/types/User.kt | 4 +- .../sdk/users/settings/UserSettingsApi.kt | 1 - .../settings/requests/EditEmailRequest.kt | 18 +- settings.gradle.kts | 5 +- 153 files changed, 1688 insertions(+), 1325 deletions(-) delete mode 100644 grpc-engine/android/build.gradle.kts delete mode 100644 grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt delete mode 100644 grpc-engine/build.gradle.kts delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt delete mode 100644 grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto delete mode 100644 grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto create mode 100644 rsocket-engine/build.gradle.kts create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt create mode 100644 rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto (81%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto (100%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto (60%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto (84%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/TimersService.proto (89%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto (100%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto (73%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto (93%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto (100%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto (100%) rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/timers/types/Timer.proto (100%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto (100%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto rename {grpc-engine => rsocket-engine}/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto (100%) create mode 100644 rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto create mode 100644 sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt create mode 100644 sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt delete mode 100644 sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt rename sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/{ExperimentalApi.kt => ExperimentalTimeMatesApi.kt} (81%) delete mode 100644 sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt create mode 100644 sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt create mode 100644 sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt diff --git a/.github/workflows/publish-release-version.yml b/.github/workflows/publish-release-version.yml index 993c931..7d6c94b 100644 --- a/.github/workflows/publish-release-version.yml +++ b/.github/workflows/publish-release-version.yml @@ -30,7 +30,7 @@ jobs: - name: Build and Publish env: - TIMEMATES_SDK_VERSION: ${{ github.ref }} + TIMEMATES_SDK_VERSION: ${{ github.ref_name }} TIMEMATES_SSH_DEPLOY_PATH: ${{ secrets.TIMEMATES_SSH_DEPLOY_PATH }} TIMEMATES_SSH_HOST: ${{ secrets.TIMEMATES_SSH_HOST }} TIMEMATES_SSH_PASSWORD: ${{ secrets.TIMEMATES_SSH_PASSWORD }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index a6ea7ce..e8ebb4b 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -17,4 +17,4 @@ jobs: distribution: 'corretto' java-version: '17' cache: 'gradle' - - run: ./gradlew test --no-daemon + - run: ./gradlew build --no-daemon diff --git a/README.md b/README.md index d6fafaf..0b05aed 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,9 @@ platform and integrate its features into your own applications. To demonstrate the usage of the SDK, consider the following example: ```kotlin -val engineBuilder = DefaultGrpcEngineBuilder() -val engine = GrpcTimeMatesRequestsEngine(engineBuilder) +val engine = RSocketTimeMatesRequestsEngine( + coroutineScope = Dispatchers.IO, +) val emailAuth = AccountLoginApi(engineBuilder).email val email = EmailAddress.create("developer@y9vad9.com").getOrElse { return } @@ -24,12 +25,6 @@ val authorizationResult = emailAuth.authorize(email) // until we complete our registration .map { (isNewAccount, authorization) -> ... } ``` -> **Note**
-> For android use [AndroidGrpcEngineBuilder](/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt) ->```kotlin -> val engineBuilder = AndroidGrpcEngineBuilder(applicationContext) ->``` - In the provided code snippet, the SDK utilizes the Kotlin Result API extensively. It's important to note that the SDK's value objects, such as `EmailAddress` @@ -77,9 +72,7 @@ repositories { dependencies { implementation("io.timemates:sdk:$version") - implementation("io.timemates:grpc-engine:$version") - // for android - implementation("io.timemates:grpc-engine-android:$version") + implementation("io.timemates:rsocket-engine:$version") } ``` diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b0098e7..362fe81 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -kotlin = "1.8.21" +kotlin = "1.9.20-Beta" kotlinx-coroutines = "1.6.4" kotlinx-serialization = "1.4.1" ktor = "2.0.1" @@ -7,7 +7,7 @@ kafka = "3.3.1" jupiter = "5.4.0" exposed = "0.41.1" kmongo = "4.8.0" -androidGradlePlugin = "8.2.0-alpha13" +androidGradlePlugin = "8.3.0-alpha05" androidComposeVersion = "1.4.0-alpha02" grpc = "1.3.0" protobuf = "3.22.0" @@ -15,6 +15,7 @@ protobuf-plugin = "0.9.2" grpc-netty = "1.55.1" android-target = "33" android-min = "24" +rsproto = "0.3.2" [libraries] kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } @@ -66,6 +67,11 @@ grpc-android = { module = "io.grpc:grpc-android", version.require = "1.56.1" } protobuf-kotlin = { module = "com.google.protobuf:protobuf-kotlin", version.ref = "protobuf" } protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuf" } +rsocket-client = { module = "io.rsocket.kotlin:rsocket-ktor-client", version.require = "0.15.4" } + +timemates-rsproto-client = { module = "io.timemates.rsproto:client-core", version.ref = "rsproto" } +timemates-rsproto-common = { module = "io.timemates.rsproto:common-core", version.ref = "rsproto" } + [plugins] kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } @@ -76,3 +82,4 @@ android-library = { id = "com.android.library", version.ref = "androidGradlePlug android-application = { id = "com.android.library", version.ref = "androidGradlePlugin" } google-protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" } library-publish = { id = "publish-library", version.require = "SNAPSHOT" } +timemates-rsproto = { id = "io.timemates.rsproto", version.ref = "rsproto" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 15de902..b982b3c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-rc-2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/grpc-engine/android/build.gradle.kts b/grpc-engine/android/build.gradle.kts deleted file mode 100644 index 27b1883..0000000 --- a/grpc-engine/android/build.gradle.kts +++ /dev/null @@ -1,48 +0,0 @@ -plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.library.publish) -} - -android { - compileSdk = libs.versions.android.target.get().toInt() - - defaultConfig { - minSdk = libs.versions.android.min.get().toInt() - } - - compileOptions { - targetCompatibility = JavaVersion.VERSION_17 - sourceCompatibility = JavaVersion.VERSION_17 - } - - namespace = "io.timemates.android.grpc" -} - -dependencies { - implementation(projects.grpcEngine) - - implementation(libs.grpc.android) -} - -kotlin { - jvmToolchain(17) -} - -deployLibrary { - ssh(tag = "maven.timemates.io") { - host = System.getenv("TIMEMATES_SSH_HOST") - user = System.getenv("TIMEMATES_SSH_USER") - password = System.getenv("TIMEMATES_SSH_PASSWORD") - deployPath = System.getenv("TIMEMATES_SSH_DEPLOY_PATH") - - group = "io.timemates" - componentName = "release" - artifactId = "grpc-engine-android" - name = "grpc-engine-android" - - description = "TimeMates android grpc adapter for SDK" - - version = System.getenv("TIMEMATES_SDK_VERSION") - } -} \ No newline at end of file diff --git a/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt b/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt deleted file mode 100644 index 377b055..0000000 --- a/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.timemates.android.grpc - -import android.content.Context -import io.grpc.ManagedChannel -import io.grpc.android.AndroidChannelBuilder -import io.timemates.api.grpc.factory.GrpcEngineBuilder - -class AndroidGrpcEngineBuilder(private val context: Context) : GrpcEngineBuilder { - override fun createGrpcEngine(endpoint: String): ManagedChannel { - return AndroidChannelBuilder.forTarget(endpoint) - .useTransportSecurity() - .context(context) - .build() - } -} \ No newline at end of file diff --git a/grpc-engine/build.gradle.kts b/grpc-engine/build.gradle.kts deleted file mode 100644 index cae6d30..0000000 --- a/grpc-engine/build.gradle.kts +++ /dev/null @@ -1,72 +0,0 @@ -import org.gradle.kotlin.dsl.dependencies -import org.gradle.kotlin.dsl.implementation -import org.gradle.kotlin.dsl.projects -import com.google.protobuf.gradle.id - -plugins { - alias(libs.plugins.kotlin.jvm) - alias(libs.plugins.google.protobuf) - alias(libs.plugins.library.publish) -} - -dependencies { - implementation(libs.kotlinx.coroutines) - implementation(libs.grpc.kotlin.stub) - implementation(libs.grpc.protobuf) - implementation(libs.grpc.netty) - implementation(libs.protobuf.kotlin) - implementation(libs.protobuf.java) - - implementation(libs.kotlinx.datetime) - implementation(projects.sdk) -} - -kotlin { - explicitApi() - jvmToolchain(17) -} - -protobuf { - protoc { - artifact = "com.google.protobuf:protoc:3.22.2" - } - plugins { - id("grpc") { - artifact = "io.grpc:protoc-gen-grpc-java:1.54.0" - } - id("grpckt") { - artifact = "io.grpc:protoc-gen-grpc-kotlin:1.3.0:jdk8@jar" - } - } - generateProtoTasks { - all().forEach { - it.plugins { - id("grpc") - id("grpckt") - } - it.builtins { - id("kotlin") - } - } - } -} - -group = "io.timemates" - -deployLibrary { - ssh(tag = "maven.timemates.io") { - host = System.getenv("TIMEMATES_SSH_HOST") - user = System.getenv("TIMEMATES_SSH_USER") - password = System.getenv("TIMEMATES_SSH_PASSWORD") - deployPath = System.getenv("TIMEMATES_SSH_DEPLOY_PATH") - - group = "io.timemates" - componentName = "kotlin" - artifactId = "grpc-engine" - name = "grpc-engine" - - description = "TimeMates grpc adapter for SDK" - - version = System.getenv("TIMEMATES_SDK_VERSION") - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt deleted file mode 100644 index ef9f211..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt +++ /dev/null @@ -1,429 +0,0 @@ -@file:Suppress("UNCHECKED_CAST") - -package io.timemates.api.grpc - -import com.google.protobuf.Empty -import com.google.protobuf.kotlin.toByteString -import io.grpc.Metadata -import io.grpc.Status -import io.grpc.StatusException -import io.timemates.api.authorizations.AuthorizationServiceGrpcKt -import io.timemates.api.files.FilesServiceGrpcKt -import io.timemates.api.files.requests.UploadFileRequestKt.fileMetadata -import io.timemates.api.grpc.factory.GrpcEngineBuilder -import io.timemates.api.grpc.internal.mapException -import io.timemates.api.grpc.mappers.AuthorizationsMapper -import io.timemates.api.grpc.mappers.FilesMapper -import io.timemates.api.grpc.mappers.TimersMapper -import io.timemates.api.grpc.mappers.UsersMapper -import io.timemates.api.timers.TimerSessionsServiceGrpcKt -import io.timemates.api.timers.TimersServiceGrpcKt -import io.timemates.api.timers.sessions.requests.getTimerStateRequest -import io.timemates.api.users.UsersServiceGrpcKt -import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest -import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest -import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest -import io.timemates.sdk.authorization.email.types.value.VerificationHash -import io.timemates.sdk.authorization.sessions.requests.GetAuthorizationSessionsRequest -import io.timemates.sdk.authorization.sessions.requests.TerminateCurrentAuthorizationSessionRequest -import io.timemates.sdk.authorization.types.value.AccessHash -import io.timemates.sdk.common.constructor.createOrThrow -import io.timemates.sdk.common.engine.TimeMatesRequestsEngine -import io.timemates.sdk.common.exceptions.AlreadyExistsException -import io.timemates.sdk.common.exceptions.InternalServerError -import io.timemates.sdk.common.exceptions.InvalidArgumentException -import io.timemates.sdk.common.exceptions.NotFoundException -import io.timemates.sdk.common.exceptions.PermissionDeniedException -import io.timemates.sdk.common.exceptions.TooManyRequestsException -import io.timemates.sdk.common.exceptions.UnauthorizedException -import io.timemates.sdk.common.exceptions.UnavailableException -import io.timemates.sdk.common.exceptions.UnsupportedException -import io.timemates.sdk.common.pagination.Page -import io.timemates.sdk.common.pagination.PageToken -import io.timemates.sdk.common.types.TimeMatesEntity -import io.timemates.sdk.common.types.TimeMatesRequest -import io.timemates.sdk.common.types.value.Count -import io.timemates.sdk.files.requests.GetFileBytesRequest -import io.timemates.sdk.files.requests.UploadFileRequest -import io.timemates.sdk.files.types.value.FileId -import io.timemates.sdk.timers.members.invites.requests.CreateInviteRequest -import io.timemates.sdk.timers.members.invites.requests.GetInvitesRequest -import io.timemates.sdk.timers.members.invites.requests.RemoveInviteRequest -import io.timemates.sdk.timers.members.invites.types.value.InviteCode -import io.timemates.sdk.timers.members.requests.GetMembersRequest -import io.timemates.sdk.timers.members.requests.KickMemberRequest -import io.timemates.sdk.timers.requests.* -import io.timemates.sdk.timers.sessions.requests.ConfirmTimerRoundRequest -import io.timemates.sdk.timers.sessions.requests.GetTimerStateRequest -import io.timemates.sdk.timers.sessions.requests.GetUserCurrentSessionRequest -import io.timemates.sdk.timers.sessions.requests.JoinTimerSessionRequest -import io.timemates.sdk.timers.sessions.requests.LeaveTimerSessionRequest -import io.timemates.sdk.timers.sessions.requests.PingSessionRequest -import io.timemates.sdk.timers.sessions.requests.StartTimerRequest -import io.timemates.sdk.timers.sessions.requests.StopTimerRequest -import io.timemates.sdk.timers.types.value.TimerId -import io.timemates.sdk.users.profile.requests.EditProfileRequest -import io.timemates.sdk.users.profile.requests.GetUsersRequest -import io.timemates.sdk.users.profile.types.Avatar -import io.timemates.sdk.users.settings.requests.EditEmailRequest -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.map -import kotlinx.datetime.Instant -import kotlin.reflect.KClass -import io.timemates.api.authorizations.requests.ConfirmAuthorizationRequestOuterClass.ConfirmAuthorizationRequest as GrpcConfirmAuthorizationRequest -import io.timemates.api.authorizations.requests.GetAuthorizationsRequestOuterClass.GetAuthorizationsRequest as GrpcGetAuthorizationsRequest -import io.timemates.api.authorizations.requests.StartAuthorizationRequestOuterClass.StartAuthorizationRequest as GrpcStartAuthorizationRequest -import io.timemates.api.files.requests.GetFileBytesRequestOuterClass.GetFileBytesRequest as GrpcGetFileBytesRequest -import io.timemates.api.files.requests.uploadFileRequest as buildUploadFileGrpcRequest -import io.timemates.api.timers.members.invites.requests.getInvitesRequest as buildGetInvitesGrpcRequest -import io.timemates.api.timers.members.invites.requests.inviteMemberRequest as buildCreateInviteGrpcRequest -import io.timemates.api.timers.members.invites.requests.removeInviteRequest as buildRemoveInviteGrpcRequest -import io.timemates.api.timers.members.requests.getMembersRequest as buildGetMembersGrpcRequest -import io.timemates.api.timers.members.requests.kickMemberRequest as buildKickMemberGrpcRequest -import io.timemates.api.timers.requests.CreateTimerRequestOuterClass.CreateTimerRequest as GrpcCreateTimerRequest -import io.timemates.api.timers.requests.EditTimerInfoRequest.EditTimerRequest as GrpcEditTimerRequest -import io.timemates.api.timers.requests.getTimerRequest as buildGetTimerGrpcRequest -import io.timemates.api.timers.requests.getTimersRequest as buildGetTimersGrpcRequest -import io.timemates.api.timers.requests.removeTimerRequest as buildRemoveTimerGrpcRequest -import io.timemates.api.timers.sessions.requests.joinTimerSessionRequest as buildJoinTimerSessionGrpcRequest -import io.timemates.api.timers.sessions.requests.startTimerRequest as buildStartTimerGrpcRequest -import io.timemates.api.timers.sessions.requests.stopTimerRequest as buildStopTimerGrpcRequest -import io.timemates.api.users.requests.CreateProfileRequestOuterClass.CreateProfileRequest as GrpcCreateProfileRequest -import io.timemates.api.users.requests.EditUserRequestOuterClass.EditUserRequest as GrpcEditUserRequest -import io.timemates.api.users.requests.GetUsersRequestOuterClass.GetUsersRequest as GrpcGetUsersRequest -import io.timemates.sdk.common.types.Empty as SdkEmpty - -/** - * gRPC-based implementation of the TimeMatesRequestsEngine interface. - * - * @param endpoint The endpoint URL for the gRPC API. Default value is "https://api.timemates.io". - */ -public class GrpcTimeMatesRequestsEngine( - endpoint: String = "api.timemates.io", - grpcEngineBuilder: GrpcEngineBuilder, -) : TimeMatesRequestsEngine { - private companion object { - val ACCESS_TOKEN: Metadata.Key = Metadata.Key.of("access-token", Metadata.ASCII_STRING_MARSHALLER) - } - - private val channel = grpcEngineBuilder.createGrpcEngine(endpoint) - - private val authorizationService = AuthorizationServiceGrpcKt.AuthorizationServiceCoroutineStub(channel) - private val authMapper = AuthorizationsMapper() - - private val filesService = FilesServiceGrpcKt.FilesServiceCoroutineStub(channel) - private val filesMapper = FilesMapper() - - private val usersService = UsersServiceGrpcKt.UsersServiceCoroutineStub(channel) - private val usersMapper = UsersMapper() - - private val timersService = TimersServiceGrpcKt.TimersServiceCoroutineStub(channel) - private val timerSessionsService = TimerSessionsServiceGrpcKt.TimerSessionsServiceCoroutineStub(channel) - private val timersMapper = TimersMapper() - - override suspend fun execute(request: TimeMatesRequest): Result = runCatching { - when (request) { - is StartAuthorizationRequest -> authorizationService.startAuthorization( - GrpcStartAuthorizationRequest - .newBuilder() - .setEmailAddress(request.emailAddress.string) - .build() - ).let { - StartAuthorizationRequest.Result( - verificationHash = VerificationHash.createOrThrow(it.verificationHash), - attempts = Count.createOrThrow(it.attempts), - expiresAt = Instant.fromEpochMilliseconds(it.expiresAt), - ) - } - - is ConfirmAuthorizationRequest -> authorizationService.confirmAuthorization( - GrpcConfirmAuthorizationRequest - .newBuilder() - .setConfirmationCode(request.confirmationCode.string) - .setVerificationHash(request.verificationHash.string) - .build() - ).let { response -> - ConfirmAuthorizationRequest.Response( - isNewAccount = response.isNewAccount, - authorization = response.authorization.takeIf { !response.isNewAccount } - ?.let(authMapper::grpcAuthorizationToSdkAuthorization), - ) - } - - is ConfigureNewAccountRequest -> authorizationService.createProfile( - GrpcCreateProfileRequest.newBuilder() - .setName(request.name.string) - .setDescription(request.description.string) - .setVerificationHash(request.verificationHash.string) - .build() - ).let { - ConfigureNewAccountRequest.Result( - authMapper.grpcAuthorizationToSdkAuthorization(it.authorization) - ) - } - - is GetAuthorizationSessionsRequest -> authorizationService.getAuthorizations( - GrpcGetAuthorizationsRequest.newBuilder() - .setPageToken(request.nextPageToken?.string) - .build(), - headers = authorizedMetadata(request.accessHash), - ).let { response -> - Page( - response.authorizationsList.map(authMapper::grpcAuthorizationToSdkAuthorization), - nextPageToken = response.nextPageToken.takeIf { it.isNotEmpty() } - ?.let(PageToken::createOrThrow), - ) - } - - is TerminateCurrentAuthorizationSessionRequest -> - authorizationService.terminateAuthorization(Empty.getDefaultInstance()) - .let { SdkEmpty } - - is GetFileBytesRequest -> - filesService.getFileBytes( - GrpcGetFileBytesRequest - .newBuilder() - .setFileId(request.fileId.string) - .build(), - ).map { it.chunk.toByteArray() }.let { GetFileBytesRequest.Result(it) } - - is UploadFileRequest -> filesService.uploadFile( - requests = flow { - emit(buildUploadFileGrpcRequest { - metadata = fileMetadata { - fileName = request.fileName.string - fileType = filesMapper.sdkFileTypeToGrpcFileType(request.fileType) - } - }) - - request.bytes.collect { - emit(buildUploadFileGrpcRequest { - chunk = it.toByteString() - }) - } - }, - headers = authorizedMetadata(request.accessHash), - ).let { UploadFileRequest.Result(FileId.createOrThrow(it.fileId)) } - - is EditProfileRequest -> usersService.setUser( - GrpcEditUserRequest.newBuilder() - .apply { - request.name?.let { name = it.string } - request.description?.let { description = it.string } - request.avatar?.let { - avatarId = (it as? Avatar.FileId)?.string - gravatarId = (it as? Avatar.GravatarId)?.string - } - }.build(), - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is GetUsersRequest -> usersService.getUsers( - GrpcGetUsersRequest.newBuilder() - .addAllUserId(request.users.map { it.long }) - .build(), - ).let { GetUsersRequest.Result(it.usersList.map { usersMapper.grpcUserToSdkUser(it) }) } - - is EditEmailRequest -> unsupported() - - is CreateTimerRequest -> timersService.createTimer( - GrpcCreateTimerRequest.newBuilder() - .setName(request.name.string) - .setDescription(request.description.string) - .setSettings(timersMapper.sdkSettingsToGrpcSettings(request.settings)) - .build(), - headers = authorizedMetadata(request.accessHash) - ).let { CreateTimerRequest.Result(TimerId.createOrThrow(it.timerId)) } - - is EditTimerRequest -> timersService.editTimer( - GrpcEditTimerRequest.newBuilder() - .setTimerId(request.timerId.long) - .apply { - request.name?.let { name = it.string } - request.description?.let { description = it.string } - request.settings?.let { - settings = timersMapper.sdkSettingsPatchToGrpcSettingsPatch(it) - } - }.build(), - headers = authorizedMetadata(request.accessHash) - ).let { SdkEmpty } - - is GetTimerRequest -> timersService.getTimer( - buildGetTimerGrpcRequest { - timerId = request.timerId.long - }, - headers = authorizedMetadata(request.accessHash) - ).let { timersMapper.grpcTimerToSdkTimer(it) } - - is GetUserTimersRequest -> timersService.getTimers( - buildGetTimersGrpcRequest { - request.pageToken?.let { nextPageToken = it.string } - }, - headers = authorizedMetadata(request.accessHash) - ).let { response -> - Page( - response.timersList.map { timersMapper.grpcTimerToSdkTimer(it) }, - nextPageToken = response.nextPageToken.takeIf { - response.hasNextPageToken() - }?.let { - PageToken.createOrThrow(it) - }, - ) - } - - is RemoveTimerRequest -> timersService.removeTimer( - buildRemoveTimerGrpcRequest { - timerId = request.timerId.long - }, - headers = authorizedMetadata(request.accessHash) - ).let { SdkEmpty } - - is GetMembersRequest -> timersService.getMembers( - buildGetMembersGrpcRequest { - timerId = request.timerId.long - request.pageToken?.let { nextPageToken = it.string } - }, - headers = authorizedMetadata(request.accessHash) - ).let { response -> - Page( - response.usersList.map { usersMapper.grpcUserToSdkUser(it) }, - nextPageToken = response.nextPageToken?.takeIf { it.isNotEmpty() } - ?.let { PageToken.createOrThrow(it) } - ) - } - - is KickMemberRequest -> timersService.kickMember( - buildKickMemberGrpcRequest { - timerId = request.timerId.long - userId = request.userId.long - }, - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is CreateInviteRequest -> timersService.createInvite( - buildCreateInviteGrpcRequest { - timerId = request.timerId.long - maxJoiners = request.maxJoinersCount.int - }, - headers = authorizedMetadata(request.accessHash), - ).let { CreateInviteRequest.Result(InviteCode.createOrThrow(it.inviteCode)) } - - is GetInvitesRequest -> timersService.getInvites( - buildGetInvitesGrpcRequest { - timerId = request.timerId.long - request.pageToken?.let { nextPageToken = it.string } - }, - headers = authorizedMetadata(request.accessHash), - ).let { response -> - Page( - results = response.invitesList.map { timersMapper.grpcInviteToSdkInvite(it) }, - nextPageToken = response.nextPageToken.takeIf { it.isNotEmpty() } - ?.let { PageToken.createOrThrow(it) } - ) - } - - is RemoveInviteRequest -> timersService.removeInvite( - buildRemoveInviteGrpcRequest { - timerId = request.timerId.long - inviteCode = request.inviteCode.string - }, - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is StartTimerRequest -> timerSessionsService.startTimer( - buildStartTimerGrpcRequest { - timerId = request.timerId.long - }, - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is StopTimerRequest -> timerSessionsService.stopTimer( - buildStopTimerGrpcRequest { - timerId = request.timerId.long - }, - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is JoinTimerSessionRequest -> timerSessionsService.joinSession( - buildJoinTimerSessionGrpcRequest { - timerId = request.timerId.long - }, - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is LeaveTimerSessionRequest -> timerSessionsService.leaveSession( - Empty.getDefaultInstance(), - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is ConfirmTimerRoundRequest -> timerSessionsService.pingSession( - Empty.getDefaultInstance(), - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is PingSessionRequest -> timerSessionsService.pingSession( - Empty.getDefaultInstance(), - headers = authorizedMetadata(request.accessHash), - ).let { SdkEmpty } - - is GetUserCurrentSessionRequest -> timerSessionsService.getUserCurrentSession( - request = Empty.getDefaultInstance(), - headers = authorizedMetadata(request.accessHash), - ).let { timersMapper.grpcTimerToSdkTimer(it) } - - is GetTimerStateRequest -> timerSessionsService.getState( - request = getTimerStateRequest { - - }, - headers = authorizedMetadata(request.accessHash) - ).let { states -> - GetTimerStateRequest.Result( - states.map { state -> timersMapper.grpcStateToSdkState(state) } - ) - } - - else -> unsupported(request::class) - } as T - }.mapException { - val exception = (it as? StatusException) ?: return@mapException it - val status = exception.status - - val message = exception.message ?: NO_MESSAGE - - when (status) { - Status.RESOURCE_EXHAUSTED -> - TooManyRequestsException("Too many requests.", exception) - - Status.INVALID_ARGUMENT, Status.FAILED_PRECONDITION -> - InvalidArgumentException(message, exception) - - Status.UNAUTHENTICATED -> - UnauthorizedException(message, exception) - - Status.INTERNAL -> - InternalServerError(message, exception) - - Status.NOT_FOUND -> - NotFoundException(message, exception) - - Status.ALREADY_EXISTS -> - AlreadyExistsException(message, exception) - - Status.PERMISSION_DENIED -> PermissionDeniedException(message, exception) - Status.UNAVAILABLE -> UnavailableException(message, exception) - - else -> InternalServerError(message, exception) - } - } - - private fun authorizedMetadata(accessHash: AccessHash) = Metadata().apply { - put(ACCESS_TOKEN, accessHash.string) - } - - private fun unsupported(kClass: KClass<*>): Nothing = - throw UnsupportedException("Request of type ${kClass.simpleName} is not supported") - - private inline fun unsupported(): Nothing = unsupported(T::class) -} - -private const val NO_MESSAGE = "No message is provided." \ No newline at end of file diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt deleted file mode 100644 index 5137877..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.timemates.api.grpc.factory - -import io.grpc.ManagedChannel -import io.grpc.ManagedChannelBuilder - -public class DefaultGrpcEngineBuilder : GrpcEngineBuilder { - override fun createGrpcEngine(endpoint: String): ManagedChannel { - return ManagedChannelBuilder.forTarget(endpoint) - .useTransportSecurity() - .build() - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt deleted file mode 100644 index c9318f8..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.timemates.api.grpc.factory - -import io.grpc.ManagedChannel - -public interface GrpcEngineBuilder { - public fun createGrpcEngine(endpoint: String): ManagedChannel -} \ No newline at end of file diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt deleted file mode 100644 index 4564846..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.timemates.api.grpc.internal - -/** - * Applies the given transformation function to the exception contained in the `Result` and returns a new `Result` - * with the transformed exception. If the `Result` does not contain an exception, - * it returns the original `Result` unchanged. - * - * @param transform The transformation function to apply to the exception. - * @return A new `Result` with the transformed exception, or the original `Result` if no exception is present. - */ -@JvmSynthetic -internal inline fun Result.mapException(transform: (Throwable) -> Throwable): Result { - val exception = exceptionOrNull() ?: return this - - return Result.failure(transform(exception)) -} diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt deleted file mode 100644 index 15fc28c..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt +++ /dev/null @@ -1,39 +0,0 @@ -package io.timemates.api.grpc.mappers - -import io.timemates.api.authorizations.types.AuthorizationOuterClass.Authorization -import io.timemates.sdk.authorization.sessions.types.value.ClientIpAddress -import io.timemates.sdk.authorization.sessions.types.value.ClientName -import io.timemates.sdk.authorization.sessions.types.value.ClientVersion -import io.timemates.sdk.authorization.types.value.HashValue -import io.timemates.sdk.common.constructor.createOrThrow -import kotlinx.datetime.Instant -import io.timemates.sdk.authorization.sessions.types.Authorization as SdkAuthorization - -internal class AuthorizationsMapper { - fun grpcAuthorizationToSdkAuthorization( - authorization: Authorization - ): SdkAuthorization = with(authorization) { - return@with SdkAuthorization( - accessHash = SdkAuthorization.Hash( - value = HashValue.createOrThrow(accessHash.value), - expiresAt = Instant.fromEpochMilliseconds(accessHash.expiresAt), - ), - refreshHash = SdkAuthorization.Hash( - value = HashValue.createOrThrow(refreshHash.value), - expiresAt = Instant.fromEpochMilliseconds(refreshHash.expiresAt), - ), - generationTime = Instant.fromEpochMilliseconds(generationTime), - metadata = grpcMetadataToSdkMetadata(metadata), - ) - } - - private fun grpcMetadataToSdkMetadata( - metadata: Authorization.Metadata, - ): SdkAuthorization.Metadata = with(metadata) { - return@with SdkAuthorization.Metadata( - clientName = ClientName.createOrThrow(clientName), - clientVersion = ClientVersion.createOrThrow(clientVersion), - clientIpAddress = ClientIpAddress.createOrThrow(clientIpAddress), - ) - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt deleted file mode 100644 index e10877a..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.timemates.api.grpc.mappers - -import io.timemates.api.files.requests.UploadFileRequestOuterClass -import io.timemates.sdk.files.types.FileType -import io.timemates.api.files.requests.UploadFileRequestOuterClass.UploadFileRequest.FileMetadata.FileType as GrpcFileType - -internal class FilesMapper { - fun sdkFileTypeToGrpcFileType(fileType: FileType): GrpcFileType { - return when (fileType) { - FileType.IMAGE -> GrpcFileType.IMAGE - } - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt deleted file mode 100644 index 37b5659..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt +++ /dev/null @@ -1,116 +0,0 @@ -package io.timemates.api.grpc.mappers - -import io.timemates.api.timers.members.invites.types.InviteOuterClass.Invite -import io.timemates.api.timers.sessions.types.TimerStateOuterClass.TimerState -import io.timemates.api.timers.types.TimerKt -import io.timemates.api.timers.types.TimerOuterClass.Timer -import io.timemates.sdk.common.constructor.createOrThrow -import io.timemates.sdk.common.exceptions.UnsupportedException -import io.timemates.sdk.common.types.value.Count -import io.timemates.sdk.timers.members.invites.types.value.InviteCode -import io.timemates.sdk.timers.types.value.TimerDescription -import io.timemates.sdk.timers.types.value.TimerId -import io.timemates.sdk.timers.types.value.TimerName -import io.timemates.sdk.users.profile.types.value.UserId -import kotlinx.datetime.Instant -import kotlin.time.Duration.Companion.seconds -import kotlin.time.DurationUnit -import io.timemates.sdk.timers.members.invites.types.Invite as SdkInvite -import io.timemates.sdk.timers.types.Timer as SdkTimer -import io.timemates.sdk.timers.types.TimerSettings as SdkTimerSettings - -internal class TimersMapper { - fun grpcTimerToSdkTimer(timer: Timer): SdkTimer = with(timer) { - return SdkTimer( - timerId = TimerId.createOrThrow(id), - name = TimerName.createOrThrow(name), - description = TimerDescription.createOrThrow(description), - ownerId = UserId.createOrThrow(ownerId), - membersCount = Count.createOrThrow(membersCount), - state = grpcStateToSdkState(currentState), - settings = grpcSettingsToSdkSettings(settings), - ) - } - - fun grpcStateToSdkState(timerState: TimerState): SdkTimer.State = with(timerState) { - val publishTime = Instant.fromEpochMilliseconds(publishTime) - - return when { - hasPaused() -> SdkTimer.State.Paused(publishTime) - hasRunning() -> SdkTimer.State.Running( - publishTime = publishTime, - endsAt = Instant.fromEpochMilliseconds(running.endsAt), - ) - - hasConfirmationWaiting() -> SdkTimer.State.ConfirmationWaiting( - publishTime = publishTime, - endsAt = Instant.fromEpochMilliseconds(confirmationWaiting.endsAt), - ) - - hasRest() -> SdkTimer.State.Rest( - publishTime = publishTime, - endsAt = Instant.fromEpochMilliseconds(rest.endsAt), - ) - - hasInactive() -> SdkTimer.State.Inactive( - publishTime = publishTime, - ) - - else -> throw UnsupportedException("Unsupported timer state.") - } - } - - fun grpcSettingsToSdkSettings(settings: Timer.Settings): SdkTimerSettings = with(settings) { - return SdkTimerSettings( - workTime = workTime.seconds, - restTime = restTime.seconds, - bigRestTime = bigRestTime.seconds, - bigRestEnabled = bigRestEnabled, - bigRestPer = Count.createOrThrow(bigRestPer), - isEveryoneCanPause = isEveryoneCanPause, - isConfirmationRequired = isConfirmationRequired, - ) - } - fun sdkTimerToGrpcTimer(sdkTimer: SdkTimer): Timer = with(sdkTimer) { - return Timer.newBuilder() - .setId(timerId.long) - .setName(name.string) - .setDescription(description.string) - .setOwnerId(ownerId.long) - .setMembersCount(membersCount.int) - .setSettings(sdkSettingsToGrpcSettings(settings)) - .build() - } - - fun sdkSettingsToGrpcSettings(sdkSettings: SdkTimerSettings): Timer.Settings = with(sdkSettings) { - return Timer.Settings.newBuilder() - .setWorkTime(workTime.toInt(DurationUnit.MINUTES)) - .setRestTime(restTime.toInt(DurationUnit.MINUTES)) - .setBigRestTime(bigRestTime.toInt(DurationUnit.MINUTES)) - .setBigRestEnabled(bigRestEnabled) - .setBigRestPer(bigRestPer.int) - .setIsEveryoneCanPause(isEveryoneCanPause) - .setIsConfirmationRequired(isConfirmationRequired) - .build() - } - - fun sdkSettingsPatchToGrpcSettingsPatch( - sdkSettings: SdkTimerSettings.Patch - ): Timer.Settings.Patch = TimerKt.SettingsKt.patch { - sdkSettings.workTime?.let { workTime = it.toInt(DurationUnit.MINUTES) } - sdkSettings.restTime?.let { restTime = it.toInt(DurationUnit.MINUTES) } - sdkSettings.bigRestTime?.let { bigRestTime = it.toInt(DurationUnit.MINUTES) } - sdkSettings.bigRestPer?.let { bigRestPer = it.int } - sdkSettings.bigRestEnabled?.let { bigRestEnabled = it } - sdkSettings.isConfirmationRequired?.let { isConfirmationRequired = it } - sdkSettings.isEveryoneCanPause?.let { isEveryoneCanPause = it } - } - - fun grpcInviteToSdkInvite(invite: Invite): SdkInvite { - return SdkInvite( - inviteCode = InviteCode.createOrThrow(invite.code), - creationTime = Instant.fromEpochMilliseconds(invite.creationTime), - limit = Count.createOrThrow(invite.limit), - ) - } -} diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt deleted file mode 100644 index 4fc1a08..0000000 --- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt +++ /dev/null @@ -1,23 +0,0 @@ -package io.timemates.api.grpc.mappers - -import io.timemates.api.users.types.UserOuterClass -import io.timemates.sdk.common.constructor.createOrThrow -import io.timemates.sdk.users.profile.types.Avatar -import io.timemates.sdk.users.profile.types.value.EmailAddress -import io.timemates.sdk.users.profile.types.value.UserDescription -import io.timemates.sdk.users.profile.types.value.UserId -import io.timemates.sdk.users.profile.types.value.UserName -import io.timemates.sdk.users.profile.types.User as SdkUser - -internal class UsersMapper { - fun grpcUserToSdkUser(user: UserOuterClass.User): SdkUser = with(user) { - return SdkUser( - id = UserId.createOrThrow(id), - name = UserName.createOrThrow(name), - description = UserDescription.createOrThrow(description), - emailAddress = email?.takeIf { it.isNotEmpty() }?.let { EmailAddress.createOrThrow(it) }, - avatar = gravatarId?.let { Avatar.GravatarId.createOrThrow(it) } ?: - avatarId?.let { Avatar.FileId.createOrThrow(it) } - ) - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto b/grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto deleted file mode 100644 index 00f5cad..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; - -import "io/timemates/api/files/requests/GetFileBytesRequest.proto"; -import "io/timemates/api/files/requests/UploadFileRequest.proto"; -import "io/timemates/api/authorizations/options/OmitAuthorizationOption.proto"; -import "google/protobuf/empty.proto"; - -option java_package = "io.timemates.api.files"; - -service FilesService { - /** - * Returns a sequence of bytes of the file's content. - */ - rpc getFileBytes(GetFileBytesRequest) returns (stream GetFileBytesRequest.Response) { - option (omit_authorization) = true; - } - - /* - * Uploads file to server. - * Returns status after upload file stream ends. - */ - rpc uploadFile(stream UploadFileRequest) returns (UploadFileRequest.Response); -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto deleted file mode 100644 index 625ea0d..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax = "proto3"; - -option java_package = "io.timemates.api.files.requests"; - -message GetFileBytesRequest { - string fileId = 1; - - message Response { - /** - * Chunked file content bytes. - */ - bytes chunk = 1; - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto deleted file mode 100644 index f32c786..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto +++ /dev/null @@ -1,31 +0,0 @@ -syntax = "proto3"; - -option java_package = "io.timemates.api.files.requests"; - -message UploadFileRequest { - oneof request { - /** - * Should always be sent as first request. - * Should not be repeated. - */ - FileMetadata metadata = 1; - /** - * Bytes of file included into given chunk. - */ - bytes chunk = 2; - } - - message Response { - string fileId = 1; - } - - message FileMetadata { - FileType fileType = 1; - string fileName = 2; - - enum FileType { - BINARY = 0; // unsupported by default - IMAGE = 1; - } - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto deleted file mode 100644 index c73a7eb..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto3"; - -import "io/timemates/api/timers/types/Timer.proto"; - -option java_package = "io.timemates.api.timers.sessions.requests"; - -message GetUserCurrentSessionRequest { - message Response { - optional Timer timer = 1; - } -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto b/grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto deleted file mode 100644 index 4f7fc7d..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; - -import "io/timemates/api/users/requests/GetUsersRequest.proto"; -import "io/timemates/api/users/requests/EditUserRequest.proto"; -import "io/timemates/api/users/requests/EditEmailRequest.proto"; -import "io/timemates/api/users/types/User.proto"; -import "google/protobuf/empty.proto"; - -option java_package = "io.timemates.api.users"; - -service UsersService { - /** - * Gets users by given identifiers. - * - * Returns [User] or null - */ - rpc getUsers(GetUsersRequest) returns (Users); - - /** - * Sets user information (name / description / avatar file id). - * - * Returns [Status] - */ - rpc setUser(EditUserRequest) returns (google.protobuf.Empty); - - /** - * Sets new email for current user. - * - * Returns [Status] - */ - rpc setEmail(EditEmailRequest) returns (google.protobuf.Empty); -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto deleted file mode 100644 index aa19215..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto3"; - -option java_package = "io.timemates.api.users.requests"; - -message EditUserRequest { - /** - * User's avatar id - */ - oneof avatar { - string avatarId = 1; - string gravatarId = 2; - } - /** - * User's name - */ - optional string name = 3; - - /** - * User's description. - */ - optional string description = 4; -} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto b/grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto deleted file mode 100644 index b5b69c0..0000000 --- a/grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto +++ /dev/null @@ -1,39 +0,0 @@ -syntax = "proto3"; - -option java_package = "io.timemates.api.users.types"; - -message User { - /** - * User's identifier - */ - int64 id = 1; - - /** - * String identifier of 128 length. Can be null - * if there is no avatar. - */ - oneof avatar { - string avatarId = 2; - string gravatarId = 3; - } - - /** - * User's name - */ - string name = 4; - - /** - * User's description. - */ - string description = 5; - - /** - * User's email up to 200 symbols. - * Can be null if there is no access. - */ - optional string email = 6; -} - -message Users { - repeated User users = 1; -} \ No newline at end of file diff --git a/rsocket-engine/build.gradle.kts b/rsocket-engine/build.gradle.kts new file mode 100644 index 0000000..08c2ada --- /dev/null +++ b/rsocket-engine/build.gradle.kts @@ -0,0 +1,60 @@ +plugins { + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.kotlinx.serialization) + alias(libs.plugins.library.publish) + alias(libs.plugins.timemates.rsproto) +} + +kotlin { + jvm() + jvmToolchain(17) + + sourceSets { + val commonMain by getting { + kotlin.srcDirs("src/main/kotlin", "build/generated/rsproto/kotlin") + } + } + + explicitApi() +} + +dependencies { + commonMainImplementation(projects.sdk) + + commonMainImplementation(libs.timemates.rsproto.common) + commonMainImplementation(libs.timemates.rsproto.client) + + commonMainImplementation(libs.kotlinx.serialization) + commonMainImplementation(libs.kotlinx.datetime) + commonMainImplementation(libs.rsocket.client) +} + +deployLibrary { + ssh(tag = "rsocket-engine to maven.timemates.io") { + host = System.getenv("TIMEMATES_SSH_HOST") + user = System.getenv("TIMEMATES_SSH_USER") + password = System.getenv("TIMEMATES_SSH_PASSWORD") + deployPath = System.getenv("TIMEMATES_SSH_DEPLOY_PATH") + + group = "io.timemates" + componentName = "kotlin" + artifactId = "rsocket-engine" + name = "rsocket-engine" + + description = "TimeMates rsocket adapter for SDK" + + version = System.getenv("TIMEMATES_SDK_VERSION") + } +} + +rsproto { + protoSourcePath = "src/main/proto/" + generationOutputPath = "generated/rsproto/kotlin" + + clientGeneration = true + serverGeneration = false +} + +tasks.withType { + useJUnitPlatform() +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt new file mode 100644 index 0000000..9dc9a29 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt @@ -0,0 +1,13 @@ +package io.timemates.api.rsocket + +import io.timemates.api.authorizations.AuthorizationServiceApi +import io.timemates.api.timers.TimerSessionsServiceApi +import io.timemates.api.timers.TimersServiceApi +import io.timemates.api.users.UsersServiceApi + +internal class ApiContainer ( + val auth: AuthorizationServiceApi, + val users: UsersServiceApi, + val timers: TimersServiceApi, + val timerSessions: TimerSessionsServiceApi, +) \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt new file mode 100644 index 0000000..8f30c77 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt @@ -0,0 +1,18 @@ +package io.timemates.api.rsocket + +import io.timemates.api.rsocket.authorizations.commands.authorizations +import io.timemates.api.rsocket.common.commands.rSocketCommands +import io.timemates.api.rsocket.timers.commands.timers +import io.timemates.api.rsocket.users.commands.users + +/** + * Registry for RSocket commands used in the TimeMates application. + * + * The [rSocketCommandsRegistry] is responsible for initializing and registering RSocket commands + * for specific TimeMates features or functionalities. + */ +internal val rSocketCommandsRegistry = rSocketCommands { + authorizations() + users() + timers() +} diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt new file mode 100644 index 0000000..42c577b --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt @@ -0,0 +1,113 @@ +package io.timemates.api.rsocket + +import io.ktor.client.HttpClient +import io.ktor.client.HttpClientConfig +import io.ktor.client.plugins.websocket.WebSockets +import io.rsocket.kotlin.core.WellKnownMimeType +import io.rsocket.kotlin.keepalive.KeepAlive +import io.rsocket.kotlin.ktor.client.RSocketSupport +import io.rsocket.kotlin.ktor.client.rSocket +import io.rsocket.kotlin.payload.PayloadMimeType +import io.timemates.api.authorizations.AuthorizationServiceApi +import io.timemates.api.timers.TimerSessionsServiceApi +import io.timemates.api.timers.TimersServiceApi +import io.timemates.api.users.UsersServiceApi +import io.timemates.sdk.common.engine.TimeMatesRequestsEngine +import io.timemates.sdk.common.exceptions.UnsupportedException +import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.TimeMatesRequest +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.CoroutineStart +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.protobuf.ProtoBuf +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.seconds + +/** + * Creates an RSocket-based TimeMates request engine. + * + * This function configures and creates an RSocket-based TimeMates request engine + * that communicates with the TimeMates API over WebSockets. You can customize the + * WebSocket endpoint, coroutine scope, and HTTP client configuration using the + * provided parameters. + * + * **Note**: You should implement ktor client engine to use it. + * + * @param endpoint The WebSocket endpoint URL for the TimeMates API. + * @param coroutineScope The coroutine scope used for RSocket lifecycle. + * @param config Configuration lambda for customizing the underlying HTTP client. + * @return An instance of the RSocketTimeMatesRequestsEngine. + */ +public fun RSocketTimeMatesRequestsEngine( + endpoint: String = "wss://api.timemates.io/v0/rsocket", + coroutineScope: CoroutineScope, + config: HttpClientConfig<*>.() -> Unit = {}, +): RSocketTimeMatesRequestsEngine { + val client = HttpClient { + install(WebSockets) + install(RSocketSupport) { + connector { + maxFragmentSize = 1024 + + connectionConfig { + keepAlive = KeepAlive( + interval = 30.seconds, + maxLifetime = 2.minutes + ) + + payloadMimeType = PayloadMimeType( + data = WellKnownMimeType.ApplicationProtoBuf, + metadata = WellKnownMimeType.ApplicationProtoBuf, + ) + } + } + } + config() + } + + return RSocketTimeMatesRequestsEngine( + client, endpoint, coroutineScope, + ) +} + +/** + * Represents an engine for making requests using RSocket. + * + * @property client An instance of [HttpClient] for making HTTP requests. + * @param endpoint The RSocket endpoint URL. Defaults to "wss://api.timemates.io/v0/rsocket". + * @param coroutineScope A [CoroutineScope] tied to the RSocket lifecycle. + */ +public class RSocketTimeMatesRequestsEngine internal constructor( + private val client: HttpClient, + endpoint: String = "wss://api.timemates.io/rsocket", + coroutineScope: CoroutineScope, +) : TimeMatesRequestsEngine { + public companion object { + public const val API_VERSION: Double = 1.0 + } + + private val rSocket = coroutineScope.async(start = CoroutineStart.LAZY) { + client.rSocket(endpoint) + } + + @OptIn(ExperimentalSerializationApi::class) + private val container = coroutineScope.async(start = CoroutineStart.LAZY) { + val rSocket = rSocket.await() + + ApiContainer( + auth = AuthorizationServiceApi(rSocket, ProtoBuf), + users = UsersServiceApi(rSocket, ProtoBuf), + timers = TimersServiceApi(rSocket, ProtoBuf), + timerSessions = TimerSessionsServiceApi(rSocket, ProtoBuf) + ) + } + + override suspend fun execute( + request: TimeMatesRequest, + ): Result = runCatching { + return@runCatching rSocketCommandsRegistry.execute(container.await(), request) + ?: throw UnsupportedException("This type of request is not supported in RSocket engine.") + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt new file mode 100644 index 0000000..b6bf406 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt @@ -0,0 +1,42 @@ +package io.timemates.api.rsocket.authorizations + +import io.timemates.api.authorizations.types.Metadata +import io.timemates.sdk.authorization.sessions.types.value.ApplicationName +import io.timemates.sdk.authorization.sessions.types.value.ClientIpAddress +import io.timemates.sdk.authorization.sessions.types.value.ClientVersion +import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.authorization.types.value.HashValue +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.users.profile.types.value.UserId +import kotlinx.datetime.Instant +import io.timemates.api.authorizations.types.Authorization as RSAuthorization +import io.timemates.sdk.authorization.sessions.types.Authorization as SdkAuth + +internal fun Metadata.sdk(): SdkAuth.Metadata { + return SdkAuth.Metadata( + applicationName = ApplicationName.createOrThrow(clientName), + clientVersion = ClientVersion.createOrThrow(clientVersion), + clientIpAddress = ClientIpAddress.createOrThrow("UNDEFINED") + ) +} + +internal fun SdkAuth.Metadata.rs(): Metadata { + return Metadata( + clientName = applicationName.string, + clientVersion = clientVersion.double, + ) +} + +internal fun RSAuthorization.sdk(): SdkAuth { + return SdkAuth( + accessHash = accessHash?.let { SdkAuth.Hash(HashValue.createOrThrow(it.value), Instant.fromEpochMilliseconds(it.expiresAt)) }, + refreshHash = refreshHash?.let { SdkAuth.Hash(HashValue.createOrThrow(it.value), Instant.fromEpochMilliseconds(it.expiresAt)) }, + generationTime = Instant.fromEpochMilliseconds(generationTime), + metadata = metadata?.sdk(), + userId = UserId.createOrThrow(userId), + ) +} + +internal fun AccessHash.toExtra(): Map { + return mapOf("access_hash" to string.toByteArray()) +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt new file mode 100644 index 0000000..c7820d2 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt @@ -0,0 +1,23 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope +import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest +import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest +import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest +import io.timemates.sdk.authorization.sessions.requests.GetAuthorizationSessionsRequest +import io.timemates.sdk.authorization.sessions.requests.RenewAuthorizationRequest +import io.timemates.sdk.authorization.sessions.requests.TerminateCurrentAuthorizationSessionRequest +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi + +/** + * The commands that is connected to the authorization feature. + */ +@OptIn(ExperimentalTimeMatesApi::class) +internal fun RSocketCommandsBuilderScope.authorizations() { + StartAuthorizationCommand associatedWith StartAuthorizationRequest + ConfirmAuthorizationCommand associatedWith ConfirmAuthorizationRequest + ConfigureNewAccountCommand associatedWith ConfigureNewAccountRequest + GetAuthorizationSessionsCommand associatedWith GetAuthorizationSessionsRequest + TerminateCurrentAuthorizationCommand associatedWith TerminateCurrentAuthorizationSessionRequest + RenewAuthorizationCommand associatedWith RenewAuthorizationRequest +} diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt new file mode 100644 index 0000000..ed7ee83 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt @@ -0,0 +1,23 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.sdk +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest +import io.timemates.api.users.requests.CreateProfileRequest as RSCreateProfileRequest + +internal object ConfigureNewAccountCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: ConfigureNewAccountRequest): ConfigureNewAccountRequest.Result { + return apis.auth.createProfile( + message = RSCreateProfileRequest( + verificationHash = input.verificationHash.string, + name = input.name.string, + description = input.description?.string.orEmpty(), + ) + ).let { result -> + ConfigureNewAccountRequest.Result( + authorization = result.authorization!!.sdk() + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt new file mode 100644 index 0000000..2d19215 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt @@ -0,0 +1,22 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.sdk +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest +import io.timemates.api.authorizations.requests.ConfirmAuthorizationRequest as RSConfirmAuthorizationRequest + +internal object ConfirmAuthorizationCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: ConfirmAuthorizationRequest): ConfirmAuthorizationRequest.Result { + return apis.auth.confirmAuthorization( + message = RSConfirmAuthorizationRequest( + input.verificationHash.string, input.confirmationCode.string + ) + ).let { result -> + ConfirmAuthorizationRequest.Result( + isNewAccount = result.isNewAccount, + authorization = result.authorization?.sdk(), + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt new file mode 100644 index 0000000..7e3dd5b --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt @@ -0,0 +1,28 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.sdk +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.authorization.sessions.requests.GetAuthorizationSessionsRequest +import io.timemates.sdk.authorization.sessions.types.Authorization +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.common.pagination.Page +import io.timemates.sdk.common.pagination.PageToken +import io.timemates.api.authorizations.requests.GetAuthorizationsRequest as RSGetAuthorizationsRequest + +internal object GetAuthorizationSessionsCommand : RSocketCommand> { + override suspend fun execute(apis: ApiContainer, input: GetAuthorizationSessionsRequest): Page { + return apis.auth.getAuthorizations( + message = RSGetAuthorizationsRequest(input.nextPageToken?.string.orEmpty()), + extra = input.accessHash.toExtra(), + ).let { result -> + Page( + results = result.authorizations.map { it.sdk() }, + nextPageToken = result.nextPageToken + .takeIf { it.isNotEmpty() } + ?.let { PageToken.createOrThrow(it) }, + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt new file mode 100644 index 0000000..245143a --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt @@ -0,0 +1,21 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.sdk +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.authorization.sessions.requests.RenewAuthorizationRequest +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi +import io.timemates.api.authorizations.requests.RenewAuthorizationRequest as RSRenewAuthorizationRequest + +@OptIn(ExperimentalTimeMatesApi::class) +internal object RenewAuthorizationCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: RenewAuthorizationRequest): RenewAuthorizationRequest.Result { + return apis.auth.renewAuthorization( + message = RSRenewAuthorizationRequest(input.refreshHash.string), + ).let { result -> + RenewAuthorizationRequest.Result( + authorization = result.authorization!!.sdk() + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt new file mode 100644 index 0000000..cc892ee --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt @@ -0,0 +1,31 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.rs +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest +import io.timemates.sdk.authorization.email.types.value.VerificationHash +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.common.types.value.Count +import kotlinx.datetime.Instant +import io.timemates.api.authorizations.requests.StartAuthorizationRequest as RSStartAuthorizationRequest + +internal object StartAuthorizationCommand : RSocketCommand { + override suspend fun execute( + apis: ApiContainer, + input: StartAuthorizationRequest, + ): StartAuthorizationRequest.Result { + return apis.auth.startAuthorization( + message = RSStartAuthorizationRequest( + input.emailAddress.string, + input.metadata.rs(), + ) + ).let { result -> + StartAuthorizationRequest.Result( + verificationHash = VerificationHash.createOrThrow(result.verificationHash), + attempts = Count.createOrThrow(result.attempts), + expiresAt = Instant.fromEpochMilliseconds(result.expiresAt), + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt new file mode 100644 index 0000000..7e12e41 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.authorizations.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.authorization.sessions.requests.TerminateCurrentAuthorizationSessionRequest +import io.timemates.sdk.common.types.Empty +import com.google.protobuf.Empty.Companion as RSEmpty + +internal object TerminateCurrentAuthorizationCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: TerminateCurrentAuthorizationSessionRequest): Empty { + return apis.auth.terminateAuthorization( + message = RSEmpty.Default, + input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt new file mode 100644 index 0000000..6403b51 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt @@ -0,0 +1,26 @@ +package io.timemates.api.rsocket.common.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.TimeMatesRequest + +/** + * An interface representing a command that can be executed via an RSocket connection. + * + * This interface is used to decouple logic by accepting an SDK entity of type [T] + * and converting it into the engine's entity type [R] within the implementation. + * + * @param T The type of the SDK entity that serves as the command's input. + * @param R The type of the engine's entity that represents the command's result. + */ +internal interface RSocketCommand, R : TimeMatesEntity> { + /** + * Executes the command using the provided RSocket connection and input of type [T]. + * + * @param apis The RSocket connection over which the command will be executed. + * @param input The SDK entity representing the command's input. + * @return The engine's entity representing the result of executing the command. + * @throws RSocketException if there is an issue with the RSocket communication. + */ + suspend fun execute(apis: ApiContainer, input: T): R +} diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt new file mode 100644 index 0000000..902aa47 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt @@ -0,0 +1,39 @@ +package io.timemates.api.rsocket.common.commands + +import io.rsocket.kotlin.RSocket +import io.timemates.api.rsocket.ApiContainer +import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.TimeMatesRequest + +/** + * An inline class that encapsulates a set of RSocket commands for executing TimeMates requests. + * + * The [RSocketCommands] class allows you to execute TimeMates requests using the provided RSocket + * instance. It maintains a map of commands associated with request keys, which are used to look up + * the appropriate command for a given request. + * + * @param commands A map of request keys to RSocket command implementations. + */ +@JvmInline +internal value class RSocketCommands( + private val commands: Map, RSocketCommand<*, *>>, +) { + /** + * Executes a TimeMates request using the specified RSocket instance. + * + * This function looks up the appropriate RSocket command based on the request's [requestKey] + * and executes it with the provided RSocket and request object. + * + * @param T The specific type of the TimeMates request. + * @param R The type of the response expected from the request. + * @param rSocket The RSocket instance to use for executing the request. + * @param request The TimeMates request to execute. + */ + suspend inline fun , R : TimeMatesEntity> execute( + rSocket: ApiContainer, + request: T, + ): R? { + @Suppress("UNCHECKED_CAST") + return (commands[request.requestKey] as? RSocketCommand)?.execute(rSocket, request) + } +} diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt new file mode 100644 index 0000000..2889876 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt @@ -0,0 +1,37 @@ +package io.timemates.api.rsocket.common.commands + +import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.TimeMatesRequest + +@RSocketCommandsDsl +@JvmInline +internal value class RSocketCommandsBuilderScope( + private val commands: MutableMap, RSocketCommand<*, *>> = + mutableMapOf(), +) { + fun , R : TimeMatesEntity> associate( + key: TimeMatesRequest.Key, + command: RSocketCommand, + ) { + commands += key to command + } + + + infix fun , R : TimeMatesEntity> RSocketCommand.associatedWith( + key: TimeMatesRequest.Key, + ) { + associate(key, this) + } + + fun build(): RSocketCommands = RSocketCommands(commands) +} + +@DslMarker +internal annotation class RSocketCommandsDsl + +@RSocketCommandsDsl +internal inline fun rSocketCommands( + block: RSocketCommandsBuilderScope.() -> Unit, +): RSocketCommands { + return RSocketCommandsBuilderScope().apply(block).build() +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt new file mode 100644 index 0000000..218b64a --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt @@ -0,0 +1,89 @@ +package io.timemates.api.rsocket.timers + +import io.timemates.api.timers.sessions.types.TimerState +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.common.types.value.Count +import io.timemates.sdk.timers.members.invites.types.value.InviteCode +import io.timemates.sdk.timers.types.Timer +import io.timemates.sdk.timers.types.TimerSettings +import io.timemates.sdk.timers.types.value.TimerDescription +import io.timemates.sdk.timers.types.value.TimerId +import io.timemates.sdk.timers.types.value.TimerName +import io.timemates.sdk.users.profile.types.value.UserId +import kotlinx.datetime.Instant +import kotlin.time.Duration.Companion.minutes +import kotlin.time.DurationUnit +import io.timemates.api.timers.members.invites.types.Invite as RSInvite +import io.timemates.api.timers.sessions.types.TimerState as RSTimerState +import io.timemates.api.timers.types.Timer as RSTimer +import io.timemates.sdk.timers.members.invites.types.Invite as SdkInvite +import io.timemates.sdk.timers.types.Timer as SdkTimer +import io.timemates.sdk.timers.types.Timer.State as SdkTimerState +import io.timemates.sdk.timers.types.TimerSettings as SdkTimerSettings + +internal fun RSTimer.sdk(): SdkTimer { + return SdkTimer( + timerId = TimerId.createOrThrow(id), + name = TimerName.createOrThrow(name), + description = TimerDescription.createOrThrow(description), + ownerId = UserId.createOrThrow(ownerId), + membersCount = Count.createOrThrow(membersCount), + state = currentState?.sdk() ?: SdkTimerState.Inactive(Instant.DISTANT_PAST), + settings = settings?.sdk() ?: TimerSettings(), + ) +} + +internal fun RSTimerState.sdk(): SdkTimerState { + val publishTime = Instant.fromEpochMilliseconds(publishTime) + return when (phase) { + is TimerState.PhaseOneOf.ConfirmationWaiting -> SdkTimerState.ConfirmationWaiting( + endsAt = Instant.fromEpochMilliseconds(phase.value!!.endsAt), + publishTime = publishTime, + ) + is TimerState.PhaseOneOf.Inactive -> SdkTimerState.Inactive( + publishTime = publishTime, + ) + is TimerState.PhaseOneOf.Paused -> SdkTimerState.Paused( + publishTime = publishTime, + ) + is TimerState.PhaseOneOf.Rest -> SdkTimerState.Rest( + endsAt = Instant.fromEpochMilliseconds(phase.value!!.endsAt), + publishTime = publishTime, + ) + is TimerState.PhaseOneOf.Running -> SdkTimerState.Running( + endsAt = Instant.fromEpochMilliseconds(phase.value!!.endsAt), + publishTime = publishTime, + ) + null -> SdkTimerState.Inactive(Instant.DISTANT_PAST) + } +} + +internal fun RSTimer.Settings.sdk(): SdkTimerSettings { + return SdkTimerSettings( + workTime = workTime.minutes, + restTime = restTime.minutes, + bigRestTime = bigRestTime.minutes, + bigRestEnabled = bigRestEnabled, + bigRestPer = Count.createOrThrow(bigRestPer), + isEveryoneCanPause = isEveryoneCanPause, + isConfirmationRequired = isConfirmationRequired, + ) +} + +internal fun SdkTimerSettings.rs(): RSTimer.Settings { + return RSTimer.Settings( + workTime = workTime.toInt(DurationUnit.MINUTES), + restTime = restTime.toInt(DurationUnit.MINUTES), + bigRestEnabled = bigRestEnabled, + bigRestTime = bigRestTime.toInt(DurationUnit.MINUTES), + isConfirmationRequired = isConfirmationRequired, + ) +} + +internal fun RSInvite.sdk(): SdkInvite { + return SdkInvite( + inviteCode = InviteCode.createOrThrow(code), + creationTime = Instant.fromEpochMilliseconds(creationTime), + limit = Count.createOrThrow(limit), + ) +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt new file mode 100644 index 0000000..e3b0cea --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt @@ -0,0 +1,25 @@ +package io.timemates.api.rsocket.timers.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.rs +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.timers.requests.CreateTimerRequest +import io.timemates.sdk.timers.types.value.TimerId +import io.timemates.api.timers.requests.CreateTimerRequest as RSCreateTimerRequest + +internal object CreateTimerCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: CreateTimerRequest): CreateTimerRequest.Result { + return apis.timers.createTimer( + message = RSCreateTimerRequest( + name = input.name.string, + description = input.description.string, + settings = input.settings.rs(), + ), + extra = input.accessHash.toExtra(), + ).let { result -> + CreateTimerRequest.Result(TimerId.createOrThrow(result.timerId)) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt new file mode 100644 index 0000000..6ccea2c --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt @@ -0,0 +1,20 @@ +package io.timemates.api.rsocket.timers.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.requests.EditTimerRequest +import io.timemates.api.timers.requests.EditTimerRequest as RSEditTimerRequest + +internal object EditTimerCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: EditTimerRequest): Empty { + return apis.timers.editTimer( + message = RSEditTimerRequest( + timerId = input.timerId.long, + name = input.name?.string.orEmpty(), + ), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt new file mode 100644 index 0000000..4769722 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt @@ -0,0 +1,21 @@ +package io.timemates.api.rsocket.timers.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.sdk +import io.timemates.sdk.timers.requests.GetTimerRequest +import io.timemates.api.timers.requests.GetTimerRequest as RSGetTimerRequest + +internal object GetTimerCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: GetTimerRequest): GetTimerRequest.Result { + return apis.timers.getTimer( + message = RSGetTimerRequest( + timerId = input.timerId.long, + ), + extra = input.accessHash.toExtra(), + ).let { result -> + GetTimerRequest.Result(result.sdk()) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt new file mode 100644 index 0000000..cbfb139 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt @@ -0,0 +1,30 @@ +package io.timemates.api.rsocket.timers.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.sdk +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.common.pagination.Page +import io.timemates.sdk.common.pagination.PageToken +import io.timemates.sdk.timers.requests.GetUserTimersRequest +import io.timemates.sdk.timers.types.Timer +import io.timemates.api.timers.requests.GetTimersRequest as RSGetTimersRequest + +internal object GetUserTimersCommand : RSocketCommand> { + override suspend fun execute(apis: ApiContainer, input: GetUserTimersRequest): Page { + return apis.timers.getTimers( + message = RSGetTimersRequest( + nextPageToken = input.pageToken?.string.orEmpty(), + ), + extra = input.accessHash.toExtra(), + ).let { result -> + Page( + results = result.timers.map { it.sdk() }, + nextPageToken = result.nextPageToken + .takeIf { it.isNotEmpty() } + ?.let { PageToken.createOrThrow(it) }, + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt new file mode 100644 index 0000000..5abfeb5 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.timers.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.requests.RemoveTimerRequest +import io.timemates.api.timers.requests.RemoveTimerRequest as RSRemoveTimerRequest + +internal object RemoveTimerCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: RemoveTimerRequest): Empty { + return apis.timers.removeTimer( + message = RSRemoveTimerRequest(input.timerId.long), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt new file mode 100644 index 0000000..ad3f892 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt @@ -0,0 +1,24 @@ +package io.timemates.api.rsocket.timers.commands + +import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope +import io.timemates.api.rsocket.timers.members.commands.timerMembers +import io.timemates.api.rsocket.timers.sessions.commands.timerSessions +import io.timemates.sdk.timers.requests.CreateTimerRequest +import io.timemates.sdk.timers.requests.EditTimerRequest +import io.timemates.sdk.timers.requests.GetTimerRequest +import io.timemates.sdk.timers.requests.GetUserTimersRequest +import io.timemates.sdk.timers.requests.RemoveTimerRequest + +/** + * RSocket commands related to timers. + */ +internal fun RSocketCommandsBuilderScope.timers() { + timerMembers() + timerSessions() + + CreateTimerCommand associatedWith CreateTimerRequest + EditTimerCommand associatedWith EditTimerRequest + GetTimerCommand associatedWith GetTimerRequest + RemoveTimerCommand associatedWith RemoveTimerRequest + GetUserTimersCommand associatedWith GetUserTimersRequest +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt new file mode 100644 index 0000000..91fdbb2 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt @@ -0,0 +1,31 @@ +package io.timemates.api.rsocket.timers.members.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.users.sdk +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.common.pagination.Page +import io.timemates.sdk.common.pagination.PageToken +import io.timemates.sdk.timers.members.requests.GetMembersRequest +import io.timemates.sdk.users.profile.types.User +import io.timemates.api.timers.members.requests.GetMembersRequest as RSGetMembersRequest + +internal object GetTimerMembersCommand : RSocketCommand> { + override suspend fun execute(apis: ApiContainer, input: GetMembersRequest): Page { + return apis.timers.getMembers( + message = RSGetMembersRequest( + timerId = input.timerId.long, + nextPageToken = input.pageToken?.string.orEmpty(), + ), + extra = input.accessHash.toExtra(), + ).let { result -> + Page( + results = result.users.map { it.sdk() }, + nextPageToken = result.nextPageToken + .takeIf { it.isNotEmpty() } + ?.let { PageToken.createOrThrow(it) }, + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt new file mode 100644 index 0000000..557c09b --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.timers.members.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.members.requests.KickMemberRequest +import io.timemates.api.timers.members.requests.KickMemberRequest as RSKickMemberRequest + +internal object KickTimerMemberCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: KickMemberRequest): Empty { + return apis.timers.kickMember( + message = RSKickMemberRequest(timerId = input.timerId.long), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt new file mode 100644 index 0000000..e21024f --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt @@ -0,0 +1,20 @@ +package io.timemates.api.rsocket.timers.members.commands + +import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope +import io.timemates.api.rsocket.timers.members.invites.commands.timerMemberInvites +import io.timemates.sdk.timers.members.requests.GetMembersRequest +import io.timemates.sdk.timers.members.requests.KickMemberRequest +import io.timemates.sdk.timers.requests.CreateTimerRequest +import io.timemates.sdk.timers.requests.EditTimerRequest +import io.timemates.sdk.timers.requests.GetTimerRequest +import io.timemates.sdk.timers.requests.RemoveTimerRequest + +/** + * RSocket commands related to timer members. + */ +internal fun RSocketCommandsBuilderScope.timerMembers() { + timerMemberInvites() + + GetTimerMembersCommand associatedWith GetMembersRequest + KickTimerMemberCommand associatedWith KickMemberRequest +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt new file mode 100644 index 0000000..801e38e --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt @@ -0,0 +1,23 @@ +package io.timemates.api.rsocket.timers.members.invites.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.timers.members.invites.requests.InviteMemberRequest +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.timers.members.invites.requests.CreateInviteRequest +import io.timemates.sdk.timers.members.invites.types.value.InviteCode + +internal object CreateInviteCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: CreateInviteRequest): CreateInviteRequest.Result { + return apis.timers.createInvite( + message = InviteMemberRequest( + timerId = input.timerId.long, + maxJoiners = input.maxJoinersCount.int, + ), + extra = input.accessHash.toExtra(), + ).let { result -> + CreateInviteRequest.Result(InviteCode.createOrThrow(result.inviteCode)) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt new file mode 100644 index 0000000..08c4f18 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt @@ -0,0 +1,31 @@ +package io.timemates.api.rsocket.timers.members.invites.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.sdk +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.common.pagination.Page +import io.timemates.sdk.common.pagination.PageToken +import io.timemates.sdk.timers.members.invites.requests.GetInvitesRequest +import io.timemates.sdk.timers.members.invites.types.Invite +import io.timemates.api.timers.members.invites.requests.GetInvitesRequest as RSGetInvitesRequest + +internal object GetInvitesCommand : RSocketCommand> { + override suspend fun execute(apis: ApiContainer, input: GetInvitesRequest): Page { + return apis.timers.getInvites( + message = RSGetInvitesRequest( + timerId = input.timerId.long, + nextPageToken = input.pageToken?.string.orEmpty(), + ), + extra = input.accessHash.toExtra(), + ).let { result -> + Page( + results = result.invites.map { it.sdk() }, + nextPageToken = result.nextPageToken + .takeIf { it.isNotEmpty() } + ?.let { PageToken.createOrThrow(it) }, + ) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt new file mode 100644 index 0000000..11b1c67 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt @@ -0,0 +1,23 @@ +package io.timemates.api.rsocket.timers.members.invites.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.sdk +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.timers.members.invites.requests.JoinTimerByCodeRequest +import io.timemates.sdk.timers.types.value.TimerId +import io.timemates.api.timers.requests.JoinTimerByInviteCodeRequest as RSJoinTimerByInviteCodeRequest + +internal object JoinTimerByCodeCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: JoinTimerByCodeRequest): JoinTimerByCodeRequest.Result { + return apis.timers.joinByInvite( + message = RSJoinTimerByInviteCodeRequest( + inviteCode = input.code.string, + ), + extra = input.accessHash.toExtra(), + ).let { result -> + JoinTimerByCodeRequest.Result(result.timer!!.sdk()) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt new file mode 100644 index 0000000..65821c9 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt @@ -0,0 +1,20 @@ +package io.timemates.api.rsocket.timers.members.invites.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.members.invites.requests.RemoveInviteRequest +import io.timemates.api.timers.members.invites.requests.RemoveInviteRequest as RSRemoveInviteRequest + +internal object RemoveInviteCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: RemoveInviteRequest): Empty { + return apis.timers.removeInvite( + message = RSRemoveInviteRequest( + timerId = input.timerId.long, + inviteCode = input.inviteCode.string, + ), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt new file mode 100644 index 0000000..ad64e2a --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.timers.members.invites.commands + +import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope +import io.timemates.sdk.timers.members.invites.requests.CreateInviteRequest +import io.timemates.sdk.timers.members.invites.requests.GetInvitesRequest +import io.timemates.sdk.timers.members.invites.requests.JoinTimerByCodeRequest +import io.timemates.sdk.timers.members.invites.requests.RemoveInviteRequest + +/** + * RSocket commands related to timer members. + */ +internal fun RSocketCommandsBuilderScope.timerMemberInvites() { + CreateInviteCommand associatedWith CreateInviteRequest + GetInvitesCommand associatedWith GetInvitesRequest + JoinTimerByCodeCommand associatedWith JoinTimerByCodeRequest + RemoveInviteCommand associatedWith RemoveInviteRequest +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt new file mode 100644 index 0000000..ccc2dc5 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.sessions.requests.ConfirmTimerRoundRequest +import com.google.protobuf.Empty.Companion as RSEmpty + +internal object ConfirmSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: ConfirmTimerRoundRequest): Empty { + return apis.timerSessions.confirmRound( + message = RSEmpty.Default, + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt new file mode 100644 index 0000000..0172b9f --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt @@ -0,0 +1,18 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import com.google.protobuf.Empty +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.sdk +import io.timemates.sdk.timers.sessions.requests.GetUserCurrentSessionRequest +import io.timemates.sdk.timers.types.Timer + +internal object GetCurrentSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: GetUserCurrentSessionRequest): Timer { + return apis.timerSessions.getCurrentTimerSession( + message = Empty.Default, + extra = input.accessHash.toExtra(), + ).sdk() + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt new file mode 100644 index 0000000..8828690 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt @@ -0,0 +1,20 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.timers.sdk +import io.timemates.sdk.timers.sessions.requests.GetTimerStateRequest +import kotlinx.coroutines.flow.map +import io.timemates.api.timers.sessions.requests.GetTimerStateRequest as RSGetTimerStateRequest + +internal object GetTimerStateCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: GetTimerStateRequest): GetTimerStateRequest.Result { + return apis.timerSessions.getState( + message = RSGetTimerStateRequest(timerId = input.timerId.long), + extra = input.accessHash.toExtra(), + ).let { result -> + GetTimerStateRequest.Result(result.map { it.sdk() }) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt new file mode 100644 index 0000000..114f20f --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt @@ -0,0 +1,19 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.sessions.requests.JoinTimerSessionRequest +import io.timemates.api.timers.sessions.requests.JoinTimerSessionRequest as RSJoinTimerSessionRequest + +internal object JoinSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: JoinTimerSessionRequest): Empty { + return apis.timerSessions.joinSession( + message = RSJoinTimerSessionRequest( + timerId = input.timerId.long, + ), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt new file mode 100644 index 0000000..9753d39 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.sessions.requests.LeaveTimerSessionRequest +import com.google.protobuf.Empty.Companion as RSEmpty + +internal object LeaveSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: LeaveTimerSessionRequest): Empty { + return apis.timerSessions.leaveSession( + message = RSEmpty.Default, + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt new file mode 100644 index 0000000..3c63c6e --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.sessions.requests.PingSessionRequest +import com.google.protobuf.Empty.Companion as RSEmpty + +internal object PingSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: PingSessionRequest): Empty { + return apis.timerSessions.pingSession( + message = RSEmpty.Default, + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt new file mode 100644 index 0000000..c782ab8 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt @@ -0,0 +1,19 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.sessions.requests.StartTimerRequest +import io.timemates.api.timers.sessions.requests.StartTimerRequest as RSStartTimerRequest + +internal object StartSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: StartTimerRequest): Empty { + return apis.timerSessions.startTimer( + message = RSStartTimerRequest( + timerId = input.timerId.long, + ), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt new file mode 100644 index 0000000..e497cbf --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt @@ -0,0 +1,19 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.timers.sessions.requests.StopTimerRequest +import io.timemates.api.timers.sessions.requests.StopTimerRequest as RSStopTimerRequest + +internal object StopSessionCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: StopTimerRequest): Empty { + return apis.timerSessions.stopTimer( + message = RSStopTimerRequest( + timerId = input.timerId.long, + ), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt new file mode 100644 index 0000000..bd38fb0 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt @@ -0,0 +1,25 @@ +package io.timemates.api.rsocket.timers.sessions.commands + +import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope +import io.timemates.sdk.timers.sessions.requests.ConfirmTimerRoundRequest +import io.timemates.sdk.timers.sessions.requests.GetTimerStateRequest +import io.timemates.sdk.timers.sessions.requests.GetUserCurrentSessionRequest +import io.timemates.sdk.timers.sessions.requests.JoinTimerSessionRequest +import io.timemates.sdk.timers.sessions.requests.LeaveTimerSessionRequest +import io.timemates.sdk.timers.sessions.requests.PingSessionRequest +import io.timemates.sdk.timers.sessions.requests.StartTimerRequest +import io.timemates.sdk.timers.sessions.requests.StopTimerRequest + +/** + * RSocket commands related to timer members. + */ +internal fun RSocketCommandsBuilderScope.timerSessions() { + ConfirmSessionCommand associatedWith ConfirmTimerRoundRequest + LeaveSessionCommand associatedWith LeaveTimerSessionRequest + PingSessionCommand associatedWith PingSessionRequest + GetCurrentSessionCommand associatedWith GetUserCurrentSessionRequest + StartSessionCommand associatedWith StartTimerRequest + StopSessionCommand associatedWith StopTimerRequest + JoinSessionCommand associatedWith JoinTimerSessionRequest + GetTimerStateCommand associatedWith GetTimerStateRequest +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt new file mode 100644 index 0000000..84d7da2 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt @@ -0,0 +1,20 @@ +package io.timemates.api.rsocket.users + +import io.timemates.sdk.common.constructor.createOrThrow +import io.timemates.sdk.users.profile.types.Avatar +import io.timemates.sdk.users.profile.types.value.EmailAddress +import io.timemates.sdk.users.profile.types.value.UserDescription +import io.timemates.sdk.users.profile.types.value.UserId +import io.timemates.sdk.users.profile.types.value.UserName +import io.timemates.api.users.types.User as RSUser +import io.timemates.sdk.users.profile.types.User as SdkUser + +internal fun RSUser.sdk(): SdkUser { + return SdkUser( + id = UserId.createOrThrow(id), + name = UserName.createOrThrow(name), + description = description.takeIf { it.isNotEmpty() }?.let { UserDescription.createOrThrow(it) }, + emailAddress = email.takeIf { it.isNotEmpty() }?.let { EmailAddress.createOrThrow(it) }, + avatar = gravatarId.takeIf { it.isNotBlank() }?.let { Avatar.GravatarId.createOrThrow(it) }, + ) +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt new file mode 100644 index 0000000..b0bb573 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt @@ -0,0 +1,19 @@ +package io.timemates.api.rsocket.users.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.users.settings.requests.EditEmailRequest +import io.timemates.api.users.requests.EditEmailRequest as RSEditEmailRequest + +@OptIn(ExperimentalTimeMatesApi::class) +internal object EditEmailCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: EditEmailRequest): Empty { + return apis.users.setEmail( + message = RSEditEmailRequest(email = input.newEmail.string), + extra = input.accessHash.toExtra() + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt new file mode 100644 index 0000000..0b6ec97 --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt @@ -0,0 +1,22 @@ +package io.timemates.api.rsocket.users.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.authorizations.toExtra +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.users.profile.requests.EditProfileRequest +import io.timemates.sdk.users.profile.types.Avatar +import io.timemates.api.users.requests.EditUserRequest as RSEditUserRequest + +internal object EditProfileCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: EditProfileRequest): Empty { + return apis.users.setUser( + message = RSEditUserRequest( + gravatarId = (input.avatar as? Avatar.GravatarId)?.string.orEmpty(), + name = input.name?.string.orEmpty(), + description = input.description?.string.orEmpty(), + ), + extra = input.accessHash.toExtra(), + ).let { _ -> Empty } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt new file mode 100644 index 0000000..85e7a5b --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.users.commands + +import io.timemates.api.rsocket.ApiContainer +import io.timemates.api.rsocket.common.commands.RSocketCommand +import io.timemates.api.rsocket.users.sdk +import io.timemates.sdk.users.profile.requests.GetUsersRequest +import io.timemates.api.users.requests.GetUsersRequest as RSGetUsersRequest + +internal object GetUsersCommand : RSocketCommand { + override suspend fun execute(apis: ApiContainer, input: GetUsersRequest): GetUsersRequest.Result { + return apis.users.getUsers( + message = RSGetUsersRequest(userId = input.users.map { it.long }), + ).let { result -> + GetUsersRequest.Result(result.users.map { it.sdk() }) + } + } +} \ No newline at end of file diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt new file mode 100644 index 0000000..89ee76c --- /dev/null +++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt @@ -0,0 +1,17 @@ +package io.timemates.api.rsocket.users.commands + +import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi +import io.timemates.sdk.users.profile.requests.EditProfileRequest +import io.timemates.sdk.users.profile.requests.GetUsersRequest +import io.timemates.sdk.users.settings.requests.EditEmailRequest + +/** + * RSocket commands related to user operations. + */ +@OptIn(ExperimentalTimeMatesApi::class) +internal fun RSocketCommandsBuilderScope.users() { + EditProfileCommand associatedWith EditProfileRequest + GetUsersCommand associatedWith GetUsersRequest + EditEmailCommand associatedWith EditEmailRequest +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto similarity index 81% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto index 059cfea..c27c867 100644 --- a/grpc-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto +++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto @@ -5,6 +5,7 @@ import "io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.pro import "io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto"; import "io/timemates/api/authorizations/options/OmitAuthorizationOption.proto"; import "io/timemates/api/authorizations/requests/CreateProfileRequest.proto"; +import "io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto"; import "io/timemates/api/authorizations/types/Authorization.proto"; import "google/protobuf/empty.proto"; @@ -31,6 +32,18 @@ service AuthorizationService { option (omit_authorization) = true; } + /** + * Renews authorization using refresh token. + * + * Returns: new [Authorization]. + */ + rpc renewAuthorization(RenewAuthorizationRequest) returns (RenewAuthorizationRequest.Response) { + option (omit_authorization) = true; + } + + /** + * Creates a user's profile if it's a new account. + */ rpc createProfile(CreateProfileRequest) returns (CreateProfileRequest.Response) { option (omit_authorization) = true; } diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto diff --git a/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto new file mode 100644 index 0000000..f5ad398 --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +import "io/timemates/api/authorizations/types/Authorization.proto"; + +option java_package = "io.timemates.api.authorizations.requests"; + +message RenewAuthorizationRequest { + string refreshHash = 1; + + message Response { + Authorization authorization = 1; + } +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto similarity index 60% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto index 605b36e..1992b67 100644 --- a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto +++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto @@ -1,10 +1,15 @@ syntax = "proto3"; +import "io/timemates/api/authorizations/types/Authorization.proto"; +import "io/timemates/api/authorizations/types/Metadata.proto"; + option java_package = "io.timemates.api.authorizations.requests"; message StartAuthorizationRequest { string emailAddress = 1; + optional Metadata metadata = 2; + message Result { string verificationHash = 1; int64 expiresAt = 2; diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto similarity index 84% rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto index db61522..a7908e3 100644 --- a/grpc-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto +++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto @@ -1,5 +1,7 @@ syntax = "proto3"; +import "io/timemates/api/authorizations/types/Metadata.proto"; + option java_package = "io.timemates.api.authorizations.types"; message Authorization { @@ -27,14 +29,13 @@ message Authorization { */ optional Metadata metadata = 5; + /** + * Owner's id. + */ + int64 userId = 6; + message Hash { string value = 1; int64 expiresAt = 2; } - - message Metadata { - string clientName = 1; - string clientVersion = 2; - string clientIpAddress = 3; - } } \ No newline at end of file diff --git a/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto new file mode 100644 index 0000000..75d00a1 --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +option java_package = "io.timemates.api.authorizations.types"; + +message Metadata { + string clientName = 1; + double clientVersion = 2; +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/TimersService.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/TimersService.proto similarity index 89% rename from grpc-engine/src/main/proto/io/timemates/api/timers/TimersService.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/TimersService.proto index ff8cfc5..3300089 100644 --- a/grpc-engine/src/main/proto/io/timemates/api/timers/TimersService.proto +++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/TimersService.proto @@ -10,6 +10,7 @@ import "io/timemates/api/timers/members/requests/GetMembersRequest.proto"; import "io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto"; import "io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto"; import "io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto"; +import "io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto"; import "io/timemates/api/timers/types/Timer.proto"; import "google/protobuf/empty.proto"; @@ -61,6 +62,11 @@ service TimersService { */ rpc removeInvite(RemoveInviteRequest) returns (google.protobuf.Empty); + /** + * Joins timer by invite code. + */ + rpc joinByInvite(JoinTimerByInviteCodeRequest) returns (JoinTimerByInviteCodeRequest.Response); + /** * Removes timer. */ diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto diff --git a/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto new file mode 100644 index 0000000..448bb0e --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +import "io/timemates/api/timers/types/Timer.proto"; + +option java_package = "io.timemates.api.timers.requests"; + +message JoinTimerByInviteCodeRequest { + string inviteCode = 1; + + message Response { + Timer timer = 1; + } +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto similarity index 73% rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto index 945ec05..144ff68 100644 --- a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto +++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto @@ -5,18 +5,17 @@ import "io/timemates/api/timers/types/Timer.proto"; option java_package = "io.timemates.api.timers.requests"; message CreateTimerRequest { - int64 timerId = 1; /** * Timer's name. Up to 50 symbols. */ - string name = 2; + string name = 1; /** * Timer's name. Up to 500 symbols. */ - optional string description = 3; + optional string description = 2; - optional Timer.Settings settings = 4; + optional Timer.Settings settings = 3; message Response { int64 timerId = 1; diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto similarity index 93% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto index fcfe1ce..d34518d 100644 --- a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto +++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto @@ -5,10 +5,10 @@ import "io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto" import "io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto"; import "io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto"; import "io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto"; -import "io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto"; import "io/timemates/api/timers/sessions/types/TimerState.proto"; -import "io/timemates/api/timers/types/Timer.proto"; import "google/protobuf/empty.proto"; +import "io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto"; +import "io/timemates/api/timers/types/Timer.proto"; option java_package = "io.timemates.api.timers"; @@ -67,5 +67,5 @@ service TimerSessionsService { /** * Gets current timer session */ - rpc getUserCurrentSession(google.protobuf.Empty) returns (Timer); + rpc getCurrentTimerSession(google.protobuf.Empty) returns (Timer); } diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto diff --git a/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto new file mode 100644 index 0000000..150599d --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +import "io/timemates/api/timers/types/Timer.proto"; + +option java_package = "io.timemates.api.timers.requests"; + +message GetCurrentTimerSessionRequest { + message Response { + Timer timer = 1; + } +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto rename to rsocket-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto diff --git a/rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto new file mode 100644 index 0000000..f9e6524 --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +import "io/timemates/api/users/requests/GetUsersRequest.proto"; +import "io/timemates/api/users/requests/EditUserRequest.proto"; +import "io/timemates/api/users/requests/EditEmailRequest.proto"; +import "io/timemates/api/users/types/User.proto"; +import "google/protobuf/empty.proto"; + +option java_package = "io.timemates.api.users"; + +service UsersService { + /** + * Gets users by given identifiers. + * + * Returns [User] or null. + */ + rpc getUsers(GetUsersRequest) returns (Users); + + /** + * Sets user information (name / description / avatar file id). + * + * Returns [Status] + */ + rpc setUser(EditUserRequest) returns (google.protobuf.Empty); + + /** + * Sets new email for current user. + * + * Returns [Status] + */ + rpc setEmail(EditEmailRequest) returns (google.protobuf.Empty); +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto diff --git a/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto new file mode 100644 index 0000000..53b072c --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +option java_package = "io.timemates.api.users.requests"; + +message EditUserRequest { + /** + * User's avatar id + */ + string gravatarId = 1; + /** + * User's name + */ + optional string name = 2; + + /** + * User's description. + */ + optional string description = 3; +} \ No newline at end of file diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto similarity index 100% rename from grpc-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto rename to rsocket-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto diff --git a/rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto new file mode 100644 index 0000000..62e9437 --- /dev/null +++ b/rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; + +option java_package = "io.timemates.api.users.types"; + +message User { + /** + * User's identifier + */ + int64 id = 1; + + string gravatarId = 3; + + /** + * User's name + */ + string name = 4; + + /** + * User's description. + */ + string description = 5; + + /** + * User's email up to 200 symbols. + * Can be null if there is no access. + */ + optional string email = 6; +} + +message Users { + repeated User users = 1; +} \ No newline at end of file diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index bdad811..8c72269 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -33,4 +33,8 @@ deployLibrary { version = System.getenv("TIMEMATES_SDK_VERSION") } +} + +tasks.withType { + useJUnitPlatform() } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt index 011a199..3a85a35 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt @@ -4,6 +4,7 @@ import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest import io.timemates.sdk.authorization.email.types.value.VerificationHash +import io.timemates.sdk.authorization.sessions.types.Authorization import io.timemates.sdk.authorization.sessions.types.value.ConfirmationCode import io.timemates.sdk.common.engine.TimeMatesRequestsEngine import io.timemates.sdk.users.profile.types.value.EmailAddress @@ -21,8 +22,12 @@ public class EmailAuthorizationApi(private val engine: TimeMatesRequestsEngine) * * @see confirm */ - public suspend fun authorize(emailAddress: EmailAddress): Result { - return engine.execute(StartAuthorizationRequest(emailAddress)).map { it.verificationHash } + public suspend fun authorize( + emailAddress: EmailAddress, + metadata: Authorization.Metadata, + ): Result { + return engine.execute(StartAuthorizationRequest(emailAddress, metadata)) + .map { it.verificationHash } } /** @@ -36,7 +41,7 @@ public class EmailAuthorizationApi(private val engine: TimeMatesRequestsEngine) public suspend fun confirm( verificationHash: VerificationHash, confirmationCode: ConfirmationCode, - ): Result { + ): Result { return engine.execute(ConfirmAuthorizationRequest(verificationHash, confirmationCode)) } diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt index 8a11ec5..cb4f74c 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt @@ -10,7 +10,12 @@ import io.timemates.sdk.users.profile.types.value.UserName public data class ConfigureNewAccountRequest( val verificationHash: VerificationHash, val name: UserName, - val description: UserDescription, + val description: UserDescription?, ) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + public data class Result(val authorization: Authorization) : TimeMatesEntity() + + override val requestKey: Key + get() = Key } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt index 6e9d3a4..3296000 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt @@ -1,17 +1,22 @@ package io.timemates.sdk.authorization.email.requests +import io.timemates.sdk.authorization.email.types.value.VerificationHash import io.timemates.sdk.authorization.sessions.types.Authorization import io.timemates.sdk.authorization.sessions.types.value.ConfirmationCode -import io.timemates.sdk.authorization.email.types.value.VerificationHash import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest public data class ConfirmAuthorizationRequest( val verificationHash: VerificationHash, val confirmationCode: ConfirmationCode, -) : TimeMatesRequest() { - public data class Response( +) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + public data class Result( val isNewAccount: Boolean, val authorization: Authorization?, ) : TimeMatesEntity() + + override val requestKey: Key + get() = Key } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt index 7c103d4..cf1411b 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt @@ -1,18 +1,24 @@ package io.timemates.sdk.authorization.email.requests -import io.timemates.sdk.users.profile.types.value.EmailAddress import io.timemates.sdk.authorization.email.types.value.VerificationHash +import io.timemates.sdk.authorization.sessions.types.Authorization import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.common.types.value.Count +import io.timemates.sdk.users.profile.types.value.EmailAddress import kotlinx.datetime.Instant public data class StartAuthorizationRequest( - val emailAddress: EmailAddress + val emailAddress: EmailAddress, + val metadata: Authorization.Metadata, ) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + public data class Result( val verificationHash: VerificationHash, val attempts: Count, val expiresAt: Instant, ) : TimeMatesEntity() + + override val requestKey: Key get() = Key } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt index 6150783..5510830 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt @@ -16,9 +16,6 @@ import io.timemates.sdk.common.providers.AccessHashProvider import io.timemates.sdk.common.providers.getAsResult import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.value.Count -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -55,6 +52,7 @@ public class AuthorizedSessionsApi( } } +@Suppress("NAME_SHADOWING") public fun AuthorizedSessionsApi.getSessionsPages( pageToken: PageToken?, maxRetries: Count = Count.createOrThrow(5), diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt index d727df4..96d605b 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt @@ -4,10 +4,15 @@ import io.timemates.sdk.authorization.sessions.types.Authorization import io.timemates.sdk.authorization.types.value.AccessHash import io.timemates.sdk.common.pagination.Page import io.timemates.sdk.common.pagination.PageToken -import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesRequest public data class GetAuthorizationSessionsRequest( val nextPageToken: PageToken?, - val accessHash: AccessHash, -) : TimeMatesRequest>() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest>() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key + get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt new file mode 100644 index 0000000..6b9adb2 --- /dev/null +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt @@ -0,0 +1,23 @@ +package io.timemates.sdk.authorization.sessions.requests + +import io.timemates.sdk.authorization.sessions.types.Authorization +import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.authorization.types.value.HashValue +import io.timemates.sdk.common.annotations.ApiStatus +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi +import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.TimeMatesRequest + +@ExperimentalTimeMatesApi(status = ApiStatus.IN_PROGRESS) +public data class RenewAuthorizationRequest( + val refreshHash: HashValue, +) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + @ExperimentalTimeMatesApi(status = ApiStatus.NEEDS_REVISION) + public data class Result( + val authorization: Authorization, + ) : TimeMatesEntity() + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt index 2406b88..5eee55f 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt @@ -1,9 +1,14 @@ package io.timemates.sdk.authorization.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest public data class TerminateCurrentAuthorizationSessionRequest( - val accessHash: AccessHash -) : TimeMatesRequest() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt index 57260ac..f956ac5 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt @@ -1,17 +1,19 @@ package io.timemates.sdk.authorization.sessions.types +import io.timemates.sdk.authorization.sessions.types.value.ApplicationName import io.timemates.sdk.authorization.sessions.types.value.ClientIpAddress -import io.timemates.sdk.authorization.sessions.types.value.ClientName import io.timemates.sdk.authorization.sessions.types.value.ClientVersion import io.timemates.sdk.authorization.types.value.HashValue import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.users.profile.types.value.UserId import kotlinx.datetime.Instant public data class Authorization( val accessHash: Hash?, val refreshHash: Hash?, val generationTime: Instant, - val metadata: Metadata? + val metadata: Metadata?, + val userId: UserId, ) : TimeMatesEntity() { public data class Hash( val value: HashValue, @@ -19,7 +21,7 @@ public data class Authorization( ) : TimeMatesEntity() public data class Metadata( - val clientName: ClientName, + val applicationName: ApplicationName, val clientVersion: ClientVersion, val clientIpAddress: ClientIpAddress, ) : TimeMatesEntity() diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt new file mode 100644 index 0000000..aad89c8 --- /dev/null +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt @@ -0,0 +1,12 @@ +package io.timemates.sdk.authorization.sessions.types.value + +import io.timemates.sdk.common.constructor.Factory + +@JvmInline +public value class ApplicationName private constructor(public val string: String) { + public companion object : Factory() { + override fun create(input: String): Result { + return Result.success(ApplicationName(input)) + } + } +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt deleted file mode 100644 index f2eb3ca..0000000 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.timemates.sdk.authorization.sessions.types.value - -import io.timemates.sdk.common.constructor.Factory - -@JvmInline -public value class ClientName private constructor(public val string: String) { - public companion object : Factory() { - override fun create(input: String): Result { - return Result.success(ClientName(input)) - } - } -} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt index d5f2767..c43e388 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt @@ -3,9 +3,9 @@ package io.timemates.sdk.authorization.sessions.types.value import io.timemates.sdk.common.constructor.Factory @JvmInline -public value class ClientVersion private constructor(public val string: String) { - public companion object : Factory() { - override fun create(input: String): Result { +public value class ClientVersion private constructor(public val double: Double) { + public companion object : Factory() { + override fun create(input: Double): Result { return Result.success(ClientVersion(input)) } } diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalTimeMatesApi.kt similarity index 81% rename from sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalApi.kt rename to sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalTimeMatesApi.kt index a920340..a45ed91 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalApi.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalTimeMatesApi.kt @@ -4,7 +4,7 @@ package io.timemates.sdk.common.annotations * Annotation used to indicate that a given SDK API is experimental. */ @RequiresOptIn(message = "Given SDK API is experimental", level = RequiresOptIn.Level.ERROR) -public annotation class ExperimentalApi(val status: ApiStatus) +public annotation class ExperimentalTimeMatesApi(val status: ApiStatus) public enum class ApiStatus { PROTOTYPE, diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt deleted file mode 100644 index 352fdc8..0000000 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt +++ /dev/null @@ -1,221 +0,0 @@ -@file:OptIn(InternalApi::class, ExperimentalApi::class) - -package io.timemates.sdk.common.exceptions.handler - -import io.timemates.sdk.common.annotations.ApiStatus -import io.timemates.sdk.common.annotations.ExperimentalApi -import io.timemates.sdk.common.annotations.InternalApi -import io.timemates.sdk.common.types.TimeMatesEntity -import io.timemates.sdk.common.exceptions.* - -/** - * Represents a type-safe wrapper class for handling exceptions in the context of an operation's result. - * - * The [SafeExceptionResult] class provides a convenient way to handle exceptions and control the flow of execution based on the encountered exception types. - * It is designed to ensure type safety by using the generic type parameters [T] for the result value and [E] for the exception type. - * - * @param T The type of the result value. - * @param E The type of the exception. - * @property result The original result of the operation. - */ -@ExperimentalApi(status = ApiStatus.NEEDS_REVISION) -@JvmInline -public value class SafeExceptionResult @InternalApi constructor( - @property:InternalApi public val result: Result -) - -/** - * Converts a [Result] into a [SafeExceptionResult] for safe exception handling. - * - * The [safeResult] function is used to wrap the original [Result] in a [SafeExceptionResult], - * which allows for more controlled handling of exceptions within the operation's result. - * - * @receiver The original result of the operation. - * @return The [SafeExceptionResult] containing the original result. - */ -@ExperimentalApi(status = ApiStatus.NEEDS_REVISION) -public fun Result.safeResult(): SafeExceptionResult { - return SafeExceptionResult(this) -} - -/** - * Executes a specified block if the encountered exception is of type [UnauthorizedException]. - * - * The [whenUnauthorized] function enables controlled handling of the [UnauthorizedException] by executing the provided block - * if the encountered exception matches the type [UnauthorizedException]. - * - * @param block The block of code to be executed if the encountered exception is [UnauthorizedException]. - * @return The [SafeExceptionResult] after executing the block. - */ -public inline fun SafeExceptionResult.whenUnauthorized( - block: (UnauthorizedException) -> Unit -): SafeExceptionResult { - val exception = result.exceptionOrNull() - if (exception is UnauthorizedException) - block(exception) - - return SafeExceptionResult(result) -} - -/** - * Executes a specified block if the encountered exception is of type [UnavailableException]. - * - * The [whenUnavailable] function allows for controlled handling of the [UnavailableException] by executing the provided block - * if the encountered exception matches the type [UnavailableException]. - * - * @param block The block of code to be executed if the encountered exception is [UnavailableException]. - * @return The [SafeExceptionResult] after executing the block. - */ -public inline fun SafeExceptionResult.whenUnavailable( - block: (UnavailableException) -> Unit -): SafeExceptionResult { - val exception = result.exceptionOrNull() - if (exception is UnavailableException) - block(exception) - - return SafeExceptionResult(result) -} - -/** - * Executes a specified block if the encountered exception is of type [TooManyRequestsException]. - * - * The [whenTooManyRequests] function allows for controlled handling of the [TooManyRequestsException] by executing the provided block - * if the encountered exception matches the type [TooManyRequestsException]. - * - * @param block The block of code to be executed if the encountered exception is [TooManyRequestsException]. - * @return The [SafeExceptionResult] after executing the block. - */ -public inline fun SafeExceptionResult.whenTooManyRequests( - block: (TooManyRequestsException) -> Unit -): SafeExceptionResult { - val exception = result.exceptionOrNull() - if (exception is TooManyRequestsException) - block(exception) - - return SafeExceptionResult(result) -} - -/** - * Executes a specified block if the encountered exception is of type [NotFoundException]. - * - * The [whenNotFound] function allows for controlled handling of the [NotFoundException] by executing the provided block - * if the encountered exception matches the type [NotFoundException]. - * - * @param block The block of code to be executed if the encountered exception is [NotFoundException]. - * @return The [SafeExceptionResult] after executing the block. - */ -public inline fun SafeExceptionResult.whenNotFound( - block: (NotFoundException) -> Unit -): SafeExceptionResult { - val exception = result.exceptionOrNull() - if (exception is NotFoundException) - block(exception) - - return SafeExceptionResult(result) -} - -/** - * Ignores the [NotFoundException] exception and continues execution. - * - * The [ignoreNotFound] function allows for ignoring the [NotFoundException] exception - * and continuing the flow of execution without interruption. - * - * @receiver The [SafeExceptionResult]. - * @return The [SafeExceptionResult] after ignoring the [NotFoundException]. - */ -public fun SafeExceptionResult.ignoreNotFound(): SafeExceptionResult { - return SafeExceptionResult(result) -} - -/** - * Executes a specified block if any exception is encountered. - * - * **Any inheritor of [TimeMatesException] are ignored here.** - * - * The [whenOtherError] function allows for handling any encountered exception by executing the provided block. - * It is useful for executing common error-handling code regardless of the specific exception type. - * - * @param block The block of code to be executed if any exception is encountered. - * @return The [SafeExceptionResult] after executing the block. - */ -@ExperimentalApi(status = ApiStatus.NEEDS_REVISION) -public inline fun SafeExceptionResult.whenOtherError( - block: (E) -> Unit -): SafeExceptionResult { - result.exceptionOrNull()?.takeIf { it !is TimeMatesException }?.let { - @Suppress("UNCHECKED_CAST") - block(it as E) - } - - return SafeExceptionResult(result) -} - -/** - * Handles **ANY** throwable, even inheritors of [TimeMatesException]. You should use it if - * you want to handle some failure logic more than one time or when you want to ignore type-safe - * way of handling failures with [whenUnauthorized], [whenUnavailable], etc. - * - * But, if it's possible, it's better to use just [Result] API instead of [SafeExceptionResult]. - */ -@ExperimentalApi(status = ApiStatus.NEEDS_REVISION) -public inline fun SafeExceptionResult.whenAnyError( - block: (Throwable) -> Unit -): SafeExceptionResult { - result.exceptionOrNull()?.let(block) - - return SafeExceptionResult(result) -} - -/** - * Executes a specified block if the operation is successful. - * - * The [whenSuccess] function allows for executing a block of code if the operation is successful, - * providing access to the result value for further processing. - * - * @param block The block of code to be executed if the operation is successful. - */ -public inline fun SafeExceptionResult.whenSuccess( - block: (T) -> Unit -) { - if(result.isSuccess) - block(result.getOrThrow()) -} - -/** - * Ignores the [UnauthorizedException] exception and continues execution. - * - * The [ignoreUnauthorized] function allows for ignoring the [UnauthorizedException] exception - * and continuing the flow of execution without interruption. - * - * @receiver The [SafeExceptionResult]. - * @return The [SafeExceptionResult] after ignoring the [UnauthorizedException]. - */ -public fun SafeExceptionResult.ignoreUnauthorized(): SafeExceptionResult { - return SafeExceptionResult(result) -} - -/** - * Ignores the [TooManyRequestsException] exception and continues execution. - * - * The [ignoreTooManyRequests] function allows for ignoring the [TooManyRequestsException] exception - * and continuing the flow of execution without interruption. - * - * @receiver The [SafeExceptionResult]. - * @return The [SafeExceptionResult] after ignoring the [TooManyRequestsException]. - */ -public fun SafeExceptionResult.ignoreTooManyRequests(): SafeExceptionResult { - return SafeExceptionResult(result) -} - -/** - * Ignores the [UnavailableException] exception and continues execution. - * - * The [ignoreUnavailable] function allows for ignoring the [UnavailableException] exception - * and continuing the flow of execution without interruption. - * - * @receiver The [SafeExceptionResult]. - * @return The [SafeExceptionResult] after ignoring the [UnavailableException]. - */ -public fun SafeExceptionResult.ignoreUnavailable(): SafeExceptionResult { - return SafeExceptionResult(result) -} diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt index fddd1d7..647c137 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt @@ -1,7 +1,7 @@ package io.timemates.sdk.common.pagination import io.timemates.sdk.common.annotations.ApiStatus -import io.timemates.sdk.common.annotations.ExperimentalApi +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi import io.timemates.sdk.common.constructor.createOrThrow import io.timemates.sdk.common.exceptions.TimeMatesException import io.timemates.sdk.common.pagination.PagesIteratorImpl.State @@ -60,7 +60,7 @@ public fun PagesIterator.asFlow(): Flow>> = flow { * * @return A [List] containing all elements from the page iterator. */ -@ExperimentalApi(status = ApiStatus.NEEDS_REVISION) +@ExperimentalTimeMatesApi(status = ApiStatus.NEEDS_REVISION) public suspend fun PagesIterator.toList(): List> { return buildList { for (result in this@toList) { @@ -78,7 +78,7 @@ public suspend fun PagesIterator.toList(): List> { * * @return A [Sequence] containing all elements from the page iterator. */ -@ExperimentalApi(status = ApiStatus.NEEDS_REVISION) +@ExperimentalTimeMatesApi(status = ApiStatus.NEEDS_REVISION) public suspend fun PagesIterator.asSequence(): Sequence> { return toList().asSequence() } @@ -99,7 +99,7 @@ public suspend inline fun PagesIterator.forEachPage(block: (Result PagesIterator.forEach(block: (Result) -> Unit) { forEachPage { page -> if (page.isSuccess) { diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt index 83b8b23..ae80877 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt @@ -6,7 +6,7 @@ import io.timemates.sdk.common.exceptions.UnauthorizedException /** * Interface for providing access token hashes. */ -public interface AccessHashProvider { +public fun interface AccessHashProvider { /** * Retrieves the access hash or null if not available. * @return The [AccessHash] or null. diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt new file mode 100644 index 0000000..36bffc7 --- /dev/null +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt @@ -0,0 +1,18 @@ +package io.timemates.sdk.common.types + +import io.timemates.sdk.authorization.types.value.AccessHash + +/** + * An abstract class representing an authorized request within the TimeMates system. + * Subclasses of this class are used to perform operations that require valid + * authorization via an access hash. + * + * @param R The response type expected from the request. + */ +public abstract class AuthorizedTimeMatesRequest : TimeMatesRequest() { + /** + * The access hash associated with this authorized request. + * It is used for authentication and authorization purposes. + */ + public abstract val accessHash: AccessHash +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt index b74177f..531a182 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt @@ -8,4 +8,15 @@ package io.timemates.sdk.common.types * * @param R The type of the response expected from the request. */ -public abstract class TimeMatesRequest internal constructor() : TimeMatesEntity() \ No newline at end of file +public abstract class TimeMatesRequest internal constructor() : TimeMatesEntity() { + /** + * A unique key that identifies this request type. + */ + public abstract val requestKey: Key<*> + + /** + * An interface representing the key associated with a [TimeMatesRequest]. + * @param T The specific type of the [TimeMatesRequest]. + */ + public interface Key> +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt index 8aa4b3e..e95b864 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt @@ -2,13 +2,19 @@ package io.timemates.sdk.files.requests import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest +import io.timemates.sdk.files.types.FileType import io.timemates.sdk.files.types.value.FileId import kotlinx.coroutines.flow.Flow public data class GetFileBytesRequest( val fileId: FileId, ) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + public data class Result( + val fileType: FileType, val bytes: Flow ) : TimeMatesEntity() + + override val requestKey: Key = Key } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt index 00e1c44..36c13a7 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt @@ -1,6 +1,7 @@ package io.timemates.sdk.files.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.files.types.FileType @@ -9,10 +10,14 @@ import io.timemates.sdk.files.types.value.FileName import kotlinx.coroutines.flow.Flow public data class UploadFileRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val bytes: Flow, val fileName: FileName, val fileType: FileType, -) : TimeMatesRequest() { +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + public data class Result(val fileId: FileId) : TimeMatesEntity() + + override val requestKey: Key get() = Key } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt index 986a99d..8cd32c8 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt @@ -1,7 +1,5 @@ package io.timemates.sdk.files.types -import io.timemates.sdk.common.types.TimeMatesEntity - public enum class FileType { IMAGE, } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt index fbe8f2b..c4279f6 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt @@ -1,17 +1,21 @@ package io.timemates.sdk.timers.members.invites.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.common.types.value.Count import io.timemates.sdk.timers.members.invites.types.value.InviteCode -import io.timemates.sdk.timers.members.invites.types.value.InviteName import io.timemates.sdk.timers.types.value.TimerId public data class CreateInviteRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, val maxJoinersCount: Count, -) : TimeMatesRequest() { +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key + public data class Result(public val inviteCode: InviteCode) : TimeMatesEntity() } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt index 3a22851..bdef1d1 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt @@ -3,13 +3,17 @@ package io.timemates.sdk.timers.members.invites.requests import io.timemates.sdk.authorization.types.value.AccessHash import io.timemates.sdk.common.pagination.Page import io.timemates.sdk.common.pagination.PageToken -import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.members.invites.types.Invite import io.timemates.sdk.timers.types.value.TimerId public data class GetInvitesRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, val pageToken: PageToken?, -) : TimeMatesRequest>() \ No newline at end of file +) : AuthorizedTimeMatesRequest>() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt new file mode 100644 index 0000000..ace017c --- /dev/null +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt @@ -0,0 +1,19 @@ +package io.timemates.sdk.timers.members.invites.requests + +import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.TimeMatesRequest +import io.timemates.sdk.timers.members.invites.types.value.InviteCode +import io.timemates.sdk.timers.types.Timer +import io.timemates.sdk.timers.types.value.TimerId + +public data class JoinTimerByCodeRequest( + public val code: InviteCode, + public val accessHash: AccessHash, +) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key + + public data class Result(val timer: Timer) : TimeMatesEntity() +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt index f26c260..df6152a 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt @@ -1,13 +1,18 @@ package io.timemates.sdk.timers.members.invites.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.members.invites.types.value.InviteCode import io.timemates.sdk.timers.types.value.TimerId public data class RemoveInviteRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, val inviteCode: InviteCode, -) : TimeMatesRequest() \ No newline at end of file +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt index c8e4d1b..bdaac90 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt @@ -3,13 +3,17 @@ package io.timemates.sdk.timers.members.requests import io.timemates.sdk.authorization.types.value.AccessHash import io.timemates.sdk.common.pagination.Page import io.timemates.sdk.common.pagination.PageToken -import io.timemates.sdk.common.types.TimeMatesEntity +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.value.TimerId import io.timemates.sdk.users.profile.types.User public data class GetMembersRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, val pageToken: PageToken?, -) : TimeMatesRequest>() \ No newline at end of file +) : AuthorizedTimeMatesRequest>() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt index 8b8909a..a3005f8 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt @@ -10,4 +10,8 @@ public data class KickMemberRequest( val accessHash: AccessHash, val timerId: TimerId, val userId: UserId, -) : TimeMatesRequest() \ No newline at end of file +) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt index 759de46..be3e950 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt @@ -1,6 +1,7 @@ package io.timemates.sdk.timers.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.TimerSettings @@ -9,10 +10,14 @@ import io.timemates.sdk.timers.types.value.TimerId import io.timemates.sdk.timers.types.value.TimerName public data class CreateTimerRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val name: TimerName, val description: TimerDescription, val settings: TimerSettings, -) : TimeMatesRequest() { +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key + public data class Result(val timerId: TimerId) : TimeMatesEntity() } diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt index b194b7b..4a72708 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt @@ -1,6 +1,7 @@ package io.timemates.sdk.timers.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.TimerSettings @@ -9,9 +10,13 @@ import io.timemates.sdk.timers.types.value.TimerId import io.timemates.sdk.timers.types.value.TimerName public data class EditTimerRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, val name: TimerName? = null, val description: TimerDescription? = null, val settings: TimerSettings.Patch? = null, -) : TimeMatesRequest() \ No newline at end of file +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt index 2b6f6b8..d84b5c3 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt @@ -1,15 +1,20 @@ package io.timemates.sdk.timers.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.Timer import io.timemates.sdk.timers.types.value.TimerId public data class GetTimerRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, -) : TimeMatesRequest() { +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key + public data class Result( val timer: Timer, ) : TimeMatesEntity() diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt index f5f86e2..68a9f61 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt @@ -3,10 +3,15 @@ package io.timemates.sdk.timers.requests import io.timemates.sdk.authorization.types.value.AccessHash import io.timemates.sdk.common.pagination.Page import io.timemates.sdk.common.pagination.PageToken +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.Timer public data class GetUserTimersRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val pageToken: PageToken?, -) : TimeMatesRequest>() \ No newline at end of file +) : AuthorizedTimeMatesRequest>() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt index 262a9e6..60f4b72 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt @@ -8,4 +8,8 @@ import io.timemates.sdk.timers.types.value.TimerId public data class RemoveTimerRequest( val accessHash: AccessHash, val timerId: TimerId, -) : TimeMatesRequest() \ No newline at end of file +) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt index 07e7533..07d97ad 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt @@ -1,10 +1,14 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest -import io.timemates.sdk.timers.types.value.TimerId public data class ConfirmTimerRoundRequest( - val accessHash: AccessHash, -) : TimeMatesRequest() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt index 8f5fc45..096e887 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt @@ -1,7 +1,7 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash -import io.timemates.sdk.common.types.Empty +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesEntity import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.Timer @@ -12,8 +12,12 @@ import kotlinx.coroutines.flow.Flow * Gets timer session state. */ public data class GetTimerStateRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, -) : TimeMatesRequest() { +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key + public data class Result(val flow: Flow) : TimeMatesEntity() } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt index b87f957..bbab4bf 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt @@ -1,6 +1,7 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.Timer @@ -8,5 +9,10 @@ import io.timemates.sdk.timers.types.Timer * Gets current timer session. */ public data class GetUserCurrentSessionRequest( - val accessHash: AccessHash, -) : TimeMatesRequest() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest() { + + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt index 0727f89..c60c0de 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt @@ -1,11 +1,16 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.value.TimerId public data class JoinTimerSessionRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, -) : TimeMatesRequest() \ No newline at end of file +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt index b93e0cb..ff23c1b 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt @@ -1,10 +1,14 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest -import io.timemates.sdk.timers.types.value.TimerId public data class LeaveTimerSessionRequest( - val accessHash: AccessHash, -) : TimeMatesRequest() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt index bbb741b..8c48343 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt @@ -1,10 +1,14 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest -import io.timemates.sdk.timers.types.value.TimerId public data class PingSessionRequest( - val accessHash: AccessHash, -) : TimeMatesRequest() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt index 3591187..d79d4f5 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt @@ -1,6 +1,7 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.value.TimerId @@ -9,6 +10,10 @@ import io.timemates.sdk.timers.types.value.TimerId * Starts timer session if user didn't joined any yet. */ public data class StartTimerRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, -) : TimeMatesRequest() \ No newline at end of file +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt index d8849d0..77af17c 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt @@ -1,6 +1,7 @@ package io.timemates.sdk.timers.sessions.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.timers.types.value.TimerId @@ -9,6 +10,10 @@ import io.timemates.sdk.timers.types.value.TimerId * Stops timer session. */ public data class StopTimerRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val timerId: TimerId, -) : TimeMatesRequest() \ No newline at end of file +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt index 50e6cf5..3ed3b49 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt @@ -1,6 +1,5 @@ package io.timemates.sdk.users -import io.timemates.sdk.authorization.types.value.AccessHash import io.timemates.sdk.common.engine.TimeMatesRequestsEngine import io.timemates.sdk.common.providers.AccessHashProvider import io.timemates.sdk.users.profile.ProfileApi @@ -10,7 +9,7 @@ import io.timemates.sdk.users.settings.UserSettingsApi * Provides access to user-related functionality through the API. * * @param engine The TimeMatesRequestsEngine instance used for making API requests. - * @param accessHash The access hash for authentication purposes. + * @param tokenProvider The provider of access hash for authentication purposes. */ public class UserApi(engine: TimeMatesRequestsEngine, tokenProvider: AccessHashProvider) { /** diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt index eda56f8..769edf7 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt @@ -9,7 +9,6 @@ import io.timemates.sdk.users.profile.requests.EditProfileRequest import io.timemates.sdk.users.profile.requests.GetUsersRequest import io.timemates.sdk.users.profile.types.Avatar import io.timemates.sdk.users.profile.types.User -import io.timemates.sdk.users.profile.types.value.EmailAddress import io.timemates.sdk.users.profile.types.value.UserDescription import io.timemates.sdk.users.profile.types.value.UserId import io.timemates.sdk.users.profile.types.value.UserName @@ -18,7 +17,7 @@ import io.timemates.sdk.users.profile.types.value.UserName * Provides functionality for accessing and modifying user profiles through the API. * * @property engine The TimeMatesRequestsEngine instance used for making API requests. - * @property accessHash The access hash for authentication purposes. + * @property tokenProvider The provider of access hash for authentication purposes. */ public class ProfileApi( private val engine: TimeMatesRequestsEngine, diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt index cbe97af..3bfe96b 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt @@ -1,16 +1,20 @@ package io.timemates.sdk.users.profile.requests import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest -import io.timemates.sdk.files.types.value.FileId import io.timemates.sdk.users.profile.types.Avatar import io.timemates.sdk.users.profile.types.value.UserDescription import io.timemates.sdk.users.profile.types.value.UserName public data class EditProfileRequest( - val accessHash: AccessHash, + override val accessHash: AccessHash, val name: UserName?, val description: UserDescription?, - val avatar: Avatar? -) : TimeMatesRequest() \ No newline at end of file + val avatar: Avatar?, +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt index 353e241..9c8af86 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt @@ -8,5 +8,9 @@ import io.timemates.sdk.users.profile.types.value.UserId public data class GetUsersRequest( val users: List, ) : TimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + public data class Result(val users: List) : TimeMatesEntity() + + override val requestKey: Key get() = Key } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt index 671d622..1394f4f 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt @@ -15,16 +15,4 @@ public sealed interface Avatar { } } } - - @JvmInline - public value class FileId private constructor(public val string: String) : Avatar { - public companion object : Factory() { - override fun create(input: String): Result { - return when { - input.isBlank() -> Result.failure(CreationFailure.ofBlank()) - else -> Result.success(FileId(input)) - } - } - } - } } \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt index 9f4b62f..70bbc93 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt @@ -12,13 +12,13 @@ import io.timemates.sdk.users.profile.types.value.UserName * @property id The unique identifier of the user. * @property name The name of the user. * @property description The description of the user. - * @property avatarFileId The unique identifier of the user's avatar file. + * @property avatar The user's avatar file. * @property emailAddress The email address associated with the user (null if not available). */ public data class User( val id: UserId, val name: UserName, - val description: UserDescription, + val description: UserDescription?, val emailAddress: EmailAddress?, val avatar: Avatar?, ) : TimeMatesEntity() \ No newline at end of file diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt index bb09758..5833f98 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt @@ -1,6 +1,5 @@ package io.timemates.sdk.users.settings -import io.timemates.sdk.authorization.types.value.AccessHash import io.timemates.sdk.common.annotations.UnimplementedApi import io.timemates.sdk.common.engine.TimeMatesRequestsEngine import io.timemates.sdk.common.providers.AccessHashProvider diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt index b697a52..c487b9b 100644 --- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt +++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt @@ -1,9 +1,25 @@ package io.timemates.sdk.users.settings.requests +import io.timemates.sdk.authorization.types.value.AccessHash +import io.timemates.sdk.common.annotations.ApiStatus +import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi +import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest import io.timemates.sdk.common.types.Empty import io.timemates.sdk.common.types.TimeMatesRequest import io.timemates.sdk.users.profile.types.value.EmailAddress +/** + * This request is not implemented on server yet. Always throws + * [io.timemates.sdk.common.exceptions.UnsupportedException]. + * + * TODO: remove notice once implemented + */ +@ExperimentalTimeMatesApi(status = ApiStatus.IN_PROGRESS) public data class EditEmailRequest( val newEmail: EmailAddress, -) : TimeMatesRequest() \ No newline at end of file + override val accessHash: AccessHash, +) : AuthorizedTimeMatesRequest() { + public companion object Key : TimeMatesRequest.Key + + override val requestKey: Key get() = Key +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index bd3faff..57a9b30 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,6 +3,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") pluginManagement { repositories { gradlePluginPortal() + maven("https://maven.timemates.io") mavenCentral() google() } @@ -15,6 +16,7 @@ dependencyResolutionManagement { mavenCentral() maven("https://jitpack.io") maven("https://maven.y9vad9.com") + maven("https://maven.timemates.io") } } @@ -23,5 +25,4 @@ rootProject.name = "timemates-sdk" includeBuild("build-logic/publish-library-plugin") include(":sdk") -include(":grpc-engine") -include(":grpc-engine:android") +include(":rsocket-engine")