#43 new: bsd base support

This commit is contained in:
lollipopkit
2023-08-22 21:07:17 +08:00
parent e3f2b211a9
commit 417cb4c89d
23 changed files with 499 additions and 234 deletions

View File

@@ -470,7 +470,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -478,7 +478,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -602,7 +602,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -610,7 +610,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -628,7 +628,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -636,7 +636,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -657,7 +657,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -670,7 +670,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
@@ -696,7 +696,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -709,7 +709,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@@ -732,7 +732,7 @@
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -745,7 +745,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -35,11 +35,19 @@ enum DockerMenuType {
rm, rm,
logs, logs,
terminal, terminal,
stats; //stats,
;
static List<DockerMenuType> items(bool running) { static List<DockerMenuType> items(bool running) {
if (running) { if (running) {
return [stop, restart, rm, logs, terminal, stats]; return [
stop,
restart,
rm,
logs,
terminal,
//stats,
];
} else { } else {
return [start, rm, logs]; return [start, rm, logs];
} }
@@ -59,8 +67,8 @@ enum DockerMenuType {
return Icons.logo_dev; return Icons.logo_dev;
case DockerMenuType.terminal: case DockerMenuType.terminal:
return Icons.terminal; return Icons.terminal;
case DockerMenuType.stats: // case DockerMenuType.stats:
return Icons.bar_chart; // return Icons.bar_chart;
} }
} }
@@ -78,8 +86,8 @@ enum DockerMenuType {
return s.log; return s.log;
case DockerMenuType.terminal: case DockerMenuType.terminal:
return s.terminal; return s.terminal;
case DockerMenuType.stats: // case DockerMenuType.stats:
return s.stats; // return s.stats;
} }
} }

View File

