Skip to content

Commit

Permalink
Add C# example.
Browse files Browse the repository at this point in the history
GitOrigin-RevId: ab6991abd7c7dccbdd3821c41c85eb3e96c0e8a8
  • Loading branch information
levlam committed Mar 11, 2018
1 parent c950749 commit 1d7a590
Show file tree
Hide file tree
Showing 9 changed files with 420 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
*.csproj text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
*.sln text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
*.xml text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
*.rb text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
*.lock text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent
*.go text whitespace=blank-at-eol,space-before-tab,blank-at-eof,tab-in-indent

sqlite/sqlite/* linguist-vendored

Expand Down
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
- [Installing dependencies](#installing-dependencies)
- [Using in CMake C++ projects](#using-cxx)
- [Using in Java projects](#using-java)
- [Using in .NET projects](#using-dotnet)
- [Using with other programming languages](#using-json)
- [License](#license)

Expand All @@ -19,7 +20,7 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
`TDLib` has many advantages. Notably `TDLib` is:

* **Cross-platform**: `TDLib` can be used on Android, iOS, Windows, macOS, Linux, Windows Phone, WebAssembly, watchOS, tvOS, Tizen, Cygwin. It should also work on other *nix systems with or without minimal effort.
* **Multilanguage**: `TDLib` can be easily used with any programming language that is able to execute C functions. Additionally it already has native Java (using JNI) bindings and .NET (using C++/CLI and C++/CX) bindings.
* **Multilanguage**: `TDLib` can be easily used with any programming language that is able to execute C functions. Additionally it already has native Java (using `JNI`) bindings and .NET (using `C++/CLI` and `C++/CX`) bindings.
* **Easy to use**: `TDLib` takes care of all network implementation details, encryption and local data storage.
* **High-performance**: in the [Telegram Bot API](https://core.telegram.org/bots/api), each `TDLib` instance handles more than 19000 active bots simultaneously.
* **Well-documented**: all `TDLib` API methods and public interfaces are fully documented.
Expand Down Expand Up @@ -117,10 +118,18 @@ See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example

<a name="using-java"></a>
## Using in Java projects
`TDLib` provides native Java interface through JNI.
`TDLib` provides native Java interface through JNI. To enable it, specify option `-DTD_ENABLE_JNI=ON` to CMake.

See [example/java](https://github.com/tdlib/td/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions.

<a name="using-dotnet"></a>
## Using in .NET projects
`TDLib` provides native .NET interface through `C++/CLI` and `C++/CX`. To enable it, specify option `-DTD_ENABLE_DOTNET=ON` to CMake.
.NET Core doesn't support `C++/CLI`, so if .NET Core is used, then `TDLib` JSON interface should be used through P/Invoke instead.

See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".

<a name="using-json"></a>
## Using from other programming languages
`TDLib` provides efficient native C++, Java, and .NET interfaces.
Expand Down
5 changes: 5 additions & 0 deletions example/csharp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.vs/
bin/
obj/
project.lock.json
TdExample.csproj.user
29 changes: 29 additions & 0 deletions example/csharp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# TDLib C# example

This is an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C#.

## Building TDLib

* Download and install Microsoft Visual Studio 2015 or later.
* Download and install [CMake](https://cmake.org/download/).
* Install [vcpkg](https://github.com/Microsoft/vcpkg#quick-start) or update it to the latest version using `vcpkg update` and following received instructions.
* Install `zlib` and `openssl` for using `vcpkg`:
```
C:\src\vcpkg> .\vcpkg.exe install openssl:x64-windows openssl:x86-windows zlib:x64-windows zlib:x86-windows
```
* Download and install [gperf](https://sourceforge.net/projects/gnuwin32/files/gperf/3.0.1/). Add the path to gperf.exe to the PATH environment variable.
* Build `TDLib` with CMake enabling .NET support and specifying correct path to `vcpkg` toolchain file:
```
cd <path to TDLib sources>/example/csharp
mkdir build
cd build
cmake -DTD_ENABLE_DOTNET=ON -DCMAKE_TOOLCHAIN_FILE=C:\src\vcpkg\scripts\buildsystems\vcpkg.cmake ../../..
cmake --build . --config Release
cmake --build . --config Debug
```

## Example of usage

After `TDLib` is built you can open and run TdExample project.
It contains a simple console C# application with implementation of authorization and message sending.
Just open it with Visual Studio 2015 or 2017 and run.
264 changes: 264 additions & 0 deletions example/csharp/TdExample.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
//
// Copyright Aliaksei Levin ([email protected]), Arseny Smirnov ([email protected]) 2014-2018
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

using Td = Telegram.Td;
using TdApi = Telegram.Td.Api;

using System;
using System.Threading;

/**
* Example class for TDLib usage from C#.
*/
namespace TdExample
{
class Example
{
private static Td.Client _client = null;
private readonly static Td.ClientResultHandler _defaultHandler = new DefaultHandler();

private static TdApi.AuthorizationState _authorizationState = null;
private static volatile bool _haveAuthorization = false;
private static volatile bool _quiting = false;

private static volatile AutoResetEvent _gotAuthorization = new AutoResetEvent(false);

private static readonly string _newLine = Environment.NewLine;
private static readonly string _commandsLine = "Enter command (gc <chatId> - GetChat, me - GetMe, sm <chatId> <message> - SendMessage, lo - LogOut, q - Quit): ";

private static Td.Client CreateTdClient()
{
Td.Client result = Td.Client.Create(new UpdatesHandler());
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
result.Run();
}).Start();
return result;
}

