move all cwtch calls to an interface and an ffi implementation

This commit is contained in:
Dan Ballard 2021-01-11 22:21:18 -08:00
parent 8d202cfaeb
commit c1f7556636
8 changed files with 152 additions and 117 deletions

14
lib/cwtch/cwtch.dart Normal file
View File

@ -0,0 +1,14 @@
abstract class Cwtch {
void Start(String appDir, String torPath) ;
void SelectProfile(String onion);
String ACNEvents();
String ContactEvents();
String GetProfiles();
String GetContacts(String onion);
int NumMessages(String profile, String handle);
String GetMessage(String profile, String handle, int index);
}

115
lib/cwtch/ffi.dart Normal file
View File

@ -0,0 +1,115 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter_app/cwtch/cwtch.dart';
/////////////////////
/// Cwtch API ///
/////////////////////
typedef start_cwtch_function = Void Function(Pointer<Utf8> str, Int32 length);
typedef StartCwtchFn = void Function(Pointer<Utf8> dir, int len);
typedef access_cwtch_eventbus_function = Void Function();
typedef NextEventFn = void Function();
typedef get_json_blob_void_function = Pointer<Utf8> Function();
typedef GetJsonBlobVoidFn = Pointer<Utf8> Function();
typedef get_json_blob_string_function = Pointer<Utf8> Function(Pointer<Utf8> str, Int32 length);
typedef GetJsonBlobStringFn = Pointer<Utf8> Function(Pointer<Utf8> str,int len);
//func NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) {
typedef get_int_from_str_str_function = Int32 Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
typedef GetIntFromStrStrFn = int Function(Pointer<Utf8>, int, Pointer<Utf8>, int);
//func GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char {
typedef get_json_blob_from_str_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32);
typedef GetJsonBlobFromStrStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int);
typedef acn_events_function = Pointer<Utf8> Function();
typedef ACNEventsFn = Pointer<Utf8> Function();
class CwtchFfi implements Cwtch {
DynamicLibrary library;
CwtchFfi() {
library = DynamicLibrary.open("libCwtch.so");
}
void Start(String appDir, String torPath) {
var startCwtchC = library.lookup<NativeFunction<start_cwtch_function>>("StartCwtch");
// ignore: non_constant_identifier_names
final StartCwtch = startCwtchC.asFunction<StartCwtchFn>();
StartCwtch(Utf8.toUtf8(appDir), appDir.length);
}
void SelectProfile(String onion) {
var selectProfileC = library.lookup<NativeFunction<get_json_blob_string_function>>("SelectProfile");
// ignore: non_constant_identifier_names
final SelectProfile = selectProfileC.asFunction<GetJsonBlobStringFn>();
SelectProfile(Utf8.toUtf8(onion), onion.length);
}
String ACNEvents() {
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
"ACNEvents");
// ignore: non_constant_identifier_names
final ACNEvents = acnEventsC.asFunction<ACNEventsFn>();
Pointer<Utf8> result = ACNEvents();
String event = Utf8.fromUtf8(result);
return event;
}
String ContactEvents() {
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
"ContactEvents");
// ignore: non_constant_identifier_names
final ContactEvents = acnEventsC.asFunction<ACNEventsFn>();
Pointer<Utf8> result = ContactEvents();
String event = Utf8.fromUtf8(result);
return event;
}
String GetProfiles() {
var getProfilesC = library.lookup<NativeFunction<get_json_blob_void_function>>("GetProfiles");
// ignore: non_constant_identifier_names
final GetProfiles = getProfilesC.asFunction<GetJsonBlobVoidFn>();
Pointer<Utf8> jsonProfilesBytes = GetProfiles();
String jsonProfiles = Utf8.fromUtf8(jsonProfilesBytes);
return jsonProfiles;
}
String GetContacts(String onion) {
var getContactsC = library.lookup<NativeFunction<get_json_blob_string_function>>("GetContacts");
// ignore: non_constant_identifier_names
final GetContacts = getContactsC.asFunction<GetJsonBlobStringFn>();
Pointer<Utf8> jsonContactBytes = GetContacts(Utf8.toUtf8(onion), onion.length);
String jsonContacts = Utf8.fromUtf8(jsonContactBytes);
return jsonContacts;
}
int NumMessages(String profile, String handle) {
var numMessagesC = library.lookup<NativeFunction<get_int_from_str_str_function>>("NumMessages");
// ignore: non_constant_identifier_names
final NumMessages = numMessagesC.asFunction<GetIntFromStrStrFn>();
int num = NumMessages(Utf8.toUtf8(profile), profile.length, Utf8.toUtf8(handle), handle.length);
return num;
}
String GetMessage(String profile, String handle, int index) {
var getMessageC = library.lookup<NativeFunction<get_json_blob_from_str_str_int_function>>("GetMessage");
// ignore: non_constant_identifier_names
final GetMessage = getMessageC.asFunction<GetJsonBlobFromStrStrIntFn>();
Pointer<Utf8> jsonMessageBytes = GetMessage(Utf8.toUtf8(profile), profile.length, Utf8.toUtf8(handle), handle.length, index);
String jsonMessage = Utf8.fromUtf8(jsonMessageBytes);
return jsonMessage;
}
}

