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<String> CreateProfile(String nick, String pass, bool autostart) {
98 0 : return cwtchPlatform.invokeMethod("CreateProfile", {"nick": nick, "pass": pass, "autostart": autostart}) as Future<String>;
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 : cwtchPlatform
196 0 : .invokeMethod("CreateDownloadableFile", {"ProfileOnion": profileOnion, "conversation": conversation, "manifestpath": manifestpath, "filename": filenameSuggestion, "filekey": filekey});
197 : }
198 :
199 : // ignore: non_constant_identifier_names
200 0 : void ExportPreviewedFile(String sourceFile, String suggestion) {
201 0 : cwtchPlatform.invokeMethod("ExportPreviewedFile", {
202 : "Path": sourceFile,
203 : "FileName": suggestion,
204 : });
205 : }
206 :
207 0 : @override
208 : // ignore: non_constant_identifier_names
209 : void CheckDownloadStatus(String profileOnion, String fileKey) {
210 0 : cwtchPlatform.invokeMethod("CheckDownloadStatus", {"ProfileOnion": profileOnion, "fileKey": fileKey});
211 : }
212 :
213 0 : @override
214 : // ignore: non_constant_identifier_names
215 : void VerifyOrResumeDownload(String profileOnion, int conversation, String filekey) {
216 0 : cwtchPlatform.invokeMethod("VerifyOrResumeDownload", {"ProfileOnion": profileOnion, "conversation": conversation, "filekey": filekey});
217 : }
218 :
219 0 : @override
220 : // ignore: non_constant_identifier_names
221 : void ResetTor() {
222 0 : cwtchPlatform.invokeMethod("ResetTor", {});
223 : }
224 :
225 0 : @override
226 : // ignore: non_constant_identifier_names
227 : Future<dynamic> ImportBundle(String profileOnion, String bundle) {
228 0 : return cwtchPlatform.invokeMethod("ImportBundle", {"ProfileOnion": profileOnion, "bundle": bundle});
229 : }
230 :
231 0 : @override
232 : void CreateGroup(String profileOnion, String server, String groupName) {
233 0 : cwtchPlatform.invokeMethod("CreateGroup", {"ProfileOnion": profileOnion, "server": server, "groupName": groupName});
234 : }
235 :
236 0 : @override
237 : // ignore: non_constant_identifier_names
238 : void DeleteContact(String profileOnion, int conversation) {
239 0 : cwtchPlatform.invokeMethod("DeleteConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
240 : }
241 :
242 0 : @override
243 : // ignore: non_constant_identifier_names
244 : void ArchiveConversation(String profileOnion, int conversation) {
245 0 : cwtchPlatform.invokeMethod("ArchiveConversation", {"ProfileOnion": profileOnion, "conversation": conversation});
246 : }
247 :
248 0 : @override
249 : // ignore: non_constant_identifier_names
250 : void SetProfileAttribute(String profile, String key, String val) {
251 0 : cwtchPlatform.invokeMethod("SetProfileAttribute", {"ProfileOnion": profile, "Key": key, "Val": val});
252 : }
253 :
254 0 : @override
255 : // ignore: non_constant_identifier_names
256 : void SetConversationAttribute(String profile, int conversation, String key, String val) {
257 0 : cwtchPlatform.invokeMethod("SetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "Key": key, "Val": val});
258 : }
259 :
260 0 : @override
261 : // ignore: non_constant_identifier_names
262 : void LoadServers(String password) {
263 0 : cwtchPlatform.invokeMethod("LoadServers", {"Password": password});
264 : }
265 :
266 0 : @override
267 : // ignore: non_constant_identifier_names
268 : void CreateServer(String password, String description, bool autostart) {
269 0 : cwtchPlatform.invokeMethod("CreateServer", {"Password": password, "Description": description, "Autostart": autostart});
270 : }
271 :
272 0 : @override
273 : // ignore: non_constant_identifier_names
274 : void DeleteServer(String serverOnion, String password) {
275 0 : cwtchPlatform.invokeMethod("DeleteServer", {"ServerOnion": serverOnion, "Password": password});
276 : }
277 :
278 0 : @override
279 : // ignore: non_constant_identifier_names
280 : void LaunchServers() {
281 0 : cwtchPlatform.invokeMethod("LaunchServers", {});
282 : }
283 :
284 0 : @override
285 : // ignore: non_constant_identifier_names
286 : void LaunchServer(String serverOnion) {
287 0 : cwtchPlatform.invokeMethod("LaunchServer", {"ServerOnion": serverOnion});
288 : }
289 :
290 0 : @override
291 : // ignore: non_constant_identifier_names
292 : void StopServer(String serverOnion) {
293 0 : cwtchPlatform.invokeMethod("StopServer", {"ServerOnion": serverOnion});
294 : }
295 :
296 0 : @override
297 : // ignore: non_constant_identifier_names
298 : void StopServers() {
299 0 : cwtchPlatform.invokeMethod("StopServers", {});
300 : }
301 :
302 0 : @override
303 : // ignore: non_constant_identifier_names
304 : void DestroyServers() {
305 0 : cwtchPlatform.invokeMethod("DestroyServers", {});
306 : }
307 :
308 0 : @override
309 : // ignore: non_constant_identifier_names
310 : void SetServerAttribute(String serverOnion, String key, String val) {
311 0 : cwtchPlatform.invokeMethod("SetServerAttribute", {"ServerOnion": serverOnion, "Key": key, "Val": val});
312 : }
313 :
314 0 : @override
315 : Future<void> Shutdown() async {
316 0 : print("gomobile.dart Shutdown");
317 0 : cwtchPlatform.invokeMethod("Shutdown", {});
318 : }
319 :
320 0 : @override
321 : Future GetMessageByContentHash(String profile, int conversation, String contentHash) {
322 0 : return cwtchPlatform.invokeMethod("GetMessageByContentHash", {"ProfileOnion": profile, "conversation": conversation, "contentHash": contentHash});
323 : }
324 :
325 0 : @override
326 : void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val) {
327 0 : cwtchPlatform.invokeMethod("SetMessageAttribute", {"ProfileOnion": profile, "conversation": conversation, "Channel": channel, "Message": message, "Key": key, "Val": val});
328 : }
329 :
330 0 : @override
331 : String? defaultDownloadPath() {
332 0 : return this.androidHomeDirectoryStr;
333 : }
334 :
335 0 : @override
336 : void ChangePassword(String profile, String pass, String newpass, String newpassAgain) {
337 0 : cwtchPlatform.invokeMethod("ChangePassword", {"ProfileOnion": profile, "OldPass": pass, "NewPass": newpass, "NewPassAgain": newpassAgain});
338 : }
339 :
340 0 : @override
341 : bool isL10nInit() {
342 0 : return _isL10nInit;
343 : }
344 :
345 0 : @override
346 : void l10nInit(String notificationSimple, String notificationConversationInfo) {
347 0 : cwtchNotifier.l10nInit(notificationSimple, notificationConversationInfo);
348 0 : cwtchPlatform.invokeMethod("L10nInit", {"notificationSimple": notificationSimple, "notificationConversationInfo": notificationConversationInfo});
349 0 : _isL10nInit = true;
350 : }
351 :
352 0 : @override
353 : // ignore: non_constant_identifier_names
354 : void ExportProfile(String profile, String file) {
355 0 : cwtchPlatform.invokeMethod("ExportProfile", {"ProfileOnion": profile, "file": file});
356 : }
357 :
358 0 : @override
359 : // ignore: non_constant_identifier_names
360 : Future<dynamic> ImportProfile(String file, String pass) {
361 0 : return cwtchPlatform.invokeMethod("ImportProfile", {"file": file, "pass": pass});
362 : }
363 :
364 0 : @override
365 : Future GetDebugInfo() {
366 : // FIXME: getDebugInfo is less useful for Android so for now
367 : // we don't implement it
368 0 : return Future.value("{}");
369 : }
370 :
371 0 : @override
372 : Future GetSharedFiles(String profile, int handle) {
373 0 : return cwtchPlatform.invokeMethod("GetSharedFiles", {"ProfileOnion": profile, "conversation": handle});
374 : }
375 :
376 0 : @override
377 : void RestartSharing(String profile, String filekey) {
378 0 : cwtchPlatform.invokeMethod("RestartFileShare", {"ProfileOnion": profile, "filekey": filekey});
379 : }
380 :
381 0 : @override
382 : void StopSharing(String profile, String filekey) {
383 0 : cwtchPlatform.invokeMethod("StopSharing", {"ProfileOnion": profile, "filekey": filekey});
384 : }
385 :
386 0 : @override
387 : void DeleteServerInfo(String profile, String handle) {
388 0 : cwtchPlatform.invokeMethod("DeleteServerInfo", {"ProfileOnion": profile, "handle": handle});
389 : }
390 :
391 0 : @override
392 : void UpdateSettings(String json) {
393 0 : cwtchPlatform.invokeMethod("UpdateSettings", {"json": json});
394 : }
395 :
396 0 : @override
397 : bool IsServersCompiled() {
398 : // never for android builds...
399 : return false;
400 : }
401 :
402 0 : @override
403 : Future<String> SummarizeConversation(String profile, int conversation) {
404 : // TODO: implement SummarizeConversation
405 0 : throw UnimplementedError();
406 : }
407 :
408 0 : @override
409 : Future<String> TranslateMessage(String profile, int conversation, int message, String language) {
410 : // TODO: implement TranslateMessage
411 0 : throw UnimplementedError();
412 : }
413 :
414 0 : @override
415 : bool IsBlodeuweddSupported() {
416 : // Blodeuwedd is not currently supported on lower end devices.
417 : return false;
418 : }
419 :
420 0 : @override
421 : Future<String?> GetProfileAttribute(String profile, String key) async {
422 0 : return await cwtchPlatform.invokeMethod("GetProfileAttribute", {"ProfileOnion": profile, "key": key}).then((dynamic json) {
423 0 : var value = jsonDecode(json);
424 0 : if (value["Exists"]) {
425 0 : return value["Value"];
426 : }
427 : return null;
428 : });
429 : }
430 :
431 0 : @override
432 : Future<String?> GetConversationAttribute(String profile, int conversation, String key) async {
433 0 : return await cwtchPlatform.invokeMethod("GetConversationAttribute", {"ProfileOnion": profile, "conversation": conversation, "key": key}).then((dynamic json) {
434 0 : var value = jsonDecode(json);
435 0 : if (value["Exists"]) {
436 0 : return value["Value"];
437 : }
438 : return null;
439 : });
440 : }
441 :
442 0 : @override
443 : void AttemptReconnection(String profile, String onion) {
444 0 : cwtchPlatform.invokeMethod("PeerWithOnion", {"ProfileOnion": profile, "onion": onion});
445 : }
446 :
447 0 : @override
448 : void AttemptReconnectionServer(String profile, String onion) {
449 0 : cwtchPlatform.invokeMethod("QueueJoinServer", {"ProfileOnion": profile, "onion": onion});
450 : }
451 :
452 0 : @override
453 : void DisconnectFromPeer(String profile, String onion) {
454 0 : cwtchPlatform.invokeMethod("DisconnectFromPeer", {"ProfileOnion": profile, "onion": onion});
455 : }
456 :
457 0 : @override
458 : void DisconnectFromServer(String profile, String onion) {
459 0 : cwtchPlatform.invokeMethod("DisconnectFromServer", {"ProfileOnion": profile, "onion": onion});
460 : }
461 :
462 0 : @override
463 : Future<String> SearchConversations(String profile, String pattern) async {
464 0 : return await cwtchPlatform.invokeMethod("SearchConversations", {"ProfileOnion": profile, "pattern": pattern});
465 : }
466 :
467 0 : @override
468 : Future<void> ConfigureConnections(String profile, bool listen, bool peers, bool servers) async {
469 0 : cwtchPlatform.invokeMethod("ConfigureConnections", {"ProfileOnion": profile, "listen": listen, "peers": peers, "servers": servers});
470 : return;
471 : }
472 :
473 0 : @override
474 : void PublishServerUpdate(String profile) {
475 0 : cwtchPlatform.invokeMethod("PublishServerUpdate", {"ProfileOnion": profile});
476 : }
477 :
478 0 : @override
479 : bool IsLoaded() {
480 : return true;
481 : }
482 : }
|