dev
dart 236 lines 6.29 KB
Raw
1 import 'dart:io';
2 import 'package:cw_core/keyable.dart';
3 import 'package:cw_core/node_list.dart';
4 import 'package:cw_core/utils/proxy_socket/abstract.dart';
5 import 'package:cw_core/utils/proxy_wrapper.dart';
6 import 'package:cw_core/utils/print_verbose.dart';
7 import 'dart:convert';
8 import 'package:hive/hive.dart';
9 import 'package:cw_core/hive_type_ids.dart';
10 import 'package:cw_core/wallet_type.dart';
11 import 'dart:math' as math;
12 import 'package:convert/convert.dart';
13
14 import 'package:crypto/crypto.dart';
15
16 import 'cake_hive.dart';
17 import 'node.dart' as node_new;
18
19 part 'node_legacy.part.dart';
20
21 Future<void> performNodeHiveMigration() async {
22 if (!CakeHive.isAdapterRegistered(Node.typeId)) {
23 CakeHive.registerAdapter(NodeAdapter());
24 }
25
26 final nodeBox = await CakeHive.openBox<Node>(Node.boxName);
27 final powNodeBox = await CakeHive.openBox<Node>(Node.boxName + "pow");
28 final builtinNodes = await loadAllDefaultNodes();
29 final builtinPowNodes = await loadDefaultNanoPowNodes();
30 await Node.migrateAllToSqlite(nodeBox, powNodeBox, builtinNodes, builtinPowNodes);
31 }
32
33 Uri createUriFromElectrumAddress(String address, String path) =>
34 Uri.tryParse('tcp://$address$path')!;
35
36 @HiveType(typeId: Node.typeId)
37 class Node extends HiveObject with Keyable {
38 Node({
39 this.label,
40 this.login,
41 this.password,
42 this.useSSL,
43 this.trusted = false,
44 this.socksProxyAddress,
45 this.path = '',
46 this.isEnabledForAutoSwitching = false,
47 String? uri,
48 WalletType? type,
49 }) {
50 if (uri != null) {
51 uriRaw = uri;
52 }
53 if (type != null) {
54 this.type = type;
55 }
56 }
57
58 static Future<void> migrateAllToSqlite(Box<Node> nodeBox, Box<Node> powNodeBox,
59 List<node_new.Node> defaultNodes, List<node_new.Node> defaultPowNodes) async {
60 final list = nodeBox.values.toList();
61 final powList = powNodeBox.values.toList();
62 for (final node in list) {
63 if (defaultNodes.any((item) => item.uri == node.uri)) {
64 // default nodes will be added by validateBuiltinNodes(), no need to migrate them.
65 await node.delete();
66 continue;
67 }
68 await node.migrateToSqlite(isPow: false, isBuiltin: false, isOfficial: false);
69 await node.delete();
70 }
71 for (final node in powList) {
72 if (defaultPowNodes.any((item) => item.uri == node.uri)) {
73 await node.delete();
74 continue;
75 }
76 await node.migrateToSqlite(isPow: true, isBuiltin: false, isOfficial: false);
77 await node.delete();
78 }
79 }
80
81 Future<void> migrateToSqlite(
82 {required bool isPow, required bool isBuiltin, required bool isOfficial}) async {
83 final newNode = node_new.Node(
84 id: key as int,
85 login: login,
86 label: label,
87 password: password,
88 type: type,
89 useSSL: useSSL,
90 trusted: trusted,
91 socksProxyAddress: socksProxyAddress,
92 isPow: isPow,
93 path: path,
94 uri: uriRaw,
95 isEnabledForAutoSwitching: isEnabledForAutoSwitching,
96 isOfficial: isOfficial,
97 isBuiltin: isBuiltin,
98 );
99 await newNode.save();
100 }
101
102 Node.fromMap(Map<String, Object?> map)
103 : uriRaw = map['uri'] as String? ?? '',
104 path = map['path'] as String? ?? '',
105 login = map['login'] as String?,
106 label = map['label'] as String?,
107 password = map['password'] as String?,
108 useSSL = map['useSSL'] as bool?,
109 trusted = map['trusted'] as bool? ?? false,
110 socksProxyAddress = map['socksProxyPort'] as String?,
111 isEnabledForAutoSwitching = map['isEnabledForAutoSwitching'] as bool? ?? false;
112
113 static const typeId = NODE_TYPE_ID;
114 static const boxName = 'Nodes';
115
116 @HiveField(0, defaultValue: '')
117 late String uriRaw;
118
119 @HiveField(1)
120 String? login;
121
122 @HiveField(2)
123 String? password;
124
125 @HiveField(3, defaultValue: 0)
126 late int typeRaw;
127
128 @HiveField(4)
129 bool? useSSL;
130
131 @HiveField(5, defaultValue: false)
132 bool trusted;
133
134 @HiveField(6)
135 String? socksProxyAddress;
136
137 @HiveField(7, defaultValue: '')
138 String? path;
139
140 @HiveField(8)
141 bool? isElectrs;
142
143 @HiveField(9)
144 bool? supportsSilentPayments;
145
146 @HiveField(10)
147 bool? supportsMweb;
148
149 @HiveField(11, defaultValue: false)
150 bool isEnabledForAutoSwitching;
151
152 @HiveField(12, defaultValue: '')
153 String? label;
154
155 bool get isSSL => useSSL ?? false;
156
157 bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
158
159 Uri get uri {
160 try {
161 return _uri;
162 } catch (e) {
163 printV(e);
164 return Uri();
165 }
166 }
167
168 Uri get _uri {
169 switch (type) {
170 case WalletType.monero:
171 case WalletType.zcash:
172 case WalletType.haven:
173 case WalletType.wownero:
174 return Uri.http(uriRaw, '');
175 case WalletType.bitcoin:
176 case WalletType.litecoin:
177 case WalletType.bitcoinCash:
178 case WalletType.dogecoin:
179 return createUriFromElectrumAddress(uriRaw, path!);
180 case WalletType.nano:
181 case WalletType.banano:
182 case WalletType.ethereum:
183 case WalletType.polygon:
184 case WalletType.base:
185 case WalletType.bsc:
186 case WalletType.arbitrum:
187 case WalletType.solana:
188 case WalletType.tron:
189 case WalletType.zano:
190 case WalletType.decred:
191 return Uri.parse(
192 "http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}");
193 case WalletType.none:
194 throw Exception('Unexpected type ${type.toString()} for Node uri');
195 }
196 }
197
198 bool get isValidProxyAddress => socksProxyAddress?.contains(':') ?? false;
199
200 @override
201 bool operator ==(other) =>
202 other is Node &&
203 (other.uriRaw == uriRaw &&
204 other.login == login &&
205 other.label == label &&
206 other.password == password &&
207 other.typeRaw == typeRaw &&
208 other.useSSL == useSSL &&
209 other.trusted == trusted &&
210 other.socksProxyAddress == socksProxyAddress &&
211 other.path == path);
212
213 @override
214 int get hashCode =>
215 uriRaw.hashCode ^
216 login.hashCode ^
217 label.hashCode ^
218 password.hashCode ^
219 typeRaw.hashCode ^
220 useSSL.hashCode ^
221 trusted.hashCode ^
222 socksProxyAddress.hashCode ^
223 path.hashCode;
224
225 @override
226 dynamic get keyIndex {
227 _keyIndex ??= key;
228 return _keyIndex;
229 }
230
231 WalletType get type => deserializeFromInt(typeRaw);
232
233 set type(WalletType type) => typeRaw = serializeToInt(type);
234
235 dynamic _keyIndex;
236 }