private static void Print(string str)
{
Console.WriteLine();
Console.WriteLine(str);
if (_haveAuthorization)
{
Console.Write(_commandsLine);
}
}

private static string ReadLine(string str)
{
Console.WriteLine();
Console.Write(str);
return Console.ReadLine();
}

private static void OnAuthorizationStateUpdated(TdApi.AuthorizationState authorizationState)
{
if (authorizationState != null)
{
_authorizationState = authorizationState;
}
if (_authorizationState is TdApi.AuthorizationStateWaitTdlibParameters)
{
TdApi.TdlibParameters parameters = new TdApi.TdlibParameters();
parameters.DatabaseDirectory = "tdlib";
parameters.UseMessageDatabase = true;
parameters.UseSecretChats = true;
parameters.ApiId = 94575;
parameters.ApiHash = "a3406de8d171bb422bb6ddf3bbd800e2";
parameters.SystemLanguageCode = "en";
parameters.DeviceModel = "Desktop";
parameters.SystemVersion = "Unknown";
parameters.ApplicationVersion = "1.0";
parameters.EnableStorageOptimizer = true;

_client.Send(new TdApi.SetTdlibParameters(parameters), new AuthorizationRequestHandler());
}
else if (_authorizationState is TdApi.AuthorizationStateWaitEncryptionKey)
{
_client.Send(new TdApi.CheckDatabaseEncryptionKey(), new AuthorizationRequestHandler());
}
else if (_authorizationState is TdApi.AuthorizationStateWaitPhoneNumber)
{
string phoneNumber = ReadLine("Please enter phone number: ");
_client.Send(new TdApi.SetAuthenticationPhoneNumber(phoneNumber, false, false), new AuthorizationRequestHandler());
}
else if (_authorizationState is TdApi.AuthorizationStateWaitCode)
{
string code = ReadLine("Please enter authentication code: ");
_client.Send(new TdApi.CheckAuthenticationCode(code, "", ""), new AuthorizationRequestHandler());
}
else if (_authorizationState is TdApi.AuthorizationStateWaitPassword)
{
string password = ReadLine("Please enter password: ");
_client.Send(new TdApi.CheckAuthenticationPassword(password), new AuthorizationRequestHandler());
}
else if (_authorizationState is TdApi.AuthorizationStateReady)
{
_haveAuthorization = true;
_gotAuthorization.Set();
}
else if (_authorizationState is TdApi.AuthorizationStateLoggingOut)
{
_haveAuthorization = false;
Print("Logging out");
}
else if (_authorizationState is TdApi.AuthorizationStateClosing)
{
_haveAuthorization = false;
Print("Closing");
}
else if (_authorizationState is TdApi.AuthorizationStateClosed)
{
Print("Closed");
if (!_quiting)
{
_client = CreateTdClient(); // recreate _client after previous has closed
}
}
else
{
Print("Unsupported authorization state:" + _newLine + _authorizationState);
}
}

