< Summary

Line coverage
20%
Covered lines: 245
Uncovered lines: 923
Coverable lines: 1168
Total lines: 3497
Line coverage: 20.9%
Branch coverage
14%
Covered branches: 25
Total branches: 170
Branch coverage: 14.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: Authenticate(...)100%11100%
File 1: <AuthenticateAsync()100%210%
File 1: AuthEnable(...)100%11100%
File 1: <AuthEnableAsync()100%11100%
File 1: AuthDisable(...)100%11100%
File 1: <AuthDisableAsync()100%210%
File 1: UserAdd(...)100%11100%
File 1: <UserAddAsync()100%210%
File 1: UserGet(...)100%210%
File 1: <UserGetAsync()100%210%
File 1: UserList(...)100%11100%
File 1: <UserListAsync()100%210%
File 1: UserDelete(...)100%11100%
File 1: <UserDeleteAsync()100%11100%
File 1: UserChangePassword(...)100%210%
File 1: <UserChangePasswordAsync()100%210%
File 1: UserGrantRole(...)100%210%
File 1: <UserGrantRoleAsync()100%210%
File 1: UserRevokeRole(...)100%210%
File 1: <UserRevokeRoleAsync()100%210%
File 1: RoleAdd(...)100%11100%
File 1: <RoleAddAsync()100%210%
File 1: RoleGet(...)100%210%
File 1: <RoleGetAsync()100%210%
File 1: RoleList(...)100%210%
File 1: <RoleListAsync()100%210%
File 1: RoleDelete(...)100%210%
File 1: <RoleDeleteAsync()100%210%
File 1: RoleGrantPermission(...)100%11100%
File 1: <RoleGrantPermissionAsync()100%210%
File 1: RoleRevokePermission(...)100%210%
File 1: <RoleRevokePermissionAsync()100%210%
File 2: MemberAdd(...)100%210%
File 2: <MemberAddAsync()100%210%
File 2: MemberRemove(...)100%210%
File 2: <MemberRemoveAsync()100%210%
File 2: MemberUpdate(...)100%210%
File 2: <MemberUpdateAsync()100%210%
File 2: MemberList(...)100%210%
File 2: <MemberListAsync()100%210%
File 3: Campaign(...)50%22100%
File 3: Campaign(...)0%2040%
File 3: <CampaignAsync()50%22100%
File 3: <CampaignAsync()0%2040%
File 3: Proclaim(...)50%22100%
File 3: Proclaim(...)0%2040%
File 3: <ProclaimAsync()50%22100%
File 3: <ProclaimAsync()0%2040%
File 3: Leader(...)50%22100%
File 3: Leader(...)0%620%
File 3: <LeaderAsync()50%22100%
File 3: <LeaderAsync()0%620%
File 3: ObserveAsync()0%2040%
File 3: ObserveAsync()0%2040%
File 3: Resign(...)50%22100%
File 3: Resign(...)0%620%
File 3: <ResignAsync()50%22100%
File 3: <ResignAsync()0%620%
File 3: Observe(...)0%620%
File 3: Observe(...)0%620%
File 4: GetConnection()100%210%
File 4: GetWatchManager()100%210%
File 4: CancelWatch(...)100%210%
File 4: CancelWatch(...)0%620%
File 4: .ctor(...)100%11100%
File 4: .cctor()100%11100%
File 4: .ctor(...)66.66%6691.66%
File 4: .ctor(...)62.5%8892.85%
File 4: .ctor(...)0%2040%
File 4: .ctor(...)50%2264.28%
File 4: SetCredentials(...)0%2040%
File 4: AuthenticateAndCacheToken()0%2040%
File 4: Dispose(...)75%88100%
File 4: Dispose()100%11100%
File 5: Get(...)100%11100%
File 5: Get(...)100%11100%
File 5: <GetAsync()100%11100%
File 5: GetAsync()100%11100%
File 5: GetVal(...)50%22100%
File 5: GetValAsync()0%620%
File 5: GetRange(...)100%210%
File 5: GetRangeAsync()100%210%
File 5: GetRangeVal(...)100%210%
File 5: GetRangeValAsync()100%210%
File 5: Put(...)100%11100%
File 5: Put(...)100%11100%
File 5: <PutAsync()100%11100%
File 5: PutAsync()100%11100%
File 5: Delete(...)100%11100%
File 5: Delete(...)100%11100%
File 5: <DeleteAsync()100%210%
File 5: DeleteAsync()100%210%
File 5: DeleteRange(...)100%210%
File 5: DeleteRangeAsync()100%210%
File 5: Transaction(...)100%11100%
File 5: <TransactionAsync()100%210%
File 5: Compact(...)100%210%
File 5: <CompactAsync()100%210%
File 6: LeaseGrant(...)100%11100%
File 6: <LeaseGrantAsync()100%11100%
File 6: LeaseRevoke(...)100%11100%
File 6: <LeaseRevokeAsync()100%11100%
File 6: LeaseKeepAlive(...)0%2040%
File 6: LeaseKeepAlive()100%210%
File 6: <LeaseKeepAlive()0%4260%
File 6: LeaseKeepAlive()100%210%
File 6: <LeaseKeepAlive()100%210%
File 6: LeaseKeepAlive()100%210%
File 6: <LeaseKeepAlive()100%210%
File 6: LeaseKeepAlive()100%210%
File 6: <LeaseKeepAlive()0%620%
File 6: LeaseKeepAlive()100%210%
File 6: <LeaseKeepAlive()0%620%
File 6: LeaseTimeToLive(...)100%11100%
File 6: <LeaseTimeToLiveAsync()100%11100%
File 7: Lock(...)100%210%
File 7: Lock(...)100%11100%
File 7: LockAsync()100%210%
File 7: LockAsync()100%11100%
File 7: <LockAsync()100%11100%
File 7: Unlock(...)100%210%
File 7: Unlock(...)100%11100%
File 7: UnlockAsync()100%210%
File 7: UnlockAsync()100%11100%
File 7: <UnlockAsync()100%11100%
File 8: Alarm(...)100%11100%
File 8: <AlarmAsync()100%11100%
File 8: Status(...)100%11100%
File 8: <StatusAsync()100%11100%
File 8: Defragment(...)100%11100%
File 8: <DefragmentAsync()100%11100%
File 8: Hash(...)100%11100%
File 8: <HashAsync()100%11100%
File 8: HashKV(...)100%210%
File 8: <HashKVAsync()100%210%
File 8: Snapshot()100%210%
File 8: <Snapshot()0%620%
File 8: Snapshot()100%210%
File 8: <Snapshot()0%2040%
File 8: MoveLeader(...)100%210%
File 8: <MoveLeaderAsync()100%210%
File 9: RangeRespondToDictionary(...)0%620%
File 9: GetRangeEnd(...)0%620%
File 9: GetStringByteForRangeRequests(...)0%620%
File 9: CallEtcd(...)100%11100%
File 9: CallEtcdAsync(...)100%11100%
File 9: CallEtcdAsync(...)100%210%
File 10: WatchAsync()0%2040%
File 10: WatchAsync(...)0%2040%
File 10: Watch(...)0%2040%
File 10: Watch(...)0%2040%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)0%620%
File 10: WatchAsync()0%620%
File 10: WatchAsync()0%2040%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)0%620%
File 10: Watch(...)100%210%
File 10: Watch(...)100%210%
File 10: Watch(...)100%210%
File 10: Watch(...)100%210%
File 10: Watch(...)100%210%
File 10: Watch(...)0%620%
File 10: Watch(...)100%210%
File 10: Watch(...)100%210%
File 10: Watch(...)100%210%
File 10: Watch(...)0%620%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)0%620%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)100%210%
File 10: WatchAsync(...)0%620%
File 10: WatchRange(...)100%210%
File 10: WatchRange(...)0%620%
File 10: WatchRange(...)0%620%
File 10: WatchRange(...)0%2040%
File 10: WatchRangeAsync(...)100%210%
File 10: WatchRangeAsync(...)0%620%
File 10: WatchRangeAsync()0%620%
File 10: WatchRangeAsync()0%2040%

File(s)

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/authClient.cs

