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_app/cwtch/ffi.dart';
import 'package:provider/provider.dart';
import 'cwtch/cwtch.dart';
import 'model.dart';
import 'views/profilemgrview.dart';
import 'package:flutter/services.dart';
import 'dart:io' show Platform;
import 'package:path/path.dart' as path;
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());
@ -38,7 +21,7 @@ class Flwtch extends StatefulWidget {
class FlwtchState extends State<Flwtch> {
final TextStyle biggerFont = const TextStyle(fontSize: 18);
DynamicLibrary library;
Cwtch cwtch;
AppModel appStatus;
static const appInfoPlatform = const MethodChannel('test.flutter.dev/applicationInfo');
@ -70,8 +53,10 @@ class FlwtchState extends State<Flwtch> {
@override
Widget build(BuildContext context) {
library = DynamicLibrary.open("libCwtch.so");
appStatus = AppModel(library: library);
cwtch = CwtchFfi();
appStatus = AppModel(cwtch: cwtch);
String home = "";
Map<String, String> envVars = Platform.environment;
@ -85,13 +70,9 @@ class FlwtchState extends State<Flwtch> {
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/");
print("cwtchDir $cwtchDir");
StartCwtch(Utf8.toUtf8(cwtchDir), cwtchDir.length);
cwtch.Start(cwtchDir, "tor");
return Provider<FlwtchState>(
create: (_) => this,

View File

@ -3,6 +3,8 @@ import 'package:ffi/ffi.dart';
import 'dart:async';
import 'dart:collection';
import 'cwtch/cwtch.dart';
////////////////////
/// UI State ///
////////////////////
@ -28,22 +30,15 @@ class ContactModel {
/// ACN ///
/////////////
typedef acn_events_function = Pointer<Utf8> Function();
typedef ACNEventsFn = Pointer<Utf8> Function();
class AppModel {
final DynamicLibrary library;
AppModel({this.library});
final Cwtch cwtch;
AppModel({this.cwtch});
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) {
Pointer<Utf8> result = ContactEvents();
String event = Utf8.fromUtf8(result);
String event = cwtch.ContactEvents();
if (event != "") {
print(event);
yield event;
@ -53,16 +48,9 @@ class AppModel {
}
}
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) {
Pointer<Utf8> result = ACNEvents();
String event = Utf8.fromUtf8(result);
String event = cwtch.ACNEvents();
if (event != "") {
yield event;
} 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() {
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>(
stream: Provider.of<FlwtchState>(context).appStatus.contactEvents(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
Pointer<Utf8> jsonContactBytes = GetContacts(Utf8.toUtf8(widget.profileOnion), widget.profileOnion.length);
String jsonContacts = Utf8.fromUtf8(jsonContactBytes);
String jsonContacts = Provider.of<FlwtchState>(context).cwtch.GetContacts(widget.profileOnion);
print(jsonContacts);
List<dynamic> contacts = jsonDecode(jsonContacts);

View File

@ -29,32 +29,20 @@ class _MessageViewState extends State<MessageView> {
}
Widget _buildMessageView(BuildContext context) {
var numMessagesC = Provider.of<FlwtchState>(context).library.lookup<NativeFunction<get_int_from_str_str_function>>("NumMessages");
// 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);
_updateMessageCount(context);
if (timer == null) {
timer = Timer.periodic(Duration(seconds: 1), (Timer t) {
print("tick");
_updateMessageCount(context, NumMessages);
_updateMessageCount(context);
});
}
return ProxyProvider0(
update: (_, __) => MessageCounter(conversationNumMessages),
child: ListView.builder(
itemCount: conversationNumMessages,
itemBuilder: (context, index) {
Pointer<Utf8> jsonMessageBytes = GetMessage(
Utf8.toUtf8(widget.profileOnion), widget.profileOnion.length,
Utf8.toUtf8(widget.conversationHandle), widget.conversationHandle.length,
index);
String jsonMessage = Utf8.fromUtf8(jsonMessageBytes);
String jsonMessage = Provider.of<FlwtchState>(context).cwtch.GetMessage(widget.profileOnion, widget.conversationHandle, index);
//print(jsonMessage);
dynamic messageWrapper = jsonDecode(jsonMessage);
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 (timer != null && timer.isActive) timer.cancel();
return;
}
setState(() {
conversationNumMessages = cfn(
Utf8.toUtf8(widget.profileOnion), widget.profileOnion.length,
Utf8.toUtf8(widget.conversationHandle),
widget.conversationHandle.length,
);
conversationNumMessages = Provider.of<FlwtchState>(context).cwtch.NumMessages(widget.profileOnion, widget.conversationHandle);
});
}
}

View File

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