wiz0u / WTelegramClient

Telegram Client API (MTProto) library written 100% in C# and .NET
https://wiz0u.github.io/WTelegramClient/
MIT License
990 stars 163 forks source link

Issue using Stream for saving session #251

Closed lofti198 closed 6 months ago

lofti198 commented 6 months ago

I use library on server (asp net 8 webapi) thats why I cannot save session to file. I ve googled for the solution and ended up with code below. But it seems that when I am doing the second run (after the first which triggered sending verification code SMS) and trying to pass the code as request.VerificationCode; it doesn't recognize it.

When I used files, everything worked as needed:

 using var client = new WTelegram.Client(Config);//, sessionStore);

So my current code below. What should I do to correctly save session in stream?


public class WTelegramBot
{
    private readonly IStreamStorage _streamStorage;

    public WTelegramBot(IStreamStorage streamStorage)
    {
        _streamStorage = streamStorage;
    }
    public async Task<List<TelegramPost>> ReadRecentPosts(TelegramReadChannelRequest request)
    {
        // Configure WTelegram client
        string Config(string what)
        {
            switch (what)
            {
                case "api_id": return request.ApiId;
                case "api_hash": return request.ApiHash;
                case "phone_number": return request.PhoneNumber;
                case "verification_code": return request.VerificationCode;
                case "password": return request.Password;
                default: return null;
            }
        }
        Stream sessionStore = await _streamStorage.GetStreamAsync(request.PhoneNumber);
        sessionStore.Seek(0, SeekOrigin.Begin); // Ensure the stream is at the start

        using var client = new WTelegram.Client(Config, sessionStore);

        if (request.VerificationCode == default)
        {
            client.LoginUserIfNeeded();
            Thread.Sleep(5000); //Waiting for code, time can be changed
            throw new VerificationCodeNeededException();
        }
        await client.LoginUserIfNeeded();

        await _streamStorage.SaveStreamAsync(request.PhoneNumber, sessionStore);
        // Resolve channel username
        var resolvedPeer = await client.Contacts_ResolveUsername(NormalizeChannelUsername(request.ChannelUsername));
        var channel = resolvedPeer.chats[resolvedPeer.peer.ID] as Channel;

        // Get recent posts
        var messages = await client.Messages_GetHistory(channel, limit: request.NumberOfPosts + 1);

        // Extract post data
        var posts = new List<TelegramPost>();
        foreach (TL.Message message in messages.Messages.OfType<TL.Message>())
        {
            var post = new TelegramPost
            {
                Text = message.message,
                Images = new List<byte[]>()
            };

            if (message.media is MessageMediaPhoto photo)
            {
                using var memoryStream = new MemoryStream();
                await client.DownloadFileAsync((Photo)photo.photo, memoryStream);
                post.Images.Add(memoryStream.ToArray());
            }

            posts.Add(post);
        }

        return posts;
    }

}```
wiz0u commented 6 months ago

I'm not familiar with IStreamStorage so I can't tell if it fits the job.

The recommended method if you don't have access to files is to save session to DB, like in this example: https://github.com/wiz0u/WTelegramClient/blob/master/Examples/Program_Heroku.cs?ts=4#L61

lofti198 commented 6 months ago

I saw this example, I just didn't really get - how exactly in this case the config parameters (like api_id) are sent. I mean, how to implement initial authentication.

As for StreamStorage, it is just simple stream storage, based on concurrent dictionary (so that each user (phone) had their own stream with session) https://github.com/lofti198/TelegramReadChannel/blob/master/TelegramReadChannel/InMemoryStreamStorage.cs

wiz0u commented 6 months ago

I'm not going to review your whole code because it's not my job. but obviously your SaveStreamAsync is badly implemented, either rewind the stream before save, or cast original stream back to MemoryStream then ToArray()

lofti198 commented 6 months ago

Oh, I am sorry for misleading you. I just wanted to understand: if we use stream instead of file - how to pass config parameters inside client constructor? Is this the correct way to call the constructor? using var client = new WTelegram.Client(Config, sessionStore);

Thank you in advance! And once more thank you for your amazing library!

wiz0u commented 6 months ago

Yes. See also the README