new: add custom url-test for each repository
This commit is contained in:
2
Makefile
2
Makefile
@@ -39,7 +39,7 @@ DISTRIBUTOR_ARGS=--skip-clean --build-target $(TARGET) --build-dart-define sentr
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
get:
|
get:
|
||||||
flutter pub get
|
flutter pub get
|
||||||
|
|
||||||
gen:
|
gen:
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class AppDatabase extends _$AppDatabase with InfraLogger {
|
|||||||
AppDatabase.connect() : super(openConnection());
|
AppDatabase.connect() : super(openConnection());
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get schemaVersion => 3;
|
int get schemaVersion => 4;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MigrationStrategy get migration {
|
MigrationStrategy get migration {
|
||||||
@@ -48,6 +48,9 @@ class AppDatabase extends _$AppDatabase with InfraLogger {
|
|||||||
await m.createTable(schema.geoAssetEntries);
|
await m.createTable(schema.geoAssetEntries);
|
||||||
await _prePopulateGeoAssets();
|
await _prePopulateGeoAssets();
|
||||||
},
|
},
|
||||||
|
from3To4: (m, schema) async {
|
||||||
|
await m.addColumn(profileEntries, profileEntries.testUrl);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
beforeOpen: (details) async {
|
beforeOpen: (details) async {
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
|
|||||||
@@ -39,78 +39,38 @@ final class _S2 extends i0.VersionedSchema {
|
|||||||
|
|
||||||
class Shape0 extends i0.VersionedTable {
|
class Shape0 extends i0.VersionedTable {
|
||||||
Shape0({required super.source, required super.alias}) : super.aliased();
|
Shape0({required super.source, required super.alias}) : super.aliased();
|
||||||
i1.GeneratedColumn<String> get id =>
|
i1.GeneratedColumn<String> get id => columnsByName['id']! as i1.GeneratedColumn<String>;
|
||||||
columnsByName['id']! as i1.GeneratedColumn<String>;
|
i1.GeneratedColumn<String> get type => columnsByName['type']! as i1.GeneratedColumn<String>;
|
||||||
i1.GeneratedColumn<String> get type =>
|
i1.GeneratedColumn<bool> get active => columnsByName['active']! as i1.GeneratedColumn<bool>;
|
||||||
columnsByName['type']! as i1.GeneratedColumn<String>;
|
i1.GeneratedColumn<String> get name => columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||||
i1.GeneratedColumn<bool> get active =>
|
i1.GeneratedColumn<String> get url => columnsByName['url']! as i1.GeneratedColumn<String>;
|
||||||
columnsByName['active']! as i1.GeneratedColumn<bool>;
|
i1.GeneratedColumn<DateTime> get lastUpdate => columnsByName['last_update']! as i1.GeneratedColumn<DateTime>;
|
||||||
i1.GeneratedColumn<String> get name =>
|
i1.GeneratedColumn<int> get updateInterval => columnsByName['update_interval']! as i1.GeneratedColumn<int>;
|
||||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
i1.GeneratedColumn<int> get upload => columnsByName['upload']! as i1.GeneratedColumn<int>;
|
||||||
i1.GeneratedColumn<String> get url =>
|
i1.GeneratedColumn<int> get download => columnsByName['download']! as i1.GeneratedColumn<int>;
|
||||||
columnsByName['url']! as i1.GeneratedColumn<String>;
|
i1.GeneratedColumn<int> get total => columnsByName['total']! as i1.GeneratedColumn<int>;
|
||||||
i1.GeneratedColumn<DateTime> get lastUpdate =>
|
i1.GeneratedColumn<DateTime> get expire => columnsByName['expire']! as i1.GeneratedColumn<DateTime>;
|
||||||
columnsByName['last_update']! as i1.GeneratedColumn<DateTime>;
|
i1.GeneratedColumn<String> get webPageUrl => columnsByName['web_page_url']! as i1.GeneratedColumn<String>;
|
||||||
i1.GeneratedColumn<int> get updateInterval =>
|
i1.GeneratedColumn<String> get supportUrl => columnsByName['support_url']! as i1.GeneratedColumn<String>;
|
||||||
columnsByName['update_interval']! as i1.GeneratedColumn<int>;
|
|
||||||
i1.GeneratedColumn<int> get upload =>
|
|
||||||
columnsByName['upload']! as i1.GeneratedColumn<int>;
|
|
||||||
i1.GeneratedColumn<int> get download =>
|
|
||||||
columnsByName['download']! as i1.GeneratedColumn<int>;
|
|
||||||
i1.GeneratedColumn<int> get total =>
|
|
||||||
columnsByName['total']! as i1.GeneratedColumn<int>;
|
|
||||||
i1.GeneratedColumn<DateTime> get expire =>
|
|
||||||
columnsByName['expire']! as i1.GeneratedColumn<DateTime>;
|
|
||||||
i1.GeneratedColumn<String> get webPageUrl =>
|
|
||||||
columnsByName['web_page_url']! as i1.GeneratedColumn<String>;
|
|
||||||
i1.GeneratedColumn<String> get supportUrl =>
|
|
||||||
columnsByName['support_url']! as i1.GeneratedColumn<String>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i1.GeneratedColumn<String> _column_0(String aliasedName) =>
|
i1.GeneratedColumn<String> _column_0(String aliasedName) => i1.GeneratedColumn<String>('id', aliasedName, false, type: i1.DriftSqlType.string);
|
||||||
i1.GeneratedColumn<String>('id', aliasedName, false,
|
i1.GeneratedColumn<String> _column_1(String aliasedName) => i1.GeneratedColumn<String>('type', aliasedName, false, type: i1.DriftSqlType.string);
|
||||||
type: i1.DriftSqlType.string);
|
i1.GeneratedColumn<bool> _column_2(String aliasedName) => i1.GeneratedColumn<bool>('active', aliasedName, false, type: i1.DriftSqlType.bool, defaultConstraints: i1.GeneratedColumn.constraintIsAlways('CHECK ("active" IN (0, 1))'));
|
||||||
i1.GeneratedColumn<String> _column_1(String aliasedName) =>
|
i1.GeneratedColumn<String> _column_3(String aliasedName) => i1.GeneratedColumn<String>('name', aliasedName, false,
|
||||||
i1.GeneratedColumn<String>('type', aliasedName, false,
|
additionalChecks: i1.GeneratedColumn.checkTextLength(
|
||||||
type: i1.DriftSqlType.string);
|
minTextLength: 1,
|
||||||
i1.GeneratedColumn<bool> _column_2(String aliasedName) =>
|
),
|
||||||
i1.GeneratedColumn<bool>('active', aliasedName, false,
|
type: i1.DriftSqlType.string);
|
||||||
type: i1.DriftSqlType.bool,
|
i1.GeneratedColumn<String> _column_4(String aliasedName) => i1.GeneratedColumn<String>('url', aliasedName, true, type: i1.DriftSqlType.string);
|
||||||
defaultConstraints: i1.GeneratedColumn.constraintIsAlways(
|
i1.GeneratedColumn<DateTime> _column_5(String aliasedName) => i1.GeneratedColumn<DateTime>('last_update', aliasedName, false, type: i1.DriftSqlType.dateTime);
|
||||||
'CHECK ("active" IN (0, 1))'));
|
i1.GeneratedColumn<int> _column_6(String aliasedName) => i1.GeneratedColumn<int>('update_interval', aliasedName, true, type: i1.DriftSqlType.int);
|
||||||
i1.GeneratedColumn<String> _column_3(String aliasedName) =>
|
i1.GeneratedColumn<int> _column_7(String aliasedName) => i1.GeneratedColumn<int>('upload', aliasedName, true, type: i1.DriftSqlType.int);
|
||||||
i1.GeneratedColumn<String>('name', aliasedName, false,
|
i1.GeneratedColumn<int> _column_8(String aliasedName) => i1.GeneratedColumn<int>('download', aliasedName, true, type: i1.DriftSqlType.int);
|
||||||
additionalChecks: i1.GeneratedColumn.checkTextLength(
|
i1.GeneratedColumn<int> _column_9(String aliasedName) => i1.GeneratedColumn<int>('total', aliasedName, true, type: i1.DriftSqlType.int);
|
||||||
minTextLength: 1,
|
i1.GeneratedColumn<DateTime> _column_10(String aliasedName) => i1.GeneratedColumn<DateTime>('expire', aliasedName, true, type: i1.DriftSqlType.dateTime);
|
||||||
),
|
i1.GeneratedColumn<String> _column_11(String aliasedName) => i1.GeneratedColumn<String>('web_page_url', aliasedName, true, type: i1.DriftSqlType.string);
|
||||||
type: i1.DriftSqlType.string);
|
i1.GeneratedColumn<String> _column_12(String aliasedName) => i1.GeneratedColumn<String>('support_url', aliasedName, true, type: i1.DriftSqlType.string);
|
||||||
i1.GeneratedColumn<String> _column_4(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<String>('url', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.string);
|
|
||||||
i1.GeneratedColumn<DateTime> _column_5(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<DateTime>('last_update', aliasedName, false,
|
|
||||||
type: i1.DriftSqlType.dateTime);
|
|
||||||
i1.GeneratedColumn<int> _column_6(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<int>('update_interval', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.int);
|
|
||||||
i1.GeneratedColumn<int> _column_7(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<int>('upload', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.int);
|
|
||||||
i1.GeneratedColumn<int> _column_8(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<int>('download', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.int);
|
|
||||||
i1.GeneratedColumn<int> _column_9(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<int>('total', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.int);
|
|
||||||
i1.GeneratedColumn<DateTime> _column_10(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<DateTime>('expire', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.dateTime);
|
|
||||||
i1.GeneratedColumn<String> _column_11(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<String>('web_page_url', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.string);
|
|
||||||
i1.GeneratedColumn<String> _column_12(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<String>('support_url', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.string);
|
|
||||||
|
|
||||||
final class _S3 extends i0.VersionedSchema {
|
final class _S3 extends i0.VersionedSchema {
|
||||||
_S3({required super.database}) : super(version: 3);
|
_S3({required super.database}) : super(version: 3);
|
||||||
@@ -170,37 +130,26 @@ final class _S3 extends i0.VersionedSchema {
|
|||||||
|
|
||||||
class Shape1 extends i0.VersionedTable {
|
class Shape1 extends i0.VersionedTable {
|
||||||
Shape1({required super.source, required super.alias}) : super.aliased();
|
Shape1({required super.source, required super.alias}) : super.aliased();
|
||||||
i1.GeneratedColumn<String> get id =>
|
i1.GeneratedColumn<String> get id => columnsByName['id']! as i1.GeneratedColumn<String>;
|
||||||
columnsByName['id']! as i1.GeneratedColumn<String>;
|
i1.GeneratedColumn<String> get type => columnsByName['type']! as i1.GeneratedColumn<String>;
|
||||||
i1.GeneratedColumn<String> get type =>
|
i1.GeneratedColumn<bool> get active => columnsByName['active']! as i1.GeneratedColumn<bool>;
|
||||||
columnsByName['type']! as i1.GeneratedColumn<String>;
|
i1.GeneratedColumn<String> get name => columnsByName['name']! as i1.GeneratedColumn<String>;
|
||||||
i1.GeneratedColumn<bool> get active =>
|
i1.GeneratedColumn<String> get providerName => columnsByName['provider_name']! as i1.GeneratedColumn<String>;
|
||||||
columnsByName['active']! as i1.GeneratedColumn<bool>;
|
i1.GeneratedColumn<String> get version => columnsByName['version']! as i1.GeneratedColumn<String>;
|
||||||
i1.GeneratedColumn<String> get name =>
|
i1.GeneratedColumn<DateTime> get lastCheck => columnsByName['last_check']! as i1.GeneratedColumn<DateTime>;
|
||||||
columnsByName['name']! as i1.GeneratedColumn<String>;
|
|
||||||
i1.GeneratedColumn<String> get providerName =>
|
|
||||||
columnsByName['provider_name']! as i1.GeneratedColumn<String>;
|
|
||||||
i1.GeneratedColumn<String> get version =>
|
|
||||||
columnsByName['version']! as i1.GeneratedColumn<String>;
|
|
||||||
i1.GeneratedColumn<DateTime> get lastCheck =>
|
|
||||||
columnsByName['last_check']! as i1.GeneratedColumn<DateTime>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i1.GeneratedColumn<String> _column_13(String aliasedName) =>
|
i1.GeneratedColumn<String> _column_13(String aliasedName) => i1.GeneratedColumn<String>('provider_name', aliasedName, false,
|
||||||
i1.GeneratedColumn<String>('provider_name', aliasedName, false,
|
additionalChecks: i1.GeneratedColumn.checkTextLength(
|
||||||
additionalChecks: i1.GeneratedColumn.checkTextLength(
|
minTextLength: 1,
|
||||||
minTextLength: 1,
|
),
|
||||||
),
|
type: i1.DriftSqlType.string);
|
||||||
type: i1.DriftSqlType.string);
|
i1.GeneratedColumn<String> _column_14(String aliasedName) => i1.GeneratedColumn<String>('version', aliasedName, true, type: i1.DriftSqlType.string);
|
||||||
i1.GeneratedColumn<String> _column_14(String aliasedName) =>
|
i1.GeneratedColumn<DateTime> _column_15(String aliasedName) => i1.GeneratedColumn<DateTime>('last_check', aliasedName, true, type: i1.DriftSqlType.dateTime);
|
||||||
i1.GeneratedColumn<String>('version', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.string);
|
|
||||||
i1.GeneratedColumn<DateTime> _column_15(String aliasedName) =>
|
|
||||||
i1.GeneratedColumn<DateTime>('last_check', aliasedName, true,
|
|
||||||
type: i1.DriftSqlType.dateTime);
|
|
||||||
i0.MigrationStepWithVersion migrationSteps({
|
i0.MigrationStepWithVersion migrationSteps({
|
||||||
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
||||||
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
||||||
|
required Future<void> Function(i1.Migrator m, _S3 schema) from3To4,
|
||||||
}) {
|
}) {
|
||||||
return (currentVersion, database) async {
|
return (currentVersion, database) async {
|
||||||
switch (currentVersion) {
|
switch (currentVersion) {
|
||||||
@@ -214,6 +163,11 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||||||
final migrator = i1.Migrator(database, schema);
|
final migrator = i1.Migrator(database, schema);
|
||||||
await from2To3(migrator, schema);
|
await from2To3(migrator, schema);
|
||||||
return 3;
|
return 3;
|
||||||
|
case 3:
|
||||||
|
final schema = _S3(database: database);
|
||||||
|
final migrator = i1.Migrator(database, schema);
|
||||||
|
await from3To4(migrator, schema);
|
||||||
|
return 4;
|
||||||
default:
|
default:
|
||||||
throw ArgumentError.value('Unknown migration from $currentVersion');
|
throw ArgumentError.value('Unknown migration from $currentVersion');
|
||||||
}
|
}
|
||||||
@@ -223,9 +177,11 @@ i0.MigrationStepWithVersion migrationSteps({
|
|||||||
i1.OnUpgrade stepByStep({
|
i1.OnUpgrade stepByStep({
|
||||||
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
required Future<void> Function(i1.Migrator m, _S2 schema) from1To2,
|
||||||
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
required Future<void> Function(i1.Migrator m, _S3 schema) from2To3,
|
||||||
|
required Future<void> Function(i1.Migrator m, _S3 schema) from3To4,
|
||||||
}) =>
|
}) =>
|
||||||
i0.VersionedSchema.stepByStepHelper(
|
i0.VersionedSchema.stepByStepHelper(
|
||||||
step: migrationSteps(
|
step: migrationSteps(
|
||||||
from1To2: from1To2,
|
from1To2: from1To2,
|
||||||
from2To3: from2To3,
|
from2To3: from2To3,
|
||||||
|
from3To4: from3To4,
|
||||||
));
|
));
|
||||||
|
|||||||
296
lib/core/database/schemas/drift_schema_v4.json
Normal file
296
lib/core/database/schemas/drift_schema_v4.json
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
{
|
||||||
|
"_meta": {
|
||||||
|
"description": "This file contains a serialized version of schema entities for drift.",
|
||||||
|
"version": "1.1.0"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"store_date_time_values_as_text": true
|
||||||
|
},
|
||||||
|
"entities": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"references": [],
|
||||||
|
"type": "table",
|
||||||
|
"data": {
|
||||||
|
"name": "profile_entries",
|
||||||
|
"was_declared_in_moor": false,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"getter_name": "id",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"getter_name": "type",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": [],
|
||||||
|
"type_converter": {
|
||||||
|
"dart_expr": "const EnumNameConverter<ProfileType>(ProfileType.values)",
|
||||||
|
"dart_type_name": "ProfileType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "active",
|
||||||
|
"getter_name": "active",
|
||||||
|
"moor_type": "bool",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"defaultConstraints": "CHECK (\"active\" IN (0, 1))",
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"getter_name": "name",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": [
|
||||||
|
{
|
||||||
|
"allowed-lengths": {
|
||||||
|
"min": 1,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "url",
|
||||||
|
"getter_name": "url",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_update",
|
||||||
|
"getter_name": "lastUpdate",
|
||||||
|
"moor_type": "dateTime",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "update_interval",
|
||||||
|
"getter_name": "updateInterval",
|
||||||
|
"moor_type": "int",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": [],
|
||||||
|
"type_converter": {
|
||||||
|
"dart_expr": "DurationTypeConverter()",
|
||||||
|
"dart_type_name": "Duration"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "upload",
|
||||||
|
"getter_name": "upload",
|
||||||
|
"moor_type": "int",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "download",
|
||||||
|
"getter_name": "download",
|
||||||
|
"moor_type": "int",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "total",
|
||||||
|
"getter_name": "total",
|
||||||
|
"moor_type": "int",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "expire",
|
||||||
|
"getter_name": "expire",
|
||||||
|
"moor_type": "dateTime",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "web_page_url",
|
||||||
|
"getter_name": "webPageUrl",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "support_url",
|
||||||
|
"getter_name": "supportUrl",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "test_url",
|
||||||
|
"getter_name": "testUrl",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"is_virtual": false,
|
||||||
|
"without_rowid": false,
|
||||||
|
"constraints": [],
|
||||||
|
"explicit_pk": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"references": [],
|
||||||
|
"type": "table",
|
||||||
|
"data": {
|
||||||
|
"name": "geo_asset_entries",
|
||||||
|
"was_declared_in_moor": false,
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"getter_name": "id",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"getter_name": "type",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": [],
|
||||||
|
"type_converter": {
|
||||||
|
"dart_expr": "const EnumNameConverter<GeoAssetType>(GeoAssetType.values)",
|
||||||
|
"dart_type_name": "GeoAssetType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "active",
|
||||||
|
"getter_name": "active",
|
||||||
|
"moor_type": "bool",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"defaultConstraints": "CHECK (\"active\" IN (0, 1))",
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "name",
|
||||||
|
"getter_name": "name",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": [
|
||||||
|
{
|
||||||
|
"allowed-lengths": {
|
||||||
|
"min": 1,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "provider_name",
|
||||||
|
"getter_name": "providerName",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": false,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": [
|
||||||
|
{
|
||||||
|
"allowed-lengths": {
|
||||||
|
"min": 1,
|
||||||
|
"max": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "version",
|
||||||
|
"getter_name": "version",
|
||||||
|
"moor_type": "string",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "last_check",
|
||||||
|
"getter_name": "lastCheck",
|
||||||
|
"moor_type": "dateTime",
|
||||||
|
"nullable": true,
|
||||||
|
"customConstraints": null,
|
||||||
|
"default_dart": null,
|
||||||
|
"default_client_dart": null,
|
||||||
|
"dsl_features": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"is_virtual": false,
|
||||||
|
"without_rowid": false,
|
||||||
|
"constraints": [],
|
||||||
|
"explicit_pk": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"unique_keys": [
|
||||||
|
[
|
||||||
|
"name",
|
||||||
|
"provider_name"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -11,14 +11,14 @@ class ProfileEntries extends Table {
|
|||||||
TextColumn get name => text().withLength(min: 1)();
|
TextColumn get name => text().withLength(min: 1)();
|
||||||
TextColumn get url => text().nullable()();
|
TextColumn get url => text().nullable()();
|
||||||
DateTimeColumn get lastUpdate => dateTime()();
|
DateTimeColumn get lastUpdate => dateTime()();
|
||||||
IntColumn get updateInterval =>
|
IntColumn get updateInterval => integer().nullable().map(DurationTypeConverter())();
|
||||||
integer().nullable().map(DurationTypeConverter())();
|
|
||||||
IntColumn get upload => integer().nullable()();
|
IntColumn get upload => integer().nullable()();
|
||||||
IntColumn get download => integer().nullable()();
|
IntColumn get download => integer().nullable()();
|
||||||
IntColumn get total => integer().nullable()();
|
IntColumn get total => integer().nullable()();
|
||||||
DateTimeColumn get expire => dateTime().nullable()();
|
DateTimeColumn get expire => dateTime().nullable()();
|
||||||
TextColumn get webPageUrl => text().nullable()();
|
TextColumn get webPageUrl => text().nullable()();
|
||||||
TextColumn get supportUrl => text().nullable()();
|
TextColumn get supportUrl => text().nullable()();
|
||||||
|
TextColumn get testUrl => text().nullable()();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column> get primaryKey => {id};
|
Set<Column> get primaryKey => {id};
|
||||||
|
|||||||
@@ -22,12 +22,14 @@ abstract interface class ConnectionRepository {
|
|||||||
String fileName,
|
String fileName,
|
||||||
String profileName,
|
String profileName,
|
||||||
bool disableMemoryLimit,
|
bool disableMemoryLimit,
|
||||||
|
String? testUrl,
|
||||||
);
|
);
|
||||||
TaskEither<ConnectionFailure, Unit> disconnect();
|
TaskEither<ConnectionFailure, Unit> disconnect();
|
||||||
TaskEither<ConnectionFailure, Unit> reconnect(
|
TaskEither<ConnectionFailure, Unit> reconnect(
|
||||||
String fileName,
|
String fileName,
|
||||||
String profileName,
|
String profileName,
|
||||||
bool disableMemoryLimit,
|
bool disableMemoryLimit,
|
||||||
|
String? testUrl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,11 +103,16 @@ class ConnectionRepositoryImpl with ExceptionHandler, InfraLogger implements Con
|
|||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
TaskEither<ConnectionFailure, Unit> applyConfigOption(
|
TaskEither<ConnectionFailure, Unit> applyConfigOption(
|
||||||
SingboxConfigOption options,
|
SingboxConfigOption options,
|
||||||
|
String? testUrl,
|
||||||
) {
|
) {
|
||||||
return exceptionHandler(
|
return exceptionHandler(
|
||||||
() {
|
() {
|
||||||
_configOptionsSnapshot = options;
|
_configOptionsSnapshot = options;
|
||||||
return singbox.changeOptions(options).mapLeft(InvalidConfigOption.new).run();
|
var newOptions = options;
|
||||||
|
if (testUrl != null) {
|
||||||
|
newOptions = options.copyWith(connectionTestUrl: testUrl);
|
||||||
|
}
|
||||||
|
return singbox.changeOptions(newOptions).mapLeft(InvalidConfigOption.new).run();
|
||||||
},
|
},
|
||||||
UnexpectedConnectionFailure.new,
|
UnexpectedConnectionFailure.new,
|
||||||
);
|
);
|
||||||
@@ -138,10 +145,11 @@ class ConnectionRepositoryImpl with ExceptionHandler, InfraLogger implements Con
|
|||||||
String fileName,
|
String fileName,
|
||||||
String profileName,
|
String profileName,
|
||||||
bool disableMemoryLimit,
|
bool disableMemoryLimit,
|
||||||
|
String? testUrl,
|
||||||
) {
|
) {
|
||||||
return TaskEither<ConnectionFailure, Unit>.Do(
|
return TaskEither<ConnectionFailure, Unit>.Do(
|
||||||
($) async {
|
($) async {
|
||||||
final options = await $(getConfigOption());
|
var options = await $(getConfigOption());
|
||||||
loggy.info(
|
loggy.info(
|
||||||
"config options: ${options.format()}\nMemory Limit: ${!disableMemoryLimit}",
|
"config options: ${options.format()}\nMemory Limit: ${!disableMemoryLimit}",
|
||||||
);
|
);
|
||||||
@@ -159,7 +167,7 @@ class ConnectionRepositoryImpl with ExceptionHandler, InfraLogger implements Con
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
await $(setup());
|
await $(setup());
|
||||||
await $(applyConfigOption(options));
|
await $(applyConfigOption(options, testUrl));
|
||||||
return await $(
|
return await $(
|
||||||
singbox
|
singbox
|
||||||
.start(
|
.start(
|
||||||
@@ -203,23 +211,26 @@ class ConnectionRepositoryImpl with ExceptionHandler, InfraLogger implements Con
|
|||||||
String fileName,
|
String fileName,
|
||||||
String profileName,
|
String profileName,
|
||||||
bool disableMemoryLimit,
|
bool disableMemoryLimit,
|
||||||
|
String? testUrl,
|
||||||
) {
|
) {
|
||||||
return exceptionHandler(
|
return TaskEither<ConnectionFailure, Unit>.Do(
|
||||||
() async {
|
($) async {
|
||||||
return getConfigOption()
|
var options = await $(getConfigOption());
|
||||||
.flatMap((options) => applyConfigOption(options))
|
loggy.info(
|
||||||
.andThen(
|
"config options: ${options.format()}\nMemory Limit: ${!disableMemoryLimit}",
|
||||||
() => singbox
|
);
|
||||||
.restart(
|
|
||||||
profilePathResolver.file(fileName).path,
|
await $(applyConfigOption(options, testUrl));
|
||||||
profileName,
|
return await $(
|
||||||
disableMemoryLimit,
|
singbox
|
||||||
)
|
.restart(
|
||||||
.mapLeft(UnexpectedConnectionFailure.new),
|
profilePathResolver.file(fileName).path,
|
||||||
)
|
profileName,
|
||||||
.run();
|
disableMemoryLimit,
|
||||||
|
)
|
||||||
|
.mapLeft(UnexpectedConnectionFailure.new),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
UnexpectedConnectionFailure.new,
|
).handleExceptions(UnexpectedConnectionFailure.new);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
|
|||||||
profile.id,
|
profile.id,
|
||||||
profile.name,
|
profile.name,
|
||||||
ref.read(Preferences.disableMemoryLimit),
|
ref.read(Preferences.disableMemoryLimit),
|
||||||
|
profile.testUrl,
|
||||||
)
|
)
|
||||||
.mapLeft((err) {
|
.mapLeft((err) {
|
||||||
loggy.warning("error reconnecting", err);
|
loggy.warning("error reconnecting", err);
|
||||||
@@ -133,6 +134,7 @@ class ConnectionNotifier extends _$ConnectionNotifier with AppLogger {
|
|||||||
activeProfile.id,
|
activeProfile.id,
|
||||||
activeProfile.name,
|
activeProfile.name,
|
||||||
ref.read(Preferences.disableMemoryLimit),
|
ref.read(Preferences.disableMemoryLimit),
|
||||||
|
activeProfile.testUrl,
|
||||||
)
|
)
|
||||||
.mapLeft((err) async {
|
.mapLeft((err) async {
|
||||||
loggy.warning("error connecting", err);
|
loggy.warning("error connecting", err);
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import 'package:hiddify/features/profile/model/profile_entity.dart';
|
|||||||
extension ProfileEntityMapper on ProfileEntity {
|
extension ProfileEntityMapper on ProfileEntity {
|
||||||
ProfileEntriesCompanion toEntry() {
|
ProfileEntriesCompanion toEntry() {
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
RemoteProfileEntity(:final url, :final options, :final subInfo) =>
|
RemoteProfileEntity(:final url, :final options, :final subInfo) => ProfileEntriesCompanion.insert(
|
||||||
ProfileEntriesCompanion.insert(
|
|
||||||
id: id,
|
id: id,
|
||||||
type: ProfileType.remote,
|
type: ProfileType.remote,
|
||||||
active: active,
|
active: active,
|
||||||
@@ -20,6 +19,7 @@ extension ProfileEntityMapper on ProfileEntity {
|
|||||||
expire: Value(subInfo?.expire),
|
expire: Value(subInfo?.expire),
|
||||||
webPageUrl: Value(subInfo?.webPageUrl),
|
webPageUrl: Value(subInfo?.webPageUrl),
|
||||||
supportUrl: Value(subInfo?.supportUrl),
|
supportUrl: Value(subInfo?.supportUrl),
|
||||||
|
testUrl: Value(testUrl),
|
||||||
),
|
),
|
||||||
LocalProfileEntity() => ProfileEntriesCompanion.insert(
|
LocalProfileEntity() => ProfileEntriesCompanion.insert(
|
||||||
id: id,
|
id: id,
|
||||||
@@ -41,6 +41,7 @@ extension RemoteProfileEntityMapper on RemoteProfileEntity {
|
|||||||
expire: Value(subInfo?.expire),
|
expire: Value(subInfo?.expire),
|
||||||
webPageUrl: Value(subInfo?.webPageUrl),
|
webPageUrl: Value(subInfo?.webPageUrl),
|
||||||
supportUrl: Value(subInfo?.supportUrl),
|
supportUrl: Value(subInfo?.supportUrl),
|
||||||
|
testUrl: Value(testUrl),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,12 +74,14 @@ extension ProfileEntryMapper on ProfileEntry {
|
|||||||
lastUpdate: lastUpdate,
|
lastUpdate: lastUpdate,
|
||||||
options: options,
|
options: options,
|
||||||
subInfo: subInfo,
|
subInfo: subInfo,
|
||||||
|
testUrl: testUrl,
|
||||||
),
|
),
|
||||||
ProfileType.local => LocalProfileEntity(
|
ProfileType.local => LocalProfileEntity(
|
||||||
id: id,
|
id: id,
|
||||||
active: active,
|
active: active,
|
||||||
name: name,
|
name: name,
|
||||||
lastUpdate: lastUpdate,
|
lastUpdate: lastUpdate,
|
||||||
|
testUrl: testUrl,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,14 +24,12 @@ abstract class ProfileParser {
|
|||||||
var name = '';
|
var name = '';
|
||||||
if (headers['profile-title'] case [final titleHeader]) {
|
if (headers['profile-title'] case [final titleHeader]) {
|
||||||
if (titleHeader.startsWith("base64:")) {
|
if (titleHeader.startsWith("base64:")) {
|
||||||
name =
|
name = utf8.decode(base64.decode(titleHeader.replaceFirst("base64:", "")));
|
||||||
utf8.decode(base64.decode(titleHeader.replaceFirst("base64:", "")));
|
|
||||||
} else {
|
} else {
|
||||||
name = titleHeader.trim();
|
name = titleHeader.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (headers['content-disposition'] case [final contentDispositionHeader]
|
if (headers['content-disposition'] case [final contentDispositionHeader] when name.isEmpty) {
|
||||||
when name.isEmpty) {
|
|
||||||
final regExp = RegExp('filename="([^"]*)"');
|
final regExp = RegExp('filename="([^"]*)"');
|
||||||
final match = regExp.firstMatch(contentDispositionHeader);
|
final match = regExp.firstMatch(contentDispositionHeader);
|
||||||
if (match != null && match.groupCount >= 1) {
|
if (match != null && match.groupCount >= 1) {
|
||||||
@@ -52,19 +50,20 @@ abstract class ProfileParser {
|
|||||||
final updateInterval = Duration(hours: int.parse(updateIntervalStr));
|
final updateInterval = Duration(hours: int.parse(updateIntervalStr));
|
||||||
options = ProfileOptions(updateInterval: updateInterval);
|
options = ProfileOptions(updateInterval: updateInterval);
|
||||||
}
|
}
|
||||||
|
String? testUrl;
|
||||||
|
if (headers['test-url'] case [final testUrl_] when isUrl(testUrl_)) {
|
||||||
|
testUrl = testUrl_;
|
||||||
|
}
|
||||||
SubscriptionInfo? subInfo;
|
SubscriptionInfo? subInfo;
|
||||||
if (headers['subscription-userinfo'] case [final subInfoStr]) {
|
if (headers['subscription-userinfo'] case [final subInfoStr]) {
|
||||||
subInfo = parseSubscriptionInfo(subInfoStr);
|
subInfo = parseSubscriptionInfo(subInfoStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subInfo != null) {
|
if (subInfo != null) {
|
||||||
if (headers['profile-web-page-url'] case [final profileWebPageUrl]
|
if (headers['profile-web-page-url'] case [final profileWebPageUrl] when isUrl(profileWebPageUrl)) {
|
||||||
when isUrl(profileWebPageUrl)) {
|
|
||||||
subInfo = subInfo.copyWith(webPageUrl: profileWebPageUrl);
|
subInfo = subInfo.copyWith(webPageUrl: profileWebPageUrl);
|
||||||
}
|
}
|
||||||
if (headers['support-url'] case [final profileSupportUrl]
|
if (headers['support-url'] case [final profileSupportUrl] when isUrl(profileSupportUrl)) {
|
||||||
when isUrl(profileSupportUrl)) {
|
|
||||||
subInfo = subInfo.copyWith(supportUrl: profileSupportUrl);
|
subInfo = subInfo.copyWith(supportUrl: profileSupportUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,23 +76,16 @@ abstract class ProfileParser {
|
|||||||
lastUpdate: DateTime.now(),
|
lastUpdate: DateTime.now(),
|
||||||
options: options,
|
options: options,
|
||||||
subInfo: subInfo,
|
subInfo: subInfo,
|
||||||
|
testUrl: testUrl,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SubscriptionInfo? parseSubscriptionInfo(String subInfoStr) {
|
static SubscriptionInfo? parseSubscriptionInfo(String subInfoStr) {
|
||||||
final values = subInfoStr.split(';');
|
final values = subInfoStr.split(';');
|
||||||
final map = {
|
final map = {
|
||||||
for (final v in values)
|
for (final v in values) v.split('=').first.trim(): num.tryParse(v.split('=').second.trim())?.toInt(),
|
||||||
v.split('=').first.trim():
|
|
||||||
num.tryParse(v.split('=').second.trim())?.toInt(),
|
|
||||||
};
|
};
|
||||||
if (map
|
if (map case {"upload": final upload?, "download": final download?, "total": var total, "expire": var expire}) {
|
||||||
case {
|
|
||||||
"upload": final upload?,
|
|
||||||
"download": final download?,
|
|
||||||
"total": var total,
|
|
||||||
"expire": var expire
|
|
||||||
}) {
|
|
||||||
total = (total == null || total == 0) ? infiniteTrafficThreshold : total;
|
total = (total == null || total == 0) ? infiniteTrafficThreshold : total;
|
||||||
expire = (expire == null || expire == 0) ? infiniteTimeThreshold : expire;
|
expire = (expire == null || expire == 0) ? infiniteTimeThreshold : expire;
|
||||||
return SubscriptionInfo(
|
return SubscriptionInfo(
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ class ProfileRepositoryImpl with ExceptionHandler, InfraLogger implements Profil
|
|||||||
? profilePatch.copyWith(
|
? profilePatch.copyWith(
|
||||||
name: Value(baseProfile.name),
|
name: Value(baseProfile.name),
|
||||||
url: Value(baseProfile.url),
|
url: Value(baseProfile.url),
|
||||||
|
testUrl: Value(baseProfile.testUrl),
|
||||||
updateInterval: Value(baseProfile.options?.updateInterval),
|
updateInterval: Value(baseProfile.options?.updateInterval),
|
||||||
)
|
)
|
||||||
: profilePatch,
|
: profilePatch,
|
||||||
@@ -349,6 +350,7 @@ class ProfileRepositoryImpl with ExceptionHandler, InfraLogger implements Profil
|
|||||||
'profile-update-interval',
|
'profile-update-interval',
|
||||||
'support-url',
|
'support-url',
|
||||||
'profile-web-page-url',
|
'profile-web-page-url',
|
||||||
|
'test-url',
|
||||||
];
|
];
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ sealed class ProfileEntity with _$ProfileEntity {
|
|||||||
required String name,
|
required String name,
|
||||||
required String url,
|
required String url,
|
||||||
required DateTime lastUpdate,
|
required DateTime lastUpdate,
|
||||||
|
String? testUrl,
|
||||||
ProfileOptions? options,
|
ProfileOptions? options,
|
||||||
SubscriptionInfo? subInfo,
|
SubscriptionInfo? subInfo,
|
||||||
}) = RemoteProfileEntity;
|
}) = RemoteProfileEntity;
|
||||||
@@ -24,6 +25,7 @@ sealed class ProfileEntity with _$ProfileEntity {
|
|||||||
required bool active,
|
required bool active,
|
||||||
required String name,
|
required String name,
|
||||||
required DateTime lastUpdate,
|
required DateTime lastUpdate,
|
||||||
|
String? testUrl,
|
||||||
}) = LocalProfileEntity;
|
}) = LocalProfileEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,15 +17,11 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
|||||||
static const channelPrefix = "com.hiddify.app";
|
static const channelPrefix = "com.hiddify.app";
|
||||||
|
|
||||||
static const methodChannel = MethodChannel("$channelPrefix/method");
|
static const methodChannel = MethodChannel("$channelPrefix/method");
|
||||||
static const statusChannel =
|
static const statusChannel = EventChannel("$channelPrefix/service.status", JSONMethodCodec());
|
||||||
EventChannel("$channelPrefix/service.status", JSONMethodCodec());
|
static const alertsChannel = EventChannel("$channelPrefix/service.alerts", JSONMethodCodec());
|
||||||
static const alertsChannel =
|
static const statsChannel = EventChannel("$channelPrefix/stats", JSONMethodCodec());
|
||||||
EventChannel("$channelPrefix/service.alerts", JSONMethodCodec());
|
|
||||||
static const statsChannel =
|
|
||||||
EventChannel("$channelPrefix/stats", JSONMethodCodec());
|
|
||||||
static const groupsChannel = EventChannel("$channelPrefix/groups");
|
static const groupsChannel = EventChannel("$channelPrefix/groups");
|
||||||
static const activeGroupsChannel =
|
static const activeGroupsChannel = EventChannel("$channelPrefix/active-groups");
|
||||||
EventChannel("$channelPrefix/active-groups");
|
|
||||||
static const logsChannel = EventChannel("$channelPrefix/service.logs");
|
static const logsChannel = EventChannel("$channelPrefix/service.logs");
|
||||||
|
|
||||||
late final ValueStream<SingboxStatus> _status;
|
late final ValueStream<SingboxStatus> _status;
|
||||||
@@ -33,10 +29,8 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
|||||||
@override
|
@override
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
loggy.debug("initializing");
|
loggy.debug("initializing");
|
||||||
final status =
|
final status = statusChannel.receiveBroadcastStream().map(SingboxStatus.fromEvent);
|
||||||
statusChannel.receiveBroadcastStream().map(SingboxStatus.fromEvent);
|
final alerts = alertsChannel.receiveBroadcastStream().map(SingboxStatus.fromEvent);
|
||||||
final alerts =
|
|
||||||
alertsChannel.receiveBroadcastStream().map(SingboxStatus.fromEvent);
|
|
||||||
|
|
||||||
_status = ValueConnectableStream(Rx.merge([status, alerts])).autoConnect();
|
_status = ValueConnectableStream(Rx.merge([status, alerts])).autoConnect();
|
||||||
await _status.first;
|
await _status.first;
|
||||||
@@ -250,9 +244,7 @@ class PlatformSingboxService with InfraLogger implements SingboxService {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<List<String>> watchLogs(String path) async* {
|
Stream<List<String>> watchLogs(String path) async* {
|
||||||
yield* logsChannel
|
yield* logsChannel.receiveBroadcastStream().map((event) => (event as List).map((e) => e as String).toList());
|
||||||
.receiveBroadcastStream()
|
|
||||||
.map((event) => (event as List).map((e) => e as String).toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/// https://gist.github.com/dperini/729294
|
/// https://gist.github.com/dperini/729294
|
||||||
final _urlRegex = RegExp(
|
final _urlRegex = RegExp(
|
||||||
r"^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$",
|
// r"^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$",
|
||||||
|
r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+',
|
||||||
);
|
);
|
||||||
|
|
||||||
/// https://stackoverflow.com/a/12968117
|
/// https://stackoverflow.com/a/12968117
|
||||||
|
|||||||
2
libcore
2
libcore
Submodule libcore updated: e6db5f2348...77fe588eae
Reference in New Issue
Block a user