cleanup veilid-flutter

This commit is contained in:
Christien Rioux 2024-05-02 14:15:42 -04:00
parent b948c53863
commit 439d2641f1
16 changed files with 275 additions and 291 deletions

View File

@ -1,4 +1,4 @@
@Timeout(Duration(seconds: 60)) @Timeout(Duration(seconds: 120))
library veilid_flutter_integration_test; library veilid_flutter_integration_test;
@ -7,10 +7,10 @@ import 'package:integration_test/integration_test.dart';
import 'package:veilid_test/veilid_test.dart'; import 'package:veilid_test/veilid_test.dart';
import 'test_crypto.dart'; import 'test_crypto.dart';
import 'test_dht.dart';
import 'test_routing_context.dart'; import 'test_routing_context.dart';
import 'test_table_db.dart'; import 'test_table_db.dart';
import 'test_veilid_config.dart'; import 'test_veilid_config.dart';
import 'test_dht.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -49,13 +49,13 @@ void main() {
group('Routing Contexts', () { group('Routing Contexts', () {
test('routing contexts', testRoutingContexts); test('routing contexts', testRoutingContexts);
test('app message loopback', test('app message loopback',
() => testAppMessageLoopback(fixture.updateStream)); () async => testAppMessageLoopback(fixture.updateStream));
test('app call loopback', test('app call loopback',
() => testAppCallLoopback(fixture.updateStream)); () async => testAppCallLoopback(fixture.updateStream));
test('app message loopback big packets', test('app message loopback big packets',
() => testAppMessageLoopbackBigPackets(fixture.updateStream)); () async => testAppMessageLoopbackBigPackets(fixture.updateStream));
test('app call loopback big packets', test('app call loopback big packets',
() => testAppCallLoopbackBigPackets(fixture.updateStream)); () async => testAppCallLoopbackBigPackets(fixture.updateStream));
}); });
group('Veilid DHT', () { group('Veilid DHT', () {
@ -71,8 +71,8 @@ void main() {
test('get dht value nonexistent', testGetDHTValueNonexistent); test('get dht value nonexistent', testGetDHTValueNonexistent);
test('set get dht value', testSetGetDHTValue); test('set get dht value', testSetGetDHTValue);
test('open writer dht value', testOpenWriterDHTValue); test('open writer dht value', testOpenWriterDHTValue);
test( test('watch dht values',
'watch dht values', () => testWatchDHTValues(fixture.updateStream)); () async => testWatchDHTValues(fixture.updateStream));
test('inspect dht record', testInspectDHTRecord); test('inspect dht record', testInspectDHTRecord);
}); });
}); });

View File

