Merge pull request #4 from fuwa0529/dev

more stuff
master
jw 4 years ago committed by GitHub
commit 7a0098bc69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

1
.gitignore vendored

@ -7,3 +7,4 @@ screenshots/
git/
flutter_export_environment.sh
.flutter-plugins-dependencies

@ -35,7 +35,7 @@ watch:
run:
cd cyberwow && \
flutter run --release --pid-file /tmp/flutter.pid
flutter run --debug --pid-file /tmp/flutter.pid
# clang -target aarch64-linux-android21 cyberwow/native/hello.c -o cyberwow/native/output/hello
c:

@ -32,7 +32,7 @@ The binary needed is `./bin/wownerod`.
1. One docker instance per hash
See `etc/scripts/build-wownero.sh`, modify the value of `version` per build.
See `etc/scripts/docker-build-wownero.sh`, modify the value of `version` per build.
2. Debian based system similar to F-droid
@ -44,7 +44,7 @@ See the `wow` task in `Makefile`.
```
popd
git clone https://github.com/fuwa0529/cyberwow/
git clone https://github.com/wownero/cyberwow/
cd cyberwow
mkdir -p cyberwow/native/output/arm64

@ -38,7 +38,7 @@ android {
targetSdkVersion 28
versionCode 22
versionName "0.7.0.0-i"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
if(project.hasProperty("RELEASE_STORE_FILE")) {
@ -78,6 +78,6 @@ flutter {
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}

@ -5,7 +5,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.4.1'
}
}

@ -1 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true

@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
#Tue Dec 24 05:26:22 UTC 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

@ -24,15 +24,16 @@ import 'config/cyberwow.dart' as cryptoConfig;
final c = cryptoConfig.config;
const arch = 'arm64';
enum Arch { arm64, x86_64 }
const arch = Arch.arm64;
// const arch = 'x86_64';
const minimumHeight = 118361;
const isEmu = arch == 'x86_64';
const isEmu = identical(arch, Arch.x86_64);
const emuHost = '192.168.10.100';
const host = isEmu ? emuHost : '127.0.0.1';
const int hashViewBlock = 6;
const stdoutLineBufferSize = 100;

@ -93,4 +93,5 @@ final config = CryptoConfig
'--block-sync-size=5',
],
'[1337@cyberwow]: ',
6,
);

@ -30,6 +30,7 @@ class CryptoConfig {
final int port;
final List<String> extraArgs;
final String promptString;
final int hashViewBlockLength;
const CryptoConfig
(
this.outputBin,
@ -40,5 +41,6 @@ class CryptoConfig {
this.port,
this.extraArgs,
this.promptString,
this.hashViewBlockLength,
);
}

@ -65,7 +65,7 @@ Future<String> rpc2String(final String method, {final String field}) async {
Future<http.Response> getTransactionPool() async => rpc2('get_transaction_pool');
Future<List<dynamic>> getTransactionPoolSimple() async {
Future<List<Map<String, dynamic>>> getTransactionPoolSimple() async {
final response = await getTransactionPool();
if (response == null) return [];

@ -162,7 +162,8 @@ Map<String, dynamic> getInfoView(Map<String, dynamic> x) {
(k,v) => _remove.contains(k)
);
final Map<String, double> _hashRate = {'hash_rate': _filteredInfo['difficulty'] / 300};
final int _difficulty = _filteredInfo['difficulty'] ?? 0;
final Map<String, double> _hashRate = {'hash_rate': _difficulty / 300};
final Map<String, dynamic> _ammendedInfo = {
..._filteredInfo,
..._hashRate,

@ -32,11 +32,10 @@ String pretty(dynamic x) {
;
}
String trimHash(String x) =>
x.substring(0, config.hashViewBlock)
+ '-'
+ x.substring(config.hashViewBlock, config.hashViewBlock * 2)
+ ' ...';
String trimHash(String x) {
final l = config.c.hashViewBlockLength;
return x.substring(0, l) + '-' + x.substring(l, l * 2) + ' ...';
}
Map<String, dynamic> cleanKey(Map<String, dynamic> x) {
final _cleaned = x.map

@ -1,3 +1,24 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:logging/logging.dart';
final Logger log = Logger('Default');

@ -27,17 +27,12 @@ import 'package:logging/logging.dart';
import 'dart:io';
import 'dart:async';
import 'state.dart';
import 'config.dart' as config;
import 'logging.dart';
import 'controller/process/deploy.dart' as process;
import 'controller/process/run.dart' as process;
import 'widget/loading.dart' as widget;
import 'widget/blank.dart' as widget;
import 'widget/syncing.dart' as widget;
import 'widget/synced.dart' as widget;
import 'widget/resyncing.dart' as widget;
import 'widget/exiting.dart' as widget;
import 'logging.dart';
import 'state.dart' as state;
import 'widget.dart' as widget;
void main() {
Logger.root.level = kReleaseMode ? Level.INFO : Level.FINE;
@ -49,7 +44,7 @@ void main() {
class CyberWOW_App extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget build(final BuildContext context) {
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark);
@ -75,7 +70,7 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
{
// AppState _state = LoadingState("init...");
AppState _state;
state.AppState _state;
AppLifecycleState _notification = AppLifecycleState.resumed;
bool _exiting = false;
@ -83,7 +78,7 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
final StreamController<String> inputStreamController = StreamController();
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
void didChangeAppLifecycleState(final AppLifecycleState state) {
log.fine('app cycle: ${state}');
setState(() { _notification = state; });
}
@ -94,7 +89,7 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
super.dispose();
}
void _setState(AppState newState) {
void _setState(final state.AppState newState) {
setState
(
() => _state = newState
@ -109,58 +104,49 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
return _exiting;
}
AppState _getState() {
state.AppState _getState() {
return _state;
}
void _updateLoading(LoadingState state, final String msg) {
log.fine('updateLoading: ' + msg);
}
Future<void> buildStateMachine(final BlankState _blankState) async {
Future<void> buildStateMachine(final state.BlankState _blankState) async {
final loadingText = config.c.splash;
LoadingState _loadingState = await _blankState.next(loadingText);
state.LoadingState _loadingState = await _blankState.next(loadingText);
final binName = config.c.outputBin;
final resourcePath = 'native/output/' + config.arch + '/' + binName;
final resourcePath = 'native/output/' + describeEnum(config.arch) + '/' + binName;
final bundle = DefaultAssetBundle.of(context);
final loading = process.deployBinary(bundle, resourcePath, binName);
SyncingState _syncingState = await _loadingState.next(loading, '');
state.SyncingState _syncingState = await _loadingState.next(loading);
final syncing = process
.runBinary(binName, input: inputStreamController.stream, shouldExit: _isExiting)
.asBroadcastStream();
HookedState _syncedNextState = await _syncingState.next(inputStreamController.sink, syncing);
await _syncingState.next(inputStreamController.sink, syncing);
var exited = false;
bool exited = false;
bool validState = true;
if (_syncedNextState is SyncedState) {
SyncedState _syncedState = _syncedNextState;
await _syncedState.next();
} else {
ExitingState _exitingState = _syncedNextState;
await _exitingState.wait();
exited = true;
}
var validState = true;
while (validState && !exited) {
await _getState().use
(
(s) => validState = false,
(s) => validState = false,
(s) => validState = false,
(s) => s.next(),
(s) => s.next(),
(s) async {
await s.wait();
switch (_state.runtimeType) {
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();
break;
case state.ReSyncingState:
await (_state as state.ReSyncingState).next();
break;
default: validState = false;
}
}
log.finer('state machine finished');
@ -182,13 +168,14 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
WidgetsBinding.instance.addObserver(this);
final BlankState _blankState = BlankState(_setState, _getNotification, _isExiting);
final state.AppHook _appHook = state.AppHook(_setState, _getNotification, _isExiting);
final state.BlankState _blankState = state.BlankState(_appHook);
_state = _blankState;
buildStateMachine(_blankState);
}
Future<bool> _exitApp(BuildContext context) async {
Future<bool> _exitApp(final BuildContext context) async {
log.info("CyberWOW_PageState _exitApp");
WidgetsBinding.instance.removeObserver(this);
@ -203,19 +190,11 @@ class _CyberWOW_PageState extends State<CyberWOW_Page> with WidgetsBindingObserv
}
@override
Widget build(BuildContext context) {
Widget build(final BuildContext context) {
return WillPopScope
(
onWillPop: () => _exitApp(context),
child: _state.use
(
(s) => widget.buildBlank(context, s),
(s) => widget.buildLoading(context, s),
(s) => widget.buildSyncing(context, s),
(s) => widget.buildSynced(context, s),
(s) => widget.buildReSyncing(context, s),
(s) => widget.buildExiting(context, s),
),
child: widget.build(context, _state),
);
}
}

@ -19,430 +19,13 @@ along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:developer';
import 'dart:async';
import 'dart:convert';
import 'dart:collection';
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
export 'state/prototype.dart';
export 'state/blank.dart';
export 'state/loading.dart';
export 'state/syncing.dart';
export 'state/synced.dart';
export 'state/resyncing.dart';
export 'state/exiting.dart';
import 'controller/helper.dart';
import 'controller/rpc/rpc.dart' as rpc;
import 'controller/rpc/rpc2.dart' as rpc;
import 'controller/daemon.dart' as daemon;
import 'controller/refresh.dart' as refresh;
import 'config.dart' as config;
import 'logging.dart';
import 'helper.dart';
import 'controller/rpc/rpcView.dart' as rpcView;
import 'controller/rpc/rpc2View.dart' as rpc2View;
abstract class AppState {
T use<T>
(
T Function(BlankState) useBlankState,
T Function(LoadingState) useLoadingState,
T Function(SyncingState) useSyncingState,
T Function(SyncedState) useSyncedState,
T Function(ReSyncingState) useReSyncingState,
T Function(ExitingState) useExitingState,
)
{
if (this is BlankState) {
return useBlankState(this);
}
if (this is LoadingState) {
return useLoadingState(this);
}
if (this is SyncingState) {
return useSyncingState(this);
}
if (this is SyncedState) {
return useSyncedState(this);
}
if (this is ReSyncingState) {
return useReSyncingState(this);
}
if (this is ExitingState) {
return useExitingState(this);
}
throw Exception('Invalid state');
}
}
typedef SetStateFunc = void Function(AppState);
typedef GetNotificationFunc = AppLifecycleState Function();
typedef IsExitingFunc = bool Function();
class HookedState extends AppState {
final SetStateFunc setState;
final GetNotificationFunc getNotification;
final IsExitingFunc isExiting;
HookedState(this.setState, this.getNotification, this.isExiting);
syncState() {
setState(this);
}
HookedState moveState(HookedState _next) {
setState(_next);
return _next;
}
}
class BlankState extends HookedState {
BlankState(f1, f2, f3) : super (f1, f2, f3);
Future<LoadingState> next(String status) async {
LoadingState _next = LoadingState(setState, getNotification, isExiting, status);
return moveState(_next);
}
}
class LoadingState extends HookedState {
final String banner;
String status = '';
LoadingState(f1, f2, f3, this.banner) : super (f1, f2, f3);
void append(final String msg) {
this.status += msg;
syncState();
}
Future<SyncingState> next(Stream<String> loadingProgress, String status) async {
Future<void> showBanner() async {
var chars = [];
banner.runes.forEach((int rune) {
final c = String.fromCharCode(rune);
chars.add(c);
});
for (String char in chars) {
append(char);
await Future.delayed(Duration(milliseconds: config.c.splashDelay), () => "1");
}
await Future.delayed(const Duration(seconds: 2), () => "1");
}
Future<void> load() async {
log.fine("Loading next");
await for (final line in loadingProgress) {
// append(line);
log.info(line);
}
}
final outputBinExists = await binaryExists(config.c.outputBin);
if (outputBinExists) {
await load();
}
else {
await Future.wait([load(), showBanner()]);
}
SyncingState _next = SyncingState(setState, getNotification, isExiting);
return moveState(_next);
}
}
class SyncingState extends HookedState {
final Queue<String> stdout = Queue.from(['']);
bool synced = false;
SyncingState(f1, f2, f3) : super (f1, f2, f3);
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
Future<HookedState> next
(
StreamSink<String> processInput, Stream<String> processOutput
) async {
log.fine("Syncing next");
Future<void> printStdout() async {
await for (final line in processOutput) {
if (synced) break;
log.finest('syncing: print stdout loop');
append(line);
log.info(line);
}
}
Future<void> checkSync() async {
await for (final _null in refresh.pull(getNotification, 'syncingState')) {
log.finer('SyncingState: checkSync loop');
if (isExiting()) {
log.fine('Syncing state detected exiting');
break;
}
// here doc is wrong, targetHeight could match height when synced
// potential bug, targetHeight could be smaller then height
final _isConnected = await daemon.isConnected();
final _isSynced = await daemon.isSynced();
if (_isConnected && _isSynced) {
synced = true;
break;
}
}
}
printStdout();
await checkSync();
if (isExiting()) {
ExitingState _next = ExitingState
(
setState, getNotification, isExiting, stdout, processOutput
);
return moveState(_next);
}
log.fine('syncing: loop exit');
// processInput.add('exit');
final _height = await rpc.height();
SyncedState _next = SyncedState
(
setState, getNotification, isExiting, stdout, processInput, processOutput, 1,
);
_next.height = _height;
return moveState(_next);
}
}
class SyncedState extends HookedState {
final Queue<String> stdout;
final StreamSink<String> processInput;
final Stream<String> processOutput;
final TextEditingController textController = TextEditingController();
int height;
bool synced = true;
bool userExit = false;
bool connected = true;
Map<String, dynamic> getInfo = {};
List<Map<String, dynamic>> getConnections = [];
List<Map<String, dynamic>> getTransactionPool = [];
int pageIndex;
String syncInfo = 'syncInfo';
PageController pageController;
String getInfoCache = '';
String getConnectionsCache = '';
String getTransactionPoolCache = '';
SyncedState(f1, f2, f3, this.stdout, this.processInput, this.processOutput, this.pageIndex)
: super (f1, f2, f3) {
pageController = PageController( initialPage: pageIndex );
}
void appendInput(final String line) {
stdout.addLast(config.c.promptString + line + '\n');
syncState();
processInput.add(line);
if (line == 'exit') {
userExit = true;
}
}
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
void onPageChanged(int value) {
this.pageIndex = value;
}
Future<HookedState> next() async {
log.fine("Synced next");
Future<void> logStdout() async {
await for (final line in processOutput) {
if (!synced) break;
// print('synced: print stdout loop');
append(line);
log.info(line);
}
}
logStdout();
Future<void> checkSync() async {
await for (final _null in refresh.pull(getNotification, 'syncedState')) {
if (isExiting() || userExit) {
log.fine('Synced state detected exiting');
break;
}
if (await daemon.isNotSynced()) {
synced = false;
break;
}
// log.finer('SyncedState: checkSync loop');
height = await rpc.height();
connected = await daemon.isConnected();
getInfo = await rpc.getInfoSimple();
final _getInfoView = cleanKey(rpcView.getInfoView(getInfo));
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();
getConnectionsCache = pretty(_getConnectionsView);
getTransactionPool = await rpc.getTransactionPoolSimple();
final List<Map<String, dynamic>> _getTransactionPoolView =
getTransactionPool.map(rpc2View.txView).map(cleanKey).toList();
getTransactionPoolCache = pretty(_getTransactionPoolView);
syncState();
}
}
await checkSync();
if (isExiting() || userExit) {
ExitingState _next = ExitingState
(
setState, getNotification, isExiting, stdout, processOutput
);
return moveState(_next);
}
log.fine('synced: loop exit');
ReSyncingState _next = ReSyncingState
(
setState, getNotification, isExiting, stdout, processInput, processOutput, pageIndex
);
return moveState(_next);
}
}
class ReSyncingState extends HookedState {
final Queue<String> stdout;
final StreamSink<String> processInput;
final Stream<String> processOutput;
final int pageIndex;
bool synced = false;
ReSyncingState(f1, f2, f3, this.stdout, this.processInput, this.processOutput, this.pageIndex)
: super (f1, f2, f3);
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
Future<HookedState> next() async {
log.fine("ReSyncing next");
Future<void> printStdout() async {
await for (final line in processOutput) {
if (synced) break;
// print('re-syncing: print stdout loop');
append(line);
log.info(line);
}
}
Future<void> checkSync() async {
await for (final _null in refresh.pull(getNotification, 'ReSyncingState')) {
if (isExiting()) {
log.fine('ReSyncing state detected exiting');
break;
}
if (await daemon.isSynced()) {
synced = true;
break;
}
// print('re-syncing: checkSync loop');
}
}
printStdout();
await checkSync();
if (isExiting()) {
ExitingState _next = ExitingState
(
setState, getNotification, isExiting, stdout, processOutput
);
return moveState(_next);
}
log.fine('resync: await exit');
SyncedState _next = SyncedState
(
setState, getNotification, isExiting, stdout, processInput, processOutput, pageIndex
);
_next.height = await rpc.height();
return moveState(_next);
}
}
class ExitingState extends HookedState {
final Queue<String> stdout;
final Stream<String> processOutput;
ExitingState(f1, f2, f3, this.stdout, this.processOutput) : super (f1, f2, f3);
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
Future<SyncedState> wait() async {
log.finer("Exiting wait");
Future<void> printStdout() async {
await for (final line in processOutput) {
log.finer('exiting: print stdout loop');
append(line);
log.info(line);
}
}
await printStdout();
log.finer('exiting state done');
}
}

@ -0,0 +1,34 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'prototype.dart';
import 'loading.dart';
class BlankState extends AppState {
BlankState(appHook) : super (appHook);
Future<LoadingState> next(String status) async {
LoadingState _next = LoadingState(appHook, status);
return moveState(_next);
}
}

@ -0,0 +1,59 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:collection';
import '../config.dart' as config;
import '../logging.dart';
import 'prototype.dart';
class ExitingState extends AppState {
final Queue<String> stdout;
final Stream<String> processOutput;
ExitingState(appHook, this.stdout, this.processOutput) : super (appHook);
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
Future<void> wait() async {
log.finer("Exiting wait");
Future<void> printStdout() async {
await for (final line in processOutput) {
log.finer('exiting: print stdout loop');
append(line);
log.info(line);
}
}
await printStdout();
log.finer('exiting state done');
}
}

@ -0,0 +1,76 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import '../controller/helper.dart';
import '../config.dart' as config;
import '../logging.dart';
import 'prototype.dart';
import 'syncing.dart';
class LoadingState extends AppState {
final String banner;
String status = '';
LoadingState(appHook, this.banner) : super (appHook);
void append(final String msg) {
this.status += msg;
syncState();
}
Future<SyncingState> next(final Stream<String> loadingProgress) async {
Future<void> showBanner() async {
List<String> chars = [];
banner.runes.forEach((int rune) {
final c = String.fromCharCode(rune);
chars.add(c);
});
for (final String char in chars) {
append(char);
await Future.delayed(Duration(milliseconds: config.c.splashDelay), () => "1");
}
await Future.delayed(const Duration(seconds: 2), () => "1");
}
Future<void> load() async {
log.fine("Loading next");
await for (final line in loadingProgress) {
// append(line);
log.info(line);
}
}
final outputBinExists = await binaryExists(config.c.outputBin);
if (outputBinExists) {
await load();
}
else {
await Future.wait([load(), showBanner()]);
}
SyncingState _next = SyncingState(appHook);
return moveState(_next);
}
}

@ -0,0 +1,47 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:flutter/material.dart';
typedef SetStateFunc = void Function(AppState);
typedef GetNotificationFunc = AppLifecycleState Function();
typedef IsExitingFunc = bool Function();
class AppHook {
final SetStateFunc setState;
final GetNotificationFunc getNotification;
final IsExitingFunc isExiting;
AppHook(this.setState, this.getNotification, this.isExiting);
}
class AppState {
final AppHook appHook;
AppState(this.appHook);
syncState() {
appHook.setState(this);
}
AppState moveState(AppState _next) {
appHook.setState(_next);
return _next;
}
}

@ -0,0 +1,101 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:collection';
import '../controller/rpc/rpc.dart' as rpc;
import '../controller/daemon.dart' as daemon;
import '../controller/refresh.dart' as refresh;
import '../config.dart' as config;
import '../logging.dart';
import 'prototype.dart';
import 'synced.dart';
import 'exiting.dart';
class ReSyncingState extends AppState {
final Queue<String> stdout;
final StreamSink<String> processInput;
final Stream<String> processOutput;
final int pageIndex;
bool synced = false;
ReSyncingState(appHook, this.stdout, this.processInput, this.processOutput, this.pageIndex)
: super (appHook);
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
Future<AppState> next() async {
log.fine("ReSyncing next");
Future<void> printStdout() async {
await for (final line in processOutput) {
if (synced) break;
// print('re-syncing: print stdout loop');
append(line);
log.info(line);
}
}
Future<void> checkSync() async {
await for (final _null in refresh.pull(appHook.getNotification, 'ReSyncingState')) {
if (appHook.isExiting()) {
log.fine('ReSyncing state detected exiting');
break;
}
if (await daemon.isSynced()) {
synced = true;
break;
}
// print('re-syncing: checkSync loop');
}
}
printStdout();
await checkSync();
if (appHook.isExiting()) {
ExitingState _next = ExitingState
(
appHook, stdout, processOutput
);
return moveState(_next);
}
log.fine('resync: await exit');
SyncedState _next = SyncedState
(
appHook, stdout, processInput, processOutput, pageIndex
);
_next.height = await rpc.height();
return moveState(_next);
}
}

@ -0,0 +1,161 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:collection';
import 'package:flutter/material.dart';
import '../config.dart' as config;
import '../controller/daemon.dart' as daemon;
import '../controller/refresh.dart' as refresh;
import '../controller/rpc/rpc.dart' as rpc;
import '../controller/rpc/rpc2.dart' as rpc;
import '../controller/rpc/rpc2View.dart' as rpc2View;
import '../controller/rpc/rpcView.dart' as rpcView;
import '../helper.dart';
import '../logging.dart';
import 'prototype.dart';
import 'resyncing.dart';
import 'exiting.dart';
class SyncedState extends AppState {
final Queue<String> stdout;
final StreamSink<String> processInput;
final Stream<String> processOutput;
final TextEditingController textController = TextEditingController();
int height;
bool synced = true;
bool userExit = false;
bool connected = true;
Map<String, dynamic> getInfo = {};
List<Map<String, dynamic>> getConnections = [];
List<Map<String, dynamic>> getTransactionPool = [];
int pageIndex;
String syncInfo = 'syncInfo';
PageController pageController;
String getInfoCache = '';
String getConnectionsCache = '';
String getTransactionPoolCache = '';
SyncedState(appHook, this.stdout, this.processInput, this.processOutput, this.pageIndex)
: super (appHook) {
pageController = PageController( initialPage: pageIndex );
}
void appendInput(final String line) {
stdout.addLast(config.c.promptString + line + '\n');
syncState();
processInput.add(line);
if (line == 'exit') {
userExit = true;
}
}
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
void onPageChanged(int value) {
this.pageIndex = value;
}
Future<AppState> next() async {
log.fine("Synced next");
Future<void> logStdout() async {
await for (final line in processOutput) {
if (!synced) break;
// print('synced: print stdout loop');
append(line);
log.info(line);
}
}
logStdout();
Future<void> checkSync() async {
await for (final _null in refresh.pull(appHook.getNotification, 'syncedState')) {
if (appHook.isExiting() || userExit) {
log.fine('Synced state detected exiting');
break;
}
if (await daemon.isNotSynced()) {
synced = false;
break;
}
// log.finer('SyncedState: checkSync loop');
height = await rpc.height();
connected = await daemon.isConnected();
getInfo = await rpc.getInfoSimple();
final _getInfoView = cleanKey(rpcView.getInfoView(getInfo));
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();
getConnectionsCache = pretty(_getConnectionsView);
getTransactionPool = await rpc.getTransactionPoolSimple();
final List<Map<String, dynamic>> _getTransactionPoolView =
getTransactionPool.map(rpc2View.txView).map(cleanKey).toList();
getTransactionPoolCache = pretty(_getTransactionPoolView);
syncState();
}
}
await checkSync();
if (appHook.isExiting() || userExit) {
ExitingState _next = ExitingState
(
appHook, stdout, processOutput
);
return moveState(_next);
}
log.fine('synced: loop exit');
ReSyncingState _next = ReSyncingState
(
appHook, stdout, processInput, processOutput, pageIndex
);
return moveState(_next);
}
}

@ -0,0 +1,111 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'dart:async';
import 'dart:collection';
import '../controller/rpc/rpc.dart' as rpc;
import '../controller/daemon.dart' as daemon;
import '../controller/refresh.dart' as refresh;
import '../config.dart' as config;
import '../logging.dart';
import 'prototype.dart';
import 'synced.dart';
import 'exiting.dart';
class SyncingState extends AppState {
final Queue<String> stdout = Queue.from(['']);
bool synced = false;
SyncingState(appHook) : super (appHook);
void append(final String msg) {
stdout.addLast(msg);
while (stdout.length > config.stdoutLineBufferSize) {
stdout.removeFirst();
}
syncState();
}
Future<AppState> next
(
StreamSink<String> processInput, Stream<String> processOutput
) async {
log.fine("Syncing next");
Future<void> printStdout() async {
await for (final line in processOutput) {
if (synced) break;
log.finest('syncing: print stdout loop');
append(line);
log.info(line);
}
}
Future<void> checkSync() async {
await for (final _null in refresh.pull(appHook.getNotification, 'syncingState')) {
log.finer('SyncingState: checkSync loop');
if (appHook.isExiting()) {
log.fine('Syncing state detected exiting');
break;
}
// here doc is wrong, targetHeight could match height when synced
// potential bug, targetHeight could be smaller then height
final _isConnected = await daemon.isConnected();
final _isSynced = await daemon.isSynced();
if (_isConnected && _isSynced) {
synced = true;
break;
}
}
}
printStdout();
await checkSync();
if (appHook.isExiting()) {
ExitingState _next = ExitingState
(
appHook, stdout, processOutput
);
return moveState(_next);
}
log.fine('syncing: loop exit');
// processInput.add('exit');
final _height = await rpc.height();
SyncedState _next = SyncedState
(
appHook, stdout, processInput, processOutput, 1,
);
_next.height = _height;
return moveState(_next);
}
}

@ -0,0 +1,42 @@
/*
Copyright 2019 fuwa
This file is part of CyberWOW.
CyberWOW is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CyberWOW is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CyberWOW. If not, see <https://www.gnu.org/licenses/>.
*/
import 'package:flutter/material.dart';
import 'state.dart';
import 'widget/blank.dart' as blank;
import 'widget/loading.dart' as loading;
import 'widget/syncing.dart' as syncing;
import 'widget/synced.dart' as synced;
import 'widget/resyncing.dart' as resyncing;
import 'widget/exiting.dart' as exiting;
Widget build(final BuildContext context, final AppState state) {
switch (state.runtimeType) {
case BlankState: return blank.build(context, state);
case LoadingState: return loading.build(context, state);
case SyncingState: return syncing.build(context, state);
case SyncedState: return synced.build(context, state);
case ReSyncingState: return resyncing.build(context, state);
case ExitingState: return exiting.build(context, state);
default: Placeholder();
}
}

@ -24,7 +24,7 @@ import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget buildBlank(BuildContext context, BlankState state) {
Widget build(BuildContext context, BlankState state) {
return Scaffold(
body: Container
(

@ -24,7 +24,7 @@ import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget buildExiting(BuildContext context, ExitingState state) {
Widget build(BuildContext context, ExitingState state) {
return Scaffold
(
// appBar: AppBar

@ -24,7 +24,7 @@ import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget buildLoading(BuildContext context, LoadingState state) {
Widget build(BuildContext context, LoadingState state) {
return Scaffold(
// appBar: AppBar(
// // title: Text(widget.title),

@ -24,7 +24,7 @@ import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget buildReSyncing(BuildContext context, ReSyncingState state) {
Widget build(BuildContext context, ReSyncingState state) {
return Scaffold
(
// appBar: AppBar

@ -320,7 +320,7 @@ Widget pageView (BuildContext context, SyncedState state) {
);
}
Widget buildSynced(BuildContext context, SyncedState state) {
Widget build(BuildContext context, SyncedState state) {
return Scaffold
(
body: pageView(context, state)

@ -24,7 +24,7 @@ import 'package:flutter/material.dart';
import '../state.dart';
import '../config.dart' as config;
Widget buildSyncing(BuildContext context, SyncingState state) {
Widget build(BuildContext context, SyncingState state) {
return Scaffold
(
// appBar: AppBar

@ -1,13 +1,27 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.11"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.2"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
version: "2.4.0"
boolean_selector:
dependency: transitive
description:
@ -29,6 +43,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.11"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
cupertino_icons:
dependency: "direct main"
description:
@ -60,6 +88,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.3"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
intl:
dependency: "direct main"
description:
@ -80,14 +115,14 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.5"
version: "0.12.6"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.7"
version: "1.1.8"
path:
dependency: transitive
description:
@ -109,6 +144,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.0+1"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
@ -169,7 +211,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.5"
version: "0.2.11"
typed_data:
dependency: transitive
description:
@ -184,6 +226,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.5.0"
sdks:
dart: ">=2.2.2 <3.0.0"
dart: ">=2.4.0 <3.0.0"
flutter: ">=0.1.4 <2.0.0"

@ -82,7 +82,7 @@ with nixpkgs;
; profile = ''
export ANDROID_HOME=~/SDK/Android/Sdk
PATH=~/scm/flutter/vendor/flutter/bin:$PATH
PATH=~/local/sdk/flutter/bin:$PATH
PATH=~/SDK/Android/android-studio/bin:$PATH
export ANDROID_NDK_VERSION=r20
@ -96,7 +96,6 @@ with nixpkgs;
export _JAVA_AWT_WM_NONREPARENTING=1
export DART_VM_OPTIONS=--root-certs-file=/etc/ssl/certs/ca-certificates.crt
export ANDROID_NDK_VERSION_WOW=r17c
export ANDROID_NDK_ROOT_WOW=~/SDK/Android/ndk-archive/android-ndk-$ANDROID_NDK_VERSION_WOW

@ -1,42 +0,0 @@
#!/usr/bin/env bash
# Copyright (c) 2019, The Wownero Project
# Copyright (c) 2014-2019, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
version=v2.3.0.0
curl -O -L https://github.com/fuwa0529/wownerujo/releases/download/${version}/external-libs.tgz
rm -rf external-libs
echo "unpacking external-libs"
tar zxfv external-libs.tgz
rm external-libs.tgz

@ -1 +0,0 @@
curl -X POST http://nas:34568/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"get_connections"}'