Line data Source code
1 : import 'dart:collection';
2 : import 'dart:convert';
3 :
4 : import 'package:cwtch/config.dart';
5 : import 'package:flutter/services.dart';
6 : import 'package:path_provider/path_provider.dart';
7 : import 'dart:async';
8 : import 'package:path/path.dart' as path;
9 :
10 : import 'cwtch.dart';
11 : import 'cwtchNotifier.dart';
12 :
13 : /*
14 : TODO: make a reusable plugin for other flutter apps
15 :
16 : import 'package:federated_plugin_platform_interface/federated_plugin_platform_interface.dart';
17 :
18 : /// It uses [FederatedPluginInterface]
19 : Future startCwtch() async {
20 : return await FederatedPluginInterface.instance.startCwtch();
21 : }
22 : */
23 :
24 : class CwtchGomobile implements Cwtch {
25 : static const appInfoPlatform = const MethodChannel('test.flutter.dev/applicationInfo');
26 : static const cwtchPlatform = const MethodChannel('cwtch');
27 :
28 : final appbusEventChannelName = 'test.flutter.dev/eventBus';
29 :
30 : late Future<dynamic> androidLibraryDir;
31 : late Future<dynamic> androidHomeDirectory;
32 : String androidHomeDirectoryStr = "";
33 : String _cwtchDir = "";
34 : late CwtchNotifier cwtchNotifier;
35 : bool _isL10nInit = false;
36 :
37 0 : @override
38 : Future<HashMap<String, String>> PlatformChannelInfo() async {
39 0 : HashMap<String, String> info = HashMap<String, String>();
40 :
41 0 : info.addAll({"appInfoPlatform.name": appInfoPlatform.name});
42 0 : info.addAll({"appInfoPlatform.codec": appInfoPlatform.codec.toString()});
43 0 : EnvironmentConfig.debugLog("getting foreground service info...");
44 0 : appInfoPlatform.invokeMapMethod('getForegroundServiceInfo').then((foregroundServiceInfoMap) {
45 0 : EnvironmentConfig.debugLog("parsing foreground service info...");
46 0 : foregroundServiceInfoMap?.entries.forEach((element) {
47 0 : info.addAll({element.key.toString(): element.value.toString()});
48 : });
49 : });
50 0 : EnvironmentConfig.debugLog("returning foreground service info...");
51 : return info;
52 : }
53 :
54 0 : CwtchGomobile(CwtchNotifier _cwtchNotifier) {
55 0 : print("gomobile.dart: CwtchGomobile()");
56 0 : cwtchNotifier = _cwtchNotifier;
57 0 : cwtchNotifier.setMessageSeenCallback((String profile, int conversation, DateTime time) => {this.SetConversationAttribute(profile, conversation, LastMessageSeenTimeKey, time.toIso8601String())});
58 0 : androidHomeDirectory = getApplicationDocumentsDirectory();
59 0 : androidLibraryDir = appInfoPlatform.invokeMethod('getNativeLibDir');
60 :
61 : // Method channel to receive libcwtch-go events via Kotlin and dispatch them to _handleAppbusEvent (sends to cwtchNotifier)
62 0 : final appbusEventChannel = MethodChannel(appbusEventChannelName);
63 0 : appbusEventChannel.setMethodCallHandler(this._handleAppbusEvent);
64 : }
65 :
66 0 : String getAssetsDir() {
67 : // TODO
68 : return "";
69 : }
70 :
71 : // Requires Start() to have been run to initialize
72 0 : Future<String> getCwtchDir() async {
73 0 : return _cwtchDir;
74 : }
75 :
76 : // ignore: non_constant_identifier_names
77 0 : Future<void> Start() async {
78 0 : print("gomobile.dart: Start()...");
79 0 : androidHomeDirectoryStr = (await androidHomeDirectory).path;
80 0 : _cwtchDir = path.join(androidHomeDirectoryStr, ".cwtch");
81 0 : if (EnvironmentConfig.BUILD_VER == dev_version) {
82 0 : _cwtchDir = path.join(_cwtchDir, "dev");
83 : }
84 0 : String torPath = path.join(await androidLibraryDir, "libtor.so");
85 0 : print("gomobile.dart: Start invokeMethod Start($_cwtchDir, $torPath)...");
86 0 : cwtchPlatform.invokeMethod("Start", {"appDir": _cwtchDir, "torPath": torPath});
87 : }
88 :
89 : // Handle libcwtch-go events (received via kotlin) and dispatch to the cwtchNotifier
90 0 : Future<void> _handleAppbusEvent(MethodCall call) async {
91 0 : final String json = call.arguments;
92 0 : var obj = jsonDecode(json);
93 0 : cwtchNotifier.handleMessage(call.method, obj);
94 : }
95 :
96 : // ignore: non_constant_identifier_names
97 0 : Future<dynamic> CreateProfile(String nick, String pass, bool autostart) {
98 0 : return cwtchPlatform.invokeMethod("CreateProfile", {"nick": nick, "pass": pass, "autostart": autostart});
99 : }
100 :
101 : // ignore: non_constant_identifier_names
102 0 : void ActivatePeerEngine(String profile) {
103 0 : cwtchPlatform.invokeMethod("ActivatePeerEngine", {"profile": profile});
104 : }
105 :
106 : // ignore: non_constant_identifier_names
107 0 : void DeactivatePeerEngine(String profile) {
108 0 : cwtchPlatform.invokeMethod("DeactivatePeerEngine", {"profile": profile});
109 : }
110 :
111 : // ignore: non_constant_identifier_names
112 0 : void LoadProfiles(String pass) {
113 0 : cwtchPlatform.invokeMethod("LoadProfiles", {"pass": pass});
114 : }
115 :
116 : // ignore: non_constant_identifier_names
117 0 : void DeleteProfile(String onion, String pass) {
118 0 : cwtchPlatform.invokeMethod("DeleteProfile", {"ProfileOnion": onion, "pass": pass});
119 : }
120 :
121 : // ignore: non_constant_identifier_names
122 0 : Future<dynamic> GetMessage(String profile, int conversation, int index) {
123 0 : return cwtchPlatform.invokeMethod("GetMessage", {"ProfileOnion": profile, "conversation": conversation, "index": index});
124 : }
125 :
126 : // ignore: non_constant_identifier_names
127 0 : Future<dynamic> GetMessageByID(String profile, int conversation, int id) {
128 0 : return cwtchPlatform.invokeMethod("GetMessageByID", {"ProfileOnion": profile, "conversation": conversation, "id": id});
129 : }
130 :
131 : // ignore: non_constant_identifier_names
132 0 : Future<dynamic> GetMessages(String profile, int conversation, int index, int count) {
133 0 : return cwtchPlatform.invokeMethod("GetMessages", {"ProfileOnion": profile, "conversation": conversation, "index": index, "count": count});
134 : }
135 :
136 0 : @override
137 : // ignore: non_constant_identifier_names
138 : void SendProfileEvent(String onion, String jsonEvent) {
139 0 : cwtchPlatform.invokeMethod("SendProfileEvent", {"onion": onion, "jsonEvent": jsonEvent});
140 : }
141 :
142 0 : @override
143 : // ignore: non_constant_identifier_names
144 : void SendAppEvent(String jsonEvent) {
145 0 : cwtchPlatform.invokeMethod("SendAppEvent", {"jsonEvent": jsonEvent});
146 : }
147 :
148 0 : @override
149 0 : void dispose() => {};
150 :
151 0 : @override
152 : // ignore: non_constant_identifier_names
153 : void AcceptContact(String profileOnion, int conversation) {
154 0 : cwtchPlatform.invokeMethod("AcceptConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
155 : }
156 :
157 0 : @override
158 : // ignore: non_constant_identifier_names
159 : void BlockContact(String profileOnion, int conversation) {
160 0 : cwtchPlatform.invokeMethod("BlockContact", {"ProfileOnion": profileOnion, "conversation": conversation});
161 : }
162 :
163 0 : @override
164 : // ignore: non_constant_identifier_names
165 : void UnblockContact(String profileOnion, int conversation) {
166 0 : cwtchPlatform.invokeMethod("UnblockContact", {"ProfileOnion": profileOnion, "conversation": conversation});
167 : }
168 :
169 0 : @override
170 : // ignore: non_constant_identifier_names
171 : Future<dynamic> SendMessage(String profileOnion, int conversation, String message) {
172 0 : return cwtchPlatform.invokeMethod("SendMessage", {"ProfileOnion": profileOnion, "conversation": conversation, "message": message});
173 : }
174 :
175 0 : @override
176 : // ignore: non_constant_identifier_names
177 : Future<dynamic> SendInvitation(String profileOnion, int conversation, int target) {
178 0 : return cwtchPlatform.invokeMethod("SendInvitation", {"ProfileOnion": profileOnion, "conversation": conversation, "target": target});
179 : }
180 :
181 0 : @override
182 : // ignore: non_constant_identifier_names
183 : Future<dynamic> ShareFile(String profileOnion, int conversation, String filepath) {
184 0 : return cwtchPlatform.invokeMethod("ShareFile", {"ProfileOnion": profileOnion, "conversation": conversation, "filepath": filepath});
185 : }
186 :
187 0 : @override
188 : // ignore: non_constant_identifier_names
189 : void DownloadFile(String profileOnion, int conversation, String filepath, String manifestpath, String filekey) {
190 0 : cwtchPlatform.invokeMethod("DownloadFile", {"ProfileOnion": profileOnion, "conversation": conversation, "filepath": filepath, "manifestpath": manifestpath, "filekey": filekey});
191 : }
192 :
193 : // ignore: non_constant_identifier_names
194 0 : void CreateDownloadableFile(String profileOnion, int conversation, String filenameSuggestion, String filekey, String manifestpath) {
195 0 : cwtchPlatform.invokeMethod("CreateDownloadableFile", {
196 : "ProfileOnion": profileOnion,
197 : "conversation": conversation,
198 : "manifestpath": manifestpath,
199 : "filename": filenameSuggestion,
200 : "filekey": filekey,
201 : });
202 : }
203 :
204 : // ignore: non_constant_identifier_names
205 0 : void ExportPreviewedFile(String sourceFile, String suggestion) {
206 0 : cwtchPlatform.invokeMethod("ExportPreviewedFile", {"Path": sourceFile, "FileName": suggestion});
207 : }
208 :
209 0 : @override
210 : // ignore: non_constant_identifier_names
211 : void CheckDownloadStatus(String profileOnion, String fileKey) {
212 0 : cwtchPlatform.invokeMethod("CheckDownloadStatus", {"ProfileOnion": profileOnion, "fileKey": fileKey});
213 : }
214 :
215 0 : @override
216 : // ignore: non_constant_identifier_names
217 : void VerifyOrResumeDownload(String profileOnion, int conversation, String filekey) {
218 0 : cwtchPlatform.invokeMethod("VerifyOrResumeDownload", {"ProfileOnion": profileOnion, "conversation": conversation, "filekey": filekey});
219 : }
220 :
221 0 : @override
222 : // ignore: non_constant_identifier_names
223 : void ResetTor() {
224 0 : cwtchPlatform.invokeMethod("ResetTor", {});
225 : }
226 :
227 0 : @override
228 : // ignore: non_constant_identifier_names
229 : Future<dynamic> ImportBundle(String profileOnion, String bundle) {
230 0 : return cwtchPlatform.invokeMethod("ImportBundle", {"ProfileOnion": profileOnion, "bundle": bundle});
231 : }
232 :
233 0 : @override
234 : void CreateGroup(String profileOnion, String server, String groupName) {
235 0 : cwtchPlatform.invokeMethod("CreateGroup", {"ProfileOnion": profileOnion, "server": server, "groupName": groupName});
236 : }
237 :
238 0 : @override
239 : // ignore: non_constant_identifier_names
240 : void DeleteContact(String profileOnion, int conversation) {
241 0 : cwtchPlatform.invokeMethod("DeleteConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
242 : }
243 :
244 0 : @override
245 : // ignore: non_constant_identifier_names
246 : void ArchiveConversation(String profileOnion, int conversation) {
247 0 : cwtchPlatform.invokeMethod("ArchiveConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
248 : }
249 :
250 0 : @override
251 : // ignore: non_constant_identifier_names
252 : void SetProfileAttribute(String profile, String key, String val) {
253 0 : cwtchPlatform.invokeMethod("SetProfileAttribute", {"ProfileOnion": profile, "Key": key, "Val": val});
254 : }
255 :
256 0 : @override
257 : // ignore: non_constant_identifier_names
258 : void SetConversationAttribute(String profile, int conversation, String key, String val) {
259 0 : cwtchPlatform.invokeMethod("SetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "Key": key, "Val": val});
260 : }
261 :
262 0 : @override
263 : // ignore: non_constant_identifier_names
264 : void LoadServers(String password) {
265 0 : cwtchPlatform.invokeMethod("LoadServers", {"Password": password});
266 : }
267 :
268 0 : @override
269 : // ignore: non_constant_identifier_names
270 : void CreateServer(String password, String description, bool autostart) {
271 0 : cwtchPlatform.invokeMethod("CreateServer", {"Password": password, "Description": description, "Autostart": autostart});
272 : }
273 :
274 0 : @override
275 : // ignore: non_constant_identifier_names
276 : void DeleteServer(String serverOnion, String password) {
277 0 : cwtchPlatform.invokeMethod("DeleteServer", {"ServerOnion": serverOnion, "Password": password});
278 : }
279 :
280 0 : @override
281 : // ignore: non_constant_identifier_names
282 : void LaunchServers() {
283 0 : cwtchPlatform.invokeMethod("LaunchServers", {});
284 : }
285 :
286 0 : @override
287 : // ignore: non_constant_identifier_names
288 : void LaunchServer(String serverOnion) {
289 0 : cwtchPlatform.invokeMethod("LaunchServer", {"ServerOnion": serverOnion});
290 : }
291 :
292 0 : @override
293 : // ignore: non_constant_identifier_names
294 : void StopServer(String serverOnion) {
295 0 : cwtchPlatform.invokeMethod("StopServer", {"ServerOnion": serverOnion});
296 : }
297 :
298 0 : @override
299 : // ignore: non_constant_identifier_names
300 : void StopServers() {
301 0 : cwtchPlatform.invokeMethod("StopServers", {});
302 : }
303 :
304 0 : @override
305 : // ignore: non_constant_identifier_names
306 : void DestroyServers() {
307 0 : cwtchPlatform.invokeMethod("DestroyServers", {});
308 : }
309 :
310 0 : @override
311 : // ignore: non_constant_identifier_names
312 : void SetServerAttribute(String serverOnion, String key, String val) {
313 0 : cwtchPlatform.invokeMethod("SetServerAttribute", {"ServerOnion": serverOnion, "Key": key, "Val": val});
314 : }
315 :
316 0 : @override
317 : Future<void> Shutdown() async {
318 0 : print("gomobile.dart Shutdown");
319 0 : cwtchPlatform.invokeMethod("Shutdown", {});
320 : }
321 :
322 0 : @override
323 : Future GetMessageByContentHash(String profile, int conversation, String contentHash) {
324 0 : return cwtchPlatform.invokeMethod("GetMessageByContentHash", {"ProfileOnion": profile, "conversation": conversation, "contentHash": contentHash});
325 : }
326 :
327 0 : @override
328 : void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val) {
329 0 : cwtchPlatform.invokeMethod("SetMessageAttribute", {"ProfileOnion": profile, "conversation": conversation, "Channel": channel, "Message": message, "Key": key, "Val": val});
330 : }
331 :
332 0 : @override
333 : String? defaultDownloadPath() {
334 0 : return this.androidHomeDirectoryStr;
335 : }
336 :
337 0 : @override
338 : void ChangePassword(String profile, String pass, String newpass, String newpassAgain) {
339 0 : cwtchPlatform.invokeMethod("ChangePassword", {"ProfileOnion": profile, "OldPass": pass, "NewPass": newpass, "NewPassAgain": newpassAgain});
340 : }
341 :
342 0 : @override
343 : bool isL10nInit() {
344 0 : return _isL10nInit;
345 : }
346 :
347 0 : @override
348 : void l10nInit(String notificationSimple, String notificationConversationInfo) {
349 0 : cwtchNotifier.l10nInit(notificationSimple, notificationConversationInfo);
350 0 : cwtchPlatform.invokeMethod("L10nInit", {"notificationSimple": notificationSimple, "notificationConversationInfo": notificationConversationInfo});
351 0 : _isL10nInit = true;
352 : }
353 :
354 0 : @override
355 : // ignore: non_constant_identifier_names
356 : void ExportProfile(String profile, String file) {
357 0 : cwtchPlatform.invokeMethod("ExportProfile", {"ProfileOnion": profile, "file": file});
358 : }
359 :
360 0 : @override
361 : // ignore: non_constant_identifier_names
362 : Future<dynamic> ImportProfile(String file, String pass) {
363 0 : return cwtchPlatform.invokeMethod("ImportProfile", {"file": file, "pass": pass});
364 : }
365 :
366 0 : @override
367 : Future GetDebugInfo() {
368 : // FIXME: getDebugInfo is less useful for Android so for now
369 : // we don't implement it
370 0 : return Future.value("{}");
371 : }
372 :
373 0 : @override
374 : Future GetSharedFiles(String profile, int handle) {
375 0 : return cwtchPlatform.invokeMethod("GetSharedFiles", {"ProfileOnion": profile, "conversation": handle});
376 : }
377 :
378 0 : @override
379 : void RestartSharing(String profile, String filekey) {
380 0 : cwtchPlatform.invokeMethod("RestartFileShare", {"ProfileOnion": profile, "filekey": filekey});
381 : }
382 :
383 0 : @override
384 : void StopSharing(String profile, String filekey) {
385 0 : cwtchPlatform.invokeMethod("StopSharing", {"ProfileOnion": profile, "filekey": filekey});
386 : }
387 :
388 0 : @override
389 : void DeleteServerInfo(String profile, String handle) {
390 0 : cwtchPlatform.invokeMethod("DeleteServerInfo", {"ProfileOnion": profile, "handle": handle});
391 : }
392 :
393 0 : @override
394 : void UpdateSettings(String json) {
395 0 : cwtchPlatform.invokeMethod("UpdateSettings", {"json": json});
396 : }
397 :
398 0 : @override
399 : bool IsServersCompiled() {
400 : // never for android builds...
401 : return false;
402 : }
403 :
404 0 : @override
405 : Future<String> SummarizeConversation(String profile, int conversation) {
406 : // TODO: implement SummarizeConversation
407 0 : throw UnimplementedError();
408 : }
409 :
410 0 : @override
411 : Future<String> TranslateMessage(String profile, int conversation, int message, String language) {
412 : // TODO: implement TranslateMessage
413 0 : throw UnimplementedError();
414 : }
415 :
416 0 : @override
417 : bool IsBlodeuweddSupported() {
418 : // Blodeuwedd is not currently supported on lower end devices.
419 : return false;
420 : }
421 :
422 0 : @override
423 : Future<String?> GetProfileAttribute(String profile, String key) async {
424 0 : return await cwtchPlatform.invokeMethod("GetProfileAttribute", {"ProfileOnion": profile, "key": key}).then((dynamic json) {
425 0 : var value = jsonDecode(json);
426 0 : if (value["Exists"]) {
427 0 : return value["Value"];
428 : }
429 : return null;
430 : });
431 : }
432 :
433 0 : @override
434 : Future<String?> GetConversationAttribute(String profile, int conversation, String key) async {
435 0 : return await cwtchPlatform.invokeMethod("GetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "key": key}).then((dynamic json) {
436 0 : var value = jsonDecode(json);
437 0 : if (value["Exists"]) {
438 0 : return value["Value"];
439 : }
440 : return null;
441 : });
442 : }
443 :
444 0 : @override
445 : void AttemptReconnection(String profile, String onion) {
446 0 : cwtchPlatform.invokeMethod("PeerWithOnion", {"ProfileOnion": profile, "onion": onion});
447 : }
448 :
449 0 : @override
450 : void AttemptReconnectionServer(String profile, String onion) {
451 0 : cwtchPlatform.invokeMethod("QueueJoinServer", {"ProfileOnion": profile, "onion": onion});
452 : }
453 :
454 0 : @override
455 : void DisconnectFromPeer(String profile, String onion) {
456 0 : cwtchPlatform.invokeMethod("DisconnectFromPeer", {"ProfileOnion": profile, "onion": onion});
457 : }
458 :
459 0 : @override
460 : void DisconnectFromServer(String profile, String onion) {
461 0 : cwtchPlatform.invokeMethod("DisconnectFromServer", {"ProfileOnion": profile, "onion": onion});
462 : }
463 :
464 0 : @override
465 : Future<String> SearchConversations(String profile, String pattern) async {
466 0 : return await cwtchPlatform.invokeMethod("SearchConversations", {"ProfileOnion": profile, "pattern": pattern});
467 : }
468 :
469 0 : @override
470 : Future<void> ConfigureConnections(String profile, bool listen, bool peers, bool servers) async {
471 0 : cwtchPlatform.invokeMethod("ConfigureConnections", {"ProfileOnion": profile, "listen": listen, "peers": peers, "servers": servers});
472 : return;
473 : }
474 :
475 0 : @override
476 : void PublishServerUpdate(String profile) {
477 0 : cwtchPlatform.invokeMethod("PublishServerUpdate", {"ProfileOnion": profile});
478 : }
479 :
480 0 : @override
481 : bool IsLoaded() {
482 : return true;
483 : }
484 : }
|