@@ -1,7 +1,12 @@
import '../../res/build_data.dart';
import '../../res/server_cmd.dart'; import '../../res/server_cmd.dart';
import '../server/system.dart';
const _cmdDivider = '\necho $seperator\n'; const _cmdDivider = '\necho $seperator\n';
const _serverBoxDir = r'$HOME/.config/server_box';
const _shellPath = '$_serverBoxDir/mobile_app.sh';
enum AppShellFuncType { enum AppShellFuncType {
status, status,
docker; docker;
@@ -15,7 +20,7 @@ enum AppShellFuncType {
} }
} }
String get exec => 'sh $shellPath -$flag'; String get exec => 'sh $_shellPath -$flag';
String get name { String get name {
switch (this) { switch (this) {
@@ -31,16 +36,20 @@ enum AppShellFuncType {
String get cmd { String get cmd {
switch (this) { switch (this) {
case AppShellFuncType.status: case AppShellFuncType.status:
return statusCmds.join(_cmdDivider); return '''
result=\$(uname 2>&1 | grep "Linux")
if [ "\$result" != "" ]; then
${_statusCmds.join(_cmdDivider)}
else
${_bsdStatusCmd.join(_cmdDivider)}
fi''';
case AppShellFuncType.docker: case AppShellFuncType.docker:
return ''' return '''
result=\$(docker version 2>&1) result=\$(docker version 2>&1 | grep "permission denied")
deniedStr="permission denied" if [ "\$result" != "" ]; then
containStr=\$(echo \$result | grep "\${deniedStr}") ${_dockerCmds.join(_cmdDivider)}
if [[ \$containStr != "" ]]; then
${dockerCmds.join(_cmdDivider)}
else else
${dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)} ${_dockerCmds.map((e) => "sudo -S $e").join(_cmdDivider)}
fi'''; fi''';
} }
} }
@@ -83,6 +92,7 @@ extension EnumX on Enum {
} }
enum StatusCmdType { enum StatusCmdType {
echo,
time, time,
net, net,
sys, sys,
@@ -94,12 +104,81 @@ enum StatusCmdType {
tempType, tempType,
tempVal, tempVal,
host, host,
sysRhel; ;
} }
/// Cmds for linux server
const _statusCmds = [
'echo $linuxSign',
'date +%s',
'cat /proc/net/dev',
'cat /etc/*-release | grep PRETTY_NAME',
'cat /proc/stat | grep cpu',
'uptime',
'cat /proc/net/snmp',
'df -h',
'cat /proc/meminfo',
'cat /sys/class/thermal/thermal_zone*/type',
'cat /sys/class/thermal/thermal_zone*/temp',
'hostname',
];
enum DockerCmdType { enum DockerCmdType {
version, version,
ps, ps,
stats, //stats,
images; images,
;
} }
const _dockerCmds = [
'docker version',
'docker ps -a',
//'docker stats --no-stream',
'docker image ls',
];
enum BSDStatusCmdType {
echo,
time,
net,
sys,
cpu,
uptime,
disk,
mem,
//temp,
host,
;
}
/// Cmds for BSD server
const _bsdStatusCmd = [
'echo $bsdSign',
'date +%s',
'netstat -ibn',
'uname -or',
'top -l 1 | grep "CPU usage"',
'uptime',
'df -h',
'top -l 1 | grep PhysMem',
//'sysctl -a | grep temperature',
'hostname',
];
final _shellCmd = """
#!/bin/sh
#
# Script for ServerBox app v1.0.${BuildData.build}
#
# DO NOT delete this file while app is running
# DO NOT run multi ServerBox apps with different version at the same time
export LANG=en_US.UTF-8
${AppShellFuncType.shellScript}
""";
final installShellCmd = "mkdir -p $_serverBoxDir && "
"echo '$_shellCmd' > $_shellPath && "
"chmod +x $_shellPath";

View File

@@ -8,10 +8,10 @@ class DockerPsItem {
late String status; late String status;
late String ports; late String ports;
late String name; late String name;
String? cpu; // String? cpu;
String? mem; // String? mem;
String? net; // String? net;
String? disk; // String? disk;
DockerPsItem( DockerPsItem(
this.containerId, this.containerId,
@@ -41,19 +41,19 @@ class DockerPsItem {
} }
} }
void parseStats(String rawString) { // void parseStats(String rawString) {
if (rawString.isEmpty) { // if (rawString.isEmpty) {
return; // return;
} // }
final parts = rawString.split(_seperator); // final parts = rawString.split(_seperator);
if (parts.length != 8) { // if (parts.length != 8) {
return; // return;
} // }
cpu = parts[2]; // cpu = parts[2];
mem = parts[3]; // mem = parts[3];
net = parts[5]; // net = parts[5];
disk = parts[6]; // disk = parts[6];
} // }
bool get running => status.contains('Up '); bool get running => status.contains('Up ');

View File

@@ -1,3 +1,5 @@
import 'package:toolbox/data/res/status.dart';
import 'time_seq.dart'; import 'time_seq.dart';
class Cpus extends TimeSeq<OneTimeCpuStatus> { class Cpus extends TimeSeq<OneTimeCpuStatus> {
@@ -95,3 +97,22 @@ List<OneTimeCpuStatus> parseCPU(String raw) {
} }
return cpus; return cpus;
} }
final _bsdCpuPercentReg = RegExp(r'(\d+\.\d+)%');
/// TODO: Change this implementation to parse cpu status on BSD system
///
/// [raw]:
/// CPU usage: 14.70% user, 12.76% sys, 72.52% idle
Cpus parseBsdCpu(String raw) {
final percents = _bsdCpuPercentReg
.allMatches(raw)
.map((e) => double.parse(e.group(1) ?? '0') * 100)
.toList();
if (percents.length != 3) return initCpuStatus;
return initCpuStatus
..now = [
OneTimeCpuStatus('cpu', percents[0].toInt(), percents[1].toInt(), 0,
percents[2].toInt(), 0, 0, 0)
];
}

View File

@@ -115,3 +115,51 @@ List<NetSpeedPart> parseNetSpeed(String raw, int time) {
} }
return results; return results;
} }
/// [raw] example:
/// Name Mtu Network Address Ipkts Ierrs Ibytes Opkts Oerrs Obytes Coll
/// lo0 16384 <Link#1> 17296531 0 2524959720 17296531 0 2524959720 0
/// lo0 16384 127 127.0.0.1 17296531 - 2524959720 17296531 - 2524959720 -
/// lo0 16384 ::1/128 ::1 17296531 - 2524959720 17296531 - 2524959720 -
/// lo0 16384 fe80::1%lo0 fe80:1::1 17296531 - 2524959720 17296531 - 2524959720 -
/// gif0* 1280 <Link#2> 0 0 0 0 0 0 0
/// stf0* 1280 <Link#3> 0 0 0 0 0 0 0
/// en0 1500 <Link#4> 22:20:xx:xx:xx:e6 739447 0 693997876 535600 0 79008877 0
/// en0 1500 fe80::f1:xx fe80:4::f1:xxxx:9 739447 - 693997876 535600 - 79008877 -
/// en0 1500 192.168.2 192.168.2.111 739447 - 693997876 535600 - 79008877 -
/// en0 1500 fd6b:xxxx:3 fd6b:xxxx:xxxx:0: 739447 - 693997876 535600 - 79008877 -
/// en1 1500 <Link#5> 88:d8:xx:xx:xx:1d 0 0 0 0 0 0 0
/// utun0 1380 <Link#6> 0 0 0 3 0 280 0
/// utun0 1380 fe80::xxxx: fe80:6::xxxx:xxxx 0 - 0 3 - 280 -
/// utun1 2000 <Link#7> 0 0 0 3 0 280 0
/// utun1 2000 fe80::xxxx: fe80:7::xxxx:xxxx 0 - 0 3 - 280 -
/// utun2 1000 <Link#8> 0 0 0 3 0 280 0
/// utun2 1000 fe80::xxxx: fe80:8::xxxx:xxx: 0 - 0 3 - 280 -
/// utun4 9000 <Link#10> 746744 0 845373390 386111 0 424400998 0
/// utun4 9000 198.18.0/16 198.18.0.1 746744 - 845373390 386111 - 424400998 -
/// en2* 1500 <Link#11> 36:7c:xx:xx:xx:xx 0 0 0 0 0 0 0
List<NetSpeedPart> parseBsdNetSpeed(String raw, int time) {
final split = raw.split('\n');
if (split.length < 2) {
return [];
}
final results = <NetSpeedPart>[];
for (final item in split.sublist(1)) {
final data = item.trim().split(RegExp(r'\s+'));
final device = data[0];
if (device.endsWith('*')) {
continue;
}
if (results.any((element) => element.device == device)) {
continue;
}
if (data.length != 11) {
continue;
}
final bytesIn = BigInt.parse(data[6]);
final bytesOut = BigInt.parse(data[9]);
results.add(NetSpeedPart(device, bytesIn, bytesOut, time));
}
return results;
}

