rustdesk/flutter/lib/plugin/manager.dart

274 lines
6.7 KiB
Dart
Raw Normal View History

// The plugin manager is a singleton class that manages the plugins.
// 1. It merge metadata and the desc of plugins.
import 'dart:convert';
import 'dart:collection';
import 'package:flutter/material.dart';
const String kValueTrue = '1';
const String kValueFalse = '0';
class ConfigItem {
String key;
String description;
String defaultValue;
ConfigItem(this.key, this.defaultValue, this.description);
ConfigItem.fromJson(Map<String, dynamic> json)
: key = json['key'] ?? '',
description = json['description'] ?? '',
defaultValue = json['default'] ?? '';
static String get trueValue => kValueTrue;
static String get falseValue => kValueFalse;
static bool isTrue(String value) => value == kValueTrue;
static bool isFalse(String value) => value == kValueFalse;
}
class UiType {
String key;
String text;
String tooltip;
String action;
UiType(this.key, this.text, this.tooltip, this.action);
UiType.fromJson(Map<String, dynamic> json)
: key = json['key'] ?? '',
text = json['text'] ?? '',
tooltip = json['tooltip'] ?? '',
action = json['action'] ?? '';
static UiType? create(Map<String, dynamic> json) {
if (json['t'] == 'Button') {
return UiButton.fromJson(json['c']);
} else if (json['t'] == 'Checkbox') {
return UiCheckbox.fromJson(json['c']);
} else {
return null;
}
}
}
class UiButton extends UiType {
String icon;
UiButton(
{required String key,
required String text,
required this.icon,
required String tooltip,
required String action})
: super(key, text, tooltip, action);
UiButton.fromJson(Map<String, dynamic> json)
: icon = json['icon'] ?? '',
super.fromJson(json);
}
class UiCheckbox extends UiType {
UiCheckbox(
{required String key,
required String text,
required String tooltip,
required String action})
: super(key, text, tooltip, action);
UiCheckbox.fromJson(Map<String, dynamic> json) : super.fromJson(json);
}
class Location {
// location key:
// host|main|settings|plugin
// client|remote|toolbar|display
HashMap<String, UiType> ui;
Location(this.ui);
Location.fromJson(Map<String, dynamic> json) : ui = HashMap() {
(json['ui'] as Map<String, dynamic>).forEach((key, value) {
var ui = UiType.create(value);
if (ui != null) {
this.ui[ui.key] = ui;
}
});
}
}
class PublishInfo {
PublishInfo({
required this.lastReleased,
required this.published,
});
final DateTime lastReleased;
final DateTime published;
}
class Meta {
Meta({
required this.id,
required this.name,
required this.version,
required this.description,
required this.author,
required this.home,
required this.license,
required this.publishInfo,
required this.source,
});
final String id;
final String name;
final String version;
final String description;
final String author;
final String home;
final String license;
final PublishInfo publishInfo;
final String source;
}
class SourceInfo {
String name; // 1. RustDesk github 2. Local
String url;
String description;
SourceInfo({
required this.name,
required this.url,
required this.description,
});
}
class PluginInfo with ChangeNotifier {
SourceInfo sourceInfo;
Meta meta;
String installedVersion; // It is empty if not installed.
DateTime installTime;
String invalidReason; // It is empty if valid.
PluginInfo({
required this.sourceInfo,
required this.meta,
required this.installedVersion,
required this.installTime,
required this.invalidReason,
});
void update(PluginInfo plugin) {
assert(plugin.meta.id == meta.id, 'Plugin id not match');
if (plugin.meta.id != meta.id) {
// log error
return;
}
sourceInfo = plugin.sourceInfo;
meta = plugin.meta;
installedVersion = plugin.installedVersion;
installTime = plugin.installTime;
invalidReason = plugin.invalidReason;
notifyListeners();
}
}
class PluginManager with ChangeNotifier {
String failedReason = ''; // The reason of failed to load plugins.
final List<PluginInfo> _plugins = [];
PluginManager._();
static final PluginManager _instance = PluginManager._();
static PluginManager get instance => _instance;
List<PluginInfo> get plugins => _plugins;
PluginInfo? getPlugin(String id) {
for (var p in _plugins) {
if (p.meta.id == id) {
return p;
}
}
return null;
}
void handleEvent(Map<String, dynamic> evt) {
if (evt['plugin_list'] != null) {
_handlePluginList(evt['plugin_list']);
} else if (evt['plugin_update'] != null) {
_handlePluginUpdate(evt['plugin_update']);
} else {
debugPrint('Failed to handle manager event: $evt');
}
}
void _handlePluginUpdate(Map<String, dynamic> evt) {
final plugin = _getPluginFromEvent(evt);
if (plugin == null) {
return;
}
for (var i = 0; i < _plugins.length; i++) {
if (_plugins[i].meta.id == plugin.meta.id) {
_plugins[i].update(plugin);
return;
}
}
}
void _handlePluginList(String pluginList) {
_plugins.clear();
try {
for (var p in json.decode(pluginList) as List<dynamic>) {
final plugin = _getPluginFromEvent(p);
if (plugin == null) {
continue;
}
_plugins.add(plugin);
}
} catch (e) {
debugPrint('Failed to decode plugin list \'$pluginList\'');
}
notifyListeners();
}
PluginInfo? _getPluginFromEvent(Map<String, dynamic> evt) {
final s = evt['source'];
assert(s != null, 'Source is null');
if (s == null) {
return null;
}
final source = SourceInfo(
name: s['name'],
url: s['url'] ?? '',
description: s['description'] ?? '',
);
final m = evt['meta'];
assert(m != null, 'Meta is null');
if (m == null) {
return null;
}
final meta = Meta(
id: m['id'],
name: m['name'],
version: m['version'],
description: m['description'] ?? '',
author: m['author'],
home: m['home'] ?? '',
license: m['license'] ?? '',
source: m['source'] ?? '',
publishInfo: PublishInfo(
lastReleased: DateTime.parse(
m['publish_info']?['lastReleased'] ?? '1970-01-01T00+00:00'),
published: DateTime.parse(
m['publish_info']?['published'] ?? '1970-01-01T00+00:00')),
);
return PluginInfo(
sourceInfo: source,
meta: meta,
installedVersion: evt['installed_version'],
installTime: evt['install_time'],
invalidReason: evt['invalid_reason'] ?? '',
);
}
}
PluginManager get pluginManager => PluginManager.instance;