From 340c243b382322c45365a8801da782d779946e99 Mon Sep 17 00:00:00 2001 From: xavierchanth Date: Sat, 16 Nov 2024 17:03:48 -0500 Subject: [PATCH] feat: add support for local cache to at_cli --- packages/at_cli/README.md | 12 +- packages/at_cli/bin/main.dart | 7 ++ packages/at_cli/lib/src/at_cli.dart | 116 ++++++++++++++---- .../at_cli/lib/src/command_line_parser.dart | 2 + packages/at_cli/lib/src/config_util.dart | 4 + packages/at_cli/lib/src/preference.dart | 2 + 6 files changed, 115 insertions(+), 28 deletions(-) diff --git a/packages/at_cli/README.md b/packages/at_cli/README.md index b86fb3c4..210b13d8 100644 --- a/packages/at_cli/README.md +++ b/packages/at_cli/README.md @@ -157,4 +157,14 @@ The "plookup" verb, provides a proxied public lookups for a resolver that perhap # Sample output india -``` \ No newline at end of file +``` + +__sync__ + +Sync is not actually a verb, but allows you to pull a namespace to the +local cache to increase performance of batched requests. + +``` +# Requires both cache and authentication to be enabled +dart run bin/main.dart -v scan -r +``` diff --git a/packages/at_cli/bin/main.dart b/packages/at_cli/bin/main.dart index a91f75b5..70751393 100644 --- a/packages/at_cli/bin/main.dart +++ b/packages/at_cli/bin/main.dart @@ -73,5 +73,12 @@ Future _getAtCliPreference(ArgResults? parsedArgs) async { ? parsedArgs['authKeyFile'] : ConfigUtil.getYaml()!['auth']['key_file_location']); + if (preferences.authRequired) { + preferences.cache = + parsedArgs['cache'] ?? ConfigUtil.getYaml()!['cache']['enabled']; + + preferences.cacheDir = + parsedArgs['cache-dir'] ?? ConfigUtil.getYaml()!['cache']['directory']; + } return preferences; } diff --git a/packages/at_cli/lib/src/at_cli.dart b/packages/at_cli/lib/src/at_cli.dart index 3b6aa0f2..edf664db 100644 --- a/packages/at_cli/lib/src/at_cli.dart +++ b/packages/at_cli/lib/src/at_cli.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'dart:io'; +import 'dart:async'; import 'dart:typed_data'; import 'package:args/args.dart'; import 'package:at_cli/src/command_line_parser.dart'; @@ -72,9 +73,15 @@ class AtCli { 'Invalid command \n ${CommandLineParser.getUsage()}'); } var command = builder.buildCommand(); - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: true); + if (atCliPreference.authRequired && atCliPreference.cache) { + result = await _atClientImpl! + .getLocalSecondary()! + .executeVerb(builder, sync: true); + } else { + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: auth); + } break; case 'llookup': var builder = LLookupVerbBuilder(); @@ -90,9 +97,15 @@ class AtCli { 'Invalid command \n ${CommandLineParser.getUsage()}'); } var command = builder.buildCommand(); - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: true); + if (atCliPreference.authRequired && atCliPreference.cache) { + result = await _atClientImpl! + .getLocalSecondary()! + .executeVerb(builder, sync: true); + } else { + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: auth); + } break; case 'lookup': var builder = LookupVerbBuilder(); @@ -105,9 +118,15 @@ class AtCli { 'Invalid command \n ${CommandLineParser.getUsage()}'); } var command = builder.buildCommand(); - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: true); + if (atCliPreference.authRequired && atCliPreference.cache) { + result = await _atClientImpl! + .getLocalSecondary()! + .executeVerb(builder, sync: true); + } else { + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: auth); + } break; case 'plookup': var builder = PLookupVerbBuilder(); @@ -120,9 +139,15 @@ class AtCli { 'Invalid command \n ${CommandLineParser.getUsage()}'); } var command = builder.buildCommand(); - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: true); + if (atCliPreference.authRequired && atCliPreference.cache) { + result = await _atClientImpl! + .getLocalSecondary()! + .executeVerb(builder, sync: true); + } else { + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: auth); + } break; case 'delete': var builder = DeleteVerbBuilder(); @@ -137,9 +162,15 @@ class AtCli { 'Invalid command \n ${CommandLineParser.getUsage()}'); } var command = builder.buildCommand(); - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: true); + if (atCliPreference.authRequired && atCliPreference.cache) { + result = await _atClientImpl! + .getLocalSecondary()! + .executeVerb(builder, sync: true); + } else { + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: auth); + } break; case 'scan': var builder = ScanVerbBuilder(); @@ -150,9 +181,27 @@ class AtCli { throw Exception( 'Invalid command \n ${CommandLineParser.getUsage()}'); } - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: auth); + if (atCliPreference.authRequired && atCliPreference.cache) { + result = await _atClientImpl! + .getLocalSecondary()! + .executeVerb(builder, sync: true); + } else { + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: auth); + } + break; + case 'sync': + if (atCliPreference.authRequired && atCliPreference.cache) { + Completer completer = Completer(); + var prefs = _atClientImpl!.getPreferences() ?? AtClientPreference(); + prefs.namespace = arguments['regex']; + _atClientImpl!.setPreferences(prefs); + _atClientImpl!.syncService + .addProgressListener(ProgressListener(completer)); + _atClientImpl!.syncService.sync(); + result = (await completer.future).toString(); + } break; } return result; @@ -170,14 +219,9 @@ class AtCli { dynamic result; try { command = command + '\n'; - if (isAuth) { - result = await _atClientImpl! - .getRemoteSecondary()! - .executeCommand(command, auth: true); - } else { - result = - await _atClientImpl!.getRemoteSecondary()!.executeCommand(command); - } + result = await _atClientImpl! + .getRemoteSecondary()! + .executeCommand(command, auth: isAuth); } on Exception { rethrow; } @@ -214,10 +258,28 @@ class AtCli { AtClientPreference _getAtClientPreference( String privateKey, AtCliPreference atCliPreference) { var preference = AtClientPreference(); - preference.isLocalStoreRequired = false; + preference.isLocalStoreRequired = atCliPreference.cache; + if (atCliPreference.cache) { + preference.hiveStoragePath = atCliPreference.cacheDir; + preference.commitLogPath = atCliPreference.cacheDir; + } + preference.privateKey = preference.rootDomain = atCliPreference.rootDomain; preference.outboundConnectionTimeout = 60000; preference.privateKey = privateKey; return preference; } } + +class ProgressListener extends SyncProgressListener { + final Completer completer; + ProgressListener(this.completer); + + @override + void onSyncProgressEvent(SyncProgress syncProgress) { + if (syncProgress.syncStatus == SyncStatus.success || + syncProgress.syncStatus == SyncStatus.failure) { + completer.complete(syncProgress.syncStatus == SyncStatus.success); + } + } +} diff --git a/packages/at_cli/lib/src/command_line_parser.dart b/packages/at_cli/lib/src/command_line_parser.dart index 53544386..a29fdb78 100644 --- a/packages/at_cli/lib/src/command_line_parser.dart +++ b/packages/at_cli/lib/src/command_line_parser.dart @@ -36,6 +36,8 @@ class CommandLineParser { abbr: 'w', help: 'atsign to whom key is shared'); parser.addOption('shared_by', abbr: 'b', help: 'atsign who shared the key'); parser.addOption('regex', abbr: 'r', help: 'regex for scan'); + parser.addFlag('cache', help: 'enable storage cache'); + parser.addOption('cache-dir', help: 'directory to store cache'); try { if (arguments.isNotEmpty) { diff --git a/packages/at_cli/lib/src/config_util.dart b/packages/at_cli/lib/src/config_util.dart index 8bede669..5104a048 100644 --- a/packages/at_cli/lib/src/config_util.dart +++ b/packages/at_cli/lib/src/config_util.dart @@ -79,5 +79,9 @@ String defaultConfigYaml = YAMLWriter().write( 'key_file_location': '~/.atsign/keys/@alice.atKeys', 'at_sign': '@alice', }, + 'cache': { + 'enabled': false, + 'directory': '~/.atsign/at_cli/storage/@alice', + } }, ); diff --git a/packages/at_cli/lib/src/preference.dart b/packages/at_cli/lib/src/preference.dart index 60c026bb..c31833c3 100644 --- a/packages/at_cli/lib/src/preference.dart +++ b/packages/at_cli/lib/src/preference.dart @@ -5,4 +5,6 @@ class AtCliPreference { late String authMode; late String authKeyFile; String namespace = ''; + bool cache = false; + String? cacheDir; }