-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathclient.dart
155 lines (134 loc) · 5.23 KB
/
client.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:rxdart/rxdart.dart';
import "src/td_json_client.dart" show JsonClient;
import "src/api/base_classes.dart";
import "src/api/objects.dart";
import "src/api/utils.dart" show tryConvertToTdObject;
/// A controller that handles incoming requests asynchronously and exposes
/// [Observable]s that stream data to their listeners.
class TelegramClient with AsyncClient {
@override
final JsonClient _client;
final BehaviorSubject<Update> _updates = BehaviorSubject();
/// All [Update] objects received by the client are put into a
/// [BehaviorSubject] whose [Stream] is exposed to other parts of the
/// application. This way updates can be listened to, filtered, mapped, and
/// Flutter widgets can rebuild in response to them with a StreamBuilder.
Stream<Update> get updates => _updates.stream;
/// A convenience getter that streams [AuthorizationState]s. It does this by
/// filtering for [updates] that are [UpdateAuthorizationState]s and yields
/// the new authorization state.
Stream<AuthorizationState> get authorizationState =>
updates
.where((u) => u is UpdateAuthorizationState)
.map((a) => (a as UpdateAuthorizationState).authorizationState);
TdlibParameters tdlibParams;
TelegramClient([String dlDir]): _client = JsonClient.create(dlDir);
/// Generates a [Stream] of incoming [TdObject]s that the client receives.
/// Objects of the appropriate type are added to their respective
/// [BehaviorSubject]s (for example, [Update]s are added to [_updates]).
Stream<TdObject> incoming() async* {
while (true) {
var obj = await receive();
if (obj is Update) {
_updates.add(obj);
}
yield obj;
}
}
/// Asynchronously performs any necessary cleanup before [destroy]ing this
/// client.
Future<void> close() async {
await _updates.close();
await destroy();
}
@Deprecated('Use [defineTdlibParams] instead')
void setTdLibParams({
@required int apiId,
@required String apiHash,
bool useMessageDatabase = true,
String databaseDirectory = 'tdb',
String systemLanguageCode = 'en-US',
@required String deviceModel,
@required String systemVersion,
String applicationVersion = '0.0.1',
bool enableStorageOptimizer = true,
bool useSecretChats = true,
}) {
tdlibParams = TdlibParameters(
apiId: apiId,
apiHash: apiHash,
useMessageDatabase: useMessageDatabase,
databaseDirectory: databaseDirectory,
systemLanguageCode: systemLanguageCode,
deviceModel: deviceModel,
systemVersion: systemVersion,
applicationVersion: applicationVersion,
enableStorageOptimizer: enableStorageOptimizer,
useSecretChats: useSecretChats,
);
}
/// Defines this client's [tdlibParams] by taking keyword-arguments (some of
/// which have defaults) that represent the fields of [TdlibParameters].
void defineTdlibParams({
@required int apiId,
@required String apiHash,
bool useMessageDatabase = true,
String databaseDirectory = 'tdb',
String systemLanguageCode = 'en-US', // TODO: l10n
@required String deviceModel,
@required String systemVersion,
String applicationVersion = '0.0.1',
bool enableStorageOptimizer = true,
bool useSecretChats = true,
bool useChatInfoDatabase,
bool useFileDatabase,
String filesDirectory,
bool ignoreFileNames,
bool useTestDc,
}) {
tdlibParams = TdlibParameters(
apiId: apiId,
apiHash: apiHash,
useMessageDatabase: useMessageDatabase,
databaseDirectory: databaseDirectory,
systemLanguageCode: systemLanguageCode,
deviceModel: deviceModel,
systemVersion: systemVersion,
applicationVersion: applicationVersion,
enableStorageOptimizer: enableStorageOptimizer,
useSecretChats: useSecretChats,
useChatInfoDatabase: useChatInfoDatabase,
useFileDatabase: useFileDatabase,
useTestDc: useTestDc,
filesDirectory: filesDirectory,
ignoreFileNames: ignoreFileNames,
);
}
}
/// Wraps the [JsonClient] and executes its methods asynchronously. A few names
/// are different for convenience of use.
///
/// This mixin isn't strictly necessary--it could just go right in the
/// [TelegramClient]--but I wanted to separate the logic for fetching and
/// sending data from/to the Telegram API and the procedures that delegate that
/// data, just for code organization purposes.
class AsyncClient {
final JsonClient _client;
factory AsyncClient._() => null;
/// Receives a request from TD and parses it as a [TdObject]
Future<TdObject> receive([double timeout = 2.0]) async =>
tryConvertToTdObject(_client.receive(timeout)) as TdObject;
/// Sends an asynchronous request to TD
Future<void> send(TdFunction request) async =>
_client.send(request.serialize());
/// Executes a synchronous request
Map<String, dynamic> executeSync(TdFunction request) =>
_client.execute(request.serialize());
/// Executes a synchronous request asynchronously o_O
Future<Map<String, dynamic>> execute(TdFunction request) async =>
_client.execute(request.serialize());
/// Closes the client, destroying the encapsulated [JsonClient]
Future<void> destroy() async => _client.destroy();
}