xfer
This commit is contained in:
		| @@ -101,9 +101,11 @@ impl TableStore { | ||||
|         let db = Database::open(table_name.clone(), column_count) | ||||
|             .await | ||||
|             .wrap_err("failed to open tabledb")?; | ||||
|         info!( | ||||
|         trace!( | ||||
|             "opened table store '{}' with table name '{:?}' with {} columns", | ||||
|             name, table_name, column_count | ||||
|             name, | ||||
|             table_name, | ||||
|             column_count | ||||
|         ); | ||||
|  | ||||
|         let table_db = TableDB::new(table_name.clone(), self.clone(), db); | ||||
|   | ||||
| @@ -445,6 +445,10 @@ impl VeilidAPI { | ||||
|                 Ok("Connections purged".to_owned()) | ||||
|             } else if args[0] == "routes" { | ||||
|                 // Purge route spec store | ||||
|                 { | ||||
|                     let mut dc = DEBUG_CACHE.lock(); | ||||
|                     dc.imported_routes.clear(); | ||||
|                 } | ||||
|                 let rss = self.network_manager()?.routing_table().route_spec_store(); | ||||
|                 match rss.purge().await { | ||||
|                     Ok(_) => Ok("Routes purged".to_owned()), | ||||
| @@ -865,12 +869,9 @@ impl VeilidAPI { | ||||
|             } else if arg == "route" { | ||||
|                 self.debug_route(rest).await | ||||
|             } else { | ||||
|                 Ok(">>> Unknown command\n".to_owned()) | ||||
|                 Err(VeilidAPIError::generic("Unknown debug command")) | ||||
|             } | ||||
|         }; | ||||
|         // if let Ok(res) = &res { | ||||
|         //     debug!("{}", res); | ||||
|         // } | ||||
|         res | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import 'dart:async'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:veilid/veilid.dart'; | ||||
| import 'package:loggy/loggy.dart'; | ||||
| import 'package:veilid_example/veilid_theme.dart'; | ||||
| @@ -8,6 +9,7 @@ import 'package:veilid_example/veilid_theme.dart'; | ||||
| import 'log_terminal.dart'; | ||||
| import 'config.dart'; | ||||
| import 'log.dart'; | ||||
| import 'history_wrapper.dart'; | ||||
|  | ||||
| // Main App | ||||
| class MyApp extends StatefulWidget { | ||||
| @@ -22,6 +24,8 @@ class _MyAppState extends State<MyApp> with UiLoggy { | ||||
|   bool _startedUp = false; | ||||
|   Stream<VeilidUpdate>? _updateStream; | ||||
|   Future<void>? _updateProcessor; | ||||
|   final _debugHistoryWrapper = HistoryWrapper(); | ||||
|   String? _errorText; | ||||
|  | ||||
|   @override | ||||
|   void initState() { | ||||
| @@ -136,7 +140,9 @@ class _MyAppState extends State<MyApp> with UiLoggy { | ||||
|         body: Column(children: [ | ||||
|           const Expanded(child: LogTerminal()), | ||||
|           Container( | ||||
|             decoration: BoxDecoration(color: materialPrimaryColor, boxShadow: [ | ||||
|             decoration: BoxDecoration( | ||||
|                 color: materialBackgroundColor.shade100, | ||||
|                 boxShadow: [ | ||||
|                   BoxShadow( | ||||
|                     color: Colors.black.withOpacity(0.15), | ||||
|                     spreadRadius: 4, | ||||
| @@ -146,21 +152,46 @@ class _MyAppState extends State<MyApp> with UiLoggy { | ||||
|             padding: const EdgeInsets.all(5.0), | ||||
|             child: Row(children: [ | ||||
|               Expanded( | ||||
|                   child: pad(TextField( | ||||
|                       decoration: | ||||
|                           newInputDecoration('Debug Command', _startedUp), | ||||
|                       textInputAction: TextInputAction.send, | ||||
|                   child: pad(_debugHistoryWrapper.wrap( | ||||
|                 setState, | ||||
|                 TextField( | ||||
|                     controller: _debugHistoryWrapper.controller, | ||||
|                     decoration: newInputDecoration( | ||||
|                         'Debug Command', _errorText, _startedUp), | ||||
|                     textInputAction: TextInputAction.unspecified, | ||||
|                     enabled: _startedUp, | ||||
|                     onChanged: (v) { | ||||
|                       setState(() { | ||||
|                         _errorText = null; | ||||
|                       }); | ||||
|                     }, | ||||
|                     onSubmitted: (String v) async { | ||||
|                         loggy.info(await Veilid.instance.debug(v)); | ||||
|                       }))), | ||||
|               pad(const Text('Startup')), | ||||
|               pad(Switch( | ||||
|                       try { | ||||
|                         var res = await Veilid.instance.debug(v); | ||||
|                         loggy.info(res); | ||||
|                         setState(() { | ||||
|                           _debugHistoryWrapper.submit(v); | ||||
|                         }); | ||||
|                       } on VeilidAPIException catch (e) { | ||||
|                         setState(() { | ||||
|                           _errorText = e.toDisplayError(); | ||||
|                         }); | ||||
|                       } | ||||
|                     }), | ||||
|               ))), | ||||
|               pad( | ||||
|                 Column(children: [ | ||||
|                   const Text('Startup'), | ||||
|                   Switch( | ||||
|                       value: _startedUp, | ||||
|                       onChanged: (bool value) async { | ||||
|                         await toggleStartup(value); | ||||
|                   })), | ||||
|               pad(DropdownButton<LogLevel>( | ||||
|                       }), | ||||
|                 ]), | ||||
|               ), | ||||
|               pad(Column(children: [ | ||||
|                 const Text('Log Level'), | ||||
|                 DropdownButton<LogLevel>( | ||||
|                     value: loggy.level.logLevel, | ||||
|                     onChanged: (LogLevel? newLevel) { | ||||
|                       setState(() { | ||||
| @@ -180,6 +211,7 @@ class _MyAppState extends State<MyApp> with UiLoggy { | ||||
|                           value: traceLevel, child: Text("Trace")), | ||||
|                       DropdownMenuItem<LogLevel>( | ||||
|                           value: LogLevel.all, child: Text("All")), | ||||
|                     ]), | ||||
|               ])), | ||||
|             ]), | ||||
|           ), | ||||
|   | ||||
							
								
								
									
										68
									
								
								veilid-flutter/example/lib/history_wrapper.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								veilid-flutter/example/lib/history_wrapper.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,68 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
|  | ||||
| // TextField History Wrapper | ||||
| class HistoryWrapper { | ||||
|   final List<String> _history = []; | ||||
|   int _historyPosition = 0; | ||||
|   final _historyTextEditingController = TextEditingController(); | ||||
|   String _historyCurrentEdit = ""; | ||||
|  | ||||
|   TextEditingController get controller { | ||||
|     return _historyTextEditingController; | ||||
|   } | ||||
|  | ||||
|   void submit(String v) { | ||||
|     // add to history | ||||
|     if (_history.isEmpty || _history.last != v) { | ||||
|       _history.add(v); | ||||
|       if (_history.length > 100) { | ||||
|         _history.removeAt(0); | ||||
|       } | ||||
|     } | ||||
|     _historyPosition = _history.length; | ||||
|     _historyTextEditingController.text = ""; | ||||
|   } | ||||
|  | ||||
|   Widget wrap( | ||||
|       void Function(void Function())? stateSetter, TextField textField) { | ||||
|     void Function(void Function()) setState = stateSetter ?? (x) => x(); | ||||
|     return KeyboardListener( | ||||
|       onKeyEvent: (KeyEvent event) { | ||||
|         setState(() { | ||||
|           if (event.runtimeType == KeyDownEvent && | ||||
|               event.logicalKey == LogicalKeyboardKey.arrowUp) { | ||||
|             if (_historyPosition > 0) { | ||||
|               if (_historyPosition == _history.length) { | ||||
|                 _historyCurrentEdit = _historyTextEditingController.text; | ||||
|               } | ||||
|               _historyPosition -= 1; | ||||
|               _historyTextEditingController.text = _history[_historyPosition]; | ||||
|             } | ||||
|           } else if (event.runtimeType == KeyDownEvent && | ||||
|               event.logicalKey == LogicalKeyboardKey.arrowDown) { | ||||
|             if (_historyPosition < _history.length) { | ||||
|               _historyPosition += 1; | ||||
|               if (_historyPosition == _history.length) { | ||||
|                 _historyTextEditingController.text = _historyCurrentEdit; | ||||
|               } else { | ||||
|                 _historyTextEditingController.text = _history[_historyPosition]; | ||||
|               } | ||||
|             } | ||||
|           } else if (event.runtimeType == KeyDownEvent) { | ||||
|             _historyPosition = _history.length; | ||||
|             _historyCurrentEdit = _historyTextEditingController.text; | ||||
|           } | ||||
|         }); | ||||
|       }, | ||||
|       focusNode: FocusNode(onKey: (FocusNode node, RawKeyEvent event) { | ||||
|         if (event.logicalKey == LogicalKeyboardKey.arrowDown || | ||||
|             event.logicalKey == LogicalKeyboardKey.arrowUp) { | ||||
|           return KeyEventResult.handled; | ||||
|         } | ||||
|         return KeyEventResult.ignored; | ||||
|       }), | ||||
|       child: textField, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -257,29 +257,38 @@ Padding pad(Widget child) { | ||||
| ///////////////////////////////////////////////////////// | ||||
| // Theme | ||||
|  | ||||
| InputDecoration newInputDecoration(String labelText, bool enabled) { | ||||
| InputDecoration newInputDecoration( | ||||
|     String labelText, String? errorText, bool enabled) { | ||||
|   return InputDecoration( | ||||
|       labelText: labelText, | ||||
|       fillColor: enabled | ||||
|           ? materialPrimaryColor.shade200 | ||||
|           : materialPrimaryColor.shade200.withOpacity(0.5)); | ||||
|       errorText: errorText, | ||||
|       filled: !enabled, | ||||
|       fillColor: materialPrimaryColor.shade300.withOpacity(0.1)); | ||||
| } | ||||
|  | ||||
| InputDecorationTheme newInputDecorationTheme() { | ||||
|   return InputDecorationTheme( | ||||
|       border: const OutlineInputBorder(), | ||||
|       filled: true, | ||||
|       fillColor: materialPrimaryColor.shade200, | ||||
|       disabledBorder: const OutlineInputBorder( | ||||
|       border: OutlineInputBorder( | ||||
|           borderSide: | ||||
|               BorderSide(color: Color.fromARGB(0, 0, 0, 0), width: 0.0)), | ||||
|               BorderSide(color: materialPrimaryColor.shade300, width: 1.0)), | ||||
|       disabledBorder: OutlineInputBorder( | ||||
|           borderSide: | ||||
|               BorderSide(color: materialPrimaryColor.shade600, width: 1.0)), | ||||
|       focusedBorder: OutlineInputBorder( | ||||
|           borderSide: | ||||
|               BorderSide(color: materialPrimaryColor.shade900, width: 0.0)), | ||||
|       floatingLabelBehavior: FloatingLabelBehavior.never, | ||||
|               BorderSide(color: materialPrimaryColor.shade900, width: 1.0)), | ||||
|       errorBorder: OutlineInputBorder( | ||||
|           borderSide: BorderSide(color: materialPopColor.shade800, width: 1.0)), | ||||
|       focusedErrorBorder: OutlineInputBorder( | ||||
|           borderSide: BorderSide(color: materialPopColor.shade600, width: 1.0)), | ||||
|       errorStyle: TextStyle( | ||||
|         color: materialPopColor.shade600, | ||||
|         letterSpacing: 1.1, | ||||
|       ), | ||||
|       floatingLabelBehavior: FloatingLabelBehavior.auto, | ||||
|       floatingLabelStyle: TextStyle( | ||||
|         color: materialPrimaryColor.shade900, | ||||
|         letterSpacing: 1.2, | ||||
|         letterSpacing: 1.1, | ||||
|       )); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import 'dart:async'; | ||||
| import 'dart:html'; | ||||
| import 'dart:typed_data'; | ||||
| import 'dart:convert'; | ||||
|  | ||||
| @@ -1571,6 +1572,8 @@ abstract class VeilidAPIException implements Exception { | ||||
|         } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String toDisplayError(); | ||||
| } | ||||
|  | ||||
| class VeilidAPIExceptionNotInitialized implements VeilidAPIException { | ||||
| @@ -1578,6 +1581,11 @@ class VeilidAPIExceptionNotInitialized implements VeilidAPIException { | ||||
|   String toString() { | ||||
|     return "VeilidAPIException: NotInitialized"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Not initialized"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class VeilidAPIExceptionAlreadyInitialized implements VeilidAPIException { | ||||
| @@ -1585,6 +1593,11 @@ class VeilidAPIExceptionAlreadyInitialized implements VeilidAPIException { | ||||
|   String toString() { | ||||
|     return "VeilidAPIException: AlreadyInitialized"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Already initialized"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class VeilidAPIExceptionTimeout implements VeilidAPIException { | ||||
| @@ -1592,6 +1605,11 @@ class VeilidAPIExceptionTimeout implements VeilidAPIException { | ||||
|   String toString() { | ||||
|     return "VeilidAPIException: Timeout"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Timeout"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class VeilidAPIExceptionShutdown implements VeilidAPIException { | ||||
| @@ -1599,6 +1617,11 @@ class VeilidAPIExceptionShutdown implements VeilidAPIException { | ||||
|   String toString() { | ||||
|     return "VeilidAPIException: Shutdown"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Currently shut down"; | ||||
|   } | ||||
| } | ||||
|  | ||||
| class VeilidAPIExceptionNodeNotFound implements VeilidAPIException { | ||||
| @@ -1609,6 +1632,11 @@ class VeilidAPIExceptionNodeNotFound implements VeilidAPIException { | ||||
|     return "VeilidAPIException: NodeNotFound (nodeId: $nodeId)"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Node node found: $nodeId"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionNodeNotFound(this.nodeId); | ||||
| } | ||||
| @@ -1621,6 +1649,11 @@ class VeilidAPIExceptionNoDialInfo implements VeilidAPIException { | ||||
|     return "VeilidAPIException: NoDialInfo (nodeId: $nodeId)"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "No dial info: $nodeId"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionNoDialInfo(this.nodeId); | ||||
| } | ||||
| @@ -1633,6 +1666,11 @@ class VeilidAPIExceptionInternal implements VeilidAPIException { | ||||
|     return "VeilidAPIException: Internal ($message)"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Internal error: $message"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionInternal(this.message); | ||||
| } | ||||
| @@ -1645,6 +1683,11 @@ class VeilidAPIExceptionUnimplemented implements VeilidAPIException { | ||||
|     return "VeilidAPIException: Unimplemented ($message)"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Unimplemented: $message"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionUnimplemented(this.message); | ||||
| } | ||||
| @@ -1658,6 +1701,11 @@ class VeilidAPIExceptionParseError implements VeilidAPIException { | ||||
|     return "VeilidAPIException: ParseError ($message)\n    value: $value"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Parse error: $message"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionParseError(this.message, this.value); | ||||
| } | ||||
| @@ -1672,6 +1720,11 @@ class VeilidAPIExceptionInvalidArgument implements VeilidAPIException { | ||||
|     return "VeilidAPIException: InvalidArgument ($context:$argument)\n    value: $value"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Invalid argument for $context: $argument"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionInvalidArgument(this.context, this.argument, this.value); | ||||
| } | ||||
| @@ -1685,6 +1738,11 @@ class VeilidAPIExceptionMissingArgument implements VeilidAPIException { | ||||
|     return "VeilidAPIException: MissingArgument ($context:$argument)"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return "Missing argument for $context: $argument"; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionMissingArgument(this.context, this.argument); | ||||
| } | ||||
| @@ -1697,6 +1755,11 @@ class VeilidAPIExceptionGeneric implements VeilidAPIException { | ||||
|     return "VeilidAPIException: Generic (message: $message)"; | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   String toDisplayError() { | ||||
|     return message; | ||||
|   } | ||||
|  | ||||
|   // | ||||
|   VeilidAPIExceptionGeneric(this.message); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user