@ -14,8 +14,7 @@ Future<void> testGetCryptoSystem() async {
} }
Future<void> testGetCryptoSystemInvalid() async { Future<void> testGetCryptoSystemInvalid() async {
await expectLater( await expectLater(() async => Veilid.instance.getCryptoSystem(cryptoKindNONE),
() async => await Veilid.instance.getCryptoSystem(cryptoKindNONE),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} }
@ -25,12 +24,12 @@ Future<void> testHashAndVerifyPassword() async {
final salt = nonce.decode(); final salt = nonce.decode();
// Password match // Password match
final phash = await cs.hashPassword(utf8.encode("abc123"), salt); final phash = await cs.hashPassword(utf8.encode('abc123'), salt);
expect(await cs.verifyPassword(utf8.encode("abc123"), phash), isTrue); expect(await cs.verifyPassword(utf8.encode('abc123'), phash), isTrue);
// Password mismatch // Password mismatch
await cs.hashPassword(utf8.encode("abc1234"), salt); await cs.hashPassword(utf8.encode('abc1234'), salt);
expect(await cs.verifyPassword(utf8.encode("abc1235"), phash), isFalse); expect(await cs.verifyPassword(utf8.encode('abc1235'), phash), isFalse);
} }
Future<void> testGenerateSharedSecret() async { Future<void> testGenerateSharedSecret() async {
@ -41,19 +40,19 @@ Future<void> testGenerateSharedSecret() async {
final kp3 = await cs.generateKeyPair(); final kp3 = await cs.generateKeyPair();
final ssA = final ssA =
await cs.generateSharedSecret(kp1.key, kp2.secret, utf8.encode("abc123")); await cs.generateSharedSecret(kp1.key, kp2.secret, utf8.encode('abc123'));
final ssB = final ssB =
await cs.generateSharedSecret(kp2.key, kp1.secret, utf8.encode("abc123")); await cs.generateSharedSecret(kp2.key, kp1.secret, utf8.encode('abc123'));
expect(ssA, equals(ssB)); expect(ssA, equals(ssB));
final ssC = await cs.generateSharedSecret( final ssC = await cs.generateSharedSecret(
kp2.key, kp1.secret, utf8.encode("abc1234")); kp2.key, kp1.secret, utf8.encode('abc1234'));
expect(ssA, isNot(equals(ssC))); expect(ssA, isNot(equals(ssC)));
final ssD = final ssD =
await cs.generateSharedSecret(kp3.key, kp1.secret, utf8.encode("abc123")); await cs.generateSharedSecret(kp3.key, kp1.secret, utf8.encode('abc123'));
expect(ssA, isNot(equals(ssD))); expect(ssA, isNot(equals(ssD)));
} }

View File

@ -5,13 +5,12 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:veilid/veilid.dart'; import 'package:veilid/veilid.dart';
final bogusKey = final bogusKey =
TypedKey.fromString("VLD0:qD10lHHPD1_Qr23_Qy-1JnxTht12eaWwENVG_m2v7II"); TypedKey.fromString('VLD0:qD10lHHPD1_Qr23_Qy-1JnxTht12eaWwENVG_m2v7II');
Future<void> testGetDHTValueUnopened() async { Future<void> testGetDHTValueUnopened() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
try { try {
await expectLater( await expectLater(() async => rc.getDHTValue(bogusKey, 0),
() async => await rc.getDHTValue(bogusKey, 0, forceRefresh: false),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} finally { } finally {
rc.close(); rc.close();
@ -21,7 +20,7 @@ Future<void> testGetDHTValueUnopened() async {
Future<void> testOpenDHTRecordNonexistentNoWriter() async { Future<void> testOpenDHTRecordNonexistentNoWriter() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
try { try {
await expectLater(() async => await rc.openDHTRecord(bogusKey), await expectLater(() async => rc.openDHTRecord(bogusKey),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} finally { } finally {
rc.close(); rc.close();
@ -31,7 +30,7 @@ Future<void> testOpenDHTRecordNonexistentNoWriter() async {
Future<void> testCloseDHTRecordNonexistent() async { Future<void> testCloseDHTRecordNonexistent() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
try { try {
await expectLater(() async => await rc.closeDHTRecord(bogusKey), await expectLater(() async => rc.closeDHTRecord(bogusKey),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} finally { } finally {
rc.close(); rc.close();
@ -41,7 +40,7 @@ Future<void> testCloseDHTRecordNonexistent() async {
Future<void> testDeleteDHTRecordNonexistent() async { Future<void> testDeleteDHTRecordNonexistent() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
try { try {
await expectLater(() async => await rc.deleteDHTRecord(bogusKey), await expectLater(() async => rc.deleteDHTRecord(bogusKey),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} finally { } finally {
rc.close(); rc.close();
@ -84,7 +83,7 @@ Future<void> testSetGetDHTValue() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
try { try {
final rec = await rc.createDHTRecord(const DHTSchema.dflt(oCnt: 2)); final rec = await rc.createDHTRecord(const DHTSchema.dflt(oCnt: 2));
expect(await rc.setDHTValue(rec.key, 0, utf8.encode("BLAH BLAH BLAH")), expect(await rc.setDHTValue(rec.key, 0, utf8.encode('BLAH BLAH BLAH')),
isNull); isNull);
final vd2 = await rc.getDHTValue(rec.key, 0); final vd2 = await rc.getDHTValue(rec.key, 0);
expect(vd2, isNotNull); expect(vd2, isNotNull);
@ -115,9 +114,9 @@ Future<void> testOpenWriterDHTValue() async {
expect(await cs.validateKeyPair(owner, secret), isTrue); expect(await cs.validateKeyPair(owner, secret), isTrue);
final otherKeyPair = await cs.generateKeyPair(); final otherKeyPair = await cs.generateKeyPair();
final va = utf8.encode("Qwertyuiop Asdfghjkl Zxcvbnm"); final va = utf8.encode('Qwertyuiop Asdfghjkl Zxcvbnm');
final vb = utf8.encode("1234567890"); final vb = utf8.encode('1234567890');
final vc = utf8.encode("!@#\$%^&*()"); final vc = utf8.encode(r'!@#$%^&*()');
// Test subkey writes // Test subkey writes
expect(await rc.setDHTValue(key, 1, va), isNull); expect(await rc.setDHTValue(key, 1, va), isNull);
@ -179,7 +178,8 @@ Future<void> testOpenWriterDHTValue() async {
expect(vdtemp.seq, equals(1)); expect(vdtemp.seq, equals(1));
expect(vdtemp.writer, equals(owner)); expect(vdtemp.writer, equals(owner));
// Verify subkey 1 can be set a second time and it updates because seq is newer // Verify subkey 1 can be set a second time
// and it updates because seq is newer
expect(await rc.setDHTValue(key, 1, vc), isNull); expect(await rc.setDHTValue(key, 1, vc), isNull);
// Verify the network got the subkey update with a refresh check // Verify the network got the subkey update with a refresh check
@ -203,11 +203,11 @@ Future<void> testOpenWriterDHTValue() async {
expect(rec.schema.oCnt, equals(2)); expect(rec.schema.oCnt, equals(2));
// Verify subkey 1 can NOT be set because we have the wrong writer // Verify subkey 1 can NOT be set because we have the wrong writer
await expectLater(() async => await rc.setDHTValue(key, 1, va), await expectLater(() async => rc.setDHTValue(key, 1, va),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
// Verify subkey 0 can NOT be set because we have the wrong writer // Verify subkey 0 can NOT be set because we have the wrong writer
await expectLater(() async => await rc.setDHTValue(key, 0, va), await expectLater(() async => rc.setDHTValue(key, 0, va),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
// Verify subkey 0 can be set because override with the right writer // Verify subkey 0 can be set because override with the right writer
@ -250,7 +250,7 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
// Set some subkey we care about // Set some subkey we care about
expect( expect(
await rcWatch.setDHTValue(rec.key, 3, utf8.encode("BLAH BLAH BLAH")), await rcWatch.setDHTValue(rec.key, 3, utf8.encode('BLAH BLAH BLAH')),
isNull); isNull);
// Make a watch on that subkey // Make a watch on that subkey
@ -261,24 +261,23 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
rec = await rcSet.openDHTRecord(rec.key, writer: rec.ownerKeyPair()); rec = await rcSet.openDHTRecord(rec.key, writer: rec.ownerKeyPair());
// Now set the subkey and trigger an update // Now set the subkey and trigger an update
expect(await rcSet.setDHTValue(rec.key, 3, utf8.encode("BLAH")), isNull); expect(await rcSet.setDHTValue(rec.key, 3, utf8.encode('BLAH')), isNull);
// Now we should NOT get an update because the update // Now we should NOT get an update because the update
// is the same as our local copy // is the same as our local copy
if (await valueChangeQueueIterator if (await valueChangeQueueIterator
.moveNext() .moveNext()
.timeout(const Duration(seconds: 5), onTimeout: () { .timeout(const Duration(seconds: 5), onTimeout: () => false)) {
return false; fail('should not have a change');
})) {
fail("should not have a change");
} }
await valueChangeQueueIterator.cancel();
valueChangeQueueIterator = StreamIterator(valueChangeQueue.stream); valueChangeQueueIterator = StreamIterator(valueChangeQueue.stream);
// Now set multiple subkeys and trigger an update // Now set multiple subkeys and trigger an update
expect( expect(
await [ await [
rcSet.setDHTValue(rec.key, 3, utf8.encode("BLAH BLAH")), rcSet.setDHTValue(rec.key, 3, utf8.encode('BLAH BLAH')),
rcSet.setDHTValue(rec.key, 4, utf8.encode("BZORT")) rcSet.setDHTValue(rec.key, 4, utf8.encode('BZORT'))
].wait, ].wait,
equals([null, null])); equals([null, null]));
@ -286,7 +285,7 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
await valueChangeQueueIterator await valueChangeQueueIterator
.moveNext() .moveNext()
.timeout(const Duration(seconds: 5), onTimeout: () { .timeout(const Duration(seconds: 5), onTimeout: () {
fail("should have a change"); fail('should have a change');
}); });
// Verify the update // Verify the update
@ -311,8 +310,8 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
// Now set multiple subkeys and trigger an update // Now set multiple subkeys and trigger an update
expect( expect(
await [ await [
rcSet.setDHTValue(rec.key, 3, utf8.encode("BLAH BLAH BLAH")), rcSet.setDHTValue(rec.key, 3, utf8.encode('BLAH BLAH BLAH')),
rcSet.setDHTValue(rec.key, 5, utf8.encode("BZORT BZORT")) rcSet.setDHTValue(rec.key, 5, utf8.encode('BZORT BZORT'))
].wait, ].wait,
equals([null, null])); equals([null, null]));
@ -320,10 +319,11 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
await valueChangeQueueIterator await valueChangeQueueIterator
.moveNext() .moveNext()
.timeout(const Duration(seconds: 5), onTimeout: () { .timeout(const Duration(seconds: 5), onTimeout: () {
fail("should have a change"); fail('should have a change');
}); });
// Verify the update came back but we don't get a new value because the sequence number is the same // Verify the update came back but we don't get a new value because the
// sequence number is the same
expect(valueChangeQueueIterator.current.key, equals(rec.key)); expect(valueChangeQueueIterator.current.key, equals(rec.key));
expect(valueChangeQueueIterator.current.count, equals(0xFFFFFFFC)); expect(valueChangeQueueIterator.current.count, equals(0xFFFFFFFC));
expect(valueChangeQueueIterator.current.subkeys, expect(valueChangeQueueIterator.current.subkeys,
@ -345,18 +345,16 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
// Now set multiple subkeys and trigger an update // Now set multiple subkeys and trigger an update
expect( expect(
await [ await [
rcSet.setDHTValue(rec.key, 3, utf8.encode("BLAH BLAH BLAH BLAH")), rcSet.setDHTValue(rec.key, 3, utf8.encode('BLAH BLAH BLAH BLAH')),
rcSet.setDHTValue(rec.key, 5, utf8.encode("BZORT BZORT BZORT")) rcSet.setDHTValue(rec.key, 5, utf8.encode('BZORT BZORT BZORT'))
].wait, ].wait,
equals([null, null])); equals([null, null]));
// Now we should NOT get an update // Now we should NOT get an update
if (await valueChangeQueueIterator if (await valueChangeQueueIterator
.moveNext() .moveNext()
.timeout(const Duration(seconds: 5), onTimeout: () { .timeout(const Duration(seconds: 5), onTimeout: () => false)) {
return false; fail('should not have a change');
})) {
fail("should not have a change");
} }
// Clean up // Clean up
@ -367,16 +365,18 @@ Future<void> testWatchDHTValues(Stream<VeilidUpdate> updateStream) async {
rcSet.close(); rcSet.close();
} }
} finally { } finally {
await valueChangeQueueIterator.cancel();
await valueChangeSubscription.cancel(); await valueChangeSubscription.cancel();
await valueChangeQueue.close();
} }
} }
Future<void> testInspectDHTRecord() async { Future<void> testInspectDHTRecord() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
try { try {
var rec = await rc.createDHTRecord(const DHTSchema.dflt(oCnt: 2)); final rec = await rc.createDHTRecord(const DHTSchema.dflt(oCnt: 2));
expect(await rc.setDHTValue(rec.key, 0, utf8.encode("BLAH BLAH BLAH")), expect(await rc.setDHTValue(rec.key, 0, utf8.encode('BLAH BLAH BLAH')),
isNull); isNull);
final rr = await rc.inspectDHTRecord(rec.key); final rr = await rc.inspectDHTRecord(rec.key);

View File

@ -14,6 +14,7 @@ Future<void> testRoutingContexts() async {
{ {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
final rcp = rc.withDefaultSafety(); final rcp = rc.withDefaultSafety();
// ignore: cascade_invocations
rcp.close(); rcp.close();
rc.close(); rc.close();
} }
@ -21,6 +22,7 @@ Future<void> testRoutingContexts() async {
{ {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
final rcp = rc.withSequencing(Sequencing.ensureOrdered); final rcp = rc.withSequencing(Sequencing.ensureOrdered);
// ignore: cascade_invocations
rcp.close(); rcp.close();
rc.close(); rc.close();
} }
@ -32,6 +34,7 @@ Future<void> testRoutingContexts() async {
hopCount: 2, hopCount: 2,
stability: Stability.lowLatency, stability: Stability.lowLatency,
sequencing: Sequencing.noPreference))); sequencing: Sequencing.noPreference)));
// ignore: cascade_invocations
rcp.close(); rcp.close();
rc.close(); rc.close();
} }
@ -39,6 +42,7 @@ Future<void> testRoutingContexts() async {
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
final rcp = rc.withSafety( final rcp = rc.withSafety(
const SafetySelectionUnsafe(sequencing: Sequencing.preferOrdered)); const SafetySelectionUnsafe(sequencing: Sequencing.preferOrdered));
// ignore: cascade_invocations
rcp.close(); rcp.close();
rc.close(); rc.close();
} }
@ -52,7 +56,7 @@ Future<void> testAppMessageLoopback(Stream<VeilidUpdate> updateStream) async {
} }
}); });
try { try {
await Veilid.instance.debug("purge routes"); await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route // make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
@ -64,7 +68,7 @@ Future<void> testAppMessageLoopback(Stream<VeilidUpdate> updateStream) async {
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob); final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
try { try {
// send an app message to our own private route // send an app message to our own private route
final message = utf8.encode("abcd1234"); final message = utf8.encode('abcd1234');
await rc.appMessage(prr, message); await rc.appMessage(prr, message);
// we should get the same message back // we should get the same message back
@ -82,6 +86,7 @@ Future<void> testAppMessageLoopback(Stream<VeilidUpdate> updateStream) async {
} }
} finally { } finally {
await appMessageSubscription.cancel(); await appMessageSubscription.cancel();
await appMessageQueue.close();
} }
} }
@ -93,7 +98,7 @@ Future<void> testAppCallLoopback(Stream<VeilidUpdate> updateStream) async {
} }
}); });
try { try {
await Veilid.instance.debug("purge routes"); await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route // make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
@ -105,7 +110,7 @@ Future<void> testAppCallLoopback(Stream<VeilidUpdate> updateStream) async {
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob); final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
try { try {
// send an app call to our own private route // send an app call to our own private route
final message = utf8.encode("abcd1234"); final message = utf8.encode('abcd1234');
final appCallFuture = rc.appCall(prr, message); final appCallFuture = rc.appCall(prr, message);
// we should get the same call back // we should get the same call back
@ -116,7 +121,7 @@ Future<void> testAppCallLoopback(Stream<VeilidUpdate> updateStream) async {
expect(update.routeId, isNotNull); expect(update.routeId, isNotNull);
// now we reply to the request // now we reply to the request
final reply = utf8.encode("qwer5678"); final reply = utf8.encode('qwer5678');
await Veilid.instance.appCallReply(appcallid, reply); await Veilid.instance.appCallReply(appcallid, reply);
// now we should get the reply from the call // now we should get the reply from the call
@ -133,6 +138,7 @@ Future<void> testAppCallLoopback(Stream<VeilidUpdate> updateStream) async {
} }
} finally { } finally {
await appMessageSubscription.cancel(); await appMessageSubscription.cancel();
await appCallQueue.close();
} }
} }
@ -150,7 +156,7 @@ Future<void> testAppMessageLoopbackBigPackets(
final cs = await Veilid.instance.bestCryptoSystem(); final cs = await Veilid.instance.bestCryptoSystem();
try { try {
await Veilid.instance.debug("purge routes"); await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route // make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
@ -160,6 +166,8 @@ Future<void> testAppMessageLoopbackBigPackets(
try { try {
// import it as a remote route as well so we can send to it // import it as a remote route as well so we can send to it
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob); final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
final appMessageQueueIterator = StreamIterator(appMessageQueue.stream);
try { try {
for (var i = 0; i < 5; i++) { for (var i = 0; i < 5; i++) {
// send an app message to our own private route // send an app message to our own private route
@ -168,9 +176,6 @@ Future<void> testAppMessageLoopbackBigPackets(
sentMessages.add(base64Url.encode(message)); sentMessages.add(base64Url.encode(message));
} }
final appMessageQueueIterator =
StreamIterator(appMessageQueue.stream);
// we should get the same messages back // we should get the same messages back
for (var i = 0; i < sentMessages.length; i++) { for (var i = 0; i < sentMessages.length; i++) {
if (await appMessageQueueIterator.moveNext()) { if (await appMessageQueueIterator.moveNext()) {
@ -178,10 +183,11 @@ Future<void> testAppMessageLoopbackBigPackets(
expect(sentMessages.contains(base64Url.encode(update.message)), expect(sentMessages.contains(base64Url.encode(update.message)),
isTrue); isTrue);
} else { } else {
fail("not enough messages in the queue"); fail('not enough messages in the queue');
} }
} }
} finally { } finally {
await appMessageQueueIterator.cancel();
await Veilid.instance.releasePrivateRoute(prr); await Veilid.instance.releasePrivateRoute(prr);
} }
} finally { } finally {
@ -192,6 +198,7 @@ Future<void> testAppMessageLoopbackBigPackets(
} }
} finally { } finally {
await appMessageSubscription.cancel(); await appMessageSubscription.cancel();
await appMessageQueue.close();
} }
} }
@ -214,7 +221,7 @@ Future<void> testAppCallLoopbackBigPackets(
final cs = await Veilid.instance.bestCryptoSystem(); final cs = await Veilid.instance.bestCryptoSystem();
try { try {
await Veilid.instance.debug("purge routes"); await Veilid.instance.debug('purge routes');
// make a routing context that uses a safety route // make a routing context that uses a safety route
final rc = await Veilid.instance.routingContext(); final rc = await Veilid.instance.routingContext();
@ -224,6 +231,8 @@ Future<void> testAppCallLoopbackBigPackets(
try { try {
// import it as a remote route as well so we can send to it // import it as a remote route as well so we can send to it
final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob); final prr = await Veilid.instance.importRemotePrivateRoute(prl.blob);
final appMessageQueueIterator = StreamIterator(appCallQueue.stream);
try { try {
for (var i = 0; i < 5; i++) { for (var i = 0; i < 5; i++) {
// send an app message to our own private route // send an app message to our own private route
@ -232,8 +241,6 @@ Future<void> testAppCallLoopbackBigPackets(
expect(message, equals(outmessage)); expect(message, equals(outmessage));
} }
final appMessageQueueIterator = StreamIterator(appCallQueue.stream);
// we should get the same messages back // we should get the same messages back
for (var i = 0; i < sentMessages.length; i++) { for (var i = 0; i < sentMessages.length; i++) {
if (await appMessageQueueIterator.moveNext()) { if (await appMessageQueueIterator.moveNext()) {
@ -241,10 +248,11 @@ Future<void> testAppCallLoopbackBigPackets(
expect(sentMessages.contains(base64Url.encode(update.message)), expect(sentMessages.contains(base64Url.encode(update.message)),
isTrue); isTrue);
} else { } else {
fail("not enough messages in the queue"); fail('not enough messages in the queue');
} }
} }
} finally { } finally {
await appMessageQueueIterator.cancel();
await Veilid.instance.releasePrivateRoute(prr); await Veilid.instance.releasePrivateRoute(prr);
} }
} finally { } finally {

View File

@ -3,8 +3,8 @@ import 'dart:convert';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:veilid/veilid.dart'; import 'package:veilid/veilid.dart';
const testDb = "__dart_test_db"; const testDb = '__dart_test_db';
const testNonexistentDb = "__dart_test_nonexistent_db"; const testNonexistentDb = '__dart_test_nonexistent_db';
Future<void> testDeleteTableDbNonExistent() async { Future<void> testDeleteTableDbNonExistent() async {
expect(await Veilid.instance.deleteTableDB(testNonexistentDb), isFalse); expect(await Veilid.instance.deleteTableDB(testNonexistentDb), isFalse);
@ -16,7 +16,7 @@ Future<void> testOpenDeleteTableDb() async {
final tdb = await Veilid.instance.openTableDB(testDb, 1); final tdb = await Veilid.instance.openTableDB(testDb, 1);
try { try {
await expectLater(() async => await Veilid.instance.deleteTableDB(testDb), await expectLater(() async => Veilid.instance.deleteTableDB(testDb),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} finally { } finally {
tdb.close(); tdb.close();
@ -32,11 +32,11 @@ Future<void> testOpenTwiceTableDb() async {
final tdb2 = await Veilid.instance.openTableDB(testDb, 1); final tdb2 = await Veilid.instance.openTableDB(testDb, 1);
// delete should fail because open // delete should fail because open
await expectLater(() async => await Veilid.instance.deleteTableDB(testDb), await expectLater(() async => Veilid.instance.deleteTableDB(testDb),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
tdb.close(); tdb.close();
// delete should fail because open // delete should fail because open
await expectLater(() async => await Veilid.instance.deleteTableDB(testDb), await expectLater(() async => Veilid.instance.deleteTableDB(testDb),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
tdb2.close(); tdb2.close();
@ -53,10 +53,10 @@ Future<void> testOpenTwiceTableDbStoreLoad() async {
final tdb2 = await Veilid.instance.openTableDB(testDb, 1); final tdb2 = await Veilid.instance.openTableDB(testDb, 1);
try { try {
// store into first db copy // store into first db copy
await tdb.store(0, utf8.encode("asdf"), utf8.encode("1234")); await tdb.store(0, utf8.encode('asdf'), utf8.encode('1234'));
// load from second db copy // load from second db copy
expect( expect(
await tdb2.load(0, utf8.encode("asdf")), equals(utf8.encode("1234"))); await tdb2.load(0, utf8.encode('asdf')), equals(utf8.encode('1234')));
} finally { } finally {
tdb2.close(); tdb2.close();
} }
@ -77,14 +77,14 @@ Future<void> testOpenTwiceTableDbStoreDeleteLoad() async {
final tdb2 = await Veilid.instance.openTableDB(testDb, 1); final tdb2 = await Veilid.instance.openTableDB(testDb, 1);
try { try {
// store into first db copy // store into first db copy
await tdb.store(0, utf8.encode("asdf"), utf8.encode("1234")); await tdb.store(0, utf8.encode('asdf'), utf8.encode('1234'));
// delete from second db copy and clean up // delete from second db copy and clean up
await tdb2.delete(0, utf8.encode("asdf")); await tdb2.delete(0, utf8.encode('asdf'));
} finally { } finally {
tdb2.close(); tdb2.close();
} }
// load from first db copy // load from first db copy
expect(await tdb.load(0, utf8.encode("asdf")), isNull); expect(await tdb.load(0, utf8.encode('asdf')), isNull);
} finally { } finally {
tdb.close(); tdb.close();
} }
@ -100,7 +100,7 @@ Future<void> testResizeTableDb() async {
final tdb = await Veilid.instance.openTableDB(testDb, 1); final tdb = await Veilid.instance.openTableDB(testDb, 1);
try { try {
// reopen the db with more columns should fail if it is already open // reopen the db with more columns should fail if it is already open
await expectLater(() async => await Veilid.instance.openTableDB(testDb, 2), await expectLater(() async => Veilid.instance.openTableDB(testDb, 2),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
} finally { } finally {
tdb.close(); tdb.close();
@ -109,18 +109,18 @@ Future<void> testResizeTableDb() async {
final tdb2 = await Veilid.instance.openTableDB(testDb, 2); final tdb2 = await Veilid.instance.openTableDB(testDb, 2);
try { try {
// write something to second column // write something to second column
await tdb2.store(1, utf8.encode("qwer"), utf8.encode("5678")); await tdb2.store(1, utf8.encode('qwer'), utf8.encode('5678'));
// reopen the db with fewer columns // reopen the db with fewer columns
final tdb3 = await Veilid.instance.openTableDB(testDb, 1); final tdb3 = await Veilid.instance.openTableDB(testDb, 1);
try { try {
// Should fail access to second column // Should fail access to second column
await expectLater(() async => await tdb3.load(1, utf8.encode("qwer")), await expectLater(() async => tdb3.load(1, utf8.encode('qwer')),
throwsA(isA<VeilidAPIException>())); throwsA(isA<VeilidAPIException>()));
// Should succeed with access to second column // Should succeed with access to second column
expect( expect(
await tdb2.load(1, utf8.encode("qwer")), equals(utf8.encode("5678"))); await tdb2.load(1, utf8.encode('qwer')), equals(utf8.encode('5678')));
} finally { } finally {
tdb3.close(); tdb3.close();
} }

View File

@ -3,13 +3,13 @@ import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:veilid/veilid.dart';
import 'package:loggy/loggy.dart'; import 'package:loggy/loggy.dart';
import 'package:veilid_example/veilid_theme.dart'; import 'package:veilid/veilid.dart';
import 'log_terminal.dart';
import 'log.dart';
import 'history_wrapper.dart'; import 'history_wrapper.dart';
import 'log.dart';
import 'log_terminal.dart';
import 'veilid_theme.dart';
// Main App // Main App
class MyApp extends StatefulWidget { class MyApp extends StatefulWidget {
@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> with UiLoggy {
void initState() { void initState() {
super.initState(); super.initState();
initPlatformState(); unawaited(initPlatformState());
} }
// Platform messages are asynchronous, so we initialize in an async method. // Platform messages are asynchronous, so we initialize in an async method.
@ -55,7 +55,9 @@ class _MyAppState extends State<MyApp> with UiLoggy {
// If the widget was removed from the tree while the asynchronous platform // If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling // message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance. // setState to update our non-existent appearance.
if (!mounted) return; if (!mounted) {
return;
}
setState(() { setState(() {
_veilidVersion = veilidVersion; _veilidVersion = veilidVersion;
@ -67,8 +69,7 @@ class _MyAppState extends State<MyApp> with UiLoggy {
Object? error; Object? error;
final backtrace = log.backtrace; final backtrace = log.backtrace;
if (backtrace != null) { if (backtrace != null) {
stackTrace = stackTrace = StackTrace.fromString('$backtrace\n${StackTrace.current}');
StackTrace.fromString("$backtrace\n${StackTrace.current.toString()}");
error = 'embedded stack trace for ${log.logLevel} ${log.message}'; error = 'embedded stack trace for ${log.logLevel} ${log.message}';
} }
@ -92,17 +93,17 @@ class _MyAppState extends State<MyApp> with UiLoggy {
} }
Future<void> processUpdates() async { Future<void> processUpdates() async {
var stream = _updateStream; final stream = _updateStream;
if (stream != null) { if (stream != null) {
await for (final update in stream) { await for (final update in stream) {
if (update is VeilidLog) { if (update is VeilidLog) {
await processLog(update); await processLog(update);
} else if (update is VeilidAppMessage) { } else if (update is VeilidAppMessage) {
loggy.info("AppMessage: ${jsonEncode(update)}"); loggy.info('AppMessage: ${jsonEncode(update)}');
} else if (update is VeilidAppCall) { } else if (update is VeilidAppCall) {
loggy.info("AppCall: ${jsonEncode(update)}"); loggy.info('AppCall: ${jsonEncode(update)}');
} else { } else {
loggy.trace("Update: ${jsonEncode(update)}"); loggy.trace('Update: ${jsonEncode(update)}');
} }
} }
} }
@ -111,21 +112,24 @@ class _MyAppState extends State<MyApp> with UiLoggy {
Future<void> toggleStartup(bool startup) async { Future<void> toggleStartup(bool startup) async {
if (startup && !_startedUp) { if (startup && !_startedUp) {
var config = await getDefaultVeilidConfig( var config = await getDefaultVeilidConfig(
isWeb: kIsWeb, programName: "Veilid Plugin Example"); isWeb: kIsWeb, programName: 'Veilid Plugin Example');
if (const String.fromEnvironment("DELETE_TABLE_STORE") == "1") { // ignore: do_not_use_environment
if (const String.fromEnvironment('DELETE_TABLE_STORE') == '1') {
config = config.copyWith( config = config.copyWith(
tableStore: config.tableStore.copyWith(delete: true)); tableStore: config.tableStore.copyWith(delete: true));
} }
if (const String.fromEnvironment("DELETE_PROTECTED_STORE") == "1") { // ignore: do_not_use_environment
if (const String.fromEnvironment('DELETE_PROTECTED_STORE') == '1') {
config = config.copyWith( config = config.copyWith(
protectedStore: config.protectedStore.copyWith(delete: true)); protectedStore: config.protectedStore.copyWith(delete: true));
} }
if (const String.fromEnvironment("DELETE_BLOCK_STORE") == "1") { // ignore: do_not_use_environment
if (const String.fromEnvironment('DELETE_BLOCK_STORE') == '1') {
config = config.copyWith( config = config.copyWith(
blockStore: config.blockStore.copyWith(delete: true)); blockStore: config.blockStore.copyWith(delete: true));
} }
var updateStream = await Veilid.instance.startupVeilidCore(config); final updateStream = await Veilid.instance.startupVeilidCore(config);
setState(() { setState(() {
_updateStream = updateStream; _updateStream = updateStream;
_updateProcessor = processUpdates(); _updateProcessor = processUpdates();
@ -149,92 +153,90 @@ class _MyAppState extends State<MyApp> with UiLoggy {
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => Scaffold(
return Scaffold( appBar: AppBar(
appBar: AppBar( title: Text('Veilid Plugin Version $_veilidVersion'),
title: Text('Veilid Plugin Version $_veilidVersion'), ),
), body: Column(children: [
body: Column(children: [ const Expanded(child: LogTerminal()),
const Expanded(child: LogTerminal()), Container(
Container( decoration: BoxDecoration(
decoration: BoxDecoration( color: materialBackgroundColor.shade100,
color: materialBackgroundColor.shade100, boxShadow: [
boxShadow: [ BoxShadow(
BoxShadow( color: Colors.black.withOpacity(0.15),
color: Colors.black.withOpacity(0.15), spreadRadius: 4,
spreadRadius: 4, blurRadius: 4,
blurRadius: 4, )
) ]),
]), padding: const EdgeInsets.all(5),
padding: const EdgeInsets.all(5.0), child: Row(children: [
child: Row(children: [ Expanded(
Expanded( child: pad(_debugHistoryWrapper.wrap(
child: pad(_debugHistoryWrapper.wrap( setState,
setState, TextField(
TextField( controller: _debugHistoryWrapper.controller,
controller: _debugHistoryWrapper.controller, decoration: newInputDecoration(
decoration: newInputDecoration( 'Debug Command', _errorText, _startedUp),
'Debug Command', _errorText, _startedUp), textInputAction: TextInputAction.unspecified,
textInputAction: TextInputAction.unspecified, enabled: _startedUp,
enabled: _startedUp, onChanged: (v) {
onChanged: (v) { setState(() {
setState(() { _errorText = null;
_errorText = null; });
}); },
}, onSubmitted: (v) async {
onSubmitted: (String v) async { try {
try { if (v.isEmpty) {
if (v.isEmpty) { return;
return;
}
var res = await Veilid.instance.debug(v);
loggy.info(res);
setState(() {
_debugHistoryWrapper.submit(v);
});
} on VeilidAPIException catch (e) {
setState(() {
_errorText = e.toDisplayError();
});
} }
}), final res = await Veilid.instance.debug(v);
))), loggy.info(res);
pad(
Column(children: [
const Text('Startup'),
Switch(
value: _startedUp,
onChanged: (bool value) async {
await toggleStartup(value);
}),
]),
),
pad(Column(children: [
const Text('Log Level'),
DropdownButton<LogLevel>(
value: loggy.level.logLevel,
onChanged: (LogLevel? newLevel) {
setState(() { setState(() {
setRootLogLevel(newLevel); _debugHistoryWrapper.submit(v);
}); });
}, } on VeilidAPIException catch (e) {
items: const [ setState(() {
DropdownMenuItem<LogLevel>( _errorText = e.toDisplayError();
value: LogLevel.error, child: Text("Error")), });
DropdownMenuItem<LogLevel>( }
value: LogLevel.warning, child: Text("Warning")), }),
DropdownMenuItem<LogLevel>( ))),
value: LogLevel.info, child: Text("Info")), pad(
DropdownMenuItem<LogLevel>( Column(children: [
value: LogLevel.debug, child: Text("Debug")), const Text('Startup'),
DropdownMenuItem<LogLevel>( Switch(
value: traceLevel, child: Text("Trace")), value: _startedUp,
DropdownMenuItem<LogLevel>( onChanged: (value) async {
value: LogLevel.all, child: Text("All")), await toggleStartup(value);
]), }),
])), ]),
]), ),
), pad(Column(children: [
])); const Text('Log Level'),
} DropdownButton<LogLevel>(
value: loggy.level.logLevel,
onChanged: (newLevel) {
setState(() {
setRootLogLevel(newLevel);
});
},
items: const [
DropdownMenuItem<LogLevel>(
value: LogLevel.error, child: Text('Error')),
DropdownMenuItem<LogLevel>(
value: LogLevel.warning, child: Text('Warning')),
DropdownMenuItem<LogLevel>(
value: LogLevel.info, child: Text('Info')),
DropdownMenuItem<LogLevel>(
value: LogLevel.debug, child: Text('Debug')),
DropdownMenuItem<LogLevel>(
value: traceLevel, child: Text('Trace')),
DropdownMenuItem<LogLevel>(
value: LogLevel.all, child: Text('All')),
]),
])),
]),
),
]));
} }

View File

@ -6,11 +6,9 @@ class HistoryWrapper {
final List<String> _history = []; final List<String> _history = [];
int _historyPosition = 0; int _historyPosition = 0;
final _historyTextEditingController = TextEditingController(); final _historyTextEditingController = TextEditingController();
String _historyCurrentEdit = ""; String _historyCurrentEdit = '';
TextEditingController get controller { TextEditingController get controller => _historyTextEditingController;
return _historyTextEditingController;
}
void submit(String v) { void submit(String v) {
// add to history // add to history
@ -21,14 +19,14 @@ class HistoryWrapper {
} }
} }
_historyPosition = _history.length; _historyPosition = _history.length;
_historyTextEditingController.text = ""; _historyTextEditingController.text = '';
} }
Widget wrap( Widget wrap(
void Function(void Function())? stateSetter, TextField textField) { void Function(void Function())? stateSetter, TextField textField) {
void Function(void Function()) setState = stateSetter ?? (x) => x(); final setState = stateSetter ?? (x) => x();
return KeyboardListener( return KeyboardListener(
onKeyEvent: (KeyEvent event) { onKeyEvent: (event) {
setState(() { setState(() {
if (event.runtimeType == KeyDownEvent && if (event.runtimeType == KeyDownEvent &&
event.logicalKey == LogicalKeyboardKey.arrowUp) { event.logicalKey == LogicalKeyboardKey.arrowUp) {
@ -55,7 +53,7 @@ class HistoryWrapper {
} }
}); });
}, },
focusNode: FocusNode(onKeyEvent: (FocusNode node, KeyEvent event) { focusNode: FocusNode(onKeyEvent: (node, event) {
if (event.logicalKey == LogicalKeyboardKey.arrowDown || if (event.logicalKey == LogicalKeyboardKey.arrowDown ||
event.logicalKey == LogicalKeyboardKey.arrowUp) { event.logicalKey == LogicalKeyboardKey.arrowUp) {
return KeyEventResult.handled; return KeyEventResult.handled;

View File

@ -1,3 +1,5 @@
// ignore_for_file: prefer_single_quotes
import 'package:ansicolor/ansicolor.dart'; import 'package:ansicolor/ansicolor.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';

View File

@ -17,39 +17,39 @@ class LogTerminal extends StatefulWidget {
} }
class _LogTerminalState extends State<LogTerminal> { class _LogTerminalState extends State<LogTerminal> {
final terminal = Terminal( final _terminal = Terminal(
maxLines: 10000, maxLines: 10000,
); );
final terminalController = TerminalController(); final _terminalController = TerminalController();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
terminal.setLineFeedMode(true); _terminal.setLineFeedMode(true);
globalTerminalPrinter.setCallback((log) { globalTerminalPrinter.setCallback((log) {
terminal.write('${log.pretty()}\n'); _terminal.write('${log.pretty()}\n');
}); });
} }
@override @override
Widget build(BuildContext context) => TerminalView( Widget build(BuildContext context) => TerminalView(
terminal, _terminal,
textStyle: kDefaultTerminalStyle, textStyle: kDefaultTerminalStyle,
controller: terminalController, controller: _terminalController,
autofocus: true, autofocus: true,
backgroundOpacity: 0.9, backgroundOpacity: 0.9,
onSecondaryTapDown: (details, offset) async { onSecondaryTapDown: (details, offset) async {
final selection = terminalController.selection; final selection = _terminalController.selection;
if (selection != null) { if (selection != null) {
final text = terminal.buffer.getText(selection); final text = _terminal.buffer.getText(selection);
terminalController.clearSelection(); _terminalController.clearSelection();
await Clipboard.setData(ClipboardData(text: text)); await Clipboard.setData(ClipboardData(text: text));
} else { } else {
final data = await Clipboard.getData('text/plain'); final data = await Clipboard.getData('text/plain');
final text = data?.text; final text = data?.text;
if (text != null) { if (text != null) {
terminal.paste(text); _terminal.paste(text);
} }
} }
}, },

View File

@ -1,32 +1,9 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'veilid_theme.dart';
import 'log.dart';
import 'app.dart'; import 'app.dart';
import 'log.dart';
import 'veilid_init.dart'; import 'veilid_init.dart';
import 'veilid_theme.dart';
/////////////////////////////// Acrylic
bool get isDesktop {
if (kIsWeb) return false;
return [
TargetPlatform.windows,
TargetPlatform.linux,
TargetPlatform.macOS,
].contains(defaultTargetPlatform);
}
Future<void> setupAcrylic() async {
await Window.initialize();
await Window.makeTitlebarTransparent();
await Window.setEffect(
effect: WindowEffect.aero, color: const Color(0xFFFFFFFF));
await Window.setBlurViewState(MacOSBlurViewState.active);
}
/////////////////////////////// Entrypoint /////////////////////////////// Entrypoint
void main() { void main() {

View File

@ -5,7 +5,7 @@ import 'package:veilid/veilid.dart';
// Call only once. // Call only once.
void veilidInit() { void veilidInit() {
if (kIsWeb) { if (kIsWeb) {
var platformConfig = const VeilidWASMConfig( const platformConfig = VeilidWASMConfig(
logging: VeilidWASMConfigLogging( logging: VeilidWASMConfigLogging(
performance: VeilidWASMConfigLoggingPerformance( performance: VeilidWASMConfigLoggingPerformance(
enabled: true, enabled: true,
@ -16,7 +16,7 @@ void veilidInit() {
enabled: true, level: VeilidConfigLogLevel.info))); enabled: true, level: VeilidConfigLogLevel.info)));
Veilid.instance.initializeVeilidCore(platformConfig.toJson()); Veilid.instance.initializeVeilidCore(platformConfig.toJson());
} else { } else {
var platformConfig = const VeilidFFIConfig( const platformConfig = VeilidFFIConfig(
logging: VeilidFFIConfigLogging( logging: VeilidFFIConfigLogging(
terminal: VeilidFFIConfigLoggingTerminal( terminal: VeilidFFIConfigLoggingTerminal(
enabled: false, enabled: false,
@ -25,8 +25,8 @@ void veilidInit() {
otlp: VeilidFFIConfigLoggingOtlp( otlp: VeilidFFIConfigLoggingOtlp(
enabled: false, enabled: false,
level: VeilidConfigLogLevel.trace, level: VeilidConfigLogLevel.trace,
grpcEndpoint: "localhost:4317", grpcEndpoint: 'localhost:4317',
serviceName: "VeilidExample"), serviceName: 'VeilidExample'),
api: VeilidFFIConfigLoggingApi( api: VeilidFFIConfigLoggingApi(
enabled: true, level: VeilidConfigLogLevel.info))); enabled: true, level: VeilidConfigLogLevel.info)));
Veilid.instance.initializeVeilidCore(platformConfig.toJson()); Veilid.instance.initializeVeilidCore(platformConfig.toJson());

View File

@ -241,62 +241,49 @@ const MaterialColor materialPopComplementaryColor =
const kDefaultSpacingFactor = 4.0; const kDefaultSpacingFactor = 4.0;
const kDefaultMonoTerminalFontFamily = "Fira Code"; const kDefaultMonoTerminalFontFamily = 'Fira Code';
const kDefaultMonoTerminalFontHeight = 1.2; const kDefaultMonoTerminalFontHeight = 1.2;
const kDefaultMonoTerminalFontSize = 12.0; const kDefaultMonoTerminalFontSize = 12.0;
double spacingFactor(double multiplier) { double spacingFactor(double multiplier) => multiplier * kDefaultSpacingFactor;
return multiplier * kDefaultSpacingFactor;
}
Padding pad(Widget child) { Padding pad(Widget child) =>
return Padding( Padding(padding: const EdgeInsets.all(kDefaultSpacingFactor), child: child);
padding: const EdgeInsets.all(kDefaultSpacingFactor), child: child);
}
///////////////////////////////////////////////////////// /////////////////////////////////////////////////////////
// Theme // Theme
InputDecoration newInputDecoration( InputDecoration newInputDecoration(
String labelText, String? errorText, bool enabled) { String labelText, String? errorText, bool enabled) =>
return InputDecoration( InputDecoration(
labelText: labelText, labelText: labelText,
errorText: errorText, errorText: errorText,
filled: !enabled, filled: !enabled,
fillColor: materialPrimaryColor.shade300.withOpacity(0.1)); fillColor: materialPrimaryColor.shade300.withOpacity(0.1));
}
InputDecorationTheme newInputDecorationTheme() { InputDecorationTheme newInputDecorationTheme() => InputDecorationTheme(
return InputDecorationTheme( border: OutlineInputBorder(
border: OutlineInputBorder( borderSide: BorderSide(color: materialPrimaryColor.shade300)),
borderSide: disabledBorder: OutlineInputBorder(
BorderSide(color: materialPrimaryColor.shade300, width: 1.0)), borderSide: BorderSide(color: materialPrimaryColor.shade600)),
disabledBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: borderSide: BorderSide(color: materialPrimaryColor.shade900)),
BorderSide(color: materialPrimaryColor.shade600, width: 1.0)), errorBorder: OutlineInputBorder(
focusedBorder: OutlineInputBorder( borderSide: BorderSide(color: materialPopColor.shade800)),
borderSide: focusedErrorBorder: OutlineInputBorder(
BorderSide(color: materialPrimaryColor.shade900, width: 1.0)), borderSide: BorderSide(color: materialPopColor.shade600)),
errorBorder: OutlineInputBorder( errorStyle: TextStyle(
borderSide: BorderSide(color: materialPopColor.shade800, width: 1.0)), color: materialPopColor.shade600,
focusedErrorBorder: OutlineInputBorder( letterSpacing: 1.1,
borderSide: BorderSide(color: materialPopColor.shade600, width: 1.0)), ),
errorStyle: TextStyle( floatingLabelStyle: TextStyle(
color: materialPopColor.shade600, color: materialPrimaryColor.shade900,
letterSpacing: 1.1, letterSpacing: 1.1,
), ));
floatingLabelBehavior: FloatingLabelBehavior.auto,
floatingLabelStyle: TextStyle(
color: materialPrimaryColor.shade900,
letterSpacing: 1.1,
));
}
ThemeData newVeilidTheme() { ThemeData newVeilidTheme() => ThemeData(
return ThemeData( primarySwatch: materialPrimaryColor,
primarySwatch: materialPrimaryColor, secondaryHeaderColor: materialSecondaryColor,
secondaryHeaderColor: materialSecondaryColor, visualDensity: VisualDensity.adaptivePlatformDensity,
visualDensity: VisualDensity.adaptivePlatformDensity, inputDecorationTheme: newInputDecorationTheme(),
inputDecorationTheme: newInputDecorationTheme(), );
);
}

View File

@ -425,10 +425,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = XP5LBLT7M7;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -559,10 +559,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = XP5LBLT7M7;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
@ -587,10 +587,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = XP5LBLT7M7;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",

View File

@ -6,11 +6,15 @@
<true/> <true/>
<key>com.apple.security.cs.allow-jit</key> <key>com.apple.security.cs.allow-jit</key>
<true/> <true/>
<key>com.apple.security.network.server</key> <key>com.apple.security.files.user-selected.read-write</key>
<true/> <true/>
<key>com.apple.security.network.client</key> <key>com.apple.security.network.client</key>
<true/> <true/>
<key>com.apple.security.files.user-selected.read-write</key> <key>com.apple.security.network.server</key>
<true/> <true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.veilid.example</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -4,11 +4,15 @@
<dict> <dict>
<key>com.apple.security.app-sandbox</key> <key>com.apple.security.app-sandbox</key>
<true/> <true/>
<key>com.apple.security.network.server</key> <key>com.apple.security.files.user-selected.read-write</key>
<true/> <true/>
<key>com.apple.security.network.client</key> <key>com.apple.security.network.client</key>
<true/> <true/>
<key>com.apple.security.files.user-selected.read-write</key> <key>com.apple.security.network.server</key>
<true/> <true/>
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.veilid.example</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@ -3,7 +3,8 @@ import 'dart:async';
import 'package:async_tools/async_tools.dart'; import 'package:async_tools/async_tools.dart';
import 'package:veilid/veilid.dart'; import 'package:veilid/veilid.dart';
bool kIsWeb = bool.fromEnvironment('dart.library.js_util'); // ignore: do_not_use_environment
bool kIsWeb = const bool.fromEnvironment('dart.library.js_util');
abstract class VeilidFixture { abstract class VeilidFixture {
Future<void> setUp(); Future<void> setUp();
@ -18,8 +19,7 @@ class DefaultVeilidFixture implements VeilidFixture {
StreamSubscription<VeilidUpdate>? _veilidUpdateSubscription; StreamSubscription<VeilidUpdate>? _veilidUpdateSubscription;
Stream<VeilidUpdate>? _veilidUpdateStream; Stream<VeilidUpdate>? _veilidUpdateStream;
final StreamController<VeilidUpdate> _updateStreamController = late final StreamController<VeilidUpdate> _updateStreamController;
StreamController.broadcast();
static final _fixtureMutex = Mutex(); static final _fixtureMutex = Mutex();
final String programName; final String programName;
@ -27,9 +27,10 @@ class DefaultVeilidFixture implements VeilidFixture {
@override @override
Future<void> setUp() async { Future<void> setUp() async {
await _fixtureMutex.acquire(); await _fixtureMutex.acquire();
assert(_veilidUpdateStream == null, 'should not set up fixture twice'); assert(_veilidUpdateStream == null, 'should not set up fixture twice');
_updateStreamController = StreamController.broadcast();
final ignoreLogTargetsStr = final ignoreLogTargetsStr =
// ignore: do_not_use_environment // ignore: do_not_use_environment
const String.fromEnvironment('IGNORE_LOG_TARGETS').trim(); const String.fromEnvironment('IGNORE_LOG_TARGETS').trim();
@ -163,6 +164,8 @@ class DefaultVeilidFixture implements VeilidFixture {
await Veilid.instance.shutdownVeilidCore(); await Veilid.instance.shutdownVeilidCore();
await cancelFut; await cancelFut;
await _updateStreamController.close();
_veilidUpdateSubscription = null; _veilidUpdateSubscription = null;
_veilidUpdateStream = null; _veilidUpdateStream = null;