lolnode
fuwa 4 years ago
parent 7f37f554ef
commit 72fb69a512

@ -19,7 +19,6 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'config/prototype.dart';
import 'config/lolnode.dart' as cryptoConfig;
final c = cryptoConfig.config;
@ -39,4 +38,3 @@ const stdoutLineBufferSize = 200;
const bannerShownKey = 'banner-shown';
const int maxPoolTxSize = 5000;

@ -32,37 +32,32 @@ import '../../sensor/helper.dart' as helper;
typedef ShouldExit = bool Function();
Stream<String> runBinary
(
final String name,
{ final Stream<String> input,
final ShouldExit shouldExit,
final List<String> userArgs = const [],
}
) async* {
Stream<String> runBinary(
final String name, {
final Stream<String> input,
final ShouldExit shouldExit,
final List<String> userArgs = const [],
}) async* {
final binPath = await helper.getBinaryPath(name);
final appDocDir = await getApplicationDocumentsDirectory();
final appDocPath = appDocDir.path;
final binDir = Directory(appDocDir.path + "/" + config.c.appPath);
await binDir.create();
// print('binDir: ' + binDir.path);
const List<String> debugArgs =
[
];
const List<String> releaseArgs =
[
];
const List<String> debugArgs = [];
const List<String> releaseArgs = [];
const extraArgs = kReleaseMode ? releaseArgs : debugArgs;
final args =
[
"--data-dir",
binDir.path,
] + extraArgs + config.c.extraArgs + userArgs;
final args = [
"--data-dir",
binDir.path,
] +
extraArgs +
config.c.extraArgs +
userArgs;
log.info('args: ' + args.toString());
@ -81,7 +76,8 @@ Stream<String> runBinary
}
final _stdout = outputProcess.stdout
.transform(utf8.decoder).transform(const LineSplitter());
.transform(utf8.decoder)
.transform(const LineSplitter());
await for (final line in _stdout) {
log.finest('process output: ' + line);

@ -19,21 +19,19 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:logging/logging.dart';
import 'dart:ui';
import 'dart:async';
import '../../config.dart';
import '../../logging.dart';
import '../../helper.dart';
typedef GetNotificationFunc = AppLifecycleState Function();
Stream<Null> pull(GetNotificationFunc getNotification, final String puller) async* {
Stream<Null> pull(
GetNotificationFunc getNotification, final String puller) async* {
while (true) {
final _appState = getNotification();
log.finer('refresh pull by ${puller}: app state: ${_appState}');
log.finer('refresh pull by $puller: app state: $_appState');
if (_appState == AppLifecycleState.resumed) {
yield null;

@ -25,22 +25,20 @@ import 'dart:math';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';
import '../../../config.dart' as config;
import '../../../helper.dart';
import '../../../logging.dart';
Future<http.Response> rpc2(final String method) async {
final url = 'http://${config.host}:${config.c.port}/${method}';
final url = 'http://${config.host}:${config.c.port}/$method';
try {
final response = await http.post
( url,
final response = await http.post(
url,
);
return response;
}
catch (e) {
} catch (e) {
log.warning(e);
return null;
}
@ -57,7 +55,7 @@ Future<String> rpc2String(final String method, {final String field}) async {
return '';
} else {
final _body = await compute(jsonDecode, response.body);
final _field = field == null ? _body: _body[field];
final _field = field == null ? _body : _body[field];
return pretty(_field);
}

@ -20,7 +20,6 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:convert';
import 'rpc/rpc.dart' as rpc;
import '../../config.dart' as config;
@ -28,14 +27,16 @@ import '../../logging.dart';
Future<bool> isConnected() async {
final _connections = await rpc.getConnectionsSimple();
log.finer('cyberwow: _connections: ${_connections}');
return !_connections.isEmpty;
log.finer('cyberwow: _connections: $_connections');
return _connections.isNotEmpty;
}
Future<bool> isSynced() async {
final _targetHeight = await rpc.targetHeight();
final _height = await rpc.height();
return _targetHeight >= 0 && _targetHeight <= _height && _height > config.minimumHeight;
return _targetHeight >= 0 &&
_targetHeight <= _height &&
_height > config.minimumHeight;
}
Future<bool> isNotSynced() async {

@ -20,22 +20,13 @@ along with Wowllet. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import '../../logging.dart';
const _methodChannel = const MethodChannel('send-intent');
Future<String> getBinaryDir() async {
final _dir = await _methodChannel.invokeMethod('getBinaryDir');
final _binDir = Directory(_dir);
final _bins = _binDir.listSync(recursive: true);
return _dir;
}

@ -20,18 +20,17 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../../helper.dart';
import '../../../logging.dart';
import '../../interface/rpc/rpc.dart';
Future<http.Response> syncInfo() => rpc('sync_info');
Future<String> syncInfoString() => rpcString('sync_info');
Future<int> targetHeight() => rpc('sync_info', field: 'target_height').then(asInt);
Future<int> targetHeight() =>
rpc('sync_info', field: 'target_height').then(asInt);
Future<int> height() => rpc('sync_info', field: 'height').then(asInt);
Future<http.Response> getInfo() => rpc('get_info');
@ -47,26 +46,24 @@ Future<String> getInfoString() => rpcString('get_info');
Future<bool> offline() => rpc('get_info', field: 'offline').then(asBool);
Future<int> outgoingConnectionsCount() =>
rpc('get_info', field: 'outgoing_connections_count').then(asInt);
rpc('get_info', field: 'outgoing_connections_count').then(asInt);
Future<int> incomingConnectionsCount() =>
rpc('get_info', field: 'incoming_connections_count').then(asInt);
rpc('get_info', field: 'incoming_connections_count').then(asInt);
Future<List<Map<String, dynamic>>> getConnectionsSimple() async {
final _connections = await rpc('get_connections', field: 'connections').then(asJsonArray);
final _connections =
await rpc('get_connections', field: 'connections').then(asJsonArray);
const minActiveTime = 8;
final _activeConnections = _connections.where((x) => x['live_time'] > minActiveTime);
final _activeConnections =
_connections.where((x) => x['live_time'] > minActiveTime);
final _sortedConn = _activeConnections.toList()..sort
(
(x, y) {
final _sortedConn = _activeConnections.toList()
..sort((x, y) {
final int a = x['live_time'];
final int b = y['live_time'];
return a.compareTo(b);
}
);
});
return _sortedConn.toList();
}

@ -31,7 +31,8 @@ import '../../../config.dart' as config;
import '../../../logging.dart';
import '../../interface/rpc/rpc2.dart' as rpc2;
Future<http.Response> getTransactionPool() async => rpc2.rpc2('get_transaction_pool');
Future<http.Response> getTransactionPool() async =>
rpc2.rpc2('get_transaction_pool');
Map<String, String> txInOutCache = {};
@ -48,46 +49,41 @@ Future<List<Map<String, dynamic>>> getTransactionPoolSimple() async {
} else {
final responseBody = json.decode(response.body);
final result = asJsonArray(responseBody['transactions']);
final _sortedPool = result..sort
(
(x, y) {
final _sortedPool = result
..sort((x, y) {
final int a = x['receive_time'];
final int b = y['receive_time'];
return b.compareTo(a);
}
);
final _decodedPool = await Stream.fromIterable(_sortedPool).asyncMap
(
(x) async {
if (txInOutCache.length > config.maxPoolTxSize) {
txInOutCache = {};
}
});
final _txid = x['id_hash'];
final _decodedPool = Stream.fromIterable(_sortedPool).asyncMap((x) async {
if (txInOutCache.length > config.maxPoolTxSize) {
txInOutCache = {};
}
if (txInOutCache[_txid] == null) {
final String _tx_json = x['tx_json'];
final _tx_json_decoded = await compute(jsonDecode, _tx_json);
final _txid = x['id_hash'];
final _inOut =
{
'vin': _tx_json_decoded['vin'].length,
'vout': _tx_json_decoded['vout'].length,
};
if (txInOutCache[_txid] == null) {
final String _tx_json = x['tx_json'];
final _tx_json_decoded = await compute(jsonDecode, _tx_json);
final _inOutString = _inOut['vin'].toString() + '/' + _inOut['vout'].toString();
final _inOut = {
'vin': _tx_json_decoded['vin'].length,
'vout': _tx_json_decoded['vout'].length,
};
txInOutCache[_txid] = _inOutString;
log.fine('cached tx_json in pool for: ${_txid}');
}
final _inOutString =
_inOut['vin'].toString() + '/' + _inOut['vout'].toString();
return {
...x,
...{'i/o': txInOutCache[_txid]},
};
txInOutCache[_txid] = _inOutString;
log.fine('cached tx_json in pool for: $_txid');
}
);
return {
...x,
...{'i/o': txInOutCache[_txid]},
};
});
return _decodedPool.toList();
}

@ -21,12 +21,10 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:intl/intl.dart';
import '../../../config.dart' as config;
import '../../../helper.dart';
Map<String, dynamic> getConnectionView(Map<String, dynamic> x) {
const _remove =
[
const _remove = [
'address_type',
'connection_id',
'ip',
@ -50,44 +48,38 @@ Map<String, dynamic> getConnectionView(Map<String, dynamic> x) {
'incoming',
];
final _filteredConn = x..removeWhere
(
(k,v) => _remove.contains(k)
);
final _filteredConn = x..removeWhere((k, v) => _remove.contains(k));
final _formattedConn = _filteredConn.map
(
(k, v) {
switch (k) {
case 'connection_id': {
final _formattedConn = _filteredConn.map((k, v) {
switch (k) {
case 'connection_id':
{
return MapEntry(k, trimHash(v));
}
case 'live_time': {
case 'live_time':
{
final _duration = Duration(seconds: v);
format(Duration d) => d.toString().split('.').first.padLeft(8, "0");
return MapEntry(k, format(_duration));
}
default: {
const speedField =
[
default:
{
const speedField = [
'avg_download',
'avg_upload',
'current_download',
'current_upload',
];
if (speedField.contains(k)) {
return MapEntry(k, '${v} kB/s');
}
else {
return MapEntry(k, '$v kB/s');
} else {
return MapEntry(k, v);
}
}
}
}
);
});
final List<String> keys =
[
final List<String> keys = [
'host',
'height',
'live_time',
@ -96,53 +88,36 @@ Map<String, dynamic> getConnectionView(Map<String, dynamic> x) {
'avg_download',
'avg_upload',
'pruning_seed',
]
.where((k) => _formattedConn.keys.contains(k))
.toList();
].where((k) => _formattedConn.keys.contains(k)).toList();
final _sortedConn = {
for (final k in keys) k: _formattedConn[k]
};
final _sortedConn = {for (final k in keys) k: _formattedConn[k]};
final _cleanedUpConn = _sortedConn..removeWhere
(
(k,v) => k == 'pruning_seed' && x[k] == 0
);
final _cleanedUpConn = _sortedConn
..removeWhere((k, v) => k == 'pruning_seed' && x[k] == 0);
return _cleanedUpConn;
}
Map<String, dynamic> simpleHeight(int height, Map<String, dynamic> x) {
return x.map
(
(k, v) {
if (k == 'height') {
if (v == 0) {
return MapEntry(k, '');
}
else if (v < height) {
return MapEntry(k, '-${height - v}');
}
else if (v == height) {
return MapEntry(k, '');
}
else {
return MapEntry(k, '+${v - height}');
}
}
else {
return MapEntry(k, v);
return x.map((k, v) {
if (k == 'height') {
if (v == 0) {
return MapEntry(k, '');
} else if (v < height) {
return MapEntry(k, '-${height - v}');
} else if (v == height) {
return MapEntry(k, '');
} else {
return MapEntry(k, '+${v - height}');
}
} else {
return MapEntry(k, v);
}
);
});
}
Map<String, dynamic> getInfoView(Map<String, dynamic> x) {
const _remove =
[
const _remove = [
'difficulty_top64',
'stagenet',
'testnet',
@ -157,10 +132,7 @@ Map<String, dynamic> getInfoView(Map<String, dynamic> x) {
'credits',
];
final _filteredInfo = x..removeWhere
(
(k,v) => _remove.contains(k)
);
final _filteredInfo = x..removeWhere((k, v) => _remove.contains(k));
final int _difficulty = _filteredInfo['difficulty'] ?? 0;
final Map<String, double> _hashRate = {'hash_rate': _difficulty / 300};
@ -169,23 +141,23 @@ Map<String, dynamic> getInfoView(Map<String, dynamic> x) {
..._hashRate,
};
final _formattedInfo = _ammendedInfo.map
(
(k, v) {
switch (k) {
case 'top_block_hash': {
final _formattedInfo = _ammendedInfo.map((k, v) {
switch (k) {
case 'top_block_hash':
{
return MapEntry(k, trimHash(v));
}
case 'start_time': {
case 'start_time':
{
final _receive_time = DateTime.fromMillisecondsSinceEpoch(v * 1000);
final _diff = DateTime.now().difference(_receive_time);
format(Duration d) => d.toString().split('.').first.padLeft(8, "0");
return MapEntry('uptime', format(_diff));
}
default: {
const sizeField =
[
default:
{
const sizeField = [
'block_size_limit',
'block_size_median',
'block_weight_limit',
@ -200,27 +172,20 @@ Map<String, dynamic> getInfoView(Map<String, dynamic> x) {
if (sizeField.contains(k)) {
final formatter = NumberFormat.compact();
return MapEntry(k, formatter.format(v));
}
else {
} else {
return MapEntry(k, v);
}
}
}
}
);
final _cleanedUpInfo = _formattedInfo.map
(
(k, v) {
if (k.contains('_count') && k != 'tx_count') {
return MapEntry(k.replaceAll('_count', ''), v);
}
});
else {
return MapEntry(k, v);
}
final _cleanedUpInfo = _formattedInfo.map((k, v) {
if (k.contains('_count') && k != 'tx_count') {
return MapEntry(k.replaceAll('_count', ''), v);
} else {
return MapEntry(k, v);
}
);
});
final _sortedInfo = {
for (final k in _cleanedUpInfo.keys.toList()..sort()) k: _cleanedUpInfo[k]

@ -23,12 +23,10 @@ import 'dart:math';
import 'package:intl/intl.dart';
import '../../../config.dart' as config;
import '../../../helper.dart';
Map<String, dynamic> txView(Map<String, dynamic> x) {
const _remove =
[
const _remove = [
'tx_blob',
// 'tx_json',
'last_failed_id_hash',
@ -45,57 +43,44 @@ Map<String, dynamic> txView(Map<String, dynamic> x) {
// 'blob_size',
];
final _filteredTx = x..removeWhere
(
(k,v) => _remove.contains(k)
);
final _formattedTx = _filteredTx.map
(
(k, v) {
switch (k) {
case 'id_hash':
return MapEntry('id', trimHash(v));
case 'blob_size':
return MapEntry('size', (v / 1024).toStringAsFixed(2) + ' kB');
case 'fee': {
final formatter = NumberFormat.currency
(
final _filteredTx = x..removeWhere((k, v) => _remove.contains(k));
final _formattedTx = _filteredTx.map((k, v) {
switch (k) {
case 'id_hash':
return MapEntry('id', trimHash(v));
case 'blob_size':
return MapEntry('size', (v / 1024).toStringAsFixed(2) + ' kB');
case 'fee':
{
final formatter = NumberFormat.currency(
symbol: '',
decimalDigits: 2,
);
return MapEntry(k, formatter.format(v / pow(10, 11)) + '');
}
case 'receive_time': {
case 'receive_time':
{
final _receive_time = DateTime.fromMillisecondsSinceEpoch(v * 1000);
final _diff = DateTime.now().difference(_receive_time);
format(Duration d) => d.toString().split('.').first.padLeft(8, "0");
return MapEntry('age', format(_diff));
}
default:
return MapEntry(k, v);
}
default:
return MapEntry(k, v);
}
});
);
final List<String> keys =
[
final List<String> keys = [
'id',
'age',
'fee',
'i/o',
'size',
]
.where((k) => _formattedTx.keys.contains(k))
.toList();
].where((k) => _formattedTx.keys.contains(k)).toList();
final _sortedTx = {
for (final k in keys) k: _formattedTx[k]
};
final _sortedTx = {for (final k in keys) k: _formattedTx[k]};
return _sortedTx;
}

@ -36,7 +36,7 @@ import 'widget.dart' as widget;
void main() {
Logger.root.level = kReleaseMode ? Level.INFO : Level.FINE;
Logger.root.onRecord.listen((LogRecord rec) {
print('${rec.level.name}: ${rec.time}: ${rec.message}');
print('${rec.level.name}: ${rec.time}: ${rec.message}');
});
runApp(CyberWOW_App());
}
@ -47,8 +47,7 @@ class CyberWOW_App extends StatelessWidget {
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
return MaterialApp
(
return MaterialApp(
title: 'CyberWOW',
theme: config.c.theme,
darkTheme: config.c.theme,
@ -65,8 +64,8 @@ class CyberWOW_Page extends StatefulWidget {
_CyberWOW_PageState createState() => _CyberWOW_PageState();
}
class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserver
{
class _CyberWOW_PageState extends State<CyberWOW_Page>
with WidgetsBindingObserver {
// AppState _state = LoadingState("init...");
static const _channel = const MethodChannel('send-intent');
@ -86,7 +85,9 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
@override
void didChangeAppLifecycleState(final AppLifecycleState state) {
log.fine('app cycle: ${state}');
setState(() { _notification = state; });
setState(() {
_notification = state;
});
}
@override
@ -96,10 +97,7 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
}
void _setState(final state.AppState newState) {
setState
(
() => _state = newState
);
setState(() => _state = newState);
}
AppLifecycleState _getNotification() {
@ -110,10 +108,6 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
return _exiting;
}
state.AppState _getState() {
return _state;
}
Future<void> buildStateMachine(final state.BlankState _blankState) async {
final loadingText = config.c.splash;
state.LoadingState _loadingState = await _blankState.next(loadingText);
@ -121,24 +115,23 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
final _initialIntent = await getInitialIntent();
final _userArgs = _initialIntent
.trim()
.split(RegExp(r"\s+"))
.where((x) => !x.isEmpty)
.toList();
.trim()
.split(RegExp(r"\s+"))
.where((x) => x.isNotEmpty)
.toList();
if (!_userArgs.isEmpty) {
log.info('user args: ${_userArgs}');
if (_userArgs.isNotEmpty) {
log.info('user args: $_userArgs');
}
final syncing = process
.runBinary
(
config.c.outputBin,
input: inputStreamController.stream,
shouldExit: _isExiting,
userArgs: _userArgs,
)
.asBroadcastStream();
.runBinary(
config.c.outputBin,
input: inputStreamController.stream,
shouldExit: _isExiting,
userArgs: _userArgs,
)
.asBroadcastStream();
await _syncingState.next(inputStreamController.sink, syncing);
@ -147,12 +140,13 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
while (validState && !exited) {
switch (_state.runtimeType) {
case state.ExitingState: {
await (_state as state.ExitingState).wait();
log.finer('exit state wait done');
exited = true;
}
break;
case state.ExitingState:
{
await (_state as state.ExitingState).wait();
log.finer('exit state wait done');
exited = true;
}
break;
case state.SyncedState:
await (_state as state.SyncedState).next();
@ -162,7 +156,8 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
await (_state as state.ReSyncingState).next();
break;
default: validState = false;
default:
validState = false;
}
}
@ -185,7 +180,8 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
WidgetsBinding.instance.addObserver(this);
final state.AppHook _appHook = state.AppHook(_setState, _getNotification, _isExiting);
final state.AppHook _appHook =
state.AppHook(_setState, _getNotification, _isExiting);
final state.BlankState _blankState = state.BlankState(_appHook);
_state = _blankState;
@ -208,8 +204,7 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
@override
Widget build(final BuildContext context) {
return WillPopScope
(
return WillPopScope(
onWillPop: () => _exitApp(context),
child: widget.build(context, _state),
);

@ -22,7 +22,6 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:shared_preferences/shared_preferences.dart';
import '../config.dart' as config;
import '../logging.dart';
import '../helper.dart';
import 'prototype.dart';
@ -32,7 +31,7 @@ class LoadingState extends AppState {
final String banner;
String status = '';
LoadingState(appHook, this.banner) : super (appHook);
LoadingState(appHook, this.banner) : super(appHook);
void append(final String msg) {
this.status += msg;
@ -41,7 +40,8 @@ class LoadingState extends AppState {
Future<SyncingState> next() async {
Future<void> showBanner() async {
final Iterable<String> chars = banner.runes.map((x) => String.fromCharCode(x));
final Iterable<String> chars =
banner.runes.map((x) => String.fromCharCode(x));
for (final String char in chars) {
append(char);
@ -53,7 +53,7 @@ class LoadingState extends AppState {
}
SharedPreferences _prefs = await SharedPreferences.getInstance();
final _bannerShown = await _prefs.getBool(config.bannerShownKey);
final _bannerShown = _prefs.getBool(config.bannerShownKey);
if (_bannerShown == null) {
await showBanner();

@ -32,7 +32,6 @@ import 'prototype.dart';
import 'synced.dart';
import 'exiting.dart';
class ReSyncingState extends AppState {
final Queue<String> stdout;
final StreamSink<String> processInput;
@ -41,8 +40,9 @@ class ReSyncingState extends AppState {
bool synced = false;
ReSyncingState(appHook, this.stdout, this.processInput, this.processOutput, this.pageIndex)
: super (appHook);
ReSyncingState(appHook, this.stdout, this.processInput, this.processOutput,
this.pageIndex)
: super(appHook);
void append(final String msg) {
stdout.addLast(msg);
@ -65,7 +65,8 @@ class ReSyncingState extends AppState {
}
Future<void> checkSync() async {
await for (final _null in refresh.pull(appHook.getNotification, 'ReSyncingState')) {
await for (final _
in refresh.pull(appHook.getNotification, 'ReSyncingState')) {
if (appHook.isExiting()) {
log.fine('ReSyncing state detected exiting');
break;
@ -83,18 +84,13 @@ class ReSyncingState extends AppState {
await checkSync();
if (appHook.isExiting()) {
ExitingState _next = ExitingState
(
appHook, stdout, processOutput
);
ExitingState _next = ExitingState(appHook, stdout, processOutput);
return moveState(_next);
}
log.fine('resync: await exit');
SyncedState _next = SyncedState
(
appHook, stdout, processInput, processOutput, pageIndex
);
SyncedState _next =
SyncedState(appHook, stdout, processInput, processOutput, pageIndex);
_next.height = await rpc.height();
return moveState(_next);
}

@ -19,7 +19,6 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:collection';
@ -60,9 +59,10 @@ class SyncedState extends AppState {
String getConnectionsCache = '';
String getTransactionPoolCache = '';
SyncedState(appHook, this.stdout, this.processInput, this.processOutput, this.pageIndex)
: super (appHook) {
pageController = PageController( initialPage: pageIndex );
SyncedState(appHook, this.stdout, this.processInput, this.processOutput,
this.pageIndex)
: super(appHook) {
pageController = PageController(initialPage: pageIndex);
}
void appendInput(final String line) {
@ -102,8 +102,9 @@ class SyncedState extends AppState {
logStdout();
Future<void> checkSync() async {
await for (final _null in refresh.pull(appHook.getNotification, 'syncedState')) {
Future<void> checkSync() async {
await for (final _
in refresh.pull(appHook.getNotification, 'syncedState')) {
if (appHook.isExiting() || userExit) {
log.fine('Synced state detected exiting');
break;
@ -121,17 +122,16 @@ class SyncedState extends AppState {
getInfoCache = pretty(_getInfoView);
getConnections = await rpc.getConnectionsSimple();
final List<Map<String, dynamic>> _getConnectionsView =
getConnections
.map(rpcView.getConnectionView)
.map((x) => rpcView.simpleHeight(height, x))
.map(cleanKey)
.toList();
final List<Map<String, dynamic>> _getConnectionsView = getConnections
.map(rpcView.getConnectionView)
.map((x) => rpcView.simpleHeight(height, x))
.map(cleanKey)
.toList();
getConnectionsCache = pretty(_getConnectionsView);
getTransactionPool = await rpc.getTransactionPoolSimple();
final List<Map<String, dynamic>> _getTransactionPoolView =
getTransactionPool.map(rpc2View.txView).map(cleanKey).toList();
getTransactionPool.map(rpc2View.txView).map(cleanKey).toList();
getTransactionPoolCache = pretty(_getTransactionPoolView);
syncState();
@ -141,21 +141,14 @@ class SyncedState extends AppState {
await checkSync();
if (appHook.isExiting() || userExit) {
ExitingState _next = ExitingState
(
appHook, stdout, processOutput
);
ExitingState _next = ExitingState(appHook, stdout, processOutput);
return moveState(_next);
}
log.fine('synced: loop exit');
ReSyncingState _next = ReSyncingState
(
appHook, stdout, processInput, processOutput, pageIndex
);
ReSyncingState _next =
ReSyncingState(appHook, stdout, processInput, processOutput, pageIndex);
return moveState(_next);
}
}

@ -32,13 +32,12 @@ import 'prototype.dart';
import 'synced.dart';
import 'exiting.dart';
class SyncingState extends AppState {
final Queue<String> stdout = Queue();
bool synced = false;
SyncingState(appHook) : super (appHook);
SyncingState(appHook) : super(appHook);
void append(final String msg) {
stdout.addLast(msg);
@ -48,10 +47,8 @@ class SyncingState extends AppState {
syncState();
}
Future<AppState> next
(
StreamSink<String> processInput, Stream<String> processOutput
) async {
Future<AppState> next(
StreamSink<String> processInput, Stream<String> processOutput) async {
log.fine("Syncing next");
Future<void> printStdout() async {
@ -65,7 +62,8 @@ class SyncingState extends AppState {
}
Future<void> checkSync() async {
await for (final _null in refresh.pull(appHook.getNotification, 'syncingState')) {
await for (final _
in refresh.pull(appHook.getNotification, 'syncingState')) {
log.finer('SyncingState: checkSync loop');
if (appHook.isExiting()) {
@ -89,10 +87,7 @@ class SyncingState extends AppState {
await checkSync();
if (appHook.isExiting()) {
ExitingState _next = ExitingState
(
appHook, stdout, processOutput
);
ExitingState _next = ExitingState(appHook, stdout, processOutput);
return moveState(_next);
}
@ -101,9 +96,12 @@ class SyncingState extends AppState {
// processInput.add('exit');
final _height = await rpc.height();
SyncedState _next = SyncedState
(
appHook, stdout, processInput, processOutput, 1,
SyncedState _next = SyncedState(
appHook,
stdout,
processInput,
processOutput,
1,
);
_next.height = _height;
return moveState(_next);

@ -22,12 +22,9 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget build(BuildContext context, BlankState state) {
return Scaffold(
body: Container
(
),
body: Container(),
);
}

@ -22,41 +22,30 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget build(BuildContext context, ExitingState state) {
return Scaffold
(
return Scaffold(
// appBar: AppBar
// (
// // title: Text(widget.title),
// title: Text('CyberWOW'),
// ),
body: Container
(
body: Container(
// padding: const EdgeInsets.all(10.0),
child: Align
(
child: Align(
alignment: Alignment.topLeft,
child: Column
(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
Expanded
(
flex: 1,
child: SingleChildScrollView
(
scrollDirection: Axis.vertical,
reverse: true,
child: Text
(
state.stdout.join(),
style: Theme.of(context).textTheme.body1,
)
)
)
children: <Widget>[
Expanded(
flex: 1,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: Text(
state.stdout.join(),
style: Theme.of(context).textTheme.body1,
)))
],
),
),

@ -22,7 +22,6 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget build(BuildContext context, LoadingState state) {
return Scaffold(
@ -30,28 +29,21 @@ Widget build(BuildContext context, LoadingState state) {
// // title: Text(widget.title),
// title: Text('WOW'),
// ),
body: Container
(
body: Container(
padding: const EdgeInsets.all(40.0),
child: Align
(
child: Align(
alignment: Alignment.topLeft,
child: Column
(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
Spacer
(
children: <Widget>[
Spacer(
flex: 1,
),
Text
(
Text(
state.status,
style: Theme.of(context).textTheme.title,
),
Spacer
(
Spacer(
flex: 1,
),
],

@ -22,56 +22,40 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget build(BuildContext context, ReSyncingState state) {
final progressWidget =
[
Spacer
(
final progressWidget = [
Spacer(
flex: 3,
),
LinearProgressIndicator(),
Spacer
(
Spacer(
flex: 2,
),
Expanded
(
flex: 5,
child: Text
(
state.stdout.last,
style: Theme.of(context).textTheme.body1,
)
),
Expanded(
flex: 5,
child: Text(
state.stdout.last,
style: Theme.of(context).textTheme.body1,
)),
];
return Scaffold
(
body: Container
(
padding: const EdgeInsets.all(10.0),
child: Column
(
return Scaffold(
body: Container(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>
[
Spacer
(
flex: 10,
),
] +
progressWidget +
[
Spacer
(
flex: 10,
),
]
),
)
);
children: <Widget>[
Spacer(
flex: 10,
),
] +
progressWidget +
[
Spacer(
flex: 10,
),
]),
));
}

@ -22,10 +22,7 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:collection';
import '../state.dart';
import '../config.dart' as config;
import '../helper.dart';
import '../logging.dart';
@ -34,92 +31,73 @@ Widget summary(BuildContext context, SyncedState state) {
final onFire = state.getTransactionPool.length >= 10;
final onFireNotice = onFire ? ' 🔥' : '';
final poolLength = state.getTransactionPool.length;
final poolLengthNotice = poolLength > 1 ? '[${poolLength}] ' : '';
final txNotice = state.getTransactionPool.isEmpty ?
'' : poolLengthNotice + state.getTransactionPool.first['id_hash'].substring(0, 6) + ' ...';
final poolLengthNotice = poolLength > 1 ? '[$poolLength] ' : '';
final txNotice = state.getTransactionPool.isEmpty
? ''
: poolLengthNotice +
state.getTransactionPool.first['id_hash'].substring(0, 6) +
' ...';
return Container
(
return Container(
padding: EdgeInsets.only(bottom: 10.0),
child: Align
(
child: Align(
alignment: Alignment.center,
child: Column
(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
Spacer
(
children: <Widget>[
Spacer(
flex: 17,
),
Image.asset
('assets/lolnode_icon.png',
Image.asset(
'assets/lolnode_icon.png',
height: 220,
),
Spacer
(
Spacer(
flex: 7,
),
Expanded
(
flex: 15,
child: Row
(
children: <Widget>
[
Expanded(
flex: 15,
child: Row(children: <Widget>[
Spacer(),
AnimatedSwitcher
(
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: Text
(
child: Text(
height,
style: Theme.of(context).textTheme.display1,
key: ValueKey<int>(state.height),
),
),
AnimatedSwitcher
(
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: Text
(
child: Text(
onFireNotice,
style: TextStyle
(
style: TextStyle(
fontSize: 25,
),
key: ValueKey<int>(onFire ? 0 : 1),
),
),
Spacer(),
]
)
),
AnimatedSwitcher
(
])),
AnimatedSwitcher(
duration: Duration(milliseconds: 500),
child: Text
(
child: Text(
txNotice,
style: Theme.of(context).textTheme.body2,
key: ValueKey<int>(poolLength),
),
),
Spacer
(
Spacer(
flex: 1,
),
SizedBox
(
SizedBox(
height: 20.0,
width: 20.0,
child: (state.connected) ?
Container() :
CircularProgressIndicator
(
strokeWidth: 2,
),
child: (state.connected)
? Container()
: CircularProgressIndicator(
strokeWidth: 2,
),
),
],
),
@ -128,59 +106,48 @@ Widget summary(BuildContext context, SyncedState state) {
}
Widget rpcView(BuildContext context, String title, String body) {
return Container
(
return Container(
padding: const EdgeInsets.all(10.0),
child: Align
(
child: Align(
alignment: Alignment.topLeft,
child: Column
(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
Expanded
(
flex: 1,
child: SingleChildScrollView
(
scrollDirection: Axis.vertical,
child: Column
(
children: <Widget>
[
Container(
height: 0,
margin: const EdgeInsets.only(bottom: 15),
),
Text
(
title,
style: Theme.of(context).textTheme.display1,
),
Container(
height: 1,
color: Theme.of(context).primaryColor,
margin: const EdgeInsets.only(bottom: 20, top: 20),
),
Text
(
body,
style: Theme.of(context).textTheme.body2,
)
],
)
)
)
children: <Widget>[
Expanded(
flex: 1,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
Container(
height: 0,
margin: const EdgeInsets.only(bottom: 15),
),
Text(
title,
style: Theme.of(context).textTheme.display1,
),
Container(
height: 1,
color: Theme.of(context).primaryColor,
margin: const EdgeInsets.only(bottom: 20, top: 20),
),
Text(
body,
style: Theme.of(context).textTheme.body2,
)
],
)))
],
),
),
);
}
Widget getInfo(BuildContext context, SyncedState state) => rpcView(context, 'info', state.getInfoCache);
Widget syncInfo(BuildContext context, SyncedState state) => rpcView(context, 'sync info', pretty(state.syncInfo));
Widget getInfo(BuildContext context, SyncedState state) =>
rpcView(context, 'info', state.getInfoCache);
Widget syncInfo(BuildContext context, SyncedState state) =>
rpcView(context, 'sync info', pretty(state.syncInfo));
Widget getTransactionPool(BuildContext context, SyncedState state) {
final pool = state.getTransactionPool;
@ -196,28 +163,21 @@ Widget getConnections(BuildContext context, SyncedState state) {
return rpcView(context, 'peers' + subTitle, state.getConnectionsCache);
}
Widget terminalView(BuildContext context, String title, SyncedState state) {
final input = TextFormField
(
final input = TextFormField(
controller: state.textController,
textInputAction: TextInputAction.next,
autofocus: true,
autocorrect: false,
enableSuggestions: false,
keyboardType: TextInputType.visiblePassword,
decoration:
InputDecoration
(
decoration: InputDecoration(
// border: UnderlineInputBorder // OutlineInputBorder
// (
// ),
// hintText: 'WOW',
enabledBorder: UnderlineInputBorder
(
borderSide: BorderSide
(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColor,
),
),
@ -235,58 +195,44 @@ Widget terminalView(BuildContext context, String title, SyncedState state) {
final tail = words.sublist(1);
final guessHead = head.replaceAll('-', '_');
return [ guessHead, ...tail ].join(' ');
return [guessHead, ...tail].join(' ');
}
final _text = state.textController.text.trim();
final line = autoReplace(_text);
if (line.isNotEmpty) {
log.finer('terminal input: ${line}');
log.finer('terminal input: $line');
state.appendInput(line);
state.textController.clear();
}
else {
} else {
state.textController.clear();
SystemChannels.textInput.invokeMethod('TextInput.hide');
}
},
);
return Container
(
return Container(
// padding: const EdgeInsets.all(10.0),
child: Align
(
child: Align(
alignment: Alignment.topLeft,
child: Column
(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
Expanded
(
flex: 1,
child: SingleChildScrollView
(
scrollDirection: Axis.vertical,
reverse: true,
child: Column
(
children: <Widget>
[
Text
(
state.stdout.join('\n'),
style: Theme.of(context).textTheme.body2,
)
],
)
)
),
Container
(
children: <Widget>[
Expanded(
flex: 1,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: Column(
children: <Widget>[
Text(
state.stdout.join('\n'),
style: Theme.of(context).textTheme.body2,
)
],
))),
Container(
margin: const EdgeInsets.all(10.0),
child: input,
),
@ -296,10 +242,10 @@ Widget terminalView(BuildContext context, String title, SyncedState state) {
);
}
Widget terminal(BuildContext context, SyncedState state) =>
terminalView(context, 'terminal', state);
Widget terminal(BuildContext context, SyncedState state) => terminalView(context, 'terminal', state);
Widget pageView (BuildContext context, SyncedState state) {
Widget pageView(BuildContext context, SyncedState state) {
void _onPageChanged(int pageIndex) {
if (pageIndex != 0) {
SystemChannels.textInput.invokeMethod('TextInput.hide');
@ -307,11 +253,10 @@ Widget pageView (BuildContext context, SyncedState state) {
state.onPageChanged(pageIndex);
}
return PageView (
return PageView(
controller: state.pageController,
onPageChanged: _onPageChanged,
children:
[
children: [
terminal(context, state),
summary(context, state),
getTransactionPool(context, state),
@ -323,8 +268,5 @@ Widget pageView (BuildContext context, SyncedState state) {
}
Widget build(BuildContext context, SyncedState state) {
return Scaffold
(
body: pageView(context, state)
);
return Scaffold(body: pageView(context, state));
}

@ -22,41 +22,30 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget build(BuildContext context, SyncingState state) {
return Scaffold
(
return Scaffold(
// appBar: AppBar
// (
// // title: Text(widget.title),
// title: Text('CyberWOW'),
// ),
body: Container
(
body: Container(
// padding: const EdgeInsets.all(10.0),
child: Align
(
child: Align(
alignment: Alignment.topLeft,
child: Column
(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
Expanded
(
flex: 1,
child: SingleChildScrollView
(
scrollDirection: Axis.vertical,
reverse: true,
child: Text
(
state.stdout.join('\n'),
style: Theme.of(context).textTheme.body1,
)
)
),
children: <Widget>[
Expanded(
flex: 1,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
reverse: true,
child: Text(
state.stdout.join('\n'),
style: Theme.of(context).textTheme.body1,
))),
],
),
),