This commit is contained in:
John Smith 2022-12-14 16:50:33 -05:00
parent 78d06fb187
commit f0674e46d1
6 changed files with 235 additions and 60 deletions

View File

@ -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);

View File

@ -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
}
}

View File

@ -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,51 +140,79 @@ class _MyAppState extends State<MyApp> with UiLoggy {
body: Column(children: [
const Expanded(child: LogTerminal()),
Container(
decoration: BoxDecoration(color: materialPrimaryColor, boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
spreadRadius: 4,
blurRadius: 4,
)
]),
decoration: BoxDecoration(
color: materialBackgroundColor.shade100,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.15),
spreadRadius: 4,
blurRadius: 4,
)
]),
padding: const EdgeInsets.all(5.0),
child: Row(children: [
Expanded(
child: pad(TextField(
decoration:
newInputDecoration('Debug Command', _startedUp),
textInputAction: TextInputAction.send,
enabled: _startedUp,
onSubmitted: (String v) async {
loggy.info(await Veilid.instance.debug(v));
}))),
pad(const Text('Startup')),
pad(Switch(
value: _startedUp,
onChanged: (bool value) async {
await toggleStartup(value);
})),
pad(DropdownButton<LogLevel>(
value: loggy.level.logLevel,
onChanged: (LogLevel? 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")),
])),
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 {
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(Column(children: [
const Text('Log Level'),
DropdownButton<LogLevel>(
value: loggy.level.logLevel,
onChanged: (LogLevel? 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

@ -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,
);
}
}

View File

@ -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,
));
}

View File

@ -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);
}