#LineLine coverage
 1using System;
 2using System.Threading;
 3using System.Threading.Tasks;
 4using Etcdserverpb;
 5using Grpc.Core;
 6
 7namespace dotnet_etcd;
 8
 9public partial class EtcdClient
 10{
 11    /// <summary>
 12    ///     Authenticate processes an authenticate request.
 13    /// </summary>
 14    /// <param name="request">The request to send to the server.</param>
 15    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 16    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 17    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 18    /// <returns>The response received from the server.</returns>
 19    public AuthenticateResponse Authenticate(AuthenticateRequest request, Metadata headers = null,
 20        DateTime? deadline = null,
 421        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 422        .Authenticate(request, headers, deadline, cancellationToken));
 23
 24    /// <summary>
 25    ///     Authenticate processes an authenticate request.
 26    /// </summary>
 27    /// <param name="request">The request to send to the server.</param>
 28    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 29    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 30    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 31    /// <returns>The response received from the server.</returns>
 32    public async Task<AuthenticateResponse> AuthenticateAsync(AuthenticateRequest request,
 33        Metadata headers = null, DateTime? deadline = null,
 034        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 035        .AuthClient
 036        .AuthenticateAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 37
 38    /// <summary>
 39    ///     AuthEnable enables authentication
 40    /// </summary>
 41    /// <param name="request">The request to send to the server.</param>
 42    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 43    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 44    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 45    /// <returns>The response received from the server.</returns>
 46    public AuthEnableResponse AuthEnable(AuthEnableRequest request, Metadata headers = null,
 47        DateTime? deadline = null,
 448        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 449        .AuthEnable(request, headers, deadline, cancellationToken));
 50
 51    /// <summary>
 52    ///     AuthEnableAsync enables authentication in async
 53    /// </summary>
 54    /// <param name="request">The request to send to the server.</param>
 55    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 56    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 57    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 58    /// <returns>The response received from the server.</returns>
 59    public async Task<AuthEnableResponse> AuthEnableAsync(AuthEnableRequest request,
 60        Metadata headers = null, DateTime? deadline = null,
 461        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 462        .AuthClient
 463        .AuthEnableAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 64
 65    /// <summary>
 66    ///     AuthDisable disables authentication
 67    /// </summary>
 68    /// <param name="request">The request to send to the server.</param>
 69    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 70    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 71    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 72    /// <returns>The response received from the server.</returns>
 73    public AuthDisableResponse AuthDisable(AuthDisableRequest request, Metadata headers = null,
 74        DateTime? deadline = null,
 275        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 276        .AuthDisable(request, headers, deadline, cancellationToken));
 77
 78    /// <summary>
 79    ///     AuthDisableAsync disables authentication in async
 80    /// </summary>
 81    /// <param name="request">The request to send to the server.</param>
 82    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 83    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 84    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 85    /// <returns>The response received from the server.</returns>
 86    public async Task<AuthDisableResponse> AuthDisableAsync(AuthDisableRequest request,
 87        Metadata headers = null, DateTime? deadline = null,
 088        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 089        .AuthClient
 090        .AuthDisableAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 91
 92    /// <summary>
 93    ///     UserAdd adds a new user
 94    /// </summary>
 95    /// <param name="request">The request to send to the server.</param>
 96    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 97    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 98    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 99    /// <returns>The response received from the server.</returns>
 100    public AuthUserAddResponse UserAdd(AuthUserAddRequest request, Metadata headers = null,
 101        DateTime? deadline = null,
 2102        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 2103        .UserAdd(request, headers, deadline, cancellationToken));
 104
 105    /// <summary>
 106    ///     UserAddAsync adds a new user in async
 107    /// </summary>
 108    /// <param name="request">The request to send to the server.</param>
 109    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 110    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 111    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 112    /// <returns>The response received from the server.</returns>
 113    public async Task<AuthUserAddResponse> UserAddAsync(AuthUserAddRequest request,
 114        Metadata headers = null, DateTime? deadline = null,
 0115        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0116        .AuthClient
 0117        .UserAddAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 118
 119    /// <summary>
 120    ///     UserGet gets detailed user information
 121    /// </summary>
 122    /// <param name="request">The request to send to the server.</param>
 123    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 124    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 125    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 126    /// <returns>The response received from the server.</returns>
 127    public AuthUserGetResponse UserGet(AuthUserGetRequest request, Metadata headers = null,
 128        DateTime? deadline = null,
 0129        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0130        .UserGet(request, headers, deadline, cancellationToken));
 131
 132    /// <summary>
 133    ///     UserGetAsync gets detailed user information in async
 134    /// </summary>
 135    /// <param name="request">The request to send to the server.</param>
 136    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 137    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 138    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 139    /// <returns>The response received from the server.</returns>
 140    public async Task<AuthUserGetResponse> UserGetAsync(AuthUserGetRequest request,
 141        Metadata headers = null, DateTime? deadline = null,
 0142        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0143        .AuthClient
 0144        .UserGetAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 145
 146    /// <summary>
 147    ///     UserList gets a list of all users
 148    /// </summary>
 149    /// <param name="request">The request to send to the server.</param>
 150    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 151    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 152    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 153    /// <returns>The response received from the server.</returns>
 154    public AuthUserListResponse UserList(AuthUserListRequest request, Metadata headers = null,
 155        DateTime? deadline = null,
 2156        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 2157        .UserList(request, headers, deadline, cancellationToken));
 158
 159    /// <summary>
 160    ///     UserListAsync gets a list of all users in async
 161    /// </summary>
 162    /// <param name="request">The request to send to the server.</param>
 163    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 164    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 165    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 166    /// <returns>The response received from the server.</returns>
 167    public async Task<AuthUserListResponse> UserListAsync(AuthUserListRequest request,
 168        Metadata headers = null, DateTime? deadline = null,
 0169        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0170        .AuthClient
 0171        .UserListAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 172
 173    /// <summary>
 174    ///     UserDelete deletes a specified user
 175    /// </summary>
 176    /// <param name="request">The request to send to the server.</param>
 177    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 178    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 179    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 180    /// <returns>The response received from the server.</returns>
 181    public AuthUserDeleteResponse UserDelete(AuthUserDeleteRequest request, Metadata headers = null,
 182        DateTime? deadline = null,
 2183        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 2184        .UserDelete(request, headers, deadline, cancellationToken));
 185
 186    /// <summary>
 187    ///     UserDeleteAsync deletes a specified user in async
 188    /// </summary>
 189    /// <param name="request">The request to send to the server.</param>
 190    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 191    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 192    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 193    /// <returns>The response received from the server.</returns>
 194    public async Task<AuthUserDeleteResponse> UserDeleteAsync(AuthUserDeleteRequest request,
 195        Metadata headers = null, DateTime? deadline = null,
 2196        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 2197        .AuthClient
 2198        .UserDeleteAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 199
 200    /// <summary>
 201    ///     UserChangePassword changes the password of a specified user
 202    /// </summary>
 203    /// <param name="request">The request to send to the server.</param>
 204    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 205    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 206    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 207    /// <returns>The response received from the server.</returns>
 208    public AuthUserChangePasswordResponse UserChangePassword(AuthUserChangePasswordRequest request,
 209        Metadata headers = null, DateTime? deadline = null,
 0210        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0211        .UserChangePassword(request, headers, deadline, cancellationToken));
 212
 213    /// <summary>
 214    ///     UserChangePasswordAsync changes the password of a specified user in async
 215    /// </summary>
 216    /// <param name="request">The request to send to the server.</param>
 217    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 218    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 219    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 220    /// <returns>The response received from the server.</returns>
 221    public async Task<AuthUserChangePasswordResponse> UserChangePasswordAsync(AuthUserChangePasswordRequest request,
 222        Metadata headers = null, DateTime? deadline = null,
 0223        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0224        .AuthClient
 0225        .UserChangePasswordAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 226
 227    /// <summary>
 228    ///     UserGrant grants a role to a specified user
 229    /// </summary>
 230    /// <param name="request">The request to send to the server.</param>
 231    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 232    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 233    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 234    /// <returns>The response received from the server.</returns>
 235    public AuthUserGrantRoleResponse UserGrantRole(AuthUserGrantRoleRequest request,
 236        Metadata headers = null, DateTime? deadline = null,
 0237        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0238        .UserGrantRole(request, headers, deadline, cancellationToken));
 239
 240    /// <summary>
 241    ///     UserGrantRoleAsync grants a role to a specified user in async
 242    /// </summary>
 243    /// <param name="request">The request to send to the server.</param>
 244    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 245    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 246    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 247    /// <returns>The response received from the server.</returns>
 248    public async Task<AuthUserGrantRoleResponse> UserGrantRoleAsync(AuthUserGrantRoleRequest request,
 249        Metadata headers = null, DateTime? deadline = null,
 0250        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0251        .AuthClient
 0252        .UserGrantRoleAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 253
 254    /// <summary>
 255    ///     UserRevokeRole revokes a role of specified user
 256    /// </summary>
 257    /// <param name="request">The request to send to the server.</param>
 258    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 259    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 260    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 261    /// <returns>The response received from the server.</returns>
 262    public AuthUserRevokeRoleResponse UserRevokeRole(AuthUserRevokeRoleRequest request,
 263        Metadata headers = null, DateTime? deadline = null,
 0264        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0265        .UserRevokeRole(request, headers, deadline, cancellationToken));
 266
 267    /// <summary>
 268    ///     UserRevokeRoleAsync revokes a role of specified user in async
 269    /// </summary>
 270    /// <param name="request">The request to send to the server.</param>
 271    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 272    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 273    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 274    /// <returns>The response received from the server.</returns>
 275    public async Task<AuthUserRevokeRoleResponse> UserRevokeRoleAsync(AuthUserRevokeRoleRequest request,
 276        Metadata headers = null, DateTime? deadline = null,
 0277        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0278        .AuthClient
 0279        .UserRevokeRoleAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 280
 281    /// <summary>
 282    ///     RoleAdd adds a new role
 283    /// </summary>
 284    /// <param name="request">The request to send to the server.</param>
 285    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 286    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 287    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 288    /// <returns>The response received from the server.</returns>
 289    public AuthRoleAddResponse RoleAdd(AuthRoleAddRequest request, Metadata headers = null,
 290        DateTime? deadline = null,
 2291        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 2292        .RoleAdd(request, headers, deadline, cancellationToken));
 293
 294    /// <summary>
 295    ///     RoleAddAsync adds a new role in async
 296    /// </summary>
 297    /// <param name="request">The request to send to the server.</param>
 298    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 299    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 300    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 301    /// <returns>The response received from the server.</returns>
 302    public async Task<AuthRoleAddResponse> RoleAddAsync(AuthRoleAddRequest request,
 303        Metadata headers = null, DateTime? deadline = null,
 0304        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0305        .AuthClient
 0306        .RoleAddAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 307
 308    /// <summary>
 309    ///     RoleGet gets detailed role information
 310    /// </summary>
 311    /// <param name="request">The request to send to the server.</param>
 312    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 313    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 314    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 315    /// <returns>The response received from the server.</returns>
 316    public AuthRoleGetResponse RoleGet(AuthRoleGetRequest request, Metadata headers = null,
 317        DateTime? deadline = null,
 0318        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0319        .RoleGet(request, headers, deadline, cancellationToken));
 320
 321    /// <summary>
 322    ///     RoleGetAsync gets detailed role information in async
 323    /// </summary>
 324    /// <param name="request">The request to send to the server.</param>
 325    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 326    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 327    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 328    /// <returns>The response received from the server.</returns>
 329    public async Task<AuthRoleGetResponse> RoleGetAsync(AuthRoleGetRequest request,
 330        Metadata headers = null, DateTime? deadline = null,
 0331        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0332        .AuthClient
 0333        .RoleGetAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 334
 335    /// <summary>
 336    ///     RoleList gets lists of all roles
 337    /// </summary>
 338    /// <param name="request">The request to send to the server.</param>
 339    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 340    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 341    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 342    /// <returns>The response received from the server.</returns>
 343    public AuthRoleListResponse RoleList(AuthRoleListRequest request, Metadata headers = null,
 344        DateTime? deadline = null,
 0345        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0346        .RoleList(request, headers, deadline, cancellationToken));
 347
 348    /// <summary>
 349    ///     RoleListAsync gets lists of all roles async
 350    /// </summary>
 351    /// <param name="request">The request to send to the server.</param>
 352    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 353    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 354    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 355    /// <returns>The response received from the server.</returns>
 356    public async Task<AuthRoleListResponse> RoleListAsync(AuthRoleListRequest request,
 357        Metadata headers = null, DateTime? deadline = null,
 0358        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0359        .AuthClient
 0360        .RoleListAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 361
 362    /// <summary>
 363    ///     RoleDelete deletes a specified role
 364    /// </summary>
 365    /// <param name="request">The request to send to the server.</param>
 366    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 367    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 368    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 369    /// <returns>The response received from the server.</returns>
 370    public AuthRoleDeleteResponse RoleDelete(AuthRoleDeleteRequest request, Metadata headers = null,
 371        DateTime? deadline = null,
 0372        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0373        .RoleDelete(request, headers, deadline, cancellationToken));
 374
 375    /// <summary>
 376    ///     RoleDeleteAsync deletes a specified role in async
 377    /// </summary>
 378    /// <param name="request">The request to send to the server.</param>
 379    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 380    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 381    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 382    /// <returns>The response received from the server.</returns>
 383    public async Task<AuthRoleDeleteResponse> RoleDeleteAsync(AuthRoleDeleteRequest request,
 384        Metadata headers = null, DateTime? deadline = null,
 0385        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0386        .AuthClient
 0387        .RoleDeleteAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 388
 389    /// <summary>
 390    ///     RoleGrantPermission grants a permission of a specified key or range to a specified role
 391    /// </summary>
 392    /// <param name="request">The request to send to the server.</param>
 393    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 394    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 395    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 396    /// <returns>The response received from the server.</returns>
 397    public AuthRoleGrantPermissionResponse RoleGrantPermission(AuthRoleGrantPermissionRequest request,
 398        Metadata headers = null, DateTime? deadline = null,
 2399        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 2400        .RoleGrantPermission(request, headers, deadline, cancellationToken));
 401
 402    /// <summary>
 403    ///     RoleGrantPermissionAsync grants a permission of a specified key or range to a specified role in async
 404    /// </summary>
 405    /// <param name="request">The request to send to the server.</param>
 406    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 407    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 408    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 409    /// <returns>The response received from the server.</returns>
 410    public async Task<AuthRoleGrantPermissionResponse> RoleGrantPermissionAsync(
 411        AuthRoleGrantPermissionRequest request, Metadata headers = null, DateTime? deadline = null,
 0412        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0413        .AuthClient
 0414        .RoleGrantPermissionAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 415
 416    /// <summary>
 417    ///     RoleRevokePermission revokes a key or range permission of a specified role
 418    /// </summary>
 419    /// <param name="request">The request to send to the server.</param>
 420    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 421    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 422    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 423    /// <returns>The response received from the server.</returns>
 424    public AuthRoleRevokePermissionResponse RoleRevokePermission(AuthRoleRevokePermissionRequest request,
 425        Metadata headers = null, DateTime? deadline = null,
 0426        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.AuthClient
 0427        .RoleRevokePermission(request, headers, deadline, cancellationToken));
 428
 429    /// <summary>
 430    ///     RoleRevokePermissionAsync revokes a key or range permission of a specified role in async
 431    /// </summary>
 432    /// <param name="request">The request to send to the server.</param>
 433    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 434    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 435    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 436    /// <returns>The response received from the server.</returns>
 437    public async Task<AuthRoleRevokePermissionResponse> RoleRevokePermissionAsync(
 438        AuthRoleRevokePermissionRequest request, Metadata headers = null, DateTime? deadline = null,
 0439        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0440        .AuthClient
 0441        .RoleRevokePermissionAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 442}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/clusterClient.cs

#LineLine coverage
 1using System;
 2using System.Threading;
 3using System.Threading.Tasks;
 4using Etcdserverpb;
 5using Grpc.Core;
 6
 7namespace dotnet_etcd;
 8
 9public partial class EtcdClient
 10{
 11    /// <summary>
 12    ///     MemberAdd adds a member into the cluster
 13    /// </summary>
 14    /// <param name="request">The request to send to the server.</param>
 15    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 16    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 17    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 18    /// <returns>The response received from the server.</returns>
 19    public MemberAddResponse MemberAdd(MemberAddRequest request, Metadata headers = null,
 20        DateTime? deadline = null,
 021        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.ClusterClient
 022        .MemberAdd(request, headers, deadline, cancellationToken));
 23
 24    /// <summary>
 25    ///     MemberAddAsync adds a member into the cluster in async
 26    /// </summary>
 27    /// <param name="request">The request to send to the server.</param>
 28    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 29    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 30    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 31    /// <returns>The response received from the server.</returns>
 32    public async Task<MemberAddResponse> MemberAddAsync(MemberAddRequest request, Metadata headers = null,
 33        DateTime? deadline = null,
 034        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 035        .ClusterClient
 036        .MemberAddAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 37
 38    /// <summary>
 39    ///     MemberRemove removes an existing member from the cluster
 40    /// </summary>
 41    /// <param name="request">The request to send to the server.</param>
 42    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 43    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 44    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 45    /// <returns>The response received from the server.</returns>
 46    public MemberRemoveResponse MemberRemove(MemberRemoveRequest request, Metadata headers = null,
 47        DateTime? deadline = null,
 048        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.ClusterClient
 049        .MemberRemove(request, headers, deadline, cancellationToken));
 50
 51    /// <summary>
 52    ///     MemberRemoveAsync removes an existing member from the cluster in async
 53    /// </summary>
 54    /// <param name="request">The request to send to the server.</param>
 55    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 56    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 57    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 58    /// <returns>The response received from the server.</returns>
 59    public async Task<MemberRemoveResponse> MemberRemoveAsync(MemberRemoveRequest request,
 60        Metadata headers = null, DateTime? deadline = null,
 061        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 062        .ClusterClient
 063        .MemberRemoveAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 64
 65    /// <summary>
 66    ///     MemberUpdate updates the member configuration
 67    /// </summary>
 68    /// <param name="request">The request to send to the server.</param>
 69    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 70    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 71    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 72    /// <returns>The response received from the server.</returns>
 73    public MemberUpdateResponse MemberUpdate(MemberUpdateRequest request, Metadata headers = null,
 74        DateTime? deadline = null,
 075        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.ClusterClient
 076        .MemberUpdate(request, headers, deadline, cancellationToken));
 77
 78    /// <summary>
 79    ///     MemberUpdateAsync updates the member configuration in async
 80    /// </summary>
 81    /// <param name="request">The request to send to the server.</param>
 82    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 83    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 84    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 85    /// <returns>The response received from the server.</returns>
 86    public async Task<MemberUpdateResponse> MemberUpdateAsync(MemberUpdateRequest request,
 87        Metadata headers = null, DateTime? deadline = null,
 088        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 089        .ClusterClient
 090        .MemberUpdateAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 91
 92    /// <summary>
 93    ///     MemberList lists all the members in the cluster
 94    /// </summary>
 95    /// <param name="request">The request to send to the server.</param>
 96    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 97    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 98    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 99    /// <returns>The response received from the server.</returns>
 100    public MemberListResponse MemberList(MemberListRequest request, Metadata headers = null,
 101        DateTime? deadline = null,
 0102        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.ClusterClient
 0103        .MemberList(request, headers, deadline, cancellationToken));
 104
 105    /// <summary>
 106    ///     MemberListAsync lists all the members in the cluster in async
 107    /// </summary>
 108    /// <param name="request">The request to send to the server.</param>
 109    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 110    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 111    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 112    /// <returns>The response received from the server.</returns>
 113    public async Task<MemberListResponse> MemberListAsync(MemberListRequest request,
 114        Metadata headers = null, DateTime? deadline = null,
 0115        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0116        .ClusterClient
 0117        .MemberListAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 118}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/electionClient.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Runtime.CompilerServices;
 4using System.Threading;
 5using System.Threading.Tasks;
 6using Google.Protobuf;
 7using Grpc.Core;
 8using V3Electionpb;
 9
 10namespace dotnet_etcd;
 11
 12public partial class EtcdClient
 13{
 14    /// <summary>
 15    ///     Campaign waits to acquire leadership in an election, returning a LeaderKey
 16    ///     representing the leadership if successful. The LeaderKey can then be used
 17    ///     to issue new values on the election, transactionally guard API requests on
 18    ///     leadership still being held, and resign from the election.
 19    /// </summary>
 20    /// <param name="request">The request to send to the server.</param>
 21    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 22    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 23    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 24    /// <returns>The response received from the server.</returns>
 25    public CampaignResponse Campaign(
 26        CampaignRequest request,
 27        Metadata headers = null,
 28        DateTime? deadline = null,
 29        CancellationToken cancellationToken = default)
 230        => CallEtcd(connection => connection.ElectionClient.Campaign(
 231            request ?? throw new ArgumentNullException(nameof(request)),
 232            headers,
 233            deadline,
 234            cancellationToken));
 35
 36    /// <summary>
 37    ///     Campaign waits to acquire leadership in an election, returning a LeaderKey
 38    ///     representing the leadership if successful. The LeaderKey can then be used
 39    ///     to issue new values on the election, transactionally guard API requests on
 40    ///     leadership still being held, and resign from the election.
 41    /// </summary>
 42    /// <param name="name">The name is the election�s identifier for the campaign.</param>
 43    /// <param name="value">The value is the initial proclaimed value set when the campaigner wins the election.</param>
 44    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 45    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 46    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 47    /// <returns>The response received from the server.</returns>
 48    public CampaignResponse Campaign(
 49        string name,
 50        string value = null,
 51        Metadata headers = null,
 52        DateTime? deadline = null,
 53        CancellationToken cancellationToken = default)
 054        => CallEtcd(connection => connection.ElectionClient.Campaign(
 055            new CampaignRequest
 056            {
 057                Name = ByteString.CopyFromUtf8(name ?? throw new ArgumentNullException(nameof(name))),
 058                Value = value == null ? null : ByteString.CopyFromUtf8(value)
 059            },
 060            headers,
 061            deadline,
 062            cancellationToken));
 63
 64    /// <summary>
 65    ///     CampaignAsync waits to acquire leadership in an election, returning a LeaderKey
 66    ///     representing the leadership if successful. The LeaderKey can then be used
 67    ///     to issue new values on the election, transactionally guard API requests on
 68    ///     leadership still being held, and resign from the election.
 69    /// </summary>
 70    /// <param name="request">The request to send to the server.</param>
 71    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 72    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 73    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 74    /// <returns>The response received from the server.</returns>
 75    public async Task<CampaignResponse> CampaignAsync(
 76        CampaignRequest request,
 77        Metadata headers = null,
 78        DateTime? deadline = null,
 79        CancellationToken cancellationToken = default)
 280        => await CallEtcdAsync(async connection => await connection.ElectionClient.CampaignAsync(
 281            request ?? throw new ArgumentNullException(nameof(request)),
 282            headers,
 283            deadline,
 284            cancellationToken)).ConfigureAwait(false);
 85
 86    /// <summary>
 87    ///     Campaign waits to acquire leadership in an election, returning a LeaderKey
 88    ///     representing the leadership if successful. The LeaderKey can then be used
 89    ///     to issue new values on the election, transactionally guard API requests on
 90    ///     leadership still being held, and resign from the election.
 91    /// </summary>
 92    /// <param name="name">The name is the election�s identifier for the campaign.</param>
 93    /// <param name="value">The value is the initial proclaimed value set when the campaigner wins the election.</param>
 94    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 95    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 96    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 97    /// <returns>The response received from the server.</returns>
 98    public async Task<CampaignResponse> CampaignAsync(
 99        string name,
 100        string value,
 101        Metadata headers = null,
 102        DateTime? deadline = null,
 103        CancellationToken cancellationToken = default)
 0104        => await CallEtcdAsync(async connection => await connection.ElectionClient.CampaignAsync(
 0105            new CampaignRequest
 0106            {
 0107                Name = ByteString.CopyFromUtf8(name ?? throw new ArgumentNullException(nameof(name))),
 0108                Value = value == null ? null : ByteString.CopyFromUtf8(value)
 0109            },
 0110            headers,
 0111            deadline,
 0112            cancellationToken)).ConfigureAwait(false);
 113
 114    /// <summary>
 115    ///     Proclaim updates the leader's posted value with a new value.
 116    /// </summary>
 117    /// <param name="request">The request to send to the server.</param>
 118    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 119    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 120    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 121    /// <returns>The response received from the server.</returns>
 122    public ProclaimResponse Proclaim(
 123        ProclaimRequest request,
 124        Metadata headers = null,
 125        DateTime? deadline = null,
 126        CancellationToken cancellationToken = default)
 2127        => CallEtcd(connection => connection.ElectionClient.Proclaim(
 2128            request ?? throw new ArgumentNullException(nameof(request)),
 2129            headers,
 2130            deadline,
 2131            cancellationToken));
 132
 133    /// <summary>
 134    ///     Proclaim updates the leader's posted value with a new value.
 135    /// </summary>
 136    /// <param name="leader">The leader is the leadership hold on the election.</param>
 137    /// <param name="value">The value is an update meant to overwrite the leader�s current value.</param>
 138    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 139    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 140    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 141    /// <returns>The response received from the server.</returns>
 142    public ProclaimResponse Proclaim(
 143        LeaderKey leader,
 144        string value,
 145        Metadata headers = null,
 146        DateTime? deadline = null,
 147        CancellationToken cancellationToken = default)
 0148        => CallEtcd(connection => connection.ElectionClient.Proclaim(
 0149            new ProclaimRequest
 0150            {
 0151                Leader = leader ?? throw new ArgumentNullException(nameof(leader)),
 0152                Value = ByteString.CopyFromUtf8(value ?? throw new ArgumentNullException(nameof(value)))
 0153            },
 0154            headers,
 0155            deadline,
 0156            cancellationToken));
 157
 158    /// <summary>
 159    ///     Proclaim updates the leader's posted value with a new value.
 160    /// </summary>
 161    /// <param name="request">The request to send to the server.</param>
 162    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 163    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 164    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 165    /// <returns>The response received from the server.</returns>
 166    public async Task<ProclaimResponse> ProclaimAsync(
 167        ProclaimRequest request,
 168        Metadata headers = null,
 169        DateTime? deadline = null,
 170        CancellationToken cancellationToken = default)
 2171        => await CallEtcdAsync(async connection => await connection.ElectionClient.ProclaimAsync(
 2172            request ?? throw new ArgumentNullException(nameof(request)),
 2173            headers,
 2174            deadline,
 2175            cancellationToken)).ConfigureAwait(false);
 176
 177    /// <summary>
 178    ///     Proclaim updates the leader's posted value with a new value.
 179    /// </summary>
 180    /// <param name="leader">The leader is the leadership hold on the election.</param>
 181    /// <param name="value">The value is an update meant to overwrite the leader�s current value.</param>
 182    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 183    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 184    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 185    /// <returns>The response received from the server.</returns>
 186    public async Task<ProclaimResponse> ProclaimAsync(
 187        LeaderKey leader,
 188        string value,
 189        Metadata headers = null,
 190        DateTime? deadline = null,
 191        CancellationToken cancellationToken = default)
 0192        => await CallEtcdAsync(async connection => await connection.ElectionClient.ProclaimAsync(
 0193            new ProclaimRequest
 0194            {
 0195                Leader = leader ?? throw new ArgumentNullException(nameof(leader)),
 0196                Value = ByteString.CopyFromUtf8(value ?? throw new ArgumentNullException(nameof(value)))
 0197            },
 0198            headers,
 0199            deadline,
 0200            cancellationToken)).ConfigureAwait(false);
 201
 202    /// <summary>
 203    ///     Leader returns the current election proclamation, if any.
 204    /// </summary>
 205    /// <param name="request">The request to send to the server.</param>
 206    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 207    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 208    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 209    /// <returns>The response received from the server.</returns>
 210    public LeaderResponse Leader(
 211        LeaderRequest request,
 212        Metadata headers = null,
 213        DateTime? deadline = null,
 214        CancellationToken cancellationToken = default)
 4215        => CallEtcd(connection => connection.ElectionClient.Leader(
 4216            request ?? throw new ArgumentNullException(nameof(request)),
 4217            headers,
 4218            deadline,
 4219            cancellationToken));
 220
 221    /// <summary>
 222    ///     Leader returns the current election proclamation, if any.
 223    /// </summary>
 224    /// <param name="name">The name is the election identifier for the leadership information.</param>
 225    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 226    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 227    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 228    /// <returns>The response received from the server.</returns>
 229    public LeaderResponse Leader(
 230        string name,
 231        Metadata headers = null,
 232        DateTime? deadline = null,
 233        CancellationToken cancellationToken = default)
 0234        => CallEtcd(connection => connection.ElectionClient.Leader(
 0235            new LeaderRequest { Name = ByteString.CopyFromUtf8(name ?? throw new ArgumentNullException(nameof(name))) },
 0236            headers,
 0237            deadline,
 0238            cancellationToken));
 239
 240    /// <summary>
 241    ///     Leader returns the current election proclamation, if any.
 242    /// </summary>
 243    /// <param name="request">The request to send to the server.</param>
 244    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 245    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 246    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 247    /// <returns>The response received from the server.</returns>
 248    public async Task<LeaderResponse> LeaderAsync(
 249        LeaderRequest request,
 250        Metadata headers = null,
 251        DateTime? deadline = null,
 252        CancellationToken cancellationToken = default)
 4253        => await CallEtcdAsync(async connection => await connection.ElectionClient.LeaderAsync(
 4254            request ?? throw new ArgumentNullException(nameof(request)),
 4255            headers,
 4256            deadline,
 4257            cancellationToken)).ConfigureAwait(false);
 258
 259    /// <summary>
 260    ///     Leader returns the current election proclamation, if any.
 261    /// </summary>
 262    /// <param name="name">The name is the election identifier for the leadership information.</param>
 263    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 264    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 265    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 266    /// <returns>The response received from the server.</returns>
 267    public async Task<LeaderResponse> LeaderAsync(
 268        string name,
 269        Metadata headers = null,
 270        DateTime? deadline = null,
 271        CancellationToken cancellationToken = default)
 0272        => await CallEtcdAsync(async connection => await connection.ElectionClient.LeaderAsync(
 0273            new LeaderRequest { Name = ByteString.CopyFromUtf8(name ?? throw new ArgumentNullException(nameof(name))) },
 0274            headers,
 0275            deadline,
 0276            cancellationToken)).ConfigureAwait(false);
 277
 278    /// <summary>
 279    ///     Observe streams election proclamations in-order as made by the election's
 280    ///     elected leaders.
 281    /// </summary>
 282    /// <param name="request">The request to send to the server.</param>
 283    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 284    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 285    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 286    /// <returns>The response received from the server.</returns>
 287    public async IAsyncEnumerable<LeaderResponse> ObserveAsync(
 288        LeaderRequest request,
 289        Metadata headers = null,
 290        DateTime? deadline = null,
 291        [EnumeratorCancellation] CancellationToken cancellationToken = default)
 0292    {
 0293        using (AsyncServerStreamingCall<LeaderResponse> leaderResponse = _connection.ElectionClient.Observe(
 0294                   request ?? throw new ArgumentNullException(nameof(request)),
 0295                   headers,
 0296                   deadline,
 0297                   cancellationToken))
 0298        {
 0299            while (await leaderResponse.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0300            {
 0301                yield return leaderResponse.ResponseStream.Current;
 0302            }
 0303        }
 0304    }
 305
 306    /// <summary>
 307    ///     Observe streams election proclamations in-order as made by the election's
 308    ///     elected leaders.
 309    /// </summary>
 310    /// <param name="name">The name is the election identifier for the leadership information.</param>
 311    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 312    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 313    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 314    /// <returns>The response received from the server.</returns>
 315    public async IAsyncEnumerable<LeaderResponse> ObserveAsync(
 316        string name,
 317        Metadata headers = null,
 318        DateTime? deadline = null,
 319        [EnumeratorCancellation] CancellationToken cancellationToken = default)
 0320    {
 0321        using (AsyncServerStreamingCall<LeaderResponse> leaderResponse = _connection.ElectionClient.Observe(
 0322                   new LeaderRequest
 0323                   {
 0324                       Name = ByteString.CopyFromUtf8(name ?? throw new ArgumentNullException(nameof(name)))
 0325                   },
 0326                   headers,
 0327                   deadline,
 0328                   cancellationToken))
 0329        {
 0330            while (await leaderResponse.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0331            {
 0332                yield return leaderResponse.ResponseStream.Current;
 0333            }
 0334        }
 0335    }
 336
 337    /// <summary>
 338    ///     Resign releases election leadership so other campaigners may acquire
 339    ///     leadership on the election.
 340    /// </summary>
 341    /// <param name="request">The request to send to the server.</param>
 342    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 343    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 344    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 345    /// <returns>The response received from the server.</returns>
 346    public ResignResponse Resign(
 347        ResignRequest request,
 348        Metadata headers = null,
 349        DateTime? deadline = null,
 350        CancellationToken cancellationToken = default)
 2351        => CallEtcd(connection => connection.ElectionClient.Resign(
 2352            request ?? throw new ArgumentNullException(nameof(request)),
 2353            headers,
 2354            deadline,
 2355            cancellationToken));
 356
 357    /// <summary>
 358    ///     Resign releases election leadership so other campaigners may acquire
 359    ///     leadership on the election.
 360    /// </summary>
 361    /// <param name="leader">The leader is the leadership to relinquish by resignation.</param>
 362    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 363    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 364    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 365    /// <returns>The response received from the server.</returns>
 366    public ResignResponse Resign(
 367        LeaderKey leader,
 368        Metadata headers = null,
 369        DateTime? deadline = null,
 370        CancellationToken cancellationToken = default)
 0371        => CallEtcd(connection => connection.ElectionClient.Resign(
 0372            new ResignRequest { Leader = leader ?? throw new ArgumentNullException(nameof(leader)) },
 0373            headers,
 0374            deadline,
 0375            cancellationToken));
 376
 377    /// <summary>
 378    ///     Resign releases election leadership so other campaigners may acquire
 379    ///     leadership on the election.
 380    /// </summary>
 381    /// <param name="request">The request to send to the server.</param>
 382    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 383    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 384    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 385    /// <returns>The response received from the server.</returns>
 386    public async Task<ResignResponse> ResignAsync(
 387        ResignRequest request,
 388        Metadata headers = null,
 389        DateTime? deadline = null,
 390        CancellationToken cancellationToken = default)
 2391        => await CallEtcdAsync(async connection => await connection.ElectionClient.ResignAsync(
 2392            request ?? throw new ArgumentNullException(nameof(request)),
 2393            headers,
 2394            deadline,
 2395            cancellationToken)).ConfigureAwait(false);
 396
 397    /// <summary>
 398    ///     Resign releases election leadership so other campaigners may acquire
 399    ///     leadership on the election.
 400    /// </summary>
 401    /// <param name="leader">The leader is the leadership to relinquish by resignation.</param>
 402    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 403    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 404    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 405    /// <returns>The response received from the server.</returns>
 406    public async Task<ResignResponse> ResignAsync(
 407        LeaderKey leader,
 408        Metadata headers = null,
 409        DateTime? deadline = null,
 410        CancellationToken cancellationToken = default)
 0411        => await CallEtcdAsync(async connection => await connection.ElectionClient.ResignAsync(
 0412            new ResignRequest { Leader = leader ?? throw new ArgumentNullException(nameof(leader)) },
 0413            headers,
 0414            deadline,
 0415            cancellationToken)).ConfigureAwait(false);
 416
 417    /// <summary>
 418    ///     Observe streams election proclamations in-order as made by the election's
 419    ///     elected leaders.
 420    /// </summary>
 421    /// <param name="request">The request to send to the server.</param>
 422    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 423    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 424    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 425    /// <returns>The response received from the server.</returns>
 426    public AsyncServerStreamingCall<LeaderResponse> Observe(
 427        LeaderRequest request,
 428        Metadata headers = null,
 429        DateTime? deadline = null,
 430        CancellationToken cancellationToken = default)
 0431        => CallEtcd(connection => connection.ElectionClient.Observe(
 0432            request ?? throw new ArgumentNullException(nameof(request)),
 0433            headers,
 0434            deadline,
 0435            cancellationToken));
 436
 437    /// <summary>
 438    ///     Observe streams election proclamations in-order as made by the election's
 439    ///     elected leaders.
 440    /// </summary>
 441    /// <param name="name">The name is the election identifier for the leadership information.</param>
 442    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 443    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 444    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 445    /// <returns>The response received from the server.</returns>
 446    public AsyncServerStreamingCall<LeaderResponse> Observe(
 447        string name,
 448        Metadata headers = null,
 449        DateTime? deadline = null,
 450        CancellationToken cancellationToken = default)
 0451        => CallEtcd(connection => connection.ElectionClient.Observe(
 0452            new LeaderRequest { Name = ByteString.CopyFromUtf8(name ?? throw new ArgumentNullException(nameof(name))) },
 0453            headers,
 0454            deadline,
 0455            cancellationToken));
 456}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/etcdClient.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Globalization;
 4using System.Linq;
 5using System.Net.Http;
 6using System.Net.Security;
 7using dotnet_etcd.interfaces;
 8using dotnet_etcd.multiplexer;
 9using Etcdserverpb;
 10using Grpc.Core;
 11using Grpc.Core.Interceptors;
 12using Grpc.Net.Client;
 13using Grpc.Net.Client.Balancer;
 14using Grpc.Net.Client.Configuration;
 15using Microsoft.Extensions.DependencyInjection;
 16
 17namespace dotnet_etcd;
 18
 19/// <summary>
 20///     Etcd client is the entrypoint for this library.
 21///     It contains all the functions required to perform operations on etcd.
 22/// </summary>
 23public partial class EtcdClient : IDisposable, IEtcdClient
 24{
 25    /// <summary>
 26    ///     Gets the connection object
 27    /// </summary>
 28    /// <returns>The connection object</returns>
 029    public IConnection GetConnection() => _connection;
 30
 31    /// <summary>
 32    ///     Gets the watch manager
 33    /// </summary>
 34    /// <returns>The watch manager</returns>
 035    public IWatchManager GetWatchManager() => _watchManager;
 36
 37    /// <summary>
 38    ///     Cancels a watch request
 39    /// </summary>
 40    /// <param name="watchId">The ID of the watch to cancel</param>
 041    public void CancelWatch(long watchId) => _watchManager.CancelWatch(watchId);
 42
 43    /// <summary>
 44    ///     Cancels multiple watch requests
 45    /// </summary>
 46    /// <param name="watchIds">The IDs of the watches to cancel</param>
 47    public void CancelWatch(long[] watchIds)
 048    {
 049        foreach (long watchId in watchIds)
 050        {
 051            _watchManager.CancelWatch(watchId);
 052        }
 053    }
 54
 55    #region Variables
 56
 57    private const string InsecurePrefix = "http://";
 58    private const string SecurePrefix = "https://";
 59
 60    private const string StaticHostsPrefix = "static://";
 61    private const string DnsPrefix = "dns://";
 62    private const string AlternateDnsPrefix = "discovery-srv://";
 63
 64    private const string DefaultServerName = "my-etcd-server";
 65
 66    internal readonly IConnection _connection;
 67    private readonly GrpcChannel _channel;
 68    private readonly IWatchManager _watchManager;
 69    private readonly AsyncStreamCallFactory<WatchRequest, WatchResponse> _watchCallFactory;
 70
 71    private string _username;
 72    private string _password;
 73    private string _authToken;
 6474    private readonly object _authLock = new object();
 75
 76    // https://learn.microsoft.com/en-us/aspnet/core/grpc/retries?view=aspnetcore-6.0#configure-a-grpc-retry-policy
 177    private static readonly MethodConfig _defaultGrpcMethodConfig = new()
 178    {
 179        Names = { MethodName.Default },
 180        RetryPolicy = new RetryPolicy
 181        {
 182            MaxAttempts = 5,
 183            InitialBackoff = TimeSpan.FromSeconds(1),
 184            MaxBackoff = TimeSpan.FromSeconds(5),
 185            BackoffMultiplier = 1.5,
 186            RetryableStatusCodes = { StatusCode.Unavailable }
 187        }
 188    };
 89
 90    // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#throttling-retry-attempts-and-hedged-rpcs
 191    private static readonly RetryThrottlingPolicy _defaultRetryThrottlingPolicy = new()
 192    {
 193        MaxTokens = 10, TokenRatio = 0.1
 194    };
 95
 96    #endregion
 97
 98    #region Initializers
 99
 100    /// <summary>
 101    ///     Initializes a new instance of the <see cref="EtcdClient" /> class with a CallInvoker.
 102    /// </summary>
 103    /// <param name="callInvoker">The call invoker to use for gRPC calls</param>
 104    /// <exception cref="ArgumentNullException">Thrown if callInvoker is null</exception>
 54105    public EtcdClient(CallInvoker callInvoker)
 54106    {
 54107        ArgumentNullException.ThrowIfNull(callInvoker);
 108
 109        // Add authentication interceptor - it passively reads the cached token
 54110        var authInterceptor = new AuthenticationInterceptor(() => _authToken);
 54111        var interceptedCallInvoker = callInvoker.Intercept(authInterceptor);
 112
 54113        _connection = new Connection(interceptedCallInvoker);
 114
 115        // Create the watch call factory
 54116        _watchCallFactory = new AsyncStreamCallFactory<WatchRequest, WatchResponse>(
 54117            (headers, deadline, cancellationToken) =>
 54118                _connection.WatchClient.Watch(headers, deadline, cancellationToken));
 119
 120        // Initialize the watch manager
 54121        _watchManager = new WatchManager((headers, deadline, cancellationToken) =>
 54122            _watchCallFactory.CreateDuplexStreamingCall(headers, deadline, cancellationToken));
 54123    }
 124
 125    /// <summary>
 126    ///     Initializes a new instance of the <see cref="EtcdClient" /> class with a connection string.
 127    /// </summary>
 128    /// <param name="connectionString">The connection string for etcd</param>
 129    /// <param name="port">The port to connect to</param>
 130    /// <param name="serverName">The server name</param>
 131    /// <param name="configureChannelOptions">Function to configure channel options</param>
 132    /// <param name="interceptors">Interceptors to apply to calls</param>
 133    /// <exception cref="ArgumentNullException">Thrown if connectionString is null or empty</exception>
 8134    public EtcdClient(string connectionString, int port = 2379, string serverName = DefaultServerName,
 8135        Action<GrpcChannelOptions> configureChannelOptions = null, Interceptor[] interceptors = null)
 8136    {
 137        // Param check
 8138        if (string.IsNullOrWhiteSpace(connectionString))
 0139        {
 0140            throw new ArgumentNullException(nameof(connectionString));
 141        }
 142
 143        // Param sanitization
 8144        interceptors ??= Array.Empty<Interceptor>();
 145
 8146        var channelFactory = new GrpcChannelFactory();
 8147        _channel = channelFactory.CreateChannel(
 8148            connectionString,
 8149            port,
 8150            serverName,
 8151            ChannelCredentials.Insecure, // Default to insecure for backward compatibility
 8152            configureChannelOptions,
 8153            configureSslOptions: null); // No custom SSL by default
 154
 155        // Always add authentication interceptor first (it will be a no-op if credentials aren't set)
 8156        var authInterceptor = new AuthenticationInterceptor(() => _authToken);
 8157        var allInterceptors = new[] { authInterceptor }.Concat(interceptors).ToArray();
 158
 8159        CallInvoker callInvoker = allInterceptors.Length > 0
 8160            ? _channel.Intercept(allInterceptors)
 8161            : _channel.CreateCallInvoker();
 162
 163        // Setup Connection
 8164        _connection = new Connection(callInvoker);
 165
 166        // Create the watch call factory
 8167        _watchCallFactory = new AsyncStreamCallFactory<WatchRequest, WatchResponse>(
 8168            (headers, deadline, cancellationToken) =>
 8169                _connection.WatchClient.Watch(headers, deadline, cancellationToken));
 170
 171        // Initialize the watch manager
 8172        _watchManager = new WatchManager((headers, deadline, cancellationToken) =>
 8173            _watchCallFactory.CreateDuplexStreamingCall(headers, deadline, cancellationToken));
 8174    }
 175
 176    /// <summary>
 177    ///     Initializes a new instance of the <see cref="EtcdClient" /> class with a connection string and SSL options c
 178    ///     Use this constructor to configure custom SSL certificates for self-signed certificates.
 179    /// </summary>
 180    /// <param name="connectionString">The connection string for etcd</param>
 181    /// <param name="configureSslOptions">Action to configure SSL options for custom SSL certificates</param>
 182    /// <param name="port">The port to connect to</param>
 183    /// <param name="serverName">The server name</param>
 184    /// <param name="configureChannelOptions">Function to configure channel options</param>
 185    /// <param name="interceptors">Interceptors to apply to calls</param>
 186    /// <exception cref="ArgumentNullException">Thrown if connectionString is null or empty</exception>
 1187    public EtcdClient(string connectionString, Action<SslClientAuthenticationOptions> configureSslOptions, int port = 23
 1188       string serverName = DefaultServerName, Action<GrpcChannelOptions> configureChannelOptions = null,
 1189        Interceptor[] interceptors = null)
 1190    {
 191        // Param check
 1192       if (string.IsNullOrWhiteSpace(connectionString))
 0193        {
 0194            throw new ArgumentNullException(nameof(connectionString));
 195        }
 196
 197        // Param sanitization
 1198        interceptors ??= Array.Empty<Interceptor>();
 199
 1200        var channelFactory = new GrpcChannelFactory();
 201
 202        // Use SSL credentials when SSL options configuration is provided
 1203        var credentials = configureSslOptions != null
 1204            ? new SslCredentials()
 1205            : ChannelCredentials.Insecure;
 206
 1207        _channel = channelFactory.CreateChannel(
 1208            connectionString,
 1209            port,
 1210            serverName,
 1211            credentials,
 1212            configureChannelOptions,
 1213            configureSslOptions);
 214
 215        // Always add authentication interceptor first (it will be a no-op if credentials aren't set)
 1216        var authInterceptor = new AuthenticationInterceptor(() => _authToken);
 1217        var allInterceptors = new[] { authInterceptor }.Concat(interceptors).ToArray();
 218
 1219        CallInvoker callInvoker = allInterceptors.Length > 0
 1220            ? _channel.Intercept(allInterceptors)
 1221            : _channel.CreateCallInvoker();
 222
 223        // Setup Connection
 1224        _connection = new Connection(callInvoker);
 225
 226        // Create the watch call factory
 1227        _watchCallFactory = new AsyncStreamCallFactory<WatchRequest, WatchResponse>(
 1228            (headers, deadline, cancellationToken) =>
 1229                _connection.WatchClient.Watch(headers, deadline, cancellationToken));
 230
 231        // Initialize the watch manager
 1232        _watchManager = new WatchManager((headers, deadline, cancellationToken) =>
 1233            _watchCallFactory.CreateDuplexStreamingCall(headers, deadline, cancellationToken));
 1234    }
 235
 236    /// <summary>
 237    ///     Initializes a new instance of the <see cref="EtcdClient" /> class with a connection string and credentials.
 238    /// </summary>
 239    /// <param name="connectionString">The connection string for etcd</param>
 240    /// <param name="username">The username for authentication</param>
 241    /// <param name="password">The password for authentication</param>
 242    /// <param name="port">The port to connect to</param>
 243    /// <param name="serverName">The server name</param>
 244    /// <param name="configureChannelOptions">Function to configure channel options</param>
 245    /// <exception cref="ArgumentNullException">Thrown if connectionString is null or empty</exception>
 246    public EtcdClient(string connectionString, string username, string password, int port = 2379,
 247        string serverName = DefaultServerName, Action<GrpcChannelOptions> configureChannelOptions = null)
 0248        : this(connectionString, port, serverName, configureChannelOptions)
 0249    {
 250        // Validate and set credentials
 0251        if (string.IsNullOrWhiteSpace(username))
 0252        {
 0253            throw new ArgumentNullException(nameof(username));
 254        }
 255
 0256        if (string.IsNullOrWhiteSpace(password))
 0257        {
 0258            throw new ArgumentNullException(nameof(password));
 259        }
 260
 0261        _username = username;
 0262        _password = password;
 263
 264        // Authenticate immediately with the provided credentials
 0265        AuthenticateAndCacheToken();
 0266    }
 267
 268    /// <summary>
 269    ///     Initializes a new instance of the <see cref="EtcdClient" /> class for testing.
 270    /// </summary>
 271    /// <param name="connection">The connection to use</param>
 272    /// <param name="watchManager">The watch manager to use</param>
 273    /// <exception cref="ArgumentNullException">Thrown if connection or watchManager is null</exception>
 1274    public EtcdClient(IConnection connection, IWatchManager watchManager = null)
 1275    {
 1276        ArgumentNullException.ThrowIfNull(connection);
 277
 1278        _connection = connection;
 279
 1280        if (watchManager != null)
 1281        {
 1282            _watchManager = watchManager;
 1283        }
 284        else
 0285        {
 286            // Create the watch call factory
 0287            _watchCallFactory = new AsyncStreamCallFactory<WatchRequest, WatchResponse>(
 0288                (headers, deadline, cancellationToken) =>
 0289                    _connection.WatchClient.Watch(headers, deadline, cancellationToken));
 290
 291            // Initialize the watch manager with default implementation
 0292            _watchManager = new WatchManager((headers, deadline, cancellationToken) =>
 0293                _watchCallFactory.CreateDuplexStreamingCall(headers, deadline, cancellationToken));
 0294        }
 1295    }
 296
 297    #endregion
 298
 299    #region Authentication
 300
 301    /// <summary>
 302    ///     Sets the credentials for automatic authentication with etcd.
 303    ///     When credentials are set, all subsequent requests will automatically include the authentication token.
 304    /// </summary>
 305    /// <param name="username">The username for authentication</param>
 306    /// <param name="password">The password for authentication</param>
 307    /// <exception cref="ArgumentNullException">Thrown if username or password is null or empty</exception>
 308    public void SetCredentials(string username, string password)
 0309    {
 0310        if (string.IsNullOrWhiteSpace(username))
 0311        {
 0312            throw new ArgumentNullException(nameof(username));
 313        }
 314
 0315        if (string.IsNullOrWhiteSpace(password))
 0316        {
 0317            throw new ArgumentNullException(nameof(password));
 318        }
 319
 0320        lock (_authLock)
 0321        {
 0322            _username = username;
 0323            _password = password;
 0324            _authToken = null; // Reset token to force re-authentication on next request
 0325        }
 326
 327        // Authenticate immediately with the new credentials
 0328        AuthenticateAndCacheToken();
 0329    }
 330
 331    /// <summary>
 332    ///     Authenticates with etcd and caches the token.
 333    ///     This method is called immediately when credentials are set (constructor or SetCredentials).
 334    /// </summary>
 335    private void AuthenticateAndCacheToken()
 0336    {
 0337        if (string.IsNullOrWhiteSpace(_username) || string.IsNullOrWhiteSpace(_password))
 0338        {
 0339            return;
 340        }
 341
 0342        lock (_authLock)
 0343        {
 344            try
 0345            {
 0346                var authRequest = new AuthenticateRequest
 0347                {
 0348                    Name = _username,
 0349                    Password = _password
 0350                };
 351
 352                // Call authenticate directly on the connection's auth client
 353                // The interceptor won't interfere because it only reads the cached token
 0354                var authResponse = _connection.AuthClient.Authenticate(authRequest, null, null, default);
 0355                _authToken = authResponse.Token;
 0356            }
 0357            catch
 0358            {
 359                // Clear token on failure
 0360                _authToken = null;
 0361                throw;
 362            }
 0363        }
 0364    }
 365
 366    #endregion
 367
 368    #region IDisposable Support
 369
 370    private bool _disposed;
 371
 372    /// <summary>
 373    ///     Disposes the resources used by this instance
 374    /// </summary>
 375    /// <param name="disposing">Whether to dispose managed resources</param>
 376    protected virtual void Dispose(bool disposing)
 1377    {
 1378        if (!_disposed)
 1379        {
 1380            if (disposing)
 1381            {
 382                // Dispose managed resources
 1383                _channel?.Dispose();
 1384                _watchManager?.Dispose();
 1385            }
 386
 1387            _disposed = true;
 1388        }
 1389    }
 390
 391    /// <summary>
 392    ///     Disposes the resources used by this instance
 393    /// </summary>
 394    public void Dispose()
 1395    {
 1396        Dispose(true);
 1397        GC.SuppressFinalize(this);
 1398    }
 399
 400    #endregion
 401}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/kvClient.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Threading;
 4using System.Threading.Tasks;
 5using Etcdserverpb;
 6using Google.Protobuf;
 7using Grpc.Core;
 8
 9namespace dotnet_etcd;
 10
 11public partial class EtcdClient
 12{
 13    /// <summary>
 14    ///     Get the etcd response for a specified RangeRequest
 15    /// </summary>
 16    /// <param name="request">The request to send to the server.</param>
 17    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 18    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 19    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 20    /// <returns>The etcd response for the specified request</returns>
 21    public RangeResponse Get(RangeRequest request, Metadata headers = null, DateTime? deadline = null,
 622        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.KVClient
 623        .Range(request, headers, deadline, cancellationToken));
 24
 25    /// <summary>
 26    ///     Get the etcd response for a specified key
 27    /// </summary>
 28    /// <param name="key">Key for which value need to be fetched</param>
 29    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 30    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 31    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 32    /// <returns>The etcd response for the specified key</returns>
 33    public RangeResponse Get(string key, Metadata headers = null, DateTime? deadline = null,
 234        CancellationToken cancellationToken = default) => Get(new RangeRequest { Key = ByteString.CopyFromUtf8(key) },
 235        headers, deadline, cancellationToken);
 36
 37    /// <summary>
 38    ///     Get the etcd response for a specified key in async
 39    /// </summary>
 40    /// <param name="request">The request to send to the server.</param>
 41    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 42    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 43    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 44    /// <returns>The etcd response for the specified request</returns>
 45    public async Task<RangeResponse> GetAsync(RangeRequest request, Metadata headers = null,
 46        DateTime? deadline = null,
 247        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 248        .KVClient
 249        .RangeAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 50
 51    /// <summary>
 52    ///     Get the etcd response for a specified key in async
 53    /// </summary>
 54    /// <param name="key">Key for which value need to be fetched</param>
 55    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 56    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 57    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 58    /// <returns>The etcd response for the specified key</returns>
 59    public async Task<RangeResponse> GetAsync(string key, Metadata headers = null,
 60        DateTime? deadline = null,
 61        CancellationToken cancellationToken = default) =>
 162        await GetAsync(new RangeRequest { Key = ByteString.CopyFromUtf8(key) }, headers, deadline, cancellationToken)
 163            .ConfigureAwait(false);
 64
 65    /// <summary>
 66    ///     Get the value for a specified key
 67    /// </summary>
 68    /// <param name="key">Key for which value need to be fetched</param>
 69    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 70    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 71    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 72    /// <returns>The value for the specified key</returns>
 73    public string GetVal(string key, Metadata headers = null, DateTime? deadline = null,
 74        CancellationToken cancellationToken = default)
 175    {
 176        RangeResponse rangeResponse = Get(key, headers, deadline, cancellationToken);
 177        return rangeResponse.Count != 0 ? rangeResponse.Kvs[0].Value.ToStringUtf8().Trim() : string.Empty;
 178    }
 79
 80    /// <summary>
 81    ///     Get the value for a specified key in async
 82    /// </summary>
 83    /// <param name="key">Key for which value need to be fetched</param>
 84    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 85    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 86    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 87    /// <returns>The value for the specified key</returns>
 88    public async Task<string> GetValAsync(string key, Metadata headers = null, DateTime? deadline = null,
 89        CancellationToken cancellationToken = default)
 090    {
 091        RangeResponse rangeResponse = await GetAsync(key, headers, deadline, cancellationToken).ConfigureAwait(false);
 092        return rangeResponse.Count != 0 ? rangeResponse.Kvs[0].Value.ToStringUtf8().Trim() : string.Empty;
 093    }
 94
 95    /// <summary>
 96    ///     Gets the range of keys with the specified prefix
 97    /// </summary>
 98    /// <param name="prefixKey">Prefix key</param>
 99    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 100    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 101    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 102    /// <returns>RangeResponse containing range of key-values</returns>
 103    public RangeResponse GetRange(string prefixKey, Metadata headers = null, DateTime? deadline = null,
 104        CancellationToken cancellationToken = default)
 0105    {
 0106        string rangeEnd = GetRangeEnd(prefixKey);
 0107        return Get(
 0108            new RangeRequest
 0109            {
 0110                Key = GetStringByteForRangeRequests(prefixKey), RangeEnd = ByteString.CopyFromUtf8(rangeEnd)
 0111            }, headers, deadline, cancellationToken);
 0112    }
 113
 114    /// <summary>
 115    ///     Gets the range of keys with the specified prefix in async
 116    /// </summary>
 117    /// <param name="prefixKey">Prefix key</param>
 118    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 119    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 120    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 121    /// <returns>RangeResponse containing range of key-values</returns>
 122    public async Task<RangeResponse> GetRangeAsync(string prefixKey, Metadata headers = null,
 123        DateTime? deadline = null,
 124        CancellationToken cancellationToken = default)
 0125    {
 0126        string rangeEnd = GetRangeEnd(prefixKey);
 0127        return await GetAsync(
 0128            new RangeRequest
 0129            {
 0130                Key = GetStringByteForRangeRequests(prefixKey), RangeEnd = ByteString.CopyFromUtf8(rangeEnd)
 0131            }, headers, deadline, cancellationToken).ConfigureAwait(false);
 0132    }
 133
 134    /// <summary>
 135    ///     Gets the range of keys with the specified prefix
 136    /// </summary>
 137    /// <param name="prefixKey">Prefix key</param>
 138    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 139    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 140    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 141    /// <returns>Dictionary containing range of key-values</returns>
 142    public IDictionary<string, string> GetRangeVal(string prefixKey, Metadata headers = null,
 143        DateTime? deadline = null,
 144        CancellationToken cancellationToken = default)
 0145    {
 0146        string rangeEnd = GetRangeEnd(prefixKey);
 0147        return RangeRespondToDictionary(Get(
 0148            new RangeRequest
 0149            {
 0150                Key = GetStringByteForRangeRequests(prefixKey), RangeEnd = ByteString.CopyFromUtf8(rangeEnd)
 0151            }, headers, deadline, cancellationToken));
 0152    }
 153
 154    /// <summary>
 155    ///     Gets the range of keys with the specified prefix in async
 156    /// </summary>
 157    /// <param name="prefixKey">Prefix key</param>
 158    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 159    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 160    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 161    /// <returns>Dictionary containing range of key-values</returns>
 162    public async Task<IDictionary<string, string>> GetRangeValAsync(string prefixKey,
 163        Metadata headers = null, DateTime? deadline = null,
 164        CancellationToken cancellationToken = default)
 0165    {
 0166        string rangeEnd = GetRangeEnd(prefixKey);
 0167        return RangeRespondToDictionary(
 0168            await GetAsync(
 0169                new RangeRequest
 0170                {
 0171                    Key = GetStringByteForRangeRequests(prefixKey), RangeEnd = ByteString.CopyFromUtf8(rangeEnd)
 0172                }, headers, deadline, cancellationToken).ConfigureAwait(false));
 0173    }
 174
 175    /// <summary>
 176    ///     Sets the key value in etcd
 177    /// </summary>
 178    /// <param name="request">The request to send to the server.</param>
 179    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 180    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 181    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 182    /// <returns>The response received from the server.</returns>
 183    public PutResponse Put(PutRequest request, Metadata headers = null, DateTime? deadline = null,
 2184        CancellationToken cancellationToken = default) => CallEtcd(connection =>
 4185        connection.KVClient.Put(request, headers, deadline, cancellationToken));
 186
 187    /// <summary>
 188    ///     Sets the key value in etcd
 189    /// </summary>
 190    /// <param name="key">Key for which value need to be set</param>
 191    /// <param name="val">Value corresponding the key</param>
 192    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 193    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 194    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 195    /// <returns>The response received from the server.</returns>
 196    public PutResponse Put(string key, string val, Metadata headers = null, DateTime? deadline = null,
 197        CancellationToken cancellationToken = default) =>
 1198        Put(new PutRequest { Key = ByteString.CopyFromUtf8(key), Value = ByteString.CopyFromUtf8(val) }, headers,
 1199            deadline, cancellationToken);
 200
 201    /// <summary>
 202    ///     Sets the key value in etcd in async
 203    /// </summary>
 204    /// <param name="request">The request to send to the server.</param>
 205    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 206    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 207    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 208    /// <returns>The response received from the server.</returns>
 209    public async Task<PutResponse> PutAsync(PutRequest request, Metadata headers = null,
 210        DateTime? deadline = null,
 2211        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 2212        .KVClient
 2213        .PutAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 214
 215
 216    /// <summary>
 217    ///     Sets the key value in etcd in async
 218    /// </summary>
 219    /// <param name="key">Key for which value need to be set</param>
 220    /// <param name="val">Value corresponding the key</param>
 221    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 222    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 223    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 224    /// <returns>The response received from the server.</returns>
 225    public async Task<PutResponse> PutAsync(string key, string val, Metadata headers = null,
 226        DateTime? deadline = null,
 227        CancellationToken cancellationToken = default) =>
 1228        await PutAsync(new PutRequest { Key = ByteString.CopyFromUtf8(key), Value = ByteString.CopyFromUtf8(val) },
 1229            headers, deadline, cancellationToken).ConfigureAwait(false);
 230
 231    /// <summary>
 232    ///     Delete the specified key in etcd
 233    /// </summary>
 234    /// <param name="request">The request to send to the server.</param>
 235    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 236    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 237    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 238    /// <returns>The response received from the server.</returns>
 239    public DeleteRangeResponse Delete(DeleteRangeRequest request, Metadata headers = null,
 240        DateTime? deadline = null,
 4241        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.KVClient
 4242        .DeleteRange(request, headers, deadline, cancellationToken));
 243
 244    /// <summary>
 245    ///     Delete the specified key in etcd
 246    /// </summary>
 247    /// <param name="key">Key which needs to be deleted</param>
 248    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 249    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 250    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 251    /// <returns>The response received from the server.</returns>
 252    public DeleteRangeResponse Delete(string key, Metadata headers = null, DateTime? deadline = null,
 1253        CancellationToken cancellationToken = default) => Delete(
 1254        new DeleteRangeRequest { Key = ByteString.CopyFromUtf8(key) }, headers, deadline, cancellationToken);
 255
 256
 257    /// <summary>
 258    ///     Delete the specified key in etcd in async
 259    /// </summary>
 260    /// <param name="request">The request to send to the server.</param>
 261    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 262    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 263    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 264    /// <returns>The response received from the server.</returns>
 265    public async Task<DeleteRangeResponse> DeleteAsync(DeleteRangeRequest request,
 266        Metadata headers = null, DateTime? deadline = null,
 0267        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0268        .KVClient
 0269        .DeleteRangeAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 270
 271    /// <summary>
 272    ///     Delete the specified key in etcd in async
 273    /// </summary>
 274    /// <param name="key">Key which needs to be deleted</param>
 275    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 276    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 277    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 278    /// <returns>The response received from the server.</returns>
 279    public async Task<DeleteRangeResponse> DeleteAsync(string key, Metadata headers = null,
 280        DateTime? deadline = null,
 281        CancellationToken cancellationToken = default) =>
 0282        await DeleteAsync(new DeleteRangeRequest { Key = ByteString.CopyFromUtf8(key) }, headers, deadline,
 0283            cancellationToken).ConfigureAwait(false);
 284
 285    /// <summary>
 286    ///     Deletes all keys with the specified prefix
 287    /// </summary>
 288    /// <param name="prefixKey">Common prefix of all keys that need to be deleted</param>
 289    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 290    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 291    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 292    /// <returns>The response received from the server.</returns>
 293    public DeleteRangeResponse DeleteRange(string prefixKey, Metadata headers = null,
 294        DateTime? deadline = null,
 295        CancellationToken cancellationToken = default)
 0296    {
 0297        string rangeEnd = GetRangeEnd(prefixKey);
 0298        return Delete(
 0299            new DeleteRangeRequest
 0300            {
 0301                Key = ByteString.CopyFromUtf8(prefixKey), RangeEnd = ByteString.CopyFromUtf8(rangeEnd)
 0302            }, headers, deadline, cancellationToken);
 0303    }
 304
 305    /// <summary>
 306    ///     Deletes all keys with the specified prefix in async
 307    /// </summary>
 308    /// <param name="prefixKey">Commin prefix of all keys that need to be deleted</param>
 309    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 310    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 311    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 312    /// <returns>The response received from the server.</returns>
 313    public async Task<DeleteRangeResponse> DeleteRangeAsync(string prefixKey, Metadata headers = null,
 314        DateTime? deadline = null,
 315        CancellationToken cancellationToken = default)
 0316    {
 0317        string rangeEnd = GetRangeEnd(prefixKey);
 0318        return await DeleteAsync(
 0319            new DeleteRangeRequest
 0320            {
 0321                Key = ByteString.CopyFromUtf8(prefixKey), RangeEnd = ByteString.CopyFromUtf8(rangeEnd)
 0322            }, headers, deadline, cancellationToken).ConfigureAwait(false);
 0323    }
 324
 325    /// <summary>
 326    ///     Txn processes multiple requests in a single transaction.
 327    ///     A txn request increments the revision of the key-value store
 328    ///     and generates events with the same revision for every completed request.
 329    ///     It is not allowed to modify the same key several times within one txn.
 330    /// </summary>
 331    /// <param name="request">The request to send to the server.</param>
 332    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 333    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 334    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 335    /// <returns>The response received from the server.</returns>
 336    public TxnResponse Transaction(TxnRequest request, Metadata headers = null, DateTime? deadline = null,
 1337        CancellationToken cancellationToken = default) => CallEtcd(connection =>
 2338        connection.KVClient.Txn(request, headers, deadline, cancellationToken));
 339
 340    /// <summary>
 341    ///     Txn processes multiple requests in a single transaction in async.
 342    ///     A txn request increments the revision of the key-value store
 343    ///     and generates events with the same revision for every completed request.
 344    ///     It is not allowed to modify the same key several times within one txn.
 345    /// </summary>
 346    /// <param name="request">The request to send to the server.</param>
 347    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 348    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 349    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 350    /// <returns>The response received from the server.</returns>
 351    public async Task<TxnResponse> TransactionAsync(TxnRequest request, Metadata headers = null,
 352        DateTime? deadline = null,
 0353        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0354        .KVClient
 0355        .TxnAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 356
 357    /// <summary>
 358    ///     Compact compacts the event history in the etcd key-value store. The key-value
 359    ///     store should be periodically compacted or the event history will continue to grow
 360    ///     indefinitely.
 361    /// </summary>
 362    /// <param name="request">The request to send to the server.</param>
 363    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 364    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 365    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 366    /// <returns>The response received from the server.</returns>
 367    public CompactionResponse Compact(CompactionRequest request, Metadata headers = null,
 368        DateTime? deadline = null,
 0369        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.KVClient
 0370        .Compact(request, headers, deadline, cancellationToken));
 371
 372    /// <summary>
 373    ///     Compact compacts the event history in the etcd key-value store in async. The key-value
 374    ///     store should be periodically compacted or the event history will continue to grow
 375    ///     indefinitely.
 376    /// </summary>
 377    /// <param name="request">The request to send to the server.</param>
 378    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 379    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 380    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 381    /// <returns>The response received from the server.</returns>
 382    public async Task<CompactionResponse> CompactAsync(CompactionRequest request, Metadata headers = null,
 383        DateTime? deadline = null,
 0384        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0385        .KVClient
 0386        .CompactAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 387}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/leaseClient.cs

#LineLine coverage
 1using System;
 2using System.IO;
 3using System.Threading;
 4using System.Threading.Tasks;
 5using dotnet_etcd.interfaces;
 6using Etcdserverpb;
 7using Grpc.Core;
 8
 9namespace dotnet_etcd;
 10
 11public partial class EtcdClient
 12{
 13    /// <summary>
 14    ///     LeaseGrant creates a lease which expires if the server does not receive a keepAlive
 15    ///     within a given time to live period. All keys attached to the lease will be expired and
 16    ///     deleted if the lease expires. Each expired key generates a delete event in the event history.
 17    /// </summary>
 18    /// <param name="request">The request to send to the server.</param>
 19    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 20    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 21    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 22    /// <returns>The response received from the server.</returns>
 23    public LeaseGrantResponse LeaseGrant(LeaseGrantRequest request, Metadata headers = null,
 24        DateTime? deadline = null,
 225        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.LeaseClient
 226        .LeaseGrant(request, headers, deadline, cancellationToken));
 27
 28    /// <summary>
 29    ///     LeaseGrant creates a lease in async which expires if the server does not receive a keepAlive
 30    ///     within a given time to live period. All keys attached to the lease will be expired and
 31    ///     deleted if the lease expires. Each expired key generates a delete event in the event history.
 32    /// </summary>
 33    /// <param name="request">The request to send to the server.</param>
 34    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 35    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 36    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 37    /// <returns>The response received from the server.</returns>
 38    public async Task<LeaseGrantResponse> LeaseGrantAsync(LeaseGrantRequest request,
 39        Metadata headers = null, DateTime? deadline = null,
 240        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 241        .LeaseClient
 242        .LeaseGrantAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 43
 44    /// <summary>
 45    ///     LeaseRevoke revokes a lease. All keys attached to the lease will expire and be deleted.
 46    /// </summary>
 47    /// <param name="request">The request to send to the server.</param>
 48    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 49    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 50    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 51    /// <returns>The response received from the server.</returns>
 52    public LeaseRevokeResponse LeaseRevoke(LeaseRevokeRequest request, Metadata headers = null,
 53        DateTime? deadline = null,
 254        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.LeaseClient
 255        .LeaseRevoke(request, headers, deadline, cancellationToken));
 56
 57    /// <summary>
 58    ///     LeaseRevoke revokes a lease in async. All keys attached to the lease will expire and be deleted.
 59    /// </summary>
 60    /// <param name="request">The request to send to the server.</param>
 61    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 62    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 63    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 64    /// <returns>The response received from the server.</returns>
 65    public async Task<LeaseRevokeResponse> LeaseRevokeAsync(LeaseRevokeRequest request,
 66        Metadata headers = null, DateTime? deadline = null,
 267        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 268        .LeaseClient
 269        .LeaseRevokeAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 70
 71    /// <summary>
 72    ///     LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
 73    ///     to the server and streaming keep alive responses from the server to the client.
 74    /// </summary>
 75    /// <param name="cancellationTokenSource">
 76    ///     Cancellation token source that reflects communication status between server and
 77    ///     client.
 78    /// </param>
 79    /// <param name="leaseId">Granted lease identifier. <see cref="LeaseGrant" /> and <see cref="LeaseGrantAsync" /></pa
 80    /// <param name="keepAliveTimeout">Time to the next communication with Etcd server in milliseconds.</param>
 81    /// <param name="communicationTimeout">Time to wait response from Etcd server in milliseconds.</param>
 82    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 83    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 84    public Task LeaseKeepAlive(CancellationTokenSource cancellationTokenSource, long leaseId,
 85        int keepAliveTimeout = 1000, int? communicationTimeout = null, Metadata headers = null,
 086        DateTime? deadline = null) => CallEtcdAsync(connection =>
 087    {
 088        ArgumentNullException.ThrowIfNull(cancellationTokenSource);
 089        ArgumentOutOfRangeException.ThrowIfNegativeOrZero(keepAliveTimeout);
 090        if (communicationTimeout.HasValue)
 091        {
 092            ArgumentOutOfRangeException.ThrowIfNegativeOrZero(communicationTimeout.Value, nameof(communicationTimeout));
 093        }
 094
 095        CancellationToken cancellationToken = cancellationTokenSource.Token;
 096        int communicationTimeoutInMilliseconds = communicationTimeout ?? keepAliveTimeout / 2;
 097
 098        async ValueTask WriteAsync(AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser,
 099            LeaseKeepAliveRequest request, int timeoutInMilliseconds, CancellationToken cancellationToken)
 0100        {
 0101            // communication timeout
 0102            using CancellationTokenSource cancellationTokenSource =
 0103                CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 0104            cancellationTokenSource.CancelAfter(timeoutInMilliseconds);
 0105
 0106            await leaser.RequestStream.WriteAsync(request, cancellationTokenSource.Token)
 0107                .ConfigureAwait(false);
 0108        }
 0109
 0110        async ValueTask<bool> MoveNextAsync(
 0111            AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser, int timeoutInMilliseconds,
 0112            CancellationToken cancellationToken)
 0113        {
 0114            // communication timeout
 0115            using CancellationTokenSource cancellationTokenSource =
 0116                CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 0117            cancellationTokenSource.CancelAfter(timeoutInMilliseconds);
 0118
 0119            return await leaser.ResponseStream.MoveNext(cancellationTokenSource.Token)
 0120                .ConfigureAwait(false);
 0121        }
 0122
 0123        AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> LeaseKeepAlive(IConnection connection,
 0124            int timeoutInMilliseconds, CancellationToken cancellationToken)
 0125        {
 0126            // communication timeout
 0127            using CancellationTokenSource cancellationTokenSource =
 0128                CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 0129            cancellationTokenSource.CancelAfter(timeoutInMilliseconds);
 0130
 0131            return connection.LeaseClient.LeaseKeepAlive(headers, deadline, cancellationTokenSource.Token);
 0132        }
 0133
 0134        async Task KeepAliveAsync()
 0135        {
 0136            LeaseKeepAliveRequest request = new() { ID = leaseId };
 0137
 0138            try
 0139            {
 0140                using AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser =
 0141                    LeaseKeepAlive(connection, communicationTimeoutInMilliseconds, cancellationToken);
 0142
 0143                while (!cancellationToken.IsCancellationRequested)
 0144                {
 0145                    await WriteAsync(leaser, request, communicationTimeoutInMilliseconds, cancellationToken)
 0146                        .ConfigureAwait(false);
 0147
 0148                    if (!await MoveNextAsync(leaser, communicationTimeoutInMilliseconds, cancellationToken)
 0149                            .ConfigureAwait(false))
 0150                    {
 0151                        try
 0152                        {
 0153                            if (!cancellationTokenSource.IsCancellationRequested)
 0154                            {
 0155#if NET8_0_OR_GREATER
 0156                                await cancellationTokenSource.CancelAsync()
 0157                                    .ConfigureAwait(false);
 0158#else
 0159                                    cancellationTokenSource.Cancel();
 0160#endif
 0161                            }
 0162                        }
 0163                        finally
 0164                        {
 0165                            await leaser.RequestStream.CompleteAsync()
 0166                                .ConfigureAwait(false);
 0167                        }
 0168
 0169                        break;
 0170                    }
 0171
 0172                    LeaseKeepAliveResponse update = leaser.ResponseStream.Current;
 0173                    if (update.ID != leaseId || update.TTL == 0) // expired
 0174                    {
 0175                        try
 0176                        {
 0177                            if (!cancellationTokenSource.IsCancellationRequested)
 0178                            {
 0179#if NET8_0_OR_GREATER
 0180                                await cancellationTokenSource.CancelAsync()
 0181                                    .ConfigureAwait(false);
 0182#else
 0183                                    cancellationTokenSource.Cancel();
 0184#endif
 0185                            }
 0186                        }
 0187                        finally
 0188                        {
 0189                            await leaser.RequestStream.CompleteAsync()
 0190                                .ConfigureAwait(false);
 0191                        }
 0192
 0193                        break;
 0194                    }
 0195
 0196                    await Task.Delay(keepAliveTimeout, cancellationToken)
 0197                        .ConfigureAwait(false);
 0198                }
 0199            }
 0200            finally
 0201            {
 0202                if (!cancellationTokenSource.IsCancellationRequested)
 0203                {
 0204#if NET8_0_OR_GREATER
 0205                    await cancellationTokenSource.CancelAsync()
 0206                        .ConfigureAwait(false);
 0207#else
 0208                        cancellationTokenSource.Cancel();
 0209#endif
 0210                }
 0211            }
 0212        }
 0213
 0214        return Task.Run(KeepAliveAsync, cancellationToken);
 0215    });
 216
 217    /// <summary>
 218    ///     LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
 219    ///     to the server and streaming keep alive responses from the server to the client.
 220    /// </summary>
 221    /// <param name="leaseId"></param>
 222    /// <param name="cancellationToken"></param>
 0223    public async Task LeaseKeepAlive(long leaseId, CancellationToken cancellationToken) => await CallEtcdAsync(
 0224        async connection =>
 0225        {
 0226            using (AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser =
 0227                   connection.LeaseClient.LeaseKeepAlive(cancellationToken: cancellationToken))
 0228            {
 0229                LeaseKeepAliveRequest request = new() { ID = leaseId };
 0230
 0231                while (true)
 0232                {
 0233                    cancellationToken.ThrowIfCancellationRequested();
 0234
 0235                    await leaser.RequestStream.WriteAsync(request).ConfigureAwait(false);
 0236                    if (!await leaser.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0237                    {
 0238                        await leaser.RequestStream.CompleteAsync().ConfigureAwait(false);
 0239                        throw new EndOfStreamException();
 0240                    }
 0241
 0242                    LeaseKeepAliveResponse update = leaser.ResponseStream.Current;
 0243                    if (update.ID != leaseId || update.TTL == 0) // expired
 0244                    {
 0245                        await leaser.RequestStream.CompleteAsync().ConfigureAwait(false);
 0246                        return;
 0247                    }
 0248
 0249                    await Task.Delay(TimeSpan.FromMilliseconds(update.TTL * 1000 / 3), cancellationToken)
 0250                        .ConfigureAwait(false);
 0251                }
 0252            }
 0253        }).ConfigureAwait(false);
 254
 255    /// <summary>
 256    ///     LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
 257    ///     to the server and streaming keep alive responses from the server to the client.
 258    /// </summary>
 259    /// <param name="request">The request to send to the server.</param>
 260    /// <param name="method"></param>
 261    /// <param name="cancellationToken"></param>
 262    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 263    public async Task LeaseKeepAlive(LeaseKeepAliveRequest request, Action<LeaseKeepAliveResponse> method,
 0264        CancellationToken cancellationToken, Metadata headers = null) => await CallEtcdAsync(async connection =>
 0265    {
 0266        using (AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser =
 0267               connection.LeaseClient
 0268                   .LeaseKeepAlive(headers, cancellationToken: cancellationToken))
 0269        {
 0270            Task leaserTask = Task.Run(async () =>
 0271            {
 0272                while (await leaser.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0273                {
 0274                    LeaseKeepAliveResponse update = leaser.ResponseStream.Current;
 0275                    method(update);
 0276                }
 0277            }, cancellationToken);
 0278
 0279            await leaser.RequestStream.WriteAsync(request).ConfigureAwait(false);
 0280            await leaser.RequestStream.CompleteAsync().ConfigureAwait(false);
 0281            await leaserTask.ConfigureAwait(false);
 0282        }
 0283    }).ConfigureAwait(false);
 284
 285    /// <summary>
 286    ///     LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
 287    ///     to the server and streaming keep alive responses from the server to the client.
 288    /// </summary>
 289    /// <param name="request">The request to send to the server.</param>
 290    /// <param name="methods"></param>
 291    /// <param name="cancellationToken"></param>
 292    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 293    public async Task LeaseKeepAlive(LeaseKeepAliveRequest request, Action<LeaseKeepAliveResponse>[] methods,
 0294        CancellationToken cancellationToken, Metadata headers = null) => await CallEtcdAsync(async connection =>
 0295    {
 0296        using (AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser =
 0297               connection.LeaseClient
 0298                   .LeaseKeepAlive(headers, cancellationToken: cancellationToken))
 0299        {
 0300            Task leaserTask = Task.Run(async () =>
 0301            {
 0302                while (await leaser.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0303                {
 0304                    LeaseKeepAliveResponse update = leaser.ResponseStream.Current;
 0305                    foreach (Action<LeaseKeepAliveResponse> method in methods)
 0306                    {
 0307                        method(update);
 0308                    }
 0309                }
 0310            }, cancellationToken);
 0311
 0312            await leaser.RequestStream.WriteAsync(request).ConfigureAwait(false);
 0313            await leaser.RequestStream.CompleteAsync().ConfigureAwait(false);
 0314            await leaserTask.ConfigureAwait(false);
 0315        }
 0316    }).ConfigureAwait(false);
 317
 318
 319    /// <summary>
 320    ///     LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
 321    ///     to the server and streaming keep alive responses from the server to the client.
 322    /// </summary>
 323    /// <param name="requests"></param>
 324    /// <param name="method"></param>
 325    /// <param name="cancellationToken"></param>
 326    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 327    public async Task LeaseKeepAlive(LeaseKeepAliveRequest[] requests, Action<LeaseKeepAliveResponse> method,
 0328        CancellationToken cancellationToken, Metadata headers = null) => await CallEtcdAsync(async connection =>
 0329    {
 0330        using (AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser =
 0331               connection.LeaseClient
 0332                   .LeaseKeepAlive(headers, cancellationToken: cancellationToken))
 0333        {
 0334            Task leaserTask = Task.Run(async () =>
 0335            {
 0336                while (await leaser.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0337                {
 0338                    LeaseKeepAliveResponse update = leaser.ResponseStream.Current;
 0339                    method(update);
 0340                }
 0341            }, cancellationToken);
 0342
 0343            foreach (LeaseKeepAliveRequest request in requests)
 0344            {
 0345                await leaser.RequestStream.WriteAsync(request).ConfigureAwait(false);
 0346            }
 0347
 0348            await leaser.RequestStream.CompleteAsync().ConfigureAwait(false);
 0349            await leaserTask.ConfigureAwait(false);
 0350        }
 0351    }).ConfigureAwait(false);
 352
 353    /// <summary>
 354    ///     LeaseKeepAlive keeps the lease alive by streaming keep alive requests from the client
 355    ///     to the server and streaming keep alive responses from the server to the client.
 356    /// </summary>
 357    /// <param name="requests"></param>
 358    /// <param name="methods"></param>
 359    /// <param name="cancellationToken"></param>
 360    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 361    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 362    public async Task LeaseKeepAlive(LeaseKeepAliveRequest[] requests, Action<LeaseKeepAliveResponse>[] methods,
 0363        CancellationToken cancellationToken, Metadata headers = null, DateTime? deadline = null) => await CallEtcdAsync(
 0364        async connection =>
 0365        {
 0366            using (AsyncDuplexStreamingCall<LeaseKeepAliveRequest, LeaseKeepAliveResponse> leaser =
 0367                   connection.LeaseClient
 0368                       .LeaseKeepAlive(headers, deadline, cancellationToken))
 0369            {
 0370                Task leaserTask = Task.Run(async () =>
 0371                {
 0372                    while (await leaser.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0373                    {
 0374                        LeaseKeepAliveResponse update = leaser.ResponseStream.Current;
 0375                        foreach (Action<LeaseKeepAliveResponse> method in methods)
 0376                        {
 0377                            method(update);
 0378                        }
 0379                    }
 0380                }, cancellationToken);
 0381
 0382                foreach (LeaseKeepAliveRequest request in requests)
 0383                {
 0384                    await leaser.RequestStream.WriteAsync(request).ConfigureAwait(false);
 0385                }
 0386
 0387                await leaser.RequestStream.CompleteAsync().ConfigureAwait(false);
 0388                await leaserTask.ConfigureAwait(false);
 0389            }
 0390        }).ConfigureAwait(false);
 391
 392    /// <summary>
 393    ///     LeaseTimeToLive retrieves lease information.
 394    /// </summary>
 395    /// <param name="request">The request to send to the server.</param>
 396    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 397    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 398    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 399    /// <returns>The response received from the server.</returns>
 400    public LeaseTimeToLiveResponse LeaseTimeToLive(LeaseTimeToLiveRequest request,
 401        Metadata headers = null, DateTime? deadline = null,
 2402        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.LeaseClient
 2403        .LeaseTimeToLive(request, headers, deadline, cancellationToken));
 404
 405    /// <summary>
 406    ///     LeaseTimeToLive retrieves lease information.
 407    /// </summary>
 408    /// <param name="request">The request to send to the server.</param>
 409    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 410    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 411    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 412    /// <returns>The call object.</returns>
 413    public async Task<LeaseTimeToLiveResponse> LeaseTimeToLiveAsync(LeaseTimeToLiveRequest request,
 414        Metadata headers = null, DateTime? deadline = null,
 2415        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 2416        .LeaseClient
 2417        .LeaseTimeToLiveAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 418}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/lockClient.cs

#LineLine coverage
 1using System;
 2using System.Threading;
 3using System.Threading.Tasks;
 4using Google.Protobuf;
 5using Grpc.Core;
 6using V3Lockpb;
 7
 8namespace dotnet_etcd;
 9
 10public partial class EtcdClient
 11{
 12    /// <summary>
 13    ///     Lock acquires a distributed shared lock on a given named lock.
 14    ///     On success, it will return a unique key that exists so long as the
 15    ///     lock is held by the caller. This key can be used in conjunction with
 16    ///     transactions to safely ensure updates to etcd only occur while holding
 17    ///     lock ownership. The lock is held until Unlock is called on the key or the
 18    ///     lease associate with the owner expires.
 19    /// </summary>
 20    /// <param name="name">is the identifier for the distributed shared lock to be acquired.</param>
 21    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 22    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 23    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 24    /// <returns>The response received from the server.</returns>
 25    public LockResponse Lock(string name, Metadata headers = null, DateTime? deadline = null,
 026        CancellationToken cancellationToken = default) => Lock(new LockRequest { Name = ByteString.CopyFromUtf8(name) },
 027        headers, deadline, cancellationToken);
 28
 29    /// <summary>
 30    ///     Lock acquires a distributed shared lock on a given named lock.
 31    ///     On success, it will return a unique key that exists so long as the
 32    ///     lock is held by the caller. This key can be used in conjunction with
 33    ///     transactions to safely ensure updates to etcd only occur while holding
 34    ///     lock ownership. The lock is held until Unlock is called on the key or the
 35    ///     lease associate with the owner expires.
 36    /// </summary>
 37    /// <param name="request">The request to send to the server</param>
 38    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 39    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 40    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 41    /// <returns>The response received from the server.</returns>
 42    public LockResponse Lock(LockRequest request, Metadata headers = null, DateTime? deadline = null,
 143        CancellationToken cancellationToken = default) => CallEtcd(connection =>
 244        connection.LockClient.Lock(request, headers, deadline, cancellationToken));
 45
 46    /// <summary>
 47    ///     LockAsync acquires a distributed shared lock on a given named lock.
 48    ///     On success, it will return a unique key that exists so long as the
 49    ///     lock is held by the caller. This key can be used in conjunction with
 50    ///     transactions to safely ensure updates to etcd only occur while holding
 51    ///     lock ownership. The lock is held until Unlock is called on the key or the
 52    ///     lease associate with the owner expires.
 53    /// </summary>
 54    /// <param name="name">is the identifier for the distributed shared lock to be acquired.</param>
 55    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 56    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 57    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 58    /// <returns>The response received from the server.</returns>
 59    public async Task<LockResponse> LockAsync(string name, Metadata headers = null,
 60        DateTime? deadline = null, CancellationToken cancellationToken = default) =>
 061        await LockAsync(new LockRequest { Name = ByteString.CopyFromUtf8(name) }, headers, deadline, cancellationToken)
 062            .ConfigureAwait(false);
 63
 64    /// <summary>
 65    ///     LockAsync acquires a distributed shared lock on a given named lock.
 66    ///     On success, it will return a unique key that exists so long as the
 67    ///     lock is held by the caller. This key can be used in conjunction with
 68    ///     transactions to safely ensure updates to etcd only occur while holding
 69    ///     lock ownership. The lock is held until Unlock is called on the key or the
 70    ///     lease associate with the owner expires.
 71    /// </summary>
 72    /// <param name="request">The request to send to the server</param>
 73    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 74    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 75    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 76    /// <returns>The response received from the server.</returns>
 77    public async Task<LockResponse> LockAsync(LockRequest request, Metadata headers = null,
 178        DateTime? deadline = null, CancellationToken cancellationToken = default) => await CallEtcdAsync(
 279        async connection => await connection.LockClient
 280            .LockAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 81
 82    /// <summary>
 83    ///     Unlock takes a key returned by Lock and releases the hold on lock. The
 84    ///     next Lock caller waiting for the lock will then be woken up and given
 85    ///     ownership of the lock.
 86    /// </summary>
 87    /// <param name="key">the lock ownership key granted by Lock.</param>
 88    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 89    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 90    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 91    /// <returns>The response received from the server.</returns>
 92    public UnlockResponse Unlock(string key, Metadata headers = null, DateTime? deadline = null,
 93        CancellationToken cancellationToken = default) =>
 094        Unlock(new UnlockRequest { Key = ByteString.CopyFromUtf8(key) }, headers, deadline, cancellationToken);
 95
 96    /// <summary>
 97    ///     Unlock takes a key returned by Lock and releases the hold on lock. The
 98    ///     next Lock caller waiting for the lock will then be woken up and given
 99    ///     ownership of the lock.
 100    /// </summary>
 101    /// <param name="request">The request to send to the server</param>
 102    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 103    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 104    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 105    /// <returns>The response received from the server.</returns>
 106    public UnlockResponse Unlock(UnlockRequest request, Metadata headers = null,
 2107        DateTime? deadline = null, CancellationToken cancellationToken = default) => CallEtcd(connection => connection
 2108        .LockClient
 2109        .Unlock(request, headers, deadline, cancellationToken));
 110
 111    /// <summary>
 112    ///     UnlockAsync takes a key returned by Lock and releases the hold on lock. The
 113    ///     next Lock caller waiting for the lock will then be woken up and given
 114    ///     ownership of the lock.
 115    /// </summary>
 116    /// <param name="key">the lock ownership key granted by Lock.</param>
 117    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 118    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 119    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 120    /// <returns>The response received from the server.</returns>
 121    public async Task<UnlockResponse> UnlockAsync(string key, Metadata headers = null,
 122        DateTime? deadline = null, CancellationToken cancellationToken = default) =>
 0123        await UnlockAsync(new UnlockRequest { Key = ByteString.CopyFromUtf8(key) }, headers, deadline,
 0124            cancellationToken).ConfigureAwait(false);
 125
 126    /// <summary>
 127    ///     UnlockAsync takes a key returned by Lock and releases the hold on lock. The
 128    ///     next Lock caller waiting for the lock will then be woken up and given
 129    ///     ownership of the lock.
 130    /// </summary>
 131    /// <param name="request">The request to send to the server</param>
 132    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 133    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 134    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 135    /// <returns>The response received from the server.</returns>
 136    public async Task<UnlockResponse> UnlockAsync(UnlockRequest request, Metadata headers = null,
 1137        DateTime? deadline = null, CancellationToken cancellationToken = default) => await CallEtcdAsync(
 2138        async connection => await connection.LockClient
 2139            .UnlockAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 140}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/maintenanceClient.cs

#LineLine coverage
 1using System;
 2using System.Threading;
 3using System.Threading.Tasks;
 4using Etcdserverpb;
 5using Grpc.Core;
 6
 7namespace dotnet_etcd;
 8
 9public partial class EtcdClient
 10{
 11    /// <summary>
 12    ///     Alarm activates, deactivates, and queries alarms regarding cluster health
 13    /// </summary>
 14    /// <param name="request">Alarm request</param>
 15    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 16    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 17    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 18    /// <returns>Alarm Response</returns>
 19    public AlarmResponse Alarm(AlarmRequest request, Metadata headers = null, DateTime? deadline = null,
 220        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.MaintenanceClient
 221        .Alarm(request, headers, deadline, cancellationToken));
 22
 23    /// <summary>
 24    ///     Alarm activates, deactivates, and queries alarms regarding cluster health in async
 25    /// </summary>
 26    /// <param name="request">Alarm request</param>
 27    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 28    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 29    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 30    /// <returns>Alarm Response</returns>
 31    public async Task<AlarmResponse> AlarmAsync(AlarmRequest request, Metadata headers = null,
 32        DateTime? deadline = null,
 233        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 234        .MaintenanceClient
 235        .AlarmAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 36
 37    /// <summary>
 38    ///     Status gets the status of the member.
 39    /// </summary>
 40    /// <param name="request">Status Request</param>
 41    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 42    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 43    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 44    /// <returns>Status response</returns>
 45    public StatusResponse Status(StatusRequest request, Metadata headers = null,
 46        DateTime? deadline = null,
 447        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.MaintenanceClient
 448        .Status(request, headers, deadline, cancellationToken));
 49
 50    /// <summary>
 51    ///     Status gets the status of the member in async.
 52    /// </summary>
 53    /// <param name="request">Status Request</param>
 54    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 55    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 56    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 57    /// <returns>Status response</returns>
 58    public async Task<StatusResponse> StatusAsync(StatusRequest request, Metadata headers = null,
 59        DateTime? deadline = null,
 460        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 461        .MaintenanceClient
 462        .StatusAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 63
 64    /// <summary>
 65    ///     Defragment defragments a member's backend database to recover storage space.
 66    /// </summary>
 67    /// <param name="request">Defragment Request</param>
 68    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 69    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 70    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 71    /// <returns>Defragment Response</returns>
 72    public DefragmentResponse Defragment(DefragmentRequest request, Metadata headers = null,
 73        DateTime? deadline = null,
 274        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.MaintenanceClient
 275        .Defragment(request, headers, deadline, cancellationToken));
 76
 77    /// <summary>
 78    ///     Defragment defragments a member's backend database to recover storage space in async.
 79    /// </summary>
 80    /// <param name="request">Defragment Request</param>
 81    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 82    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 83    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 84    /// <returns>Defragment Response</returns>
 85    public async Task<DefragmentResponse> DefragmentAsync(DefragmentRequest request,
 86        Metadata headers = null, DateTime? deadline = null,
 287        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 288        .MaintenanceClient
 289        .DefragmentAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 90
 91    /// <summary>
 92    ///     Hash computes the hash of whole backend keyspace,
 93    ///     including key, lease, and other buckets in storage.
 94    ///     This is designed for testing ONLY!
 95    ///     Do not rely on this in production with ongoing transactions,
 96    ///     since Hash operation does not hold MVCC locks.
 97    ///     Use "HashKV" API instead for "key" bucket consistency checks.
 98    /// </summary>
 99    /// <param name="request">Hash Request</param>
 100    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 101    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 102    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 103    /// <returns>Hash Response</returns>
 104    public HashResponse Hash(HashRequest request, Metadata headers = null, DateTime? deadline = null,
 2105        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.MaintenanceClient
 2106        .Hash(request, headers, deadline, cancellationToken));
 107
 108    /// <summary>
 109    ///     Hash computes the hash of whole backend keyspace,
 110    ///     including key, lease, and other buckets in storage in async.
 111    ///     This is designed for testing ONLY!
 112    ///     Do not rely on this in production with ongoing transactions,
 113    ///     since Hash operation does not hold MVCC locks.
 114    ///     Use "HashKV" API instead for "key" bucket consistency checks.
 115    /// </summary>
 116    /// <param name="request">Hash Request</param>
 117    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 118    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 119    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 120    /// <returns>Hash Response</returns>
 121    public async Task<HashResponse> HashAsync(HashRequest request, Metadata headers = null,
 122        DateTime? deadline = null,
 2123        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 2124        .MaintenanceClient
 2125        .HashAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 126
 127    /// <summary>
 128    ///     HashKV computes the hash of all MVCC keys up to a given revision.
 129    ///     It only iterates "key" bucket in backend storage.
 130    /// </summary>
 131    /// <param name="request">HashKV Request</param>
 132    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 133    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 134    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 135    /// <returns>HashKV Response</returns>
 136    public HashKVResponse HashKV(HashKVRequest request, Metadata headers = null,
 137        DateTime? deadline = null,
 0138        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.MaintenanceClient
 0139        .HashKV(request, headers, deadline, cancellationToken));
 140
 141    /// <summary>
 142    ///     HashKV computes the hash of all MVCC keys up to a given revision in async.
 143    ///     It only iterates "key" bucket in backend storage.
 144    /// </summary>
 145    /// <param name="request">HashKV Request</param>
 146    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 147    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 148    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 149    /// <returns>HashKV Response</returns>
 150    public async Task<HashKVResponse> HashKVAsync(HashKVRequest request, Metadata headers = null,
 151        DateTime? deadline = null,
 0152        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0153        .MaintenanceClient
 0154        .HashKVAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 155
 156    /// <summary>
 157    ///     Snapshot sends a snapshot of the entire backend from a member over a stream to a client.
 158    /// </summary>
 159    /// <param name="request">The request to send to the server.</param>
 160    /// <param name="method"></param>
 161    /// <param name="cancellationToken"></param>
 162    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 163    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 164    public async Task Snapshot(SnapshotRequest request, Action<SnapshotResponse> method,
 0165        CancellationToken cancellationToken, Metadata headers = null, DateTime? deadline = null) => await CallEtcdAsync(
 0166        async connection =>
 0167        {
 0168            using (AsyncServerStreamingCall<SnapshotResponse> snapshotter = connection
 0169                       .MaintenanceClient.Snapshot(request, headers, deadline, cancellationToken))
 0170            {
 0171                while (await snapshotter.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0172                {
 0173                    SnapshotResponse update = snapshotter.ResponseStream.Current;
 0174                    method(update);
 0175                }
 0176            }
 0177        }).ConfigureAwait(false);
 178
 179    /// <summary>
 180    ///     Snapshot sends a snapshot of the entire backend from a member over a stream to a client.
 181    /// </summary>
 182    /// <param name="request">The request to send to the server.</param>
 183    /// <param name="methods"></param>
 184    /// <param name="cancellationToken"></param>
 185    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 186    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 187    public async Task Snapshot(SnapshotRequest request, Action<SnapshotResponse>[] methods,
 0188        CancellationToken cancellationToken, Metadata headers = null, DateTime? deadline = null) => await CallEtcdAsync(
 0189        async connection =>
 0190        {
 0191            using (AsyncServerStreamingCall<SnapshotResponse> snapshotter = connection
 0192                       .MaintenanceClient.Snapshot(request, headers, deadline, cancellationToken))
 0193            {
 0194                while (await snapshotter.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
 0195                {
 0196                    SnapshotResponse update = snapshotter.ResponseStream.Current;
 0197                    foreach (Action<SnapshotResponse> method in methods)
 0198                    {
 0199                        method(update);
 0200                    }
 0201                }
 0202            }
 0203        }).ConfigureAwait(false);
 204
 205    /// <summary>
 206    ///     MoveLeader requests current leader node to transfer its leadership to transferee.
 207    /// </summary>
 208    /// <param name="request">MoveLeader Request</param>
 209    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 210    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 211    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 212    /// <returns>MoveLeader Response</returns>
 213    public MoveLeaderResponse MoveLeader(MoveLeaderRequest request, Metadata headers = null,
 214        DateTime? deadline = null,
 0215        CancellationToken cancellationToken = default) => CallEtcd(connection => connection.MaintenanceClient
 0216        .MoveLeader(request, headers, deadline, cancellationToken));
 217
 218    /// <summary>
 219    ///     MoveLeader requests current leader node to transfer its leadership to transferee in async.
 220    /// </summary>
 221    /// <param name="request">MoveLeader Request</param>
 222    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 223    /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param>
 224    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 225    /// <returns>MoveLeader Response</returns>
 226    public async Task<MoveLeaderResponse> MoveLeaderAsync(MoveLeaderRequest request,
 227        Metadata headers = null, DateTime? deadline = null,
 0228        CancellationToken cancellationToken = default) => await CallEtcdAsync(async connection => await connection
 0229        .MaintenanceClient
 0230        .MoveLeaderAsync(request, headers, deadline, cancellationToken)).ConfigureAwait(false);
 231}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/Util.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.Threading.Tasks;
 5using dotnet_etcd.interfaces;
 6using dotnet_etcd.multiplexer;
 7using Etcdserverpb;
 8using Google.Protobuf;
 9using Grpc.Core;
 10using Mvccpb;
 11
 12namespace dotnet_etcd;
 13
 14public partial class EtcdClient
 15{
 16    private const string rangeEndString = "\x00";
 17
 18    /// <summary>
 19    ///     Converts RangeResponse to Dictionary
 20    /// </summary>
 21    /// <returns>IDictionary corresponding the RangeResponse</returns>
 22    /// <param name="resp">RangeResponse received from etcd server</param>
 23    private static Dictionary<string, string> RangeRespondToDictionary(RangeResponse resp)
 024    {
 025        Dictionary<string, string> resDictionary = new();
 026        foreach (KeyValue kv in resp.Kvs)
 027        {
 028            resDictionary.Add(kv.Key.ToStringUtf8(), kv.Value.ToStringUtf8());
 029        }
 30
 031        return resDictionary;
 032    }
 33
 34    /// <summary>
 35    ///     Gets the range end for prefix
 36    /// </summary>
 37    /// <returns>The range end for prefix</returns>
 38    /// <param name="prefixKey">Prefix key</param>
 39    public static string GetRangeEnd(string prefixKey)
 040    {
 041        if (prefixKey.Length == 0)
 042        {
 043            return rangeEndString;
 44        }
 45
 046        StringBuilder rangeEnd = new(prefixKey);
 047        rangeEnd[rangeEnd.Length - 1] = ++rangeEnd[rangeEnd.Length - 1];
 048        return rangeEnd.ToString();
 049    }
 50
 51    /// <summary>
 52    ///     Gets the byte string for range requests
 53    /// </summary>
 54    /// <param name="key"></param>
 55    /// <returns></returns>
 56    public static ByteString GetStringByteForRangeRequests(string key) =>
 057        key.Length == 0 ? ByteString.CopyFrom(0) : ByteString.CopyFromUtf8(key);
 58
 59    /// <summary>
 60    ///     Generic helper for performing actions an a connection.
 61    ///     Gets the connection from the <seealso cref="Balancer" />
 62    ///     Also implements a retry mechanism if the calling methods returns an <seealso cref="RpcException" /> with the
 63    ///     <seealso cref="StatusCode" /> <seealso cref="StatusCode.Unavailable" />
 64    /// </summary>
 65    /// <typeparam name="TResponse">The type of the response that is returned from the call to etcd</typeparam>
 66    /// <param name="etcdCallFunc">The function to perform actions with the <seealso cref="Connection" /> object</param>
 67    /// <returns>The response from the the <paramref name="etcdCallFunc" /></returns>
 3368    private TResponse CallEtcd<TResponse>(Func<IConnection, TResponse> etcdCallFunc) => etcdCallFunc(_connection);
 69
 70    /// <summary>
 71    ///     Generic helper for performing actions an a connection.
 72    ///     Gets the connection from the <seealso cref="Balancer" />
 73    ///     Also implements a retry mechanism if the calling methods returns an <seealso cref="RpcException" /> with the
 74    ///     <seealso cref="StatusCode" /> <seealso cref="StatusCode.Unavailable" />
 75    /// </summary>
 76    /// <typeparam name="TResponse">The type of the response that is returned from the call to etcd</typeparam>
 77    /// <param name="etcdCallFunc">The function to perform actions with the <seealso cref="Connection" /> object</param>
 78    /// <returns>The response from the the <paramref name="etcdCallFunc" /></returns>
 79    private Task<TResponse> CallEtcdAsync<TResponse>(Func<IConnection, Task<TResponse>> etcdCallFunc) =>
 2080        etcdCallFunc(_connection);
 81
 82    /// <summary>
 83    ///     Generic helper for performing actions an a connection.
 84    ///     Gets the connection from the <seealso cref="Balancer" />
 85    ///     Also implements a retry mechanism if the calling methods returns an <seealso cref="RpcException" /> with the
 86    ///     <seealso cref="StatusCode" /> <seealso cref="StatusCode.Unavailable" />
 87    /// </summary>
 88    /// <param name="etcdCallFunc">The function to perform actions with the <seealso cref="Connection" /> object</param>
 89    /// <returns>The response from the the <paramref name="etcdCallFunc" /></returns>
 090    private Task CallEtcdAsync(Func<IConnection, Task> etcdCallFunc) => etcdCallFunc(_connection);
 91}

/home/runner/work/dotnet-etcd/dotnet-etcd/dotnet-etcd/watchclient/watchClient.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Threading;
 5using System.Threading.Tasks;
 6using Etcdserverpb;
 7using Google.Protobuf;
 8using Grpc.Core;
 9
 10namespace dotnet_etcd;
 11
 12public partial class EtcdClient
 13{
 14    /// <summary>
 15    ///     Watches the specified requests and passes the watch events to the methods provided asynchronously.
 16    /// </summary>
 17    /// <param name="requests">Watch Requests containing keys to be watched</param>
 18    /// <param name="methods">Methods to which watch events should be passed on</param>
 19    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 20    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 21    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 22    /// <returns>A task that completes with an array of watch IDs</returns>
 23    public async Task<long[]> WatchAsync(WatchRequest[] requests, Action<WatchEvent[]>[] methods,
 24        Metadata headers = null,
 25        DateTime? deadline = null,
 26        CancellationToken cancellationToken = default)
 027    {
 028        if (requests.Length != methods.Length)
 029        {
 030            throw new ArgumentException("The number of requests must match the number of methods");
 31        }
 32
 033        long[] watchIds = new long[requests.Length];
 34
 035        for (int i = 0; i < requests.Length; i++)
 036        {
 37            // Create a wrapper that converts WatchResponse to WatchEvent[]
 038            Action<WatchResponse> wrapper = response =>
 039            {
 040                WatchEvent[] events = response.Events.Select(e => new WatchEvent
 041                {
 042                    Key = e.Kv.Key.ToStringUtf8(), Value = e.Kv.Value.ToStringUtf8(), Type = e.Type
 043                }).ToArray();
 044
 045                methods[i](events);
 046            };
 47
 048            watchIds[i] = await _watchManager.WatchAsync(requests[i], wrapper, headers, deadline, cancellationToken)
 049                .ConfigureAwait(false);
 050        }
 51
 052        return watchIds;
 053    }
 54
 55    public Task<long[]> WatchAsync(WatchRequest[] requests, Action<WatchEvent[]> method, Metadata headers = null,
 56        DateTime? deadline = null, CancellationToken cancellationToken = default)
 057    {
 058        List<Task<long>> tasks = [];
 59
 060        foreach (WatchRequest request in requests)
 061        {
 62            // Create a wrapper that converts WatchResponse to WatchEvent[]
 063            Action<WatchResponse> wrapper = response =>
 064            {
 065                WatchEvent[] events = response.Events.Select(e => new WatchEvent
 066                {
 067                    Key = e.Kv.Key.ToStringUtf8(), Value = e.Kv.Value.ToStringUtf8(), Type = e.Type
 068                }).ToArray();
 069
 070                method(events);
 071            };
 72
 073            tasks.Add(_watchManager.WatchAsync(request, wrapper, headers, deadline, cancellationToken));
 074        }
 75
 076        return Task.WhenAll(tasks);
 077    }
 78    // CancelWatch methods are already defined in EtcdClient.cs
 79
 80    /// <summary>
 81    ///     Watches the specified requests and passes the watch response to the methods provided.
 82    /// </summary>
 83    /// <param name="requests">Watch Requests containing keys to be watched</param>
 84    /// <param name="methods">Methods to which a watch response should be passed on</param>
 85    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 86    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 87    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 88    public void Watch(WatchRequest[] requests, Action<WatchResponse>[] methods, Metadata headers = null,
 89        DateTime? deadline = null,
 90        CancellationToken cancellationToken = default)
 091    {
 092        if (requests.Length != methods.Length)
 093        {
 094            throw new ArgumentException("The number of requests must match the number of methods");
 95        }
 96
 097        for (int i = 0; i < requests.Length; i++)
 098        {
 099            _watchManager.Watch(requests[i], methods[i], headers, deadline, cancellationToken);
 0100        }
 0101    }
 102
 103    /// <summary>
 104    ///     Watches the specified requests and passes the watch events to the methods provided.
 105    /// </summary>
 106    /// <param name="requests">Watch Requests containing keys to be watched</param>
 107    /// <param name="methods">Methods to which watch events should be passed on</param>
 108    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 109    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 110    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 111    public void Watch(WatchRequest[] requests, Action<WatchEvent[]>[] methods, Metadata headers = null,
 112        DateTime? deadline = null,
 113        CancellationToken cancellationToken = default)
 0114    {
 0115        if (requests.Length != methods.Length)
 0116        {
 0117            throw new ArgumentException("The number of requests must match the number of methods");
 118        }
 119
 0120        for (int i = 0; i < requests.Length; i++)
 0121        {
 122            // Create a wrapper that converts WatchResponse to WatchEvent[]
 0123            Action<WatchResponse> wrapper = response =>
 0124            {
 0125                WatchEvent[] events = [.. response.Events.Select(e => new WatchEvent
 0126                {
 0127                    Key = e.Kv.Key.ToStringUtf8(), Value = e.Kv.Value.ToStringUtf8(), Type = e.Type
 0128                })];
 0129
 0130                methods[i](events);
 0131            };
 132
 0133            _watchManager.Watch(requests[i], wrapper, headers, deadline, cancellationToken);
 0134        }
 0135    }
 136
 137    #region Watch Key
 138
 139    /// <summary>
 140    ///     Watches a key according to the specified watch request and
 141    ///     passes the watch response to the method provided.
 142    /// </summary>
 143    /// <param name="request">Watch Request containing a key to be watched</param>
 144    /// <param name="method">Method to which a watch response should be passed on</param>
 145    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 146    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 147    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 148    /// <returns>A task that completes with the watch ID</returns>
 149    public Task<long> WatchAsync(WatchRequest request, Action<WatchResponse> method, Metadata headers = null,
 150        DateTime? deadline = null,
 151        CancellationToken cancellationToken = default) =>
 0152        _watchManager.WatchAsync(request, method, headers, deadline, cancellationToken);
 153
 154    /// <summary>
 155    ///     Watches a key according to the specified watch request and
 156    ///     passes the watch response to the methods provided.
 157    /// </summary>
 158    /// <param name="request">Watch Request containing a key to be watched</param>
 159    /// <param name="methods">Methods to which a watch response should be passed on</param>
 160    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 161    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 162    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 163    /// <returns>A task that completes with the watch ID</returns>
 164    public Task<long> WatchAsync(WatchRequest request, Action<WatchResponse>[] methods, Metadata headers = null,
 165        DateTime? deadline = null,
 166        CancellationToken cancellationToken = default)
 0167    {
 168        // Create a wrapper method that calls all the methods
 0169        Action<WatchResponse> wrapper = response =>
 0170        {
 0171            foreach (Action<WatchResponse> method in methods)
 0172            {
 0173                method(response);
 0174            }
 0175        };
 176
 0177        return _watchManager.WatchAsync(request, wrapper, headers, deadline, cancellationToken);
 0178    }
 179
 180    /// <summary>
 181    ///     Watches a key according to the specified watch requests and
 182    ///     passes the watch response to the method provided.
 183    /// </summary>
 184    /// <param name="requests">Watch Requests containing keys to be watched</param>
 185    /// <param name="method">Method to which a watch response should be passed on</param>
 186    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 187    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 188    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 189    /// <returns>A task that completes with an array of watch IDs</returns>
 190    public async Task<long[]> WatchAsync(WatchRequest[] requests, Action<WatchResponse> method, Metadata headers = null,
 191        DateTime? deadline = null,
 192        CancellationToken cancellationToken = default)
 0193    {
 0194        long[] watchIds = new long[requests.Length];
 195
 0196        for (int i = 0; i < requests.Length; i++)
 0197        {
 0198            watchIds[i] = await _watchManager.WatchAsync(requests[i], method, headers, deadline, cancellationToken)
 0199                .ConfigureAwait(false);
 0200        }
 201
 0202        return watchIds;
 0203    }
 204
 205    /// <summary>
 206    ///     Watches a key according to the specified watch requests and
 207    ///     passes the watch response to the methods provided.
 208    /// </summary>
 209    /// <param name="requests">Watch Requests containing keys to be watched</param>
 210    /// <param name="methods">Methods to which a watch response should be passed on</param>
 211    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 212    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 213    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 214    /// <returns>A task that completes with an array of watch IDs</returns>
 215    public async Task<long[]> WatchAsync(WatchRequest[] requests, Action<WatchResponse>[] methods,
 216        Metadata headers = null,
 217        DateTime? deadline = null,
 218        CancellationToken cancellationToken = default)
 0219    {
 0220        if (requests.Length != methods.Length)
 0221        {
 0222            throw new ArgumentException("The number of requests must match the number of methods");
 223        }
 224
 0225        long[] watchIds = new long[requests.Length];
 226
 0227        for (int i = 0; i < requests.Length; i++)
 0228        {
 0229            watchIds[i] = await _watchManager.WatchAsync(requests[i], methods[i], headers, deadline, cancellationToken)
 0230                .ConfigureAwait(false);
 0231        }
 232
 0233        return watchIds;
 0234    }
 235
 236    /// <summary>
 237    ///     Watches a key according to the specified watch request and
 238    ///     passes the minimal watch event data to the method provided.
 239    /// </summary>
 240    /// <param name="request">Watch Request containing a key to be watched</param>
 241    /// <param name="method">Method to which minimal watch events data should be passed on</param>
 242    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 243    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 244    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 245    public Task WatchAsync(WatchRequest request, Action<WatchEvent[]> method, Metadata headers = null,
 246        DateTime? deadline = null,
 247        CancellationToken cancellationToken = default)
 0248    {
 249        // Create a wrapper that converts WatchResponse to WatchEvent[]
 0250        Action<WatchResponse> wrapper = response =>
 0251        {
 0252            WatchEvent[] events = response.Events.Select(i =>
 0253            {
 0254                return new WatchEvent
 0255                {
 0256                    Key = i.Kv.Key.ToStringUtf8(), Value = i.Kv.Value.ToStringUtf8(), Type = i.Type
 0257                };
 0258            }).ToArray();
 0259
 0260            method(events);
 0261        };
 262
 0263        return _watchManager.WatchAsync(request, wrapper, headers, deadline, cancellationToken);
 0264    }
 265
 266    /// <summary>
 267    ///     Watches a key according to the specified watch request and
 268    ///     passes the minimal watch event data to the methods provided.
 269    /// </summary>
 270    /// <param name="request">Watch Request containing a key to be watched</param>
 271    /// <param name="methods">Methods to which minimal watch events data should be passed on</param>
 272    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 273    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 274    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 275    public Task WatchAsync(WatchRequest request, Action<WatchEvent[]>[] methods, Metadata headers = null,
 276        DateTime? deadline = null,
 277        CancellationToken cancellationToken = default)
 0278    {
 279        // Create a wrapper that converts WatchResponse to WatchEvent[] and calls all methods
 0280        Action<WatchResponse> wrapper = response =>
 0281        {
 0282            WatchEvent[] events = response.Events.Select(i =>
 0283            {
 0284                return new WatchEvent
 0285                {
 0286                    Key = i.Kv.Key.ToStringUtf8(), Value = i.Kv.Value.ToStringUtf8(), Type = i.Type
 0287                };
 0288            }).ToArray();
 0289
 0290            foreach (Action<WatchEvent[]> method in methods)
 0291            {
 0292                method(events);
 0293            }
 0294        };
 295
 0296        return _watchManager.WatchAsync(request, wrapper, headers, deadline, cancellationToken);
 0297    }
 298
 299    /// <summary>
 300    ///     Watches the specified key and passes the watch response to the method provided.
 301    /// </summary>
 302    /// <param name="request">Watch Request</param>
 303    /// <param name="method">Method to which a watch response should be passed on</param>
 304    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 305    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 306    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 307    public void Watch(WatchRequest request, Action<WatchResponse> method, Metadata headers = null,
 308        DateTime? deadline = null,
 309        CancellationToken cancellationToken = default) =>
 0310        _watchManager.Watch(request, method, headers, deadline, cancellationToken);
 311
 312    /// <summary>
 313    ///     Watches a key according to the specified watch request and
 314    ///     passes the watch response to the methods provided.
 315    /// </summary>
 316    /// <param name="request">Watch Request containing a key to be watched</param>
 317    /// <param name="methods">Methods to which a watch response should be passed on</param>
 318    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 319    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 320    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 321    public void Watch(WatchRequest request, Action<WatchResponse>[] methods,
 322        Metadata headers = null, DateTime? deadline = null,
 0323        CancellationToken cancellationToken = default) => Watch([request], methods, headers,
 0324        deadline, cancellationToken);
 325
 326
 327    /// <summary>
 328    ///     Watches the specified keys and passes the watch response to the method provided.
 329    /// </summary>
 330    /// <param name="key">Key to watch</param>
 331    /// <param name="method">Method to which a watch response should be passed on</param>
 332    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 333    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 334    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 335    public void Watch(string key, Action<WatchResponse> method, Metadata headers = null,
 336        DateTime? deadline = null,
 0337        CancellationToken cancellationToken = default) => Watch([key],
 0338        [method], headers, deadline, cancellationToken);
 339
 340    /// <summary>
 341    ///     Watches the specified key and passes the watch response to the methods provided.
 342    /// </summary>
 343    /// <param name="key">Key to be watched</param>
 344    /// <param name="methods">Methods to which a watch response should be passed on</param>
 345    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 346    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 347    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 348    public void Watch(string key, Action<WatchResponse>[] methods, Metadata headers = null,
 349        DateTime? deadline = null,
 350        CancellationToken cancellationToken = default) =>
 0351        Watch([key], methods, headers, deadline, cancellationToken);
 352
 353
 354    /// <summary>
 355    ///     Watches the specified keys and passes the watch response to the method provided.
 356    /// </summary>
 357    /// <param name="keys">Keys to be watched</param>
 358    /// <param name="method">Method to which a watch response should be passed on</param>
 359    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 360    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 361    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 362    public void Watch(string[] keys, Action<WatchResponse> method, Metadata headers = null,
 363        DateTime? deadline = null,
 0364        CancellationToken cancellationToken = default) => Watch(keys, [method], headers,
 0365        deadline, cancellationToken);
 366
 367    /// <summary>
 368    ///     Watches the specified keys and passes the watch response to the method provided.
 369    /// </summary>
 370    /// <param name="keys">Keys to be watched</param>
 371    /// <param name="methods">Methods to which a watch response should be passed on</param>
 372    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 373    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 374    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 375    public void Watch(string[] keys, Action<WatchResponse>[] methods, Metadata headers = null,
 376        DateTime? deadline = null,
 377        CancellationToken cancellationToken = default)
 0378    {
 0379        List<WatchRequest> requests = [];
 380
 0381        foreach (string key in keys)
 0382        {
 0383            WatchRequest request = new()
 0384            {
 0385                CreateRequest = new WatchCreateRequest
 0386                {
 0387                    Key = ByteString.CopyFromUtf8(key), ProgressNotify = true, PrevKv = true
 0388                }
 0389            };
 0390            requests.Add(request);
 0391        }
 392
 0393        Watch(requests.ToArray(), methods, headers, deadline, cancellationToken);
 0394    }
 395
 396
 397    /// <summary>
 398    ///     Watches the specified key and passes the minimal watch events data to the method provided.
 399    /// </summary>
 400    /// <param name="key">Key to be watched</param>
 401    /// <param name="method">Method to which minimal watch events data should be passed on</param>
 402    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 403    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 404    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 405    public void Watch(string key, Action<WatchEvent[]> method, Metadata headers = null,
 406        DateTime? deadline = null,
 0407        CancellationToken cancellationToken = default) => Watch([key],
 0408        [method], headers, deadline, cancellationToken);
 409
 410    /// <summary>
 411    ///     Watches the specified key and passes the minimal watch events data to the methods provided.
 412    /// </summary>
 413    /// <param name="key">Key to be watched</param>
 414    /// <param name="methods">Methods to which minimal watch events data should be passed on</param>
 415    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 416    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 417    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 418    public void Watch(string key, Action<WatchEvent[]>[] methods, Metadata headers = null,
 419        DateTime? deadline = null,
 420        CancellationToken cancellationToken = default) =>
 0421        Watch([key], methods, headers, deadline, cancellationToken);
 422
 423    /// <summary>
 424    ///     Watches the specified keys and passes the minimal watch events data to the method provided.
 425    /// </summary>
 426    /// <param name="keys">Keys to be watched</param>
 427    /// <param name="method">Method to which minimal watch events data should be passed on</param>
 428    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 429    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 430    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 431    public void Watch(string[] keys, Action<WatchEvent[]> method, Metadata headers = null,
 432        DateTime? deadline = null,
 0433        CancellationToken cancellationToken = default) => Watch(keys, [method], headers,
 0434        deadline, cancellationToken);
 435
 436    /// <summary>
 437    ///     Watches the specified keys and passes the minimal watch events data to the method provided.
 438    /// </summary>
 439    /// <param name="keys">Keys to be watched</param>
 440    /// <param name="methods">Methods to which minimal watch events data should be passed on</param>
 441    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 442    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 443    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 444    public void Watch(string[] keys, Action<WatchEvent[]>[] methods, Metadata headers = null,
 445        DateTime? deadline = null,
 446        CancellationToken cancellationToken = default)
 0447    {
 0448        List<WatchRequest> requests = [];
 449
 0450        foreach (string key in keys)
 0451        {
 0452            WatchRequest request = new()
 0453            {
 0454                CreateRequest = new WatchCreateRequest { Key = ByteString.CopyFromUtf8(key) }
 0455            };
 0456            requests.Add(request);
 0457        }
 458
 0459        Watch(requests.ToArray(), methods, headers, deadline, cancellationToken);
 0460    }
 461
 462
 463    /// <summary>
 464    ///     Watches the specified key and passes the watch response to the method provided.
 465    /// </summary>
 466    /// <param name="key">Key to be watched</param>
 467    /// <param name="method">Method to which a watch response should be passed on</param>
 468    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 469    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 470    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 471    public Task WatchAsync(string key, Action<WatchResponse> method, Metadata headers = null,
 472        DateTime? deadline = null,
 0473        CancellationToken cancellationToken = default) => WatchAsync([key],
 0474        [method], headers, deadline, cancellationToken);
 475
 476    /// <summary>
 477    ///     Watches the specified key and passes the watch response to the methods provided.
 478    /// </summary>
 479    /// <param name="key">Key to be watched</param>
 480    /// <param name="methods">Methods to which a watch response should be passed on</param>
 481    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 482    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 483    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 484    public Task WatchAsync(string key, Action<WatchResponse>[] methods, Metadata headers = null,
 485        DateTime? deadline = null,
 486        CancellationToken cancellationToken = default) =>
 0487        WatchAsync([key], methods, headers, deadline, cancellationToken);
 488
 489
 490    /// <summary>
 491    ///     Watches the specified keys and passes the watch response to the method provided.
 492    /// </summary>
 493    /// <param name="keys">Keys to be watched</param>
 494    /// <param name="method">Method to which a watch response should be passed on</param>
 495    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 496    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 497    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 498    public Task WatchAsync(string[] keys, Action<WatchResponse> method, Metadata headers = null,
 499        DateTime? deadline = null,
 0500        CancellationToken cancellationToken = default) => WatchAsync(keys, [method],
 0501        headers, deadline, cancellationToken);
 502
 503    /// <summary>
 504    ///     Watches the specified keys and passes the watch response to the method provided.
 505    /// </summary>
 506    /// <param name="keys">Keys to be watched</param>
 507    /// <param name="methods">Methods to which a watch response should be passed on</param>
 508    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 509    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 510    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 511    public Task WatchAsync(string[] keys, Action<WatchResponse>[] methods, Metadata headers = null,
 512        DateTime? deadline = null,
 513        CancellationToken cancellationToken = default)
 0514    {
 0515        List<WatchRequest> requests = [];
 516
 0517        foreach (string key in keys)
 0518        {
 0519            WatchRequest request = new()
 0520            {
 0521                CreateRequest = new WatchCreateRequest
 0522                {
 0523                    Key = ByteString.CopyFromUtf8(key), ProgressNotify = true, PrevKv = true
 0524                }
 0525            };
 0526            requests.Add(request);
 0527        }
 528
 0529        return WatchAsync(requests.ToArray(), methods, headers, deadline, cancellationToken);
 0530    }
 531
 532    /// <summary>
 533    ///     Watches the specified key and passes the minimal watch events data to the method provided.
 534    /// </summary>
 535    /// <param name="key">Key to be watched</param>
 536    /// <param name="method">Method to which minimal watch events data should be passed on</param>
 537    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 538    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 539    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 540    public Task WatchAsync(string key, Action<WatchEvent[]> method, Metadata headers = null,
 541        DateTime? deadline = null,
 0542        CancellationToken cancellationToken = default) => WatchAsync([key],
 0543        [method], headers, deadline, cancellationToken);
 544
 545    /// <summary>
 546    ///     Watches the specified key and passes the minimal watch events data to the methods provided.
 547    /// </summary>
 548    /// <param name="key">Key to be watched</param>
 549    /// <param name="methods">Methods to which minimal watch events data should be passed on</param>
 550    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 551    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 552    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 553    public Task WatchAsync(string key, Action<WatchEvent[]>[] methods, Metadata headers = null,
 554        DateTime? deadline = null,
 555        CancellationToken cancellationToken = default) =>
 0556        WatchAsync([key], methods, headers, deadline, cancellationToken);
 557
 558    /// <summary>
 559    ///     Watches the specified keys and passes the minimal watch events data to the method provided.
 560    /// </summary>
 561    /// <param name="keys">Keys to be watched</param>
 562    /// <param name="method">Method to which minimal watch events data should be passed on</param>
 563    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 564    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 565    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 566    public Task WatchAsync(string[] keys, Action<WatchEvent[]> method, Metadata headers = null,
 567        DateTime? deadline = null,
 0568        CancellationToken cancellationToken = default) => WatchAsync(keys, [method],
 0569        headers, deadline, cancellationToken);
 570
 571    /// <summary>
 572    ///     Watches the specified keys and passes the minimal watch events data to the method provided.
 573    /// </summary>
 574    /// <param name="keys">Keys to be watched</param>
 575    /// <param name="methods">Methods to which minimal watch events data should be passed on</param>
 576    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 577    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 578    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 579    public Task WatchAsync(string[] keys, Action<WatchEvent[]>[] methods, Metadata headers = null,
 580        DateTime? deadline = null,
 581        CancellationToken cancellationToken = default)
 0582    {
 0583        List<WatchRequest> requests = [];
 584
 0585        foreach (string key in keys)
 0586        {
 0587            WatchRequest request = new()
 0588            {
 0589                CreateRequest = new WatchCreateRequest
 0590                {
 0591                    Key = ByteString.CopyFromUtf8(key), ProgressNotify = true, PrevKv = true
 0592                }
 0593            };
 0594            requests.Add(request);
 0595        }
 596
 0597        return WatchAsync(requests.ToArray(), methods, headers, deadline, cancellationToken);
 0598    }
 599
 600    #endregion
 601
 602    #region Watch Range of keys
 603
 604    /// <summary>
 605    ///     Watches the specified key range and passes the watch response to the method provided.
 606    /// </summary>
 607    /// <param name="path">Path to be watched</param>
 608    /// <param name="method">Method to which a watch response should be passed on</param>
 609    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 610    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 611    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 612    /// <returns>A watch ID that can be used to cancel the watch</returns>
 613    public long WatchRange(string path, Action<WatchResponse> method, Metadata headers = null,
 614        DateTime? deadline = null,
 615        CancellationToken cancellationToken = default)
 0616    {
 0617        WatchRequest request = new()
 0618        {
 0619            CreateRequest = new WatchCreateRequest
 0620            {
 0621                Key = GetStringByteForRangeRequests(path),
 0622                RangeEnd = ByteString.CopyFromUtf8(GetRangeEnd(path)),
 0623                ProgressNotify = true,
 0624                PrevKv = true
 0625            }
 0626        };
 627
 0628        return _watchManager.Watch(request, method, headers, deadline, cancellationToken);
 0629    }
 630
 631    /// <summary>
 632    ///     Watches the specified key range and passes the watch response to the methods provided.
 633    /// </summary>
 634    /// <param name="path">Path to be watched</param>
 635    /// <param name="methods">Methods to which a watch response should be passed on</param>
 636    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 637    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 638    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 639    /// <returns>A watch ID that can be used to cancel the watch</returns>
 640    public long WatchRange(string path, Action<WatchResponse>[] methods, Metadata headers = null,
 641        DateTime? deadline = null,
 642        CancellationToken cancellationToken = default)
 0643    {
 644        // Create a wrapper method that calls all the methods
 0645        Action<WatchResponse> wrapper = response =>
 0646        {
 0647            foreach (Action<WatchResponse> method in methods)
 0648            {
 0649                method(response);
 0650            }
 0651        };
 652
 0653        return WatchRange(path, wrapper, headers, deadline, cancellationToken);
 0654    }
 655
 656    /// <summary>
 657    ///     Watches the specified key range and passes the watch response to the method provided.
 658    /// </summary>
 659    /// <param name="paths">Paths to be watched</param>
 660    /// <param name="method">Method to which a watch response should be passed on</param>
 661    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 662    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 663    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 664    /// <returns>An array of watch IDs that can be used to cancel the watches</returns>
 665    public long[] WatchRange(string[] paths, Action<WatchResponse> method, Metadata headers = null,
 666        DateTime? deadline = null,
 667        CancellationToken cancellationToken = default)
 0668    {
 0669        long[] watchIds = new long[paths.Length];
 670
 0671        for (int i = 0; i < paths.Length; i++)
 0672        {
 0673            watchIds[i] = WatchRange(paths[i], method, headers, deadline, cancellationToken);
 0674        }
 675
 0676        return watchIds;
 0677    }
 678
 679    /// <summary>
 680    ///     Watches the specified key range and passes the watch response to the method provided.
 681    /// </summary>
 682    /// <param name="paths">Paths to be watched</param>
 683    /// <param name="methods">Methods to which a watch response should be passed on</param>
 684    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 685    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 686    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 687    /// <returns>An array of watch IDs that can be used to cancel the watches</returns>
 688    public long[] WatchRange(string[] paths, Action<WatchResponse>[] methods, Metadata headers = null,
 689        DateTime? deadline = null,
 690        CancellationToken cancellationToken = default)
 0691    {
 0692        if (paths.Length != methods.Length)
 0693        {
 0694            throw new ArgumentException("The number of paths must match the number of methods");
 695        }
 696
 0697        long[] watchIds = new long[paths.Length];
 698
 0699        for (int i = 0; i < paths.Length; i++)
 0700        {
 0701            watchIds[i] = WatchRange(paths[i], methods[i], headers, deadline, cancellationToken);
 0702        }
 703
 0704        return watchIds;
 0705    }
 706
 707    /// <summary>
 708    ///     Watches the specified key range and passes the watch response to the method provided asynchronously.
 709    /// </summary>
 710    /// <param name="path">Path to be watched</param>
 711    /// <param name="method">Method to which a watch response should be passed on</param>
 712    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 713    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 714    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 715    /// <returns>A task that completes with the watch ID</returns>
 716    public Task<long> WatchRangeAsync(string path, Action<WatchResponse> method, Metadata headers = null,
 717        DateTime? deadline = null,
 718        CancellationToken cancellationToken = default)
 0719    {
 0720        WatchRequest request = new()
 0721        {
 0722            CreateRequest = new WatchCreateRequest
 0723            {
 0724                Key = GetStringByteForRangeRequests(path),
 0725                RangeEnd = ByteString.CopyFromUtf8(GetRangeEnd(path)),
 0726                ProgressNotify = true,
 0727                PrevKv = true
 0728            }
 0729        };
 730
 0731        return _watchManager.WatchAsync(request, method, headers, deadline, cancellationToken);
 0732    }
 733
 734    /// <summary>
 735    ///     Watches the specified key range and passes the watch response to the methods provided asynchronously.
 736    /// </summary>
 737    /// <param name="path">Path to be watched</param>
 738    /// <param name="methods">Methods to which a watch response should be passed on</param>
 739    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 740    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 741    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 742    /// <returns>A task that completes with the watch ID</returns>
 743    public Task<long> WatchRangeAsync(string path, Action<WatchResponse>[] methods, Metadata headers = null,
 744        DateTime? deadline = null,
 745        CancellationToken cancellationToken = default)
 0746    {
 747        // Create a wrapper method that calls all the methods
 0748        Action<WatchResponse> wrapper = response =>
 0749        {
 0750            foreach (Action<WatchResponse> method in methods)
 0751            {
 0752                method(response);
 0753            }
 0754        };
 755
 0756        return WatchRangeAsync(path, wrapper, headers, deadline, cancellationToken);
 0757    }
 758
 759    /// <summary>
 760    ///     Watches the specified key range and passes the watch response to the method provided asynchronously.
 761    /// </summary>
 762    /// <param name="paths">Paths to be watched</param>
 763    /// <param name="method">Method to which a watch response should be passed on</param>
 764    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 765    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 766    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 767    /// <returns>A task that completes with an array of watch IDs</returns>
 768    public async Task<long[]> WatchRangeAsync(string[] paths, Action<WatchResponse> method, Metadata headers = null,
 769        DateTime? deadline = null,
 770        CancellationToken cancellationToken = default)
 0771    {
 0772        long[] watchIds = new long[paths.Length];
 773
 0774        for (int i = 0; i < paths.Length; i++)
 0775        {
 0776            watchIds[i] = await WatchRangeAsync(paths[i], method, headers, deadline, cancellationToken)
 0777                .ConfigureAwait(false);
 0778        }
 779
 0780        return watchIds;
 0781    }
 782
 783    /// <summary>
 784    ///     Watches the specified key range and passes the watch response to the method provided asynchronously.
 785    /// </summary>
 786    /// <param name="paths">Paths to be watched</param>
 787    /// <param name="methods">Methods to which a watch response should be passed on</param>
 788    /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param>
 789    /// <param name="deadline">An optional deadline for the call. The call will be canceled if the deadline is hit.</par
 790    /// <param name="cancellationToken">An optional token for canceling the call.</param>
 791    /// <returns>A task that completes with an array of watch IDs</returns>
 792    public async Task<long[]> WatchRangeAsync(string[] paths, Action<WatchResponse>[] methods, Metadata headers = null,
 793        DateTime? deadline = null,
 794        CancellationToken cancellationToken = default)
 0795    {
 0796        if (paths.Length != methods.Length)
 0797        {
 0798            throw new ArgumentException("The number of paths must match the number of methods");
 799        }
 800
 0801        long[] watchIds = new long[paths.Length];
 802
 0803        for (int i = 0; i < paths.Length; i++)
 0804        {
 0805            watchIds[i] = await WatchRangeAsync(paths[i], methods[i], headers, deadline, cancellationToken)
 0806                .ConfigureAwait(false);
 0807        }
 808
 0809        return watchIds;
 0810    }
 811
 812    #endregion
 813}

Methods/Properties

Authenticate(Etcdserverpb.AuthenticateRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<AuthenticateAsync()
AuthEnable(Etcdserverpb.AuthEnableRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<AuthEnableAsync()
AuthDisable(Etcdserverpb.AuthDisableRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<AuthDisableAsync()
UserAdd(Etcdserverpb.AuthUserAddRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserAddAsync()
UserGet(Etcdserverpb.AuthUserGetRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserGetAsync()
UserList(Etcdserverpb.AuthUserListRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserListAsync()
UserDelete(Etcdserverpb.AuthUserDeleteRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserDeleteAsync()
UserChangePassword(Etcdserverpb.AuthUserChangePasswordRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserChangePasswordAsync()
UserGrantRole(Etcdserverpb.AuthUserGrantRoleRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserGrantRoleAsync()
UserRevokeRole(Etcdserverpb.AuthUserRevokeRoleRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<UserRevokeRoleAsync()
RoleAdd(Etcdserverpb.AuthRoleAddRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<RoleAddAsync()
RoleGet(Etcdserverpb.AuthRoleGetRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<RoleGetAsync()
RoleList(Etcdserverpb.AuthRoleListRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<RoleListAsync()
RoleDelete(Etcdserverpb.AuthRoleDeleteRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<RoleDeleteAsync()
RoleGrantPermission(Etcdserverpb.AuthRoleGrantPermissionRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<RoleGrantPermissionAsync()
RoleRevokePermission(Etcdserverpb.AuthRoleRevokePermissionRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<RoleRevokePermissionAsync()
MemberAdd(Etcdserverpb.MemberAddRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<MemberAddAsync()
MemberRemove(Etcdserverpb.MemberRemoveRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<MemberRemoveAsync()
MemberUpdate(Etcdserverpb.MemberUpdateRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<MemberUpdateAsync()
MemberList(Etcdserverpb.MemberListRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<MemberListAsync()
Campaign(V3Electionpb.CampaignRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Campaign(System.String,System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<CampaignAsync()
<CampaignAsync()
Proclaim(V3Electionpb.ProclaimRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Proclaim(V3Electionpb.LeaderKey,System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<ProclaimAsync()
<ProclaimAsync()
Leader(V3Electionpb.LeaderRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Leader(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<LeaderAsync()
<LeaderAsync()
ObserveAsync()
ObserveAsync()
Resign(V3Electionpb.ResignRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Resign(V3Electionpb.LeaderKey,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<ResignAsync()
<ResignAsync()
Observe(V3Electionpb.LeaderRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Observe(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
GetConnection()
GetWatchManager()
CancelWatch(System.Int64)
CancelWatch(System.Int64[])
.ctor(Grpc.Core.CallInvoker)
.cctor()
.ctor(System.String,System.Int32,System.String,System.Action`1<Grpc.Net.Client.GrpcChannelOptions>,Grpc.Core.Interceptors.Interceptor[])
.ctor(System.String,System.Action`1<System.Net.Security.SslClientAuthenticationOptions>,System.Int32,System.String,System.Action`1<Grpc.Net.Client.GrpcChannelOptions>,Grpc.Core.Interceptors.Interceptor[])
.ctor(System.String,System.String,System.String,System.Int32,System.String,System.Action`1<Grpc.Net.Client.GrpcChannelOptions>)
.ctor(dotnet_etcd.interfaces.IConnection,dotnet_etcd.interfaces.IWatchManager)
SetCredentials(System.String,System.String)
AuthenticateAndCacheToken()
Dispose(System.Boolean)
Dispose()
Get(Etcdserverpb.RangeRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Get(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<GetAsync()
GetAsync()
GetVal(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
GetValAsync()
GetRange(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
GetRangeAsync()
GetRangeVal(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
GetRangeValAsync()
Put(Etcdserverpb.PutRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Put(System.String,System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<PutAsync()
PutAsync()
Delete(Etcdserverpb.DeleteRangeRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Delete(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<DeleteAsync()
DeleteAsync()
DeleteRange(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
DeleteRangeAsync()
Transaction(Etcdserverpb.TxnRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<TransactionAsync()
Compact(Etcdserverpb.CompactionRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<CompactAsync()
LeaseGrant(Etcdserverpb.LeaseGrantRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<LeaseGrantAsync()
LeaseRevoke(Etcdserverpb.LeaseRevokeRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<LeaseRevokeAsync()
LeaseKeepAlive(System.Threading.CancellationTokenSource,System.Int64,System.Int32,System.Nullable`1<System.Int32>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>)
LeaseKeepAlive()
<LeaseKeepAlive()
LeaseKeepAlive()
<LeaseKeepAlive()
LeaseKeepAlive()
<LeaseKeepAlive()
LeaseKeepAlive()
<LeaseKeepAlive()
LeaseKeepAlive()
<LeaseKeepAlive()
LeaseTimeToLive(Etcdserverpb.LeaseTimeToLiveRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<LeaseTimeToLiveAsync()
Lock(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Lock(V3Lockpb.LockRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
LockAsync()
LockAsync()
<LockAsync()
Unlock(System.String,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Unlock(V3Lockpb.UnlockRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
UnlockAsync()
UnlockAsync()
<UnlockAsync()
Alarm(Etcdserverpb.AlarmRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<AlarmAsync()
Status(Etcdserverpb.StatusRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<StatusAsync()
Defragment(Etcdserverpb.DefragmentRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<DefragmentAsync()
Hash(Etcdserverpb.HashRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<HashAsync()
HashKV(Etcdserverpb.HashKVRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<HashKVAsync()
Snapshot()
<Snapshot()
Snapshot()
<Snapshot()
MoveLeader(Etcdserverpb.MoveLeaderRequest,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
<MoveLeaderAsync()
RangeRespondToDictionary(Etcdserverpb.RangeResponse)
GetRangeEnd(System.String)
GetStringByteForRangeRequests(System.String)
CallEtcd(System.Func`2<dotnet_etcd.interfaces.IConnection,TResponse>)
CallEtcdAsync(System.Func`2<dotnet_etcd.interfaces.IConnection,System.Threading.Tasks.Task`1<TResponse>>)
CallEtcdAsync(System.Func`2<dotnet_etcd.interfaces.IConnection,System.Threading.Tasks.Task>)
WatchAsync()
WatchAsync(Etcdserverpb.WatchRequest[],System.Action`1<dotnet_etcd.WatchEvent[]>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(Etcdserverpb.WatchRequest[],System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(Etcdserverpb.WatchRequest[],System.Action`1<dotnet_etcd.WatchEvent[]>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(Etcdserverpb.WatchRequest,System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(Etcdserverpb.WatchRequest,System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync()
WatchAsync()
WatchAsync(Etcdserverpb.WatchRequest,System.Action`1<dotnet_etcd.WatchEvent[]>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(Etcdserverpb.WatchRequest,System.Action`1<dotnet_etcd.WatchEvent[]>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(Etcdserverpb.WatchRequest,System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(Etcdserverpb.WatchRequest,System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String,System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String,System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String[],System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String[],System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String,System.Action`1<dotnet_etcd.WatchEvent[]>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String,System.Action`1<dotnet_etcd.WatchEvent[]>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String[],System.Action`1<dotnet_etcd.WatchEvent[]>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
Watch(System.String[],System.Action`1<dotnet_etcd.WatchEvent[]>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String,System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String,System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String[],System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String[],System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String,System.Action`1<dotnet_etcd.WatchEvent[]>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String,System.Action`1<dotnet_etcd.WatchEvent[]>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String[],System.Action`1<dotnet_etcd.WatchEvent[]>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchAsync(System.String[],System.Action`1<dotnet_etcd.WatchEvent[]>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRange(System.String,System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRange(System.String,System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRange(System.String[],System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRange(System.String[],System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRangeAsync(System.String,System.Action`1<Etcdserverpb.WatchResponse>,Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRangeAsync(System.String,System.Action`1<Etcdserverpb.WatchResponse>[],Grpc.Core.Metadata,System.Nullable`1<System.DateTime>,System.Threading.CancellationToken)
WatchRangeAsync()
WatchRangeAsync()