View File

@@ -1,3 +1,4 @@
import 'package:toolbox/data/model/server/system.dart';
import 'package:toolbox/data/model/server/temp.dart'; import 'package:toolbox/data/model/server/temp.dart';
import 'cpu.dart'; import 'cpu.dart';
@@ -16,6 +17,7 @@ class ServerStatus {
Conn tcp; Conn tcp;
NetSpeed netSpeed; NetSpeed netSpeed;
Temperatures temps; Temperatures temps;
SystemType system;
String? failedInfo; String? failedInfo;
ServerStatus({ ServerStatus({
@@ -28,6 +30,7 @@ class ServerStatus {
required this.netSpeed, required this.netSpeed,
required this.swap, required this.swap,
required this.temps, required this.temps,
required this.system,
this.failedInfo, this.failedInfo,
}); });
} }

View File

@@ -1,3 +1,5 @@
import 'package:toolbox/data/model/server/system.dart';
import '../app/shell_func.dart'; import '../app/shell_func.dart';
import 'cpu.dart'; import 'cpu.dart';
import 'disk.dart'; import 'disk.dart';
@@ -9,11 +11,25 @@ import 'conn.dart';
class ServerStatusUpdateReq { class ServerStatusUpdateReq {
final ServerStatus ss; final ServerStatus ss;
final List<String> segments; final List<String> segments;
final SystemType system;
const ServerStatusUpdateReq(this.ss, this.segments); const ServerStatusUpdateReq({
required this.system,
required this.ss,
required this.segments,
});
} }
Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async { Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
switch (req.system) {
case SystemType.linux:
return _getLinuxStatus(req);
case SystemType.bsd:
return _getBsdStatus(req);
}
}
Future<ServerStatus> _getLinuxStatus(ServerStatusUpdateReq req) async {
final segments = req.segments; final segments = req.segments;
final time = int.parse(StatusCmdType.time.find(segments)); final time = int.parse(StatusCmdType.time.find(segments));
@@ -24,7 +40,6 @@ Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
final sys = _parseSysVer( final sys = _parseSysVer(
StatusCmdType.sys.find(segments), StatusCmdType.sys.find(segments),
StatusCmdType.host.find(segments), StatusCmdType.host.find(segments),
StatusCmdType.sysRhel.find(segments),
); );
if (sys != null) { if (sys != null) {
req.ss.sysVer = sys; req.ss.sysVer = sys;
@@ -56,6 +71,30 @@ Future<ServerStatus> getStatus(ServerStatusUpdateReq req) async {
return req.ss; return req.ss;
} }
Future<ServerStatus> _getBsdStatus(ServerStatusUpdateReq req) async {
final segments = req.segments;
final time = int.parse(BSDStatusCmdType.time.find(segments));
final net = parseBsdNetSpeed(BSDStatusCmdType.net.find(segments), time);
req.ss.netSpeed.update(net);
req.ss.sysVer = BSDStatusCmdType.sys.find(segments);
req.ss.cpu = parseBsdCpu(BSDStatusCmdType.cpu.find(segments));
//req.ss.mem = parseBsdMem(BSDStatusCmdType.mem.find(segments));
final uptime = _parseUpTime(BSDStatusCmdType.uptime.find(segments));
if (uptime != null) {
req.ss.uptime = uptime;
}
req.ss.disk = parseDisk(BSDStatusCmdType.disk.find(segments));
return req.ss;
}
// raw: // raw:
// 19:39:15 up 61 days, 18:16, 1 user, load average: 0.00, 0.00, 0.00 // 19:39:15 up 61 days, 18:16, 1 user, load average: 0.00, 0.00, 0.00
String? _parseUpTime(String raw) { String? _parseUpTime(String raw) {
@@ -69,17 +108,14 @@ String? _parseUpTime(String raw) {
return null; return null;
} }
String? _parseSysVer(String raw, String hostname, String rawRhel) { String? _parseSysVer(String raw, String hostname) {
try { try {
final s = raw.split('='); final s = raw.split('=');
if (s.length == 2) { if (s.length == 2) {
return s[1].replaceAll('"', '').replaceFirst('\n', ''); return s[1].replaceAll('"', '').replaceFirst('\n', '');
} }
} catch (e) { } finally {
if (!rawRhel.contains('cat: /etc/redhat-release:')) { // ignore: control_flow_in_finally
return rawRhel; return hostname.isEmpty ? null : hostname;
}
if (hostname.isNotEmpty) return hostname;
} }
return null;
} }

View File

@@ -0,0 +1,34 @@
import 'package:toolbox/data/model/app/shell_func.dart';
enum SystemType {
linux._(linuxSign),
bsd._(bsdSign),
;
final String value;
const SystemType._(this.value);
static SystemType? parse(String? value) {
if (value == null) return null;
switch (value) {
case linuxSign:
return SystemType.linux;
case bsdSign:
return SystemType.bsd;
}
return null;
}
bool isSegmentsLenMatch(int len) {
switch (this) {
case SystemType.linux:
return len == StatusCmdType.values.length;
case SystemType.bsd:
return len == BSDStatusCmdType.values.length;
}
}
}
const linuxSign = 'linux';
const bsdSign = 'bsd';

View File

@@ -1,5 +1,3 @@
// ignore_for_file: prefer_final_fields
abstract class TimeSeq<T extends TimeSeqIface> { abstract class TimeSeq<T extends TimeSeqIface> {
List<T> pre; List<T> pre;
List<T> now; List<T> now;

View File

@@ -10,10 +10,11 @@ import 'package:toolbox/data/model/app/shell_func.dart';
import 'package:toolbox/data/model/docker/image.dart'; import 'package:toolbox/data/model/docker/image.dart';
import 'package:toolbox/data/model/docker/ps.dart'; import 'package:toolbox/data/model/docker/ps.dart';
import 'package:toolbox/data/model/app/error.dart'; import 'package:toolbox/data/model/app/error.dart';
import 'package:toolbox/data/res/server_cmd.dart';
import 'package:toolbox/data/store/docker.dart'; import 'package:toolbox/data/store/docker.dart';
import 'package:toolbox/locator.dart'; import 'package:toolbox/locator.dart';
import '../res/server_cmd.dart';
final _dockerNotFound = RegExp(r'command not found|Unknown command'); final _dockerNotFound = RegExp(r'command not found|Unknown command');
final _versionReg = RegExp(r'(Version:)\s+([0-9]+\.[0-9]+\.[0-9]+)'); final _versionReg = RegExp(r'(Version:)\s+([0-9]+\.[0-9]+\.[0-9]+)');
// eg: `Docker Engine - Community` // eg: `Docker Engine - Community`
@@ -72,7 +73,7 @@ class DockerProvider extends ChangeNotifier {
// Check result segments count // Check result segments count
final segments = raw.split(seperator); final segments = raw.split(seperator);
if (segments.length != dockerCmds.length) { if (segments.length != DockerCmdType.values.length) {
error = DockerErr(type: DockerErrType.segmentsNotMatch); error = DockerErr(type: DockerErrType.segmentsNotMatch);
_logger.warning('Docker segments not match: ${segments.length}'); _logger.warning('Docker segments not match: ${segments.length}');
notifyListeners(); notifyListeners();
@@ -119,28 +120,28 @@ class DockerProvider extends ChangeNotifier {
} }
// Parse docker stats // Parse docker stats
final statsRaw = DockerCmdType.stats.find(segments); // final statsRaw = DockerCmdType.stats.find(segments);
try { // try {
final statsLines = statsRaw.split('\n'); // final statsLines = statsRaw.split('\n');
statsLines.removeWhere((element) => element.isEmpty); // statsLines.removeWhere((element) => element.isEmpty);
if (statsLines.isNotEmpty) statsLines.removeAt(0); // if (statsLines.isNotEmpty) statsLines.removeAt(0);
for (var item in items!) { // for (var item in items!) {
final statsLine = statsLines.firstWhere( // final statsLine = statsLines.firstWhere(
(element) => element.contains(item.containerId), // (element) => element.contains(item.containerId),
orElse: () => '', // orElse: () => '',
); // );
if (statsLine.isEmpty) continue; // if (statsLine.isEmpty) continue;
item.parseStats(statsLine); // item.parseStats(statsLine);
} // }
} catch (e, trace) { // } catch (e, trace) {
error = DockerErr( // error = DockerErr(
type: DockerErrType.parseStats, // type: DockerErrType.parseStats,
message: '$statsRaw\n-\n$e', // message: '$statsRaw\n-\n$e',
); // );
_logger.warning('Parse docker stats: $statsRaw', e, trace); // _logger.warning('Parse docker stats: $statsRaw', e, trace);
} finally { // } finally {
notifyListeners(); // notifyListeners();
} // }
} }
Future<void> _onPwd(String event, StreamSink<Uint8List> stdin) async { Future<void> _onPwd(String event, StreamSink<Uint8List> stdin) async {

View File

@@ -3,6 +3,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/model/app/shell_func.dart';
import 'package:toolbox/data/model/server/system.dart';
import '../../core/extension/order.dart'; import '../../core/extension/order.dart';
import '../../core/extension/uint8list.dart'; import '../../core/extension/uint8list.dart';
@@ -265,18 +266,28 @@ class ServerProvider extends ChangeNotifier {
final raw = await s.client?.run(AppShellFuncType.status.exec).string; final raw = await s.client?.run(AppShellFuncType.status.exec).string;
final segments = raw?.split(seperator).map((e) => e.trim()).toList(); final segments = raw?.split(seperator).map((e) => e.trim()).toList();
if (raw == null || if (raw == null || raw.isEmpty || segments == null || segments.isEmpty) {
raw.isEmpty ||
segments == null ||
segments.length != StatusCmdType.values.length) {
_limiter.inc(sid); _limiter.inc(sid);
s.status.failedInfo = 'Seperate segments failed, raw:\n$raw'; s.status.failedInfo = 'Seperate segments failed, raw:\n$raw';
_setServerState(s, ServerState.failed); _setServerState(s, ServerState.failed);
return; return;
} }
final systemType = SystemType.parse(segments[0]);
if (systemType == null || !systemType.isSegmentsLenMatch(segments.length)) {
_limiter.inc(sid);
s.status.failedInfo = 'Segments not match: ${segments.length}';
_setServerState(s, ServerState.failed);
return;
}
s.status.system = systemType;
try { try {
final req = ServerStatusUpdateReq(s.status, segments); final req = ServerStatusUpdateReq(
ss: s.status,
segments: segments,
system: systemType,
);
s.status = await compute(getStatus, req); s.status = await compute(getStatus, req);
} catch (e, trace) { } catch (e, trace) {
_limiter.inc(sid); _limiter.inc(sid);

View File

@@ -2,8 +2,8 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 491; static const int build = 493;
static const String engine = "3.10.6"; static const String engine = "3.13.0";
static const String buildAt = "2023-08-20 23:32:07.343451"; static const String buildAt = "2023-08-22 16:14:41.022063";
static const int modifications = 4; static const int modifications = 8;
} }

View File

@@ -1,41 +1 @@
import '../model/app/shell_func.dart';
import 'build_data.dart';
const seperator = 'SrvBoxSep'; const seperator = 'SrvBoxSep';
const serverBoxDir = r'$HOME/.config/server_box';
const shellPath = '$serverBoxDir/mobile_app.sh';
const statusCmds = [
'date +%s',
'cat /proc/net/dev',
'cat /etc/os-release | grep PRETTY_NAME',
'cat /proc/stat | grep cpu',
'uptime',
'cat /proc/net/snmp',
'df -h',
'cat /proc/meminfo',
'cat /sys/class/thermal/thermal_zone*/type',
'cat /sys/class/thermal/thermal_zone*/temp',
'hostname',
'cat /etc/redhat-release',
];
const dockerCmds = [
'docker version',
'docker ps -a',
'docker stats --no-stream',
'docker image ls',
];
final shellCmd = """
# Script for app `${BuildData.name} v1.0.${BuildData.build}`
# Delete this file while app is running will cause app crash
export LANG=en_US.UTF-8
${AppShellFuncType.shellScript}
""";
final installShellCmd = "mkdir -p $serverBoxDir && "
"echo '$shellCmd' > $shellPath && "
"chmod +x $shellPath";

View File

@@ -6,6 +6,7 @@ import '../model/server/memory.dart';
import '../model/server/net_speed.dart'; import '../model/server/net_speed.dart';
import '../model/server/server_status.dart'; import '../model/server/server_status.dart';
import '../model/server/conn.dart'; import '../model/server/conn.dart';
import '../model/server/system.dart';
Memory get _initMemory => Memory( Memory get _initMemory => Memory(
total: 1, total: 1,
@@ -38,8 +39,8 @@ NetSpeed get initNetSpeed => NetSpeed(
[_initNetSpeedPart], [_initNetSpeedPart],
); );
Swap get _initSwap => Swap( Swap get _initSwap => Swap(
total: 1, total: 0,
free: 1, free: 0,
cached: 0, cached: 0,
); );
ServerStatus get initStatus => ServerStatus( ServerStatus get initStatus => ServerStatus(
@@ -60,5 +61,6 @@ ServerStatus get initStatus => ServerStatus(
tcp: Conn(maxConn: 0, active: 0, passive: 0, fail: 0), tcp: Conn(maxConn: 0, active: 0, passive: 0, fail: 0),
netSpeed: initNetSpeed, netSpeed: initNetSpeed,
swap: _initSwap, swap: _initSwap,
system: SystemType.linux,
temps: Temperatures(), temps: Temperatures(),
); );

View File

@@ -474,24 +474,24 @@ class _DockerManagePageState extends State<DockerManagePage> {
'Docker terminal', 'Docker terminal',
).go(context); ).go(context);
break; break;
case DockerMenuType.stats: // case DockerMenuType.stats:
showRoundDialog( // showRoundDialog(
context: context, // context: context,
title: Text(_s.stats), // title: Text(_s.stats),
child: Text( // child: Text(
'CPU: ${dItem.cpu}\n' // 'CPU: ${dItem.cpu}\n'
'Mem: ${dItem.mem}\n' // 'Mem: ${dItem.mem}\n'
'Net: ${dItem.net}\n' // 'Net: ${dItem.net}\n'
'Block: ${dItem.disk}', // 'Block: ${dItem.disk}',
), // ),
actions: [ // actions: [
TextButton( // TextButton(
onPressed: () => context.pop(), // onPressed: () => context.pop(),
child: Text(_s.ok), // child: Text(_s.ok),
), // ),
], // ],
); // );
break; // break;
} }
}, },
); );

View File

@@ -108,12 +108,6 @@ class _ServerPageState extends State<ServerPage>
); );
} }
List<String> _filterServers(ServerProvider pro) => pro.serverOrder
.where((e) => pro.servers.containsKey(e))
.where((e) =>
_tag == null || (pro.servers[e]?.spi.tags?.contains(_tag) ?? false))
.toList();
Widget _buildTagsSwitcher(ServerProvider provider) { Widget _buildTagsSwitcher(ServerProvider provider) {
return TagSwitcher( return TagSwitcher(
tags: provider.tags, tags: provider.tags,
@@ -224,14 +218,11 @@ class _ServerPageState extends State<ServerPage>
) { ) {
final rootDisk = findRootDisk(ss.disk); final rootDisk = findRootDisk(ss.disk);
late final List<Widget> children; late final List<Widget> children;
double? height;
if (cs != ServerState.finished) { if (cs != ServerState.finished) {
height = 23.0;
children = [ children = [
_buildServerCardTitle(ss, cs, spi), _buildServerCardTitle(ss, cs, spi),
]; ];
} else { } else {
height = 107;
children = [ children = [
_buildServerCardTitle(ss, cs, spi), _buildServerCardTitle(ss, cs, spi),
height13, height13,
@@ -262,7 +253,7 @@ class _ServerPageState extends State<ServerPage>
return AnimatedContainer( return AnimatedContainer(
duration: const Duration(milliseconds: 377), duration: const Duration(milliseconds: 377),
curve: Curves.fastEaseInToSlowEaseOut, curve: Curves.fastEaseInToSlowEaseOut,
height: height, height: _calcCardHeight(cs),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
@@ -355,38 +346,6 @@ class _ServerPageState extends State<ServerPage>
); );
} }
String _getTopRightStr(
ServerState cs,
double? temp,
String upTime,
String? failedInfo,
) {
switch (cs) {
case ServerState.disconnected:
return _s.disconnected;
case ServerState.finished:
final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C';
final items = [tempStr, upTime];
final str = items.where((element) => element.isNotEmpty).join(' | ');
if (str.isEmpty) return _s.noResult;
return str;
case ServerState.loading:
return _s.serverTabLoading;
case ServerState.connected:
return _s.connected;
case ServerState.connecting:
return _s.serverTabConnecting;
case ServerState.failed:
if (failedInfo == null) {
return _s.serverTabFailed;
}
if (failedInfo.contains('encypted')) {
return _s.serverTabPlzSave;
}
return failedInfo;
}
}
Widget _buildIOData(String up, String down) { Widget _buildIOData(String up, String down) {
return Column( return Column(
children: [ children: [
@@ -448,4 +407,52 @@ class _ServerPageState extends State<ServerPage>
} }
_serverProvider.startAutoRefresh(); _serverProvider.startAutoRefresh();
} }
List<String> _filterServers(ServerProvider pro) => pro.serverOrder
.where((e) => pro.servers.containsKey(e))
.where((e) =>
_tag == null || (pro.servers[e]?.spi.tags?.contains(_tag) ?? false))
.toList();
String _getTopRightStr(
ServerState cs,
double? temp,
String upTime,
String? failedInfo,
) {
switch (cs) {
case ServerState.disconnected:
return _s.disconnected;
case ServerState.finished:
final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C';
final items = [tempStr, upTime];
final str = items.where((element) => element.isNotEmpty).join(' | ');
if (str.isEmpty) return _s.noResult;
return str;
case ServerState.loading:
return _s.serverTabLoading;
case ServerState.connected:
return _s.connected;
case ServerState.connecting:
return _s.serverTabConnecting;
case ServerState.failed:
if (failedInfo == null) {
return _s.serverTabFailed;
}
if (failedInfo.contains('encypted')) {
return _s.serverTabPlzSave;
}
return failedInfo;
}
}
double _calcCardHeight(ServerState cs) {
if (cs != ServerState.finished) {
return 23.0;
}
if (_settingStore.moveOutServerTabFuncBtns.fetch()!) {
return 132;
}
return 107;
}
} }

View File

@@ -130,7 +130,7 @@ class _SSHPageState extends State<SSHPage> {
deleteDetection: isIOS, deleteDetection: isIOS,
autofocus: true, autofocus: true,
keyboardAppearance: _isDark ? Brightness.dark : Brightness.light, keyboardAppearance: _isDark ? Brightness.dark : Brightness.light,
hideScrollBar: isMobile, hideScrollBar: false,
), ),
), ),
); );

View File

@@ -55,12 +55,13 @@ class Input extends StatelessWidget {
autocorrect: autoCorrect, autocorrect: autoCorrect,
enableSuggestions: suggestiion, enableSuggestions: suggestiion,
decoration: InputDecoration( decoration: InputDecoration(
label: label != null ? Text(label!) : null, label: label != null ? Text(label!) : null,
hintText: hint, hintText: hint,
icon: icon != null ? Icon(icon) : null, icon: icon != null ? Icon(icon) : null,
border: InputBorder.none, border: InputBorder.none,
errorText: errorText, errorText: errorText,
prefix: prefix,), prefix: prefix,
),
controller: controller, controller: controller,
obscureText: obscureText, obscureText: obscureText,
), ),

