public async Task <Message> CreateDirectChannelUpdate(long channelId, long aliceId, long alicePublicId, long bobId, long bobPublicId)
        {
            long alicePrivateId = await database.MessageDependencies.AsQueryable()
                                  .Where(d => d.OwningMessageId == alicePublicId)
                                  .Select(d => d.MessageId).SingleAsync().ConfigureAwait(false);

            long bobPrivateId = await database.MessageDependencies.AsQueryable()
                                .Where(d => d.OwningMessageId == bobPublicId)
                                .Select(d => d.MessageId).SingleAsync().ConfigureAwait(false);

            var update = packets.New <P1BDirectChannelUpdate>();

            update.MessageFlags = MessageFlags.Unencrypted;
            update.Dependencies.Add(new Dependency(aliceId, alicePrivateId));
            update.Dependencies.Add(new Dependency(aliceId, bobPublicId));
            update.Dependencies.Add(new Dependency(bobId, bobPrivateId));
            update.Dependencies.Add(new Dependency(bobId, alicePublicId));
            return(await CreateMessage(update, channelId, null).ConfigureAwait(false));
        }
        public async Task StartSetChannelAction(IClient client, long channelId, ChannelAction action)
        {
            if (client.FocusedChannelId != default && client.FocusedChannelId != channelId)
            {
                var packet = packets.New <P2CChannelAction>();
                packet.ChannelId = client.FocusedChannelId;
                packet.AccountId = client.AccountId;
                packet.Action    = ChannelAction.None;
                await delivery.StartSendToChannel(packet, client.FocusedChannelId, client).ConfigureAwait(false);
            }

            if (channelId != default && (channelId != client.FocusedChannelId || action != client.ChannelAction))
            {
                var packet = packets.New <P2CChannelAction>();
                packet.ChannelId = channelId;
                packet.AccountId = client.AccountId;
                packet.Action    = action;
                await delivery.StartSendToChannel(packet, channelId, client).ConfigureAwait(false);
            }

            client.FocusedChannelId = channelId;
            client.ChannelAction    = action;
        }
        private async Task StartSyncChannels(IClient client, IReadOnlyList <long> currentState, DatabaseContext database)
        {
            Channel[] channels = await database.ChannelMembers.AsQueryable()
                                 .Where(m => m.AccountId == client.AccountId)
                                 .Join(database.Channels, m => m.ChannelId, c => c.ChannelId, (m, c) => c)
                                 .ToArrayAsync().ConfigureAwait(false);

            foreach (var channel in channels)
            {
                if (!currentState.Contains(channel.ChannelId))
                {
                    // Notify client about new channels
                    var packet = packets.New <P0ACreateChannel>();
                    packet.ChannelId    = channel.ChannelId;
                    packet.ChannelType  = channel.ChannelType;
                    packet.OwnerId      = channel.OwnerId ?? 0;
                    packet.CreationTime = channel.CreationTime;
                    if (packet.ChannelType == ChannelType.Direct)
                    {
                        packet.CounterpartId = channel.OwnerId == client.AccountId ? channel.CounterpartId.Value : channel.OwnerId.Value;
                    }
                    _ = client.Send(packet);
                }
            }

            foreach (long channelId in currentState)
            {
                if (!channels.Any(c => c.ChannelId == channelId))
                {
                    // Notify client about deleted channels
                    var packet = packets.New <P0DDeleteChannel>();
                    packet.ChannelId = channelId;
                    _ = client.Send(packet);
                }
            }
        }