View File

@ -1,30 +1,13 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_app/cwtch/ffi.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'cwtch/cwtch.dart';
import 'model.dart'; import 'model.dart';
import 'views/profilemgrview.dart'; import 'views/profilemgrview.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'model.dart' as model;
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
typedef start_cwtch_function = Void Function(Pointer<Utf8> str, Int32 length);
typedef StartCwtchFn = void Function(Pointer<Utf8> dir, int len);
typedef access_cwtch_eventbus_function = Void Function();
typedef NextEventFn = void Function();
typedef get_json_blob_void_function = Pointer<Utf8> Function();
typedef GetJsonBlobVoidFn = Pointer<Utf8> Function();
typedef get_json_blob_string_function = Pointer<Utf8> Function(Pointer<Utf8> str, Int32 length);
typedef GetJsonBlobStringFn = Pointer<Utf8> Function(Pointer<Utf8> str,int len);
void main() => runApp(Flwtch()); void main() => runApp(Flwtch());
@ -38,7 +21,7 @@ class Flwtch extends StatefulWidget {
class FlwtchState extends State<Flwtch> { class FlwtchState extends State<Flwtch> {
final TextStyle biggerFont = const TextStyle(fontSize: 18); final TextStyle biggerFont = const TextStyle(fontSize: 18);
DynamicLibrary library; Cwtch cwtch;
AppModel appStatus; AppModel appStatus;
static const appInfoPlatform = const MethodChannel('test.flutter.dev/applicationInfo'); static const appInfoPlatform = const MethodChannel('test.flutter.dev/applicationInfo');
@ -70,8 +53,10 @@ class FlwtchState extends State<Flwtch> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
library = DynamicLibrary.open("libCwtch.so");
appStatus = AppModel(library: library); cwtch = CwtchFfi();
appStatus = AppModel(cwtch: cwtch);
String home = ""; String home = "";
Map<String, String> envVars = Platform.environment; Map<String, String> envVars = Platform.environment;
@ -85,13 +70,9 @@ class FlwtchState extends State<Flwtch> {
home = androidHomeDirectory; home = androidHomeDirectory;
} }
var startCwtchC = library.lookup<NativeFunction<start_cwtch_function>>("StartCwtch");
// ignore: non_constant_identifier_names
final StartCwtch = startCwtchC.asFunction<StartCwtchFn>();
var cwtchDir = path.join(home, ".cwtch/dev/"); var cwtchDir = path.join(home, ".cwtch/dev/");
print("cwtchDir $cwtchDir"); print("cwtchDir $cwtchDir");
StartCwtch(Utf8.toUtf8(cwtchDir), cwtchDir.length); cwtch.Start(cwtchDir, "tor");
return Provider<FlwtchState>( return Provider<FlwtchState>(
create: (_) => this, create: (_) => this,

View File

@ -3,6 +3,8 @@ import 'package:ffi/ffi.dart';
import 'dart:async'; import 'dart:async';
import 'dart:collection'; import 'dart:collection';
import 'cwtch/cwtch.dart';
//////////////////// ////////////////////
/// UI State /// /// UI State ///
//////////////////// ////////////////////
@ -28,22 +30,15 @@ class ContactModel {
/// ACN /// /// ACN ///
///////////// /////////////
typedef acn_events_function = Pointer<Utf8> Function();
typedef ACNEventsFn = Pointer<Utf8> Function();
class AppModel { class AppModel {
final DynamicLibrary library; final Cwtch cwtch;
AppModel({this.library}); AppModel({this.cwtch});
Stream<String> contactEvents() async* { Stream<String> contactEvents() async* {
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
"ContactEvents");
// ignore: non_constant_identifier_names
final ContactEvents = acnEventsC.asFunction<ACNEventsFn>();
while (true) { while (true) {
Pointer<Utf8> result = ContactEvents(); String event = cwtch.ContactEvents();
String event = Utf8.fromUtf8(result);
if (event != "") { if (event != "") {
print(event); print(event);
yield event; yield event;
@ -53,16 +48,9 @@ class AppModel {
} }
} }
Stream<String> torStatus() async* { Stream<String> torStatus() async* {
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
"ACNEvents");
// ignore: non_constant_identifier_names
final ACNEvents = acnEventsC.asFunction<ACNEventsFn>();
while (true) { while (true) {
Pointer<Utf8> result = ACNEvents(); String event = cwtch.ACNEvents();
String event = Utf8.fromUtf8(result);
if (event != "") { if (event != "") {
yield event; yield event;
} else { } else {
@ -71,27 +59,3 @@ class AppModel {
} }
} }
} }
/////////////////////
/// Cwtch API ///
/////////////////////
typedef start_cwtch_function = Void Function(Pointer<Utf8> str, Int32 length);
typedef StartCwtchFn = void Function(Pointer<Utf8> dir, int len);
typedef access_cwtch_eventbus_function = Void Function();
typedef NextEventFn = void Function();
typedef get_json_blob_void_function = Pointer<Utf8> Function();
typedef GetJsonBlobVoidFn = Pointer<Utf8> Function();
typedef get_json_blob_string_function = Pointer<Utf8> Function(Pointer<Utf8> str, Int32 length);
typedef GetJsonBlobStringFn = Pointer<Utf8> Function(Pointer<Utf8> str,int len);
//func NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) {
typedef get_int_from_str_str_function = Int32 Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
typedef GetIntFromStrStrFn = int Function(Pointer<Utf8>, int, Pointer<Utf8>, int);
//func GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char {
typedef get_json_blob_from_str_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32);
typedef GetJsonBlobFromStrStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int);

View File

@ -31,15 +31,10 @@ class _ContactsViewState extends State<ContactsView> {
Widget _buildContactList() { Widget _buildContactList() {
var getContactsC = Provider.of<FlwtchState>(context).library.lookup<NativeFunction<get_json_blob_string_function>>("GetContacts");
// ignore: non_constant_identifier_names
final GetContacts = getContactsC.asFunction<GetJsonBlobStringFn>();
return StreamBuilder<String>( return StreamBuilder<String>(
stream: Provider.of<FlwtchState>(context).appStatus.contactEvents(), stream: Provider.of<FlwtchState>(context).appStatus.contactEvents(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) { builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
Pointer<Utf8> jsonContactBytes = GetContacts(Utf8.toUtf8(widget.profileOnion), widget.profileOnion.length); String jsonContacts = Provider.of<FlwtchState>(context).cwtch.GetContacts(widget.profileOnion);
String jsonContacts = Utf8.fromUtf8(jsonContactBytes);
print(jsonContacts); print(jsonContacts);
List<dynamic> contacts = jsonDecode(jsonContacts); List<dynamic> contacts = jsonDecode(jsonContacts);

View File

@ -29,32 +29,20 @@ class _MessageViewState extends State<MessageView> {
} }
Widget _buildMessageView(BuildContext context) { Widget _buildMessageView(BuildContext context) {
var numMessagesC = Provider.of<FlwtchState>(context).library.lookup<NativeFunction<get_int_from_str_str_function>>("NumMessages"); _updateMessageCount(context);
// ignore: non_constant_identifier_names
final NumMessages = numMessagesC.asFunction<GetIntFromStrStrFn>();
var getMessageC = Provider.of<FlwtchState>(context).library.lookup<NativeFunction<get_json_blob_from_str_str_int_function>>("GetMessage");
// ignore: non_constant_identifier_names
final GetMessage = getMessageC.asFunction<GetJsonBlobFromStrStrIntFn>();
_updateMessageCount(context, NumMessages);
if (timer == null) { if (timer == null) {
timer = Timer.periodic(Duration(seconds: 1), (Timer t) { timer = Timer.periodic(Duration(seconds: 1), (Timer t) {
print("tick"); print("tick");
_updateMessageCount(context, NumMessages); _updateMessageCount(context);
}); });
} }
return ProxyProvider0( return ProxyProvider0(
update: (_, __) => MessageCounter(conversationNumMessages), update: (_, __) => MessageCounter(conversationNumMessages),
child: ListView.builder( child: ListView.builder(
itemCount: conversationNumMessages, itemCount: conversationNumMessages,
itemBuilder: (context, index) { itemBuilder: (context, index) {
Pointer<Utf8> jsonMessageBytes = GetMessage( String jsonMessage = Provider.of<FlwtchState>(context).cwtch.GetMessage(widget.profileOnion, widget.conversationHandle, index);
Utf8.toUtf8(widget.profileOnion), widget.profileOnion.length,
Utf8.toUtf8(widget.conversationHandle), widget.conversationHandle.length,
index);
String jsonMessage = Utf8.fromUtf8(jsonMessageBytes);
//print(jsonMessage); //print(jsonMessage);
dynamic messageWrapper = jsonDecode(jsonMessage); dynamic messageWrapper = jsonDecode(jsonMessage);
dynamic message = jsonDecode(messageWrapper['Message']); dynamic message = jsonDecode(messageWrapper['Message']);
@ -68,18 +56,13 @@ class _MessageViewState extends State<MessageView> {
)); ));
} }
Future _updateMessageCount(BuildContext context, GetIntFromStrStrFn cfn) async { Future _updateMessageCount(BuildContext context) async {
if (!mounted) { if (!mounted) {
if (timer != null && timer.isActive) timer.cancel(); if (timer != null && timer.isActive) timer.cancel();
return; return;
} }
setState(() { setState(() {
conversationNumMessages = cfn( conversationNumMessages = Provider.of<FlwtchState>(context).cwtch.NumMessages(widget.profileOnion, widget.conversationHandle);
Utf8.toUtf8(widget.profileOnion), widget.profileOnion.length,
Utf8.toUtf8(widget.conversationHandle),
widget.conversationHandle.length,
);
}); });
} }
} }

View File

@ -24,12 +24,8 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
} }
if (_profiles.length < 1) { if (_profiles.length < 1) {
var getProfilesC = Provider.of<FlwtchState>(context).library.lookup<NativeFunction<get_json_blob_void_function>>("GetProfiles");
// ignore: non_constant_identifier_names
final GetProfiles = getProfilesC.asFunction<GetJsonBlobVoidFn>();
Pointer<Utf8> jsonProfilesBytes = GetProfiles(); String jsonProfiles = Provider.of<FlwtchState>(context).cwtch.GetProfiles();
String jsonProfiles = Utf8.fromUtf8(jsonProfilesBytes);
print(jsonProfiles); print(jsonProfiles);
Map<String, dynamic> profiles = jsonDecode(jsonProfiles); Map<String, dynamic> profiles = jsonDecode(jsonProfiles);
@ -84,11 +80,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
subtitle: Text(profile.onion), subtitle: Text(profile.onion),
onTap: () { onTap: () {
setState(() { setState(() {
var selectProfileC = Provider.of<FlwtchState>(context, listen:false).library.lookup<NativeFunction<get_json_blob_string_function>>("SelectProfile"); Provider.of<FlwtchState>(context, listen:false).cwtch.SelectProfile(profile.onion);
// ignore: non_constant_identifier_names
final SelectProfile = selectProfileC.asFunction<GetJsonBlobStringFn>();
SelectProfile(Utf8.toUtf8(profile.onion), profile.onion.length);
_pushContactList(profile.onion); _pushContactList(profile.onion);
}); });
}, },

View File

@ -31,13 +31,4 @@ class _TorStatusState extends State<TorStatusLabel> {
}, },
)); ));
} }
void _incrementCounter() {
setState(() {
var nextEventC = Provider.of<FlwtchState>(context).library.lookup<NativeFunction<access_cwtch_eventbus_function>>("NextEvent");
// ignore: non_constant_identifier_names
final NextEvent = nextEventC.asFunction<NextEventFn>();
NextEvent();
});
}
} }