View File

@@ -258,7 +258,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 0920; LastSwiftUpdateCheck = 0920;
LastUpgradeCheck = 1300; LastUpgradeCheck = 1430;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
331C80D4294CF70F00263BE5 = { 331C80D4294CF70F00263BE5 = {
@@ -474,9 +474,9 @@
baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */; baseConfigurationReference = C1C758C41C4E208965A68933 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -489,9 +489,9 @@
baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */; baseConfigurationReference = 15AF97DF993E8968098D6EBE /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -504,9 +504,9 @@
baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */; baseConfigurationReference = 7CFA7DE7FABA75685DFB6948 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CURRENT_PROJECT_VERSION = 491; CURRENT_PROJECT_VERSION = 493;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0.491; MARKETING_VERSION = 1.0.493;
PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = tech.lolli.serverBox.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1300" LastUpgradeVersion = "1430"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@@ -17,6 +17,7 @@ const buildFuncs = {
'ios': flutterBuildIOS, 'ios': flutterBuildIOS,
'android': flutterBuildAndroid, 'android': flutterBuildAndroid,
'macos': flutterBuildMacOS, 'macos': flutterBuildMacOS,
'linux': flutterBuildLinux,
}; };
int? build; int? build;
@@ -133,15 +134,21 @@ Future<void> flutterBuildIOS() async {
Future<void> flutterBuildMacOS() async { Future<void> flutterBuildMacOS() async {
await flutterBuild('macos'); await flutterBuild('macos');
await scpMacOS2CDN();
} }
Future<void> flutterBuildAndroid() async { Future<void> flutterBuildAndroid() async {
await flutterBuild('apk'); await flutterBuild('apk');
await killJava(); await killJava();
await scp2CDN(); await scpApk2CDN();
} }
Future<void> scp2CDN() async { Future<void> flutterBuildLinux() async {
await flutterBuild('linux');
await scpLinux2CDN();
}
Future<void> scpApk2CDN() async {
final sha256 = await getFileSha256(apkPath); final sha256 = await getFileSha256(apkPath);
print('SHA256: $sha256'); print('SHA256: $sha256');
final result = await Process.run( final result = await Process.run(
@@ -155,6 +162,45 @@ Future<void> scp2CDN() async {
} }
} }
Future<void> scpMacOS2CDN() async {
final zipName = '$build.app.zip';
// Zip the .app
await Process.run('zip', [
'-r',
'./release/$zipName',
'./build/macos/Build/Products/Release/server_box.app',
]);
final result = await Process.run(
'scp',
[
'./release/$zipName',
'hk:/var/www/res/serverbox/$build.app.zip',
],
runInShell: true,
);
if (result.exitCode != 0) {
print(result.stderr);
exit(1);
}
print('Upload macOS $zipName finished.');
}
Future<void> scpLinux2CDN() async {
final result = await Process.run(
'scp',
[
'./build/linux/x64/release/bundle/server_box.tar.gz',
'hk:/var/www/res/serverbox/$build.tar.gz',
],
runInShell: true,
);
if (result.exitCode != 0) {
print(result.stderr);
exit(1);
}
print('Upload Linux $build.tar.gz finished.');
}
Future<void> changeAppleVersion() async { Future<void> changeAppleVersion() async {
for (final path in ['ios', 'macos']) { for (final path in ['ios', 'macos']) {
final file = File('$path/$appleXCConfigPath'); final file = File('$path/$appleXCConfigPath');
@@ -185,38 +231,40 @@ void main(List<String> args) async {
} }
final command = args[0]; final command = args[0];
switch (command) { switch (command) {
case 'build': case 'build':
final stopwatch = Stopwatch()..start();
await dartFormat(); await dartFormat();
await getGitCommitCount(); await getGitCommitCount();
// always change version to avoid dismatch version between different // always change version to avoid dismatch version between different
// platforms // platforms
await changeAppleVersion(); await changeAppleVersion();
await updateBuildData(); await updateBuildData();
final funcs = <Future<void> Function()>[];
if (args.length > 1) { if (args.length > 1) {
final platforms = args[1]; final platforms = args[1];
for (final platform in platforms.split(',')) { for (final platform in platforms.split(',')) {
if (buildFuncs.keys.contains(platform)) { if (buildFuncs.keys.contains(platform)) {
await buildFuncs[platform]!(); funcs.add(buildFuncs[platform]!);
print('Build finished in [${stopwatch.elapsed}]');
stopwatch.reset();
stopwatch.start();
} else { } else {
print('Unknown platform: $platform'); print('Unknown platform: $platform');
} }
} }
} else {
funcs.addAll(buildFuncs.values);
}
return; final stopwatch = Stopwatch();
} for (final func in funcs) {
for (final func in buildFuncs.values) { stopwatch.start();
await func(); await func();
print('Build finished in ${stopwatch.elapsed}\n');
stopwatch.reset();
} }
print('Build finished in ${stopwatch.elapsed}\n'); break;
return;
default: default:
print('Unsupported command: $command'); print('Unsupported command: $command');
return; break;
} }
} }

View File

@@ -182,10 +182,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.1" version: "1.17.2"
convert: convert:
dependency: transitive dependency: transitive
description: description:
@@ -458,10 +458,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.0" version: "0.18.1"
io: io:
dependency: transitive dependency: transitive
description: description:
@@ -522,18 +522,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.15" version: "0.12.16"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.0" version: "0.5.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@@ -839,10 +839,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.10.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@@ -887,10 +887,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.6.0"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@@ -1003,6 +1003,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
@@ -1061,5 +1069,5 @@ packages:
source: hosted source: hosted
version: "0.0.6" version: "0.0.6"
sdks: sdks:
dart: ">=3.0.0 <4.0.0" dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=3.10.0" flutter: ">=3.10.0"