private static long GetChatId(string arg)
{
long chatId = 0;
try
{
chatId = Convert.ToInt64(arg);
}
catch (FormatException)
{
}
catch (OverflowException)
{
}
return chatId;
}

private static void GetCommand()
{
string command = ReadLine(_commandsLine);
string[] commands = command.Split(new char[] { ' ' }, 2);
try
{
switch (commands[0])
{
case "gc":
_client.Send(new TdApi.GetChat(GetChatId(commands[1])), _defaultHandler);
break;
case "me":
_client.Send(new TdApi.GetMe(), _defaultHandler);
break;
case "sm":
string[] args = commands[1].Split(new char[] { ' ' }, 2);
sendMessage(GetChatId(args[0]), args[1]);
break;
case "lo":
_haveAuthorization = false;
_client.Send(new TdApi.LogOut(), _defaultHandler);
break;
case "q":
_quiting = true;
_haveAuthorization = false;
_client.Send(new TdApi.Close(), _defaultHandler);
break;
default:
Print("Unsupported command: " + command);
break;
}
}
catch (IndexOutOfRangeException)
{
Print("Not enough arguments");
}
}

private static void sendMessage(long chatId, string message)
{
// initialize reply markup just for testing
TdApi.InlineKeyboardButton[] row = { new TdApi.InlineKeyboardButton("https://telegram.org?1", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?2", new TdApi.InlineKeyboardButtonTypeUrl()), new TdApi.InlineKeyboardButton("https://telegram.org?3", new TdApi.InlineKeyboardButtonTypeUrl()) };
TdApi.ReplyMarkup replyMarkup = new TdApi.ReplyMarkupInlineKeyboard(new TdApi.InlineKeyboardButton[][] { row, row, row });

TdApi.InputMessageContent content = new TdApi.InputMessageText(new TdApi.FormattedText(message, null), false, true);
_client.Send(new TdApi.SendMessage(chatId, 0, false, false, replyMarkup, content), _defaultHandler);
}

static void Main()
{
// disable TDLib log
Td.Log.SetVerbosityLevel(0);
if (!Td.Log.SetFilePath("tdlib.log"))
{
throw new System.IO.IOException("Write access to the current directory is required");
}

// create Td.Client
_client = CreateTdClient();

// test Client.Execute
_defaultHandler.OnResult(_client.Execute(new TdApi.GetTextEntities("@telegram /test_command https://telegram.org telegram.me @gif @test")));

// main loop
while (!_quiting)
{
// await authorization
_gotAuthorization.Reset();
_gotAuthorization.WaitOne();

_client.Send(new TdApi.GetChats(Int64.MaxValue, 0, 100), _defaultHandler); // preload chat list
while (_haveAuthorization)
{
GetCommand();
}
}
}

private class DefaultHandler : Td.ClientResultHandler
{
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
{
Print(@object.ToString());
}
}

private class UpdatesHandler : Td.ClientResultHandler
{
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
{
if (@object is TdApi.UpdateAuthorizationState)
{
OnAuthorizationStateUpdated((@object as TdApi.UpdateAuthorizationState).AuthorizationState);
}
else
{
// Print("Unsupported update: " + @object);
}
}
}

private class AuthorizationRequestHandler : Td.ClientResultHandler
{
void Td.ClientResultHandler.OnResult(TdApi.BaseObject @object)
{
if (@object is TdApi.Error)
{
Print("Receive an error:" + _newLine + @object);
OnAuthorizationStateUpdated(null); // repeat last action
}
else
{
// ok result is already received through UpdateAuthorizationState, nothing to do
}
}
}
}
}
Loading

0 comments on commit 1d7a590

Please sign in to comment.