Попробовал отправлять сообщения в телеграм при помощи TLSharp (хабр, гитхаб).
Ну, вариант рабочий. Однако есть следующая проблема: после коннекта к серверу нужно пройти аутентификацию, используя hash и code - и этот code приходит на телефон.
Этот code достаточно быстро протухает (в api точно не указано (раз, два), но где-то меньше часа кажется прошло) и если я даже сохраню этот код, то со временем всё равно получу исключение:
InvalidOperationException: PHONE_CODE_EXPIRED
А это значит, нужно снова лезть (руками!) в телефон и в отладчике менять на лету значение переменной. Да-да, автор так и советует:
var hash = await client.SendCodeRequestAsync("<user_number>");
var code = "<code_from_telegram>"; // you can change code in debugger
var user = await client.MakeAuthAsync("<user_number>", hash, code);
Только вот это совсем не production ready. :(
Кто может порекомендовать хороший способ автоматизировать этот процесс?
На ум приходит только вариант получения какого-то долгоиграющего (судя по api самого телеграмма - этот code можно получить либо в СМС на телефон, либо в приложение телеграмма) кода (на месяц хотя бы), но я не нашёл в api варианта получить такой токен (да и сомневаюсь, что по соображениям безопасности они будут выдаваться).
Моё предположение в комментариях оказалось верным. Проходить авторизацию нужно только при первом подключении. В дальнейшем TLSharp сохраняет все нужные данные в файл session.dat и использует его при последующих подключениях. Повторная авторизация может потребоваться в двух случаях:
Ниже приведу работающий пример кода:
using System;
using System.Threading.Tasks;
using TeleSharp.TL;
using TLSharp.Core;
namespace ConsoleApp1
{
internal static class Program
{
private static async Task Main()
{
// Следующие два значения нужно получить на https://my.telegram.org/apps
var apiId = 123456;
var apiHash = "foo";
// Номер телефона пользователя
var phoneNum = "+75551234567";
var client = new TelegramClient(apiId, apiHash);
await client.ConnectAsync();
var isAuth = client.IsUserAuthorized();
Console.WriteLine($"Файл авторизации существует: {isAuth}");
if (!isAuth) // Если не найден файл session.dat, то пытаемся авторизоваться
{
TLUser user;
try
{
var hash = await client.SendCodeRequestAsync(phoneNum);
Console.WriteLine("Введите код из SMS:");
var code = Console.ReadLine();
try
{
user = await client.MakeAuthAsync(phoneNum, hash, code);
}
catch (CloudPasswordNeededException)
{
// На данном аккаунте включена двухфакторная авторизация
var passwordSettings = await client.GetPasswordSetting();
Console.WriteLine("Введите пароль:");
var passwordStr = Console.ReadLine();
user = await client.MakeAuthWithPasswordAsync(passwordSettings, passwordStr);
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
return;
}
Console.WriteLine($"Пользователь '{user?.FirstName}' авторизован");
isAuth = client.IsUserAuthorized();
Console.WriteLine($"Файл авторизации существует: {isAuth}");
}
try
{
// В качестве демонстрации работы узнаем количество контактов у пользователя
var contacts = await client.GetContactsAsync();
Console.WriteLine($"У вас {contacts.Users.Count} контактов");
}
catch (InvalidOperationException ex) when (ex.Message == "AUTH_KEY_UNREGISTERED")
{
// Файл session.dat существует, но для сервера эта сессия уже мертва
Console.WriteLine("Пользователь воспользовался другим устройством чтобы закрыть текущую сессию.");
Console.WriteLine("Удалите файл session.dat и повторите попытку.");
}
}
}
}
Виртуальный выделенный сервер (VDS) становится отличным выбором
Подскажите пожалуйста, есть ли возмлжность передать данные на клиент, который находится под NAT
Сидел пробовал написать Generic метод для получения значения типа из указателя, и вот случайно написал where T : unmanaged и этот код был успешно откомпилирован!
Есть проект XamarinForms, внутри есть три приложения (iOS, Android, UWP), один общий проект с общим кодом Portable Class Library