public override async Task <GetInviteResponse> GetInvite(GetInviteRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); if (string.IsNullOrEmpty(request.InviteId)) { throw new RpcException(new Status(StatusCode.InvalidArgument, "Expected non-empty invite id")); } using (var memClient = _memoryStoreClientManager.GetClient()) { var invite = await memClient.GetAsync <InviteDataModel>(request.InviteId) ?? throw new EntryNotFoundException(request.InviteId, "No such invite with the given id found"); if (!invite.PlayerInvolved(playerId)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The player is not involved in this invite")); } return(new GetInviteResponse { Invite = ConvertToProto(invite) }); } }
public async Task <ActionResult <IEnumerable <MetadataUpdate <string> > > > UpdateAccountMetadata( [FromHeader] AuthHeaders headers) { try { var body = await Request.Body.ReadAsStringAsync(); if (!Auth.TryAuthenticate(headers, body, out var error)) { return(Unauthorized(error)); } var metadata = JsonSerializer.Deserialize <List <MetadataUpdate <string> > >(body); if (metadata.Any(x => !Regex.IsMatch(x.Key, "^(tz1|tz2|tz3|KT1)[0-9A-Za-z]{33}$"))) { return(new BadRequest("body", "Invalid account address")); } return(Ok(await Metadata.UpdateAccountMetadata(metadata))); } catch (JsonException) { return(new BadRequest("body", "Invalid json")); } }
public override async Task <DeletePartyResponse> DeleteParty(DeletePartyRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); using (var memClient = _memoryStoreClientManager.GetClient()) { var party = await GetPartyByPlayerId(memClient, playerId) ?? throw new RpcException(new Status(StatusCode.NotFound, "The player is not a member of any party")); if (playerId != party.LeaderPlayerId) { throw new RpcException(new Status(StatusCode.PermissionDenied, "Cannot delete party: player needs to be the leader of the party")); } // TODO(iuliaharasim/dom): Move logic specific to party deletion in a separate class. var entitiesToDelete = new List <Entry> { party }; entitiesToDelete.AddRange(party.GetMembers()); try { using (var transaction = memClient.CreateTransaction()) { transaction.DeleteAll(entitiesToDelete); } } catch (EntryNotFoundException exception) { if (exception.Id.Contains(party.Id)) { throw; } // If one of the members has left the party, it is safe to retry this RPC. throw new TransactionAbortedException(); } _analytics.Send("player_cancelled_party", new Dictionary <string, string> { { "partyId", party.Id } }, playerId); _analytics.Send("party_cancelled", new Dictionary <string, string> { { "partyId", party.Id } }, playerId); foreach (var m in party.GetMembers()) { _analytics.Send( "player_left_cancelled_party", new Dictionary <string, string> { { "partyId", party.Id } }, m.Id); } } return(new DeletePartyResponse()); }
public async Task <ActionResult <IEnumerable <MetadataUpdate <string> > > > UpdateSoftwareMetadata( [FromHeader] AuthHeaders headers) { try { var body = await Request.Body.ReadAsStringAsync(); if (!Auth.TryAuthenticate(headers, body, out var error)) { return(Unauthorized(error)); } var metadata = JsonSerializer.Deserialize <List <MetadataUpdate <string> > >(body); if (metadata.Any(x => !Regex.IsMatch(x.Key, "^[0-9a-f]{8}$"))) { return(BadRequest("Invalid software short hash")); } return(Ok(await Metadata.UpdateSoftwareMetadata(metadata))); } catch (JsonException) { return(new BadRequest("body", "Invalid json")); } }
public override Task <CreatePartyResponse> CreateParty(CreatePartyRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); var pit = AuthHeaders.ExtractPit(context); // TODO(iuliaharasim/dom): Move logic specific to party creation in a separate class. PartyDataModel party; try { party = new PartyDataModel(playerId, pit, request.MinMembers, request.MaxMembers, request.Metadata); } catch (ArgumentException exception) { throw new RpcException(new Status(StatusCode.InvalidArgument, exception.Message)); } var leader = party.GetLeader(); using (var memClient = _memoryStoreClientManager.GetClient()) using (var transaction = memClient.CreateTransaction()) { transaction.CreateAll(new List <Entry> { party, leader }); } return(Task.FromResult(new CreatePartyResponse { PartyId = party.Id })); }
public override async Task <LeavePartyResponse> LeaveParty(LeavePartyRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); await LeaveParty(playerId); return(new LeavePartyResponse()); }
public bool LoginWithCookie(string cookie) { AuthHeaders = new AuthHeaders { Cookie = cookie }; return(true); }
public override Task <TResponse> UnaryServerHandler <TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod <TRequest, TResponse> continuation) { var validated = context.RequestHeaders.SingleOrDefault(item => item.Key == SecretHeaderKey)?.Value == _secret; AuthHeaders.AddAuthenticatedHeaderToContext(context, validated); return(continuation(request, context)); }
public override async Task <DeleteInviteResponse> DeleteInvite(DeleteInviteRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); if (string.IsNullOrEmpty(request.InviteId)) { throw new RpcException(new Status(StatusCode.InvalidArgument, "Expected non-empty invite id")); } using (var memClient = _memoryStoreClientManager.GetClient()) { var invite = await memClient.GetAsync <InviteDataModel>(request.InviteId); if (invite == null) { return(new DeleteInviteResponse()); } if (!invite.PlayerInvolved(playerId)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The player is not involved in this invite")); } var senderInvites = await memClient.GetAsync <PlayerInvites>(invite.SenderId) ?? throw new EntryNotFoundException(playerId, "No invites found for the sender"); senderInvites.OutboundInviteIds.Remove(invite.Id); var receiverInvites = await memClient.GetAsync <PlayerInvites>(invite.ReceiverId) ?? throw new EntryNotFoundException(playerId, "No invites found for the receiver"); receiverInvites.InboundInviteIds.Remove(invite.Id); using (var transaction = memClient.CreateTransaction()) { transaction.DeleteAll(new List <InviteDataModel> { invite }); transaction.UpdateAll(new List <PlayerInvites> { senderInvites, receiverInvites }); } _analytics.Send("player_invite_to_party_revoked", new Dictionary <string, string> { { "partyId", invite.PartyId }, { "playerIdInviter", playerId }, { "inviteId", invite.Id } }, invite.ReceiverId); } return(new DeleteInviteResponse()); }
public async Task <ActionResult <RawJson> > GetStateMetadata( [FromHeader] AuthHeaders headers, string section = null) { if (!Auth.TryAuthenticate(headers, out var error)) { return(Unauthorized(error)); } return(Ok(await Metadata.GetStateMetadata(section))); }
public async Task <ActionResult <RawJson> > GetProposalMetadata( [FromHeader] AuthHeaders headers, [ProtocolHash] string hash, string section = null) { if (!Auth.TryAuthenticate(headers, out var error)) { return(Unauthorized(error)); } return(Ok(await Metadata.GetProposalMetadata(hash, section))); }
public async Task <ActionResult <RawJson> > GetConstantMetadata( [FromHeader] AuthHeaders headers, [ExpressionHash] string address, string section = null) { if (!Auth.TryAuthenticate(headers, out var error)) { return(Unauthorized(error)); } return(Ok(await Metadata.GetConstantMetadata(address, section))); }
private static string ExtractPlayerIdentityTokenFromContext(ServerCallContext context) { var pit = context.RequestHeaders.SingleOrDefault(item => item.Key == PlayerIdentityTokenHeaderKey)?.Value; if (!AuthHeaders.ValidatePit(pit)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The request header doesn't contain a Player Identity Token.")); } return(pit); }
private static string ExtractPlayerIdentifier(PlayerIdentityToken decodedPit) { var playerIdentifier = decodedPit.PlayerIdentifier; if (!AuthHeaders.ValidatePlayerId(playerIdentifier)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The Player Identity Token doesn't contain a valid player_identifier")); } return(playerIdentifier); }
public override Task <TResponse> UnaryServerHandler <TRequest, TResponse>( TRequest request, ServerCallContext context, UnaryServerMethod <TRequest, TResponse> continuation) { var pit = ExtractPlayerIdentityTokenFromContext(context); var decodedPit = DecodePlayerIdentityToken(pit); var playerIdentifier = ExtractPlayerIdentifier(decodedPit); AuthHeaders.AddPlayerIdentifierToContext(context, playerIdentifier); return(continuation(request, context)); }
public async Task <ActionResult <IEnumerable <MetadataUpdate <string> > > > GetAccountMetadata( [FromHeader] AuthHeaders headers, JsonParameter metadata, [Min(0)] int offset = 0, [Range(0, 10000)] int limit = 100, string section = null) { if (!Auth.TryAuthenticate(headers, out var error)) { return(Unauthorized(error)); } return(Ok(await Metadata.GetAccountMetadata(metadata, offset, limit, section))); }
public override async Task <GetPartyByPlayerIdResponse> GetPartyByPlayerId(GetPartyByPlayerIdRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); using (var memClient = _memoryStoreClientManager.GetClient()) { var party = await GetPartyByPlayerId(memClient, playerId) ?? throw new RpcException(new Status(StatusCode.NotFound, "The player is not a member of any party")); return(new GetPartyByPlayerIdResponse { Party = ConvertToProto(party) }); } }
// Updates the Party's information, excluding its member list. // TODO: Move to FieldMasks. public override async Task <UpdatePartyResponse> UpdateParty(UpdatePartyRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); ValidateUpdatePartyRequest(request); using (var memClient = _memoryStoreClientManager.GetClient()) { var updatedParty = request.UpdatedParty; var party = await memClient.GetAsync <PartyDataModel>(updatedParty.Id) ?? throw new RpcException(new Status(StatusCode.NotFound, "There is no such party with the given id")); if (party.LeaderPlayerId != playerId) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The update operation can only be done by the leader of the party")); } if (!party.UpdatePartyLeader(updatedParty.LeaderPlayerId)) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "The proposed new leader is not a member of the party")); } if (!party.UpdateMinMaxMembers(updatedParty.MinMembers, updatedParty.MaxMembers)) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "Encountered error while updating the minimum and maximum amount of members")); } // TODO(iuliaharasim/dom): Move logic specific to updating a party into a separate class. party.CurrentPhase = ConvertToDataModel(updatedParty.CurrentPhase); party.UpdateMetadata(updatedParty.Metadata); using (var transaction = memClient.CreateTransaction()) { transaction.UpdateAll(new List <Entry> { party }); } return(new UpdatePartyResponse { Party = ConvertToProto(party) }); } }
public override Task <CreatePartyResponse> CreateParty(CreatePartyRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); var pit = AuthHeaders.ExtractPit(context); // TODO(iuliaharasim/dom): Move logic specific to party creation in a separate class. PartyDataModel party; try { party = new PartyDataModel(playerId, pit, request.MinMembers, request.MaxMembers, request.Metadata); } catch (ArgumentException exception) { throw new RpcException(new Status(StatusCode.InvalidArgument, exception.Message)); } var leader = party.GetLeader(); using (var memClient = _memoryStoreClientManager.GetClient()) using (var transaction = memClient.CreateTransaction()) { transaction.CreateAll(new List <Entry> { party, leader }); } var eventAttributes = new Dictionary <string, string> { { "partyId", party.Id } }; string[] eventTypes = { "player_created_party", "player_joined_party", "party_created" }; foreach (string eventType in eventTypes) { if (eventType == "party_created") { eventAttributes.Add("partyPhase", party.CurrentPhase.ToString()); } _analytics.Send(eventType, eventAttributes, playerId); } return(Task.FromResult(new CreatePartyResponse { PartyId = party.Id })); }
// Updates the metadata and current status. Sender, receiver and party id are ignored. // TODO: consider moving to FieldMasks. public override async Task <UpdateInviteResponse> UpdateInvite(UpdateInviteRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); var updatedInvite = request.UpdatedInvite ?? throw new RpcException(new Status(StatusCode.InvalidArgument, "Expected non-empty updated invite")); if (string.IsNullOrEmpty(updatedInvite.Id)) { throw new RpcException(new Status(StatusCode.InvalidArgument, "Expected updated invite with non-empty id")); } using (var memClient = _memoryStoreClientManager.GetClient()) { var invite = await memClient.GetAsync <InviteDataModel>(updatedInvite.Id) ?? throw new EntryNotFoundException(updatedInvite.Id, "No such invite with the given id found"); if (!invite.PlayerInvolved(playerId)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The player is not involved in this invite")); } invite.CurrentStatus = ConvertToDataModel(updatedInvite.CurrentStatus); invite.UpdateMetadata(updatedInvite.Metadata); using (var transaction = memClient.CreateTransaction()) { transaction.UpdateAll(new List <Entry> { invite }); } return(new UpdateInviteResponse { Invite = ConvertToProto(invite) }); } }
public async Task <ActionResult <MetadataUpdate> > UpdateStateMetadata( [FromHeader] AuthHeaders headers) { try { var body = await Request.Body.ReadAsStringAsync(); if (!Auth.TryAuthenticate(headers, body, out var error)) { return(Unauthorized(error)); } var metadata = JsonSerializer.Deserialize <MetadataUpdate>(body); return(Ok(await Metadata.UpdateStateMetadata(metadata))); } catch (JsonException) { return(new BadRequest("body", "Invalid json")); } }
public override async Task <ListAllInvitesResponse> ListAllInvites(ListAllInvitesRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); using (var memClient = _memoryStoreClientManager.GetClient()) { var playerInvites = await memClient.GetAsync <PlayerInvites>(playerId); if (playerInvites == null) { return(new ListAllInvitesResponse()); } var response = new ListAllInvitesResponse(); foreach (var id in playerInvites.OutboundInviteIds) { var invite = await memClient.GetAsync <InviteDataModel>(id) ?? throw new RpcException(new Status(StatusCode.Unavailable, "Concurrent modification. Safe to retry")); response.OutboundInvites.Add(ConvertToProto(invite)); } foreach (var id in playerInvites.InboundInviteIds) { var invite = await memClient.GetAsync <InviteDataModel>(id) ?? throw new RpcException(new Status(StatusCode.Unavailable, "Concurrent modification. Safe to retry")); response.InboundInvites.Add(ConvertToProto(invite)); } return(response); } }
public bool TryAuthenticate(AuthHeaders headers, out string error) { error = null; return(true); }
public override async Task <Empty> DeleteOperation(DeleteOperationRequest request, ServerCallContext context) { var playerIdentity = AuthHeaders.ExtractPlayerId(context); if (!string.Equals(request.Name, playerIdentity)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "Deleting another player's operation is forbidden.")); } Log.Information($"Requested cancellation for the party of player identifier {request.Name}."); using (var memClient = _memoryStoreClientManager.GetClient()) { var party = await GetPartyOfMember(memClient, request.Name); if (party == null) { throw new RpcException(new Status(StatusCode.NotFound, "The player making this call is not a member of any party")); } if (party.LeaderPlayerId != request.Name) { throw new RpcException(new Status(StatusCode.PermissionDenied, "Only the leader can delete a matchmaking join request")); } try { var partyJoinRequest = await memClient.GetAsync <PartyJoinRequest>(party.Id) ?? throw new EntryNotFoundException(party.Id); var toDelete = new List <Entry> { partyJoinRequest }; foreach (var(member, _) in partyJoinRequest.Party.MemberIdToPit) { toDelete.Add(await memClient.GetAsync <PlayerJoinRequest>(member) ?? throw new EntryNotFoundException(member)); } party.CurrentPhase = PartyDataModel.Phase.Forming; using (var tx = memClient.CreateTransaction()) { tx.UpdateAll(party.Yield()); tx.RemoveAllFromQueue(partyJoinRequest.Yield()); tx.DeleteAll(toDelete); } Reporter.CancelOperationInc(); return(new Empty()); } catch (EntryNotFoundException exception) { Log.Warning($"Delete for {request.Name} failed."); if (exception.Id.Contains(party.Id)) { Reporter.CancelOperationNotFoundInc(); throw new RpcException(new Status(StatusCode.NotFound, "requested party is not in matchmaking")); } throw new RpcException(new Status(StatusCode.Internal, $"could not find join request for player {exception.Id}")); } catch (TransactionAbortedException) { Reporter.TransactionAbortedInc("DeleteOperation"); Log.Warning("Transaction for operation deletion was aborted"); throw new RpcException(new Status(StatusCode.Unavailable, "deletion aborted due to concurrent modification; safe to retry")); } } }
public override async Task <Operation> GetOperation(GetOperationRequest request, ServerCallContext context) { var playerIdentity = AuthHeaders.ExtractPlayerId(context); if (!string.Equals(request.Name, playerIdentity)) { throw new RpcException(new Status(StatusCode.PermissionDenied, "Fetching another player's operation is forbidden.")); } PlayerJoinRequest joinRequest; using (var memClient = _memoryStoreClientManager.GetClient()) { try { joinRequest = await memClient.GetAsync <PlayerJoinRequest>(request.Name) ?? throw new EntryNotFoundException(request.Name); if (joinRequest.IsComplete()) { using (var tx = memClient.CreateTransaction()) { tx.DeleteAll(joinRequest.Yield()); } } } catch (EntryNotFoundException e) { Reporter.OperationStateNotFoundInc(); Log.Warning($"Join request for {e.Id} does not exist"); throw new RpcException(new Status(StatusCode.NotFound, "requested player does not exist")); } catch (TransactionAbortedException) { Reporter.TransactionAbortedInc("GetOperation"); Log.Warning("Transaction for operation deletion was aborted"); throw new RpcException(new Status(StatusCode.Unavailable, "deletion aborted due to concurrent modification; safe to retry")); } } var op = new Operation { Name = joinRequest.PlayerIdentity, Done = joinRequest.IsComplete() }; if (!op.Done) { Reporter.OperationStateInc(MatchState.Requested); return(op); } switch (joinRequest.State) { case MatchState.Matched: op.Response = CreateJoinResponse(joinRequest); break; case MatchState.Error: op.Error = new Google.Rpc.Status { Code = (int)Google.Rpc.Code.Unknown, Message = "the join request encountered an error" }; break; } Reporter.OperationStateInc(joinRequest.State); Log.Information($"Join request for {op.Name} done in state {joinRequest.State}."); return(op); }
public override async Task <KickOutPlayerResponse> KickOutPlayer(KickOutPlayerRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); if (string.IsNullOrEmpty(request.EvictedPlayerId)) { throw new RpcException(new Status(StatusCode.InvalidArgument, "LeaveParty requires a non-empty evicted player id")); } if (playerId == request.EvictedPlayerId) { await LeaveParty(request.EvictedPlayerId); return(new KickOutPlayerResponse()); } using (var memClient = _memoryStoreClientManager.GetClient()) { var initiatorTask = memClient.GetAsync <Member>(playerId); var evictedTask = memClient.GetAsync <Member>(request.EvictedPlayerId); Task.WaitAll(initiatorTask, evictedTask); var initiator = initiatorTask.Result ?? throw new RpcException(new Status(StatusCode.NotFound, "The initiator player is not a member of any party")); // If the evicted has already left the party, we should return early. var evicted = evictedTask.Result; if (evicted == null) { return(new KickOutPlayerResponse()); } var party = await memClient.GetAsync <PartyDataModel>(initiator.PartyId) ?? throw new RpcException(new Status(StatusCode.NotFound, "The party no longer exists")); if (party.LeaderPlayerId != initiator.Id) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The initiator is not the leader of the party")); } if (initiator.PartyId != evicted.PartyId) { throw new RpcException(new Status(StatusCode.PermissionDenied, "The players are not members of the same party")); } // TODO(iuliaharasim/dom): Move logic specific to removing a player from a party into a separate class. // If false, the player has already been removed from the party so we should terminate early. if (!party.RemovePlayerFromParty(evicted.Id)) { return(new KickOutPlayerResponse()); } using (var transaction = memClient.CreateTransaction()) { transaction.DeleteAll(new List <Entry> { evicted }); transaction.UpdateAll(new List <Entry> { party }); } _analytics.Send("player_kicked_from_party", new Dictionary <string, string> { { "partyId", party.Id }, { "playerIdKicker", playerId } }, evicted.Id); } return(new KickOutPlayerResponse()); }
public override async Task <CreateInviteResponse> CreateInvite(CreateInviteRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); if (string.IsNullOrEmpty(request.ReceiverPlayerId)) { throw new RpcException( new Status(StatusCode.InvalidArgument, "Expected a non-empty receiver player id")); } using (var memClient = _memoryStoreClientManager.GetClient()) { var party = await GetPartyByPlayerId(memClient, playerId); // This extra check is necessary because the player might have meanwhile left the party (between the // Get<Member> and Get<PartyDataModel> calls). if (party?.GetMember(playerId) == null) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "The player creating this invite is not a member of any party")); } if (party.GetMember(request.ReceiverPlayerId) != null) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "The receiving player is already a member of the party")); } var entitiesToCreate = new List <Entry>(); var entitiesToUpdate = new List <Entry>(); var invite = new InviteDataModel(playerId, request.ReceiverPlayerId, party.Id, request.Metadata); entitiesToCreate.Add(invite); var senderPlayerInvites = await memClient.GetAsync <PlayerInvites>(playerId); if (senderPlayerInvites == null) { senderPlayerInvites = new PlayerInvites(playerId); entitiesToCreate.Add(senderPlayerInvites); } else { entitiesToUpdate.Add(senderPlayerInvites); } senderPlayerInvites.OutboundInviteIds.Add(invite.Id); var receiverPlayerInvites = await memClient.GetAsync <PlayerInvites>(request.ReceiverPlayerId); if (receiverPlayerInvites == null) { receiverPlayerInvites = new PlayerInvites(request.ReceiverPlayerId); entitiesToCreate.Add(receiverPlayerInvites); } else { entitiesToUpdate.Add(receiverPlayerInvites); } receiverPlayerInvites.InboundInviteIds.Add(invite.Id); using (var transaction = memClient.CreateTransaction()) { transaction.CreateAll(entitiesToCreate); transaction.UpdateAll(entitiesToUpdate); } return(new CreateInviteResponse { InviteId = invite.Id }); } }
public override async Task <JoinPartyResponse> JoinParty(JoinPartyRequest request, ServerCallContext context) { var playerId = AuthHeaders.ExtractPlayerId(context); var pit = AuthHeaders.ExtractPit(context); if (string.IsNullOrEmpty(request.PartyId)) { throw new RpcException(new Status(StatusCode.InvalidArgument, "JoinParty requires a non-empty party id")); } using (var memClient = _memoryStoreClientManager.GetClient()) { var partyToJoin = await memClient.GetAsync <PartyDataModel>(request.PartyId) ?? throw new RpcException(new Status(StatusCode.NotFound, "The party doesn't exist")); var member = await memClient.GetAsync <Member>(playerId); if (member != null && member.PartyId != request.PartyId) { throw new RpcException(new Status(StatusCode.AlreadyExists, "The player is a member of another party")); } var playerInvites = await memClient.GetAsync <PlayerInvites>(playerId); if (playerInvites == null) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "The player is not invited to this party")); } var invites = (await Task.WhenAll(playerInvites.InboundInviteIds .Select(invite => memClient.GetAsync <Invite>(invite)))) .Where(invite => { if (invite == null) { Log.Logger.Warning("Failed to fetch an invite for {player}", playerId); } return(invite != null); }).ToList(); var invited = invites .Any(invite => invite.CurrentStatus == Invite.Status.Pending && invite.ReceiverId == playerId); if (!invited) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "The player is not invited to this party")); } if (partyToJoin.CurrentPhase != PartyPhaseDataModel.Forming) { throw new RpcException(new Status(StatusCode.FailedPrecondition, "The party is no longer in the Forming phase")); } // TODO(iuliaharasim/dom): Move logic specific to joining a party into a separate class. try { var added = partyToJoin.AddPlayerToParty(playerId, pit); // If false, the player already joined the party so we should terminate early. if (!added) { return(new JoinPartyResponse { Party = ConvertToProto(partyToJoin) }); } } catch (Exception exception) { throw new RpcException(new Status(StatusCode.FailedPrecondition, exception.Message)); } using (var transaction = memClient.CreateTransaction()) { transaction.CreateAll(new List <Entry> { partyToJoin.GetMember(playerId) }); transaction.UpdateAll(new List <Entry> { partyToJoin }); } _analytics.Send("player_joined_party", new Dictionary <string, object> { { "partyId", partyToJoin.Id }, { "invites", invites.Select(invite => new Dictionary <string, string> { { "inviteId", invite.Id }, { "playerIdInviter", invite.SenderId } }) } }, playerId); return(new JoinPartyResponse { Party = ConvertToProto(partyToJoin) }); } }
protected override Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { AuthHeaders.Add(request.Headers.Authorization); return(Task.FromResult(new HttpResponseMessage())); }
public YoutubeMusicClient(ILogger logger = null) { // init to default values w/o a cookie AuthHeaders = new AuthHeaders(); Logger = logger; }