Refact. Flutter web, peer cards (#7525)

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2024-03-27 11:26:29 +08:00 committed by GitHub
parent 8ecc107c06
commit d7137990b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 266 additions and 133 deletions

View File

@ -864,7 +864,7 @@ class RecentPeerCard extends BasePeerCard {
BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
if (!isWeb) _transferFileAction(context),
];
final List favs = (await bind.mainGetFav()).toList();
@ -873,7 +873,9 @@ class RecentPeerCard extends BasePeerCard {
menuItems.add(_tcpTunnelingAction(context));
}
// menuItems.add(await _openNewConnInOptAction(peer.id));
if (!isWeb) {
menuItems.add(await _forceAlwaysRelayAction(peer.id));
}
if (isWindows && peer.platform == kPeerPlatformWindows) {
menuItems.add(_rdpAction(context, peer.id));
}
@ -881,7 +883,10 @@ class RecentPeerCard extends BasePeerCard {
menuItems.add(_createShortCutAction(peer.id));
}
menuItems.add(MenuEntryDivider());
if (!isWeb) {
// TODO: support web version
menuItems.add(_renameAction(peer.id));
}
if (await bind.mainPeerHasPassword(id: peer.id)) {
menuItems.add(_unrememberPasswordAction(peer.id));
}
@ -919,13 +924,15 @@ class FavoritePeerCard extends BasePeerCard {
BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
if (!isWeb) _transferFileAction(context),
];
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
menuItems.add(_tcpTunnelingAction(context));
}
// menuItems.add(await _openNewConnInOptAction(peer.id));
if (!isWeb) {
menuItems.add(await _forceAlwaysRelayAction(peer.id));
}
if (isWindows && peer.platform == kPeerPlatformWindows) {
menuItems.add(_rdpAction(context, peer.id));
}
@ -933,7 +940,10 @@ class FavoritePeerCard extends BasePeerCard {
menuItems.add(_createShortCutAction(peer.id));
}
menuItems.add(MenuEntryDivider());
if (!isWeb) {
// TODO: support web version
menuItems.add(_renameAction(peer.id));
}
if (await bind.mainPeerHasPassword(id: peer.id)) {
menuItems.add(_unrememberPasswordAction(peer.id));
}
@ -968,7 +978,7 @@ class DiscoveredPeerCard extends BasePeerCard {
BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
if (!isWeb) _transferFileAction(context),
];
final List favs = (await bind.mainGetFav()).toList();
@ -977,7 +987,9 @@ class DiscoveredPeerCard extends BasePeerCard {
menuItems.add(_tcpTunnelingAction(context));
}
// menuItems.add(await _openNewConnInOptAction(peer.id));
if (!isWeb) {
menuItems.add(await _forceAlwaysRelayAction(peer.id));
}
if (isWindows && peer.platform == kPeerPlatformWindows) {
menuItems.add(_rdpAction(context, peer.id));
}
@ -1019,7 +1031,7 @@ class AddressBookPeerCard extends BasePeerCard {
BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
if (!isWeb) _transferFileAction(context),
];
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
menuItems.add(_tcpTunnelingAction(context));
@ -1034,7 +1046,10 @@ class AddressBookPeerCard extends BasePeerCard {
}
if (gFFI.abModel.current.canWrite()) {
menuItems.add(MenuEntryDivider());
if (!isWeb) {
// TODO: support web version
menuItems.add(_renameAction(peer.id));
}
if (gFFI.abModel.current.isPersonal() && peer.hash.isNotEmpty) {
menuItems.add(_unrememberPasswordAction(peer.id));
}
@ -1148,7 +1163,7 @@ class MyGroupPeerCard extends BasePeerCard {
BuildContext context) async {
final List<MenuEntryBase<String>> menuItems = [
_connectAction(context),
_transferFileAction(context),
if (!isWeb) _transferFileAction(context),
];
if (isDesktop && peer.platform != kPeerPlatformAndroid) {
menuItems.add(_tcpTunnelingAction(context));

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:js' as js;
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:uuid/uuid.dart';
final _privateConstructorUsedError = UnsupportedError(
@ -111,7 +112,7 @@ class RustdeskImpl {
Future<String?> sessionGetOption(
{required UuidValue sessionId, required String arg, dynamic hint}) {
return Future(
() => js.context.callMethod('getByName', ['option:peer', arg]));
() => js.context.callMethod('getByName', ['option:session', arg]));
}
Future<void> sessionLogin(
@ -238,13 +239,13 @@ class RustdeskImpl {
{required UuidValue sessionId, dynamic hint}) {
// TODO: default values
return Future(() =>
js.context.callMethod('getByName', ['option:peer', 'view_style']));
js.context.callMethod('getByName', ['option:session', 'view_style']));
}
Future<void> sessionSetViewStyle(
{required UuidValue sessionId, required String value, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'view_style', 'value': value})
]));
}
@ -253,13 +254,13 @@ class RustdeskImpl {
{required UuidValue sessionId, dynamic hint}) {
// TODO: default values
return Future(() =>
js.context.callMethod('getByName', ['option:peer', 'scroll_style']));
js.context.callMethod('getByName', ['option:session', 'scroll_style']));
}
Future<void> sessionSetScrollStyle(
{required UuidValue sessionId, required String value, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'scroll_style', 'value': value})
]));
}
@ -268,14 +269,14 @@ class RustdeskImpl {
// TODO: default values
{required UuidValue sessionId,
dynamic hint}) {
return Future(() =>
js.context.callMethod('getByName', ['option:peer', 'image_quality']));
return Future(() => js.context
.callMethod('getByName', ['option:session', 'image_quality']));
}
Future<void> sessionSetImageQuality(
{required UuidValue sessionId, required String value, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'image_quality', 'value': value})
]));
}
@ -283,14 +284,14 @@ class RustdeskImpl {
Future<String?> sessionGetKeyboardMode(
{required UuidValue sessionId, dynamic hint}) {
// TODO: default values
return Future(() =>
js.context.callMethod('getByName', ['option:peer', 'keyboard_mode']));
return Future(() => js.context
.callMethod('getByName', ['option:session', 'keyboard_mode']));
}
Future<void> sessionSetKeyboardMode(
{required UuidValue sessionId, required String value, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'keyboard_mode', 'value': value})
]));
}
@ -298,13 +299,13 @@ class RustdeskImpl {
String? sessionGetReverseMouseWheelSync(
{required UuidValue sessionId, dynamic hint}) {
return js.context
.callMethod('getByName', ['option:peer', 'reverse_mouse_wheel']);
.callMethod('getByName', ['option:session', 'reverse_mouse_wheel']);
}
Future<void> sessionSetReverseMouseWheel(
{required UuidValue sessionId, required String value, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'reverse_mouse_wheel', 'value': value})
]));
}
@ -312,7 +313,7 @@ class RustdeskImpl {
String? sessionGetDisplaysAsIndividualWindows(
{required UuidValue sessionId, dynamic hint}) {
return js.context.callMethod(
'getByName', ['option:peer', 'displays_as_individual_windows']);
'getByName', ['option:session', 'displays_as_individual_windows']);
}
Future<void> sessionSetDisplaysAsIndividualWindows(
@ -335,7 +336,7 @@ class RustdeskImpl {
try {
return Future(() => Int32List.fromList([
int.parse(js.context.callMethod(
'getByName', ['option:peer', 'custom_image_quality']))
'getByName', ['option:session', 'custom_image_quality']))
]));
} catch (e) {
return Future.value(null);
@ -350,7 +351,7 @@ class RustdeskImpl {
Future<void> sessionSetCustomImageQuality(
{required UuidValue sessionId, required int value, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'custom_image_quality', 'value': value})
]));
}
@ -358,7 +359,7 @@ class RustdeskImpl {
Future<void> sessionSetCustomFps(
{required UuidValue sessionId, required int fps, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'option:peer',
'option:session',
jsonEncode({'name': 'custom_fps', 'value': fps})
]));
}
@ -444,7 +445,7 @@ class RustdeskImpl {
required String value,
dynamic hint}) {
return Future(() => js.context.callMethod('SetByName', [
'option:peer',
'option:session',
jsonEncode({'name': name, 'value': value})
]));
}
@ -452,7 +453,7 @@ class RustdeskImpl {
Future<String> sessionGetPeerOption(
{required UuidValue sessionId, required String name, dynamic hint}) {
return Future(
() => js.context.callMethod('getByName', ['option:peer', name]));
() => js.context.callMethod('getByName', ['option:session', name]));
}
Future<void> sessionInputOsPassword(
@ -715,12 +716,21 @@ class RustdeskImpl {
}
Future<List<String>> mainGetFav({dynamic hint}) {
throw UnimplementedError();
List<String> favs = [];
try {
favs = (jsonDecode(js.context.callMethod('getByName', ['fav']))
as List<dynamic>)
.map((e) => e.toString())
.toList();
} catch (e) {
debugPrint('Failed to load favs: $e');
}
return Future.value(favs);
}
Future<void> mainStoreFav({required List<String> favs, dynamic hint}) {
// TODO:
throw UnimplementedError();
return Future(
() => js.context.callMethod('setByName', ['fav', jsonEncode(favs)]));
}
String mainGetPeerSync({required String id, dynamic hint}) {
@ -748,7 +758,7 @@ class RustdeskImpl {
}
Future<void> mainDiscover({dynamic hint}) {
return Future(() => js.context.callMethod('setByName', ['discover']));
throw UnimplementedError();
}
Future<String> mainGetApiServer({dynamic hint}) {
@ -807,7 +817,10 @@ class RustdeskImpl {
String mainGetPeerOptionSync(
{required String id, required String key, dynamic hint}) {
return js.context.callMethod('getByName', ['option:peer', key]);
return js.context.callMethod('getByName', [
'option:peer',
jsonEncode({'id': id, 'name': key})
]);
}
String mainGetPeerFlutterOptionSync(
@ -842,7 +855,7 @@ class RustdeskImpl {
dynamic hint}) {
js.context.callMethod('setByName', [
'option:peer',
jsonEncode({'name': key, 'value': value})
jsonEncode({'id': id, 'name': key, 'value': value})
]);
return true;
}
@ -862,8 +875,9 @@ class RustdeskImpl {
}
Future<bool> mainPeerHasPassword({required String id, dynamic hint}) {
return Future(
() => js.context.callMethod('getByName', ['peer_has_password', id]));
return Future(() =>
js.context.callMethod('getByName', ['peer_has_password', id]) ==
'true');
}
Future<bool> mainPeerExists({required String id, dynamic hint}) {
@ -881,7 +895,7 @@ class RustdeskImpl {
}
String mainLoadLanPeersSync({dynamic hint}) {
return js.context.callMethod('getByName', ['load_lan_peers_sync']);
return '{}';
}
Future<String> mainLoadRecentPeersForAb(
@ -894,12 +908,11 @@ class RustdeskImpl {
}
Future<void> mainLoadLanPeers({dynamic hint}) {
return Future(() => js.context.callMethod('getByName', ['load_lan_peers']));
throw UnimplementedError();
}
Future<void> mainRemoveDiscovered({required String id, dynamic hint}) {
return Future(
() => js.context.callMethod('getByName', ['remove_discovered']));
throw UnimplementedError();
}
Future<void> mainChangeTheme({required String dark, dynamic hint}) {
@ -1102,7 +1115,7 @@ class RustdeskImpl {
String sessionGetAuditServerSync(
{required UuidValue sessionId, required String typ, dynamic hint}) {
throw UnimplementedError();
return js.context.callMethod('getByName', ['audit_server', typ]);
}
Future<void> sessionSendNote(
@ -1112,12 +1125,14 @@ class RustdeskImpl {
Future<String> sessionAlternativeCodecs(
{required UuidValue sessionId, dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('getByName', ['alternative_codecs']));
}
Future<void> sessionChangePreferCodec(
{required UuidValue sessionId, dynamic hint}) {
throw UnimplementedError();
return Future(
() => js.context.callMethod('setByName', ['change_prefer_codec']));
}
Future<void> sessionOnWaitingForImageDialogShow(
@ -1265,37 +1280,16 @@ class RustdeskImpl {
dynamic hint}) {}
Future<void> queryOnlines({required List<String> ids, dynamic hint}) {
// TODO:
throw UnimplementedError();
return Future(() =>
js.context.callMethod('setByName', ['query_onlines', jsonEncode(ids)]));
}
// Dup to the function in hbb_common, lib.rs
// Maybe we need to move this function to js part.
int versionToNumber({required String v, dynamic hint}) {
List<String> versions = v.split('-');
int n = 0;
// The first part is the version number.
// 1.1.10 -> 1001100, 1.2.3 -> 1001030, multiple the last number by 10
// to leave space for patch version.
if (versions.isNotEmpty) {
int last = 0;
for (var x in versions[0].split('.')) {
last = int.tryParse(x) ?? 0;
n = n * 1000 + last;
}
n -= last;
n += last * 10;
}
if (versions.length > 1) {
n += int.tryParse(versions[1]) ?? 0;
}
// Ignore the rest
return n;
return int.tryParse(
js.context.callMethod('getByName', ['get_version_number', v])) ??
0;
}
Future<bool> optionSynced({dynamic hint}) {
@ -1409,11 +1403,11 @@ class RustdeskImpl {
}
bool mainHasFileClipboard({dynamic hint}) {
throw UnimplementedError();
return false;
}
bool mainHasGpuTextureRender({dynamic hint}) {
throw UnimplementedError();
return false;
}
Future<void> cmInit({dynamic hint}) {

View File

@ -25,7 +25,7 @@ export async function loadVp9(callback) {
// Multithreading is used only if `options.threading` is true.
// This requires browser support for the new `SharedArrayBuffer` and `Atomics` APIs,
// currently available in Firefox and Chrome with experimental flags enabled.
// 所有主流浏览器均默认于2018年1月5日禁用SharedArrayBuffer
// All major browsers disabled SharedArrayBuffer by default on January 5, 2018
const isSIMD = await simd();
console.log('isSIMD: ' + isSIMD);
window.OGVLoader.loadClass(

View File

@ -453,6 +453,16 @@ export default class Connection {
}
}
changePreferCodec() {
const supported_decoding = message.SupportedDecoding.fromPartial({
ability_vp9: 1,
ability_h264: 1,
});
const option = message.OptionMessage.fromPartial({ supported_decoding });
const misc = message.Misc.fromPartial({ option });
this._ws?.sendMessage({ misc });
}
async reconnect() {
this.close();
await this.start(this._id);
@ -549,7 +559,15 @@ export default class Connection {
handlePeerInfo(pi: message.PeerInfo) {
localStorage.setItem('last_remote_id', this._id);
this._peerInfo = pi;
if (pi.current_display > pi.displays.length) {
pi.current_display = 0;
}
if (globals.getVersionNumber(pi.version) < globals.getVersionNumber("1.1.10")) {
this.setPermission("restart", false);
}
if (pi.displays.length == 0) {
this.setOption("info", pi);
globals.pushEvent("update_privacy_mode", {});
this.msgbox("error", "Remote Error", "No Display");
return;
}
@ -559,6 +577,7 @@ export default class Connection {
if (p) this.inputOsPassword(p);
const username = this.getOption("info")?.username;
if (username && !pi.username) pi.username = username;
globals.pushEvent("update_privacy_mode", {});
this.setOption("info", pi);
if (this.getRemember()) {
if (this._password?.length) {
@ -573,6 +592,10 @@ export default class Connection {
}
}
setPermission(name: string, value: Boolean) {
globals.pushEvent("permission", { [name]: value });
}
shouldAutoLogin(): string {
const l = this.getOption("lock-after-session-end");
const a = !!this.getOption("auto-login");
@ -608,7 +631,7 @@ export default class Connection {
default:
return;
}
globals.pushEvent("permission", { [name]: p.enabled });
this.setPermission(name, p.enabled);
} else if (misc.switch_display) {
this.loadVideoDecoder();
globals.pushEvent("switch_display", misc.switch_display);

View File

@ -288,22 +288,19 @@ window.setByName = (name, value) => {
value = JSON.parse(value);
localStorage.setItem(name + ':' + value.name, value.value);
break;
case 'option:peer':
case 'option:session':
value = JSON.parse(value);
curConn.setOption(value.name, value.value);
break;
case 'option:peer':
setPeerOption(value);
break;
case 'input_os_password':
curConn.inputOsPassword(value);
break;
case 'check_conn_status':
curConn.checkConnStatus();
break;
case 'remove_discovered':
removeDiscovered(value);
break;
case 'discover':
// TODO: discover
break;
case 'session_add_sync':
return sessionAdd(value);
case 'session_start':
@ -326,6 +323,13 @@ window.setByName = (name, value) => {
case 'restart':
curConn.restart();
break;
case 'fav':
return localStorage.setItem('fav', value);
case 'query_onlines':
queryOnlines(value);
break;
case 'change_prefer_codec':
curConn.changePreferCodec(value);
default:
break;
}
@ -338,22 +342,8 @@ window.getByName = (name, arg) => {
return JSON.stringify(v);
}
function getPeersForDart() {
const peers = [];
for (const [id, value] of Object.entries(getPeers())) {
if (!id) continue;
const tm = value['tm'];
const info = value['info'];
if (!tm || !info) continue;
peers.push([tm, id, info]);
}
return peers.sort().reverse().map(x => x.slice(1));
}
function _getByName(name, arg) {
switch (name) {
case 'peers':
return getPeersForDart();
case 'remote_id':
return localStorage.getItem('remote-id');
case 'remember':
@ -384,8 +374,10 @@ function _getByName(name, arg) {
case 'translate':
arg = JSON.parse(arg);
return translate(arg.locale, arg.text);
case 'option:peer':
case 'option:session':
return curConn.getOption(arg);
case 'option:peer':
return getPeerOption(arg);
case 'option:toggle':
return curConn.getToggleOption(arg);
case 'get_conn_status':
@ -399,31 +391,27 @@ function _getByName(name, arg) {
case 'version':
return version;
case 'load_recent_peers':
const peersRecent = localStorage.getItem('peers-recent');
if (peersRecent) {
onRegisteredEvent(JSON.stringify({ name: 'load_recent_peers', peers: peersRecent }));
}
loadRecentPeers();
break;
case 'load_fav_peers':
const peersFav = localStorage.getItem('peers-fav');
if (peersFav) {
onRegisteredEvent(JSON.stringify({ name: 'load_fav_peers', peers: peersFav }));
}
break;
case 'load_lan_peers':
const peersLan = localStorage.getItem('peers-lan');
if (peersLan) {
onRegisteredEvent(JSON.stringify({ name: 'load_lan_peers', peers: peersLan }));
}
loadFavPeers();
break;
case 'fav':
return localStorage.getItem('fav') ?? '[]';
case 'load_recent_peers_sync':
return localStorage.getItem('peers-recent') ?? '{}';
case 'load_lan_peers_sync':
return localStorage.getItem('peers-lan') ?? '{}';
return JSON.stringify({
peers: JSON.stringify(getRecentPeers())
});
case 'api_server':
return getApiServer();
case 'is_using_public_server':
return !localStorage.getItem('custom-rendezvous-server');
case 'get_version_number':
return getVersionNumber(arg);
case 'audit_server':
return getAuditServer(arg);
case 'alternative_codecs':
return getAlternativeCodecs();
}
return '';
}
@ -458,14 +446,6 @@ export function getPeers() {
return getJsonObj('peers');
}
export function getRecentPeers() {
return getJsonObj('peers-recent');
}
export function getLanPeers() {
return getJsonObj('peers-lan');
}
export function getJsonObj(key) {
try {
return JSON.parse(localStorage.getItem(key)) || {};
@ -486,7 +466,6 @@ export function copyToClipboard(text) {
if (window.clipboardData && window.clipboardData.setData) {
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
return window.clipboardData.setData("Text", text);
}
else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
var textarea = document.createElement("textarea");
@ -507,17 +486,117 @@ export function copyToClipboard(text) {
}
}
// ========================== peers begin ==========================
function removeDiscovered(id) {
// Dup to the function in hbb_common, lib.rs
// Maybe we need to move this function to js part.
export function getVersionNumber(v) {
try {
const v = localStorage.getItem('discovered');
if (!v) return;
const discovered = JSON.parse(localStorage.getItem('discovered'));
delete discovered[id];
localStorage.setItem('discovered', JSON.stringify(discovered));
} catch (e) {
console.error(e);
let versions = v.split('-');
let n = 0;
// The first part is the version number.
// 1.1.10 -> 1001100, 1.2.3 -> 1001030, multiple the last number by 10
// to leave space for patch version.
if (versions.length > 0) {
let last = 0;
for (let x of versions[0].split('.')) {
last = parseInt(x) || 0;
n = n * 1000 + last;
}
n -= last;
n += last * 10;
}
if (versions.length > 1) {
n += parseInt(versions[1]) || 0;
}
// Ignore the rest
return n;
}
catch (e) {
console.error('Failed to parse version number: "' + v + '" ' + e.message);
return 0;
}
}
function getPeerOption(value) {
try {
const obj = JSON.parse(value);
const options = getPeers()[obj.id] || {};
return options[obj.name] || '';
}
catch (e) {
console.error('Failed to get peer option: "' + value + '", ' + e.message);
}
}
function setPeerOption(value) {
try {
const obj = JSON.parse(value);
const id = obj.id;
const name = obj.name;
const value = obj.value;
const peers = getPeers();
const options = peers[id] || {};
if (value == undefined) {
delete options[name];
} else {
options[name] = value;
}
options["tm"] = new Date().getTime();
peers[id] = options;
localStorage.setItem("peers", JSON.stringify(peers));
}
catch (e) {
console.error('Failed to set peer option: "' + value + '", ' + e.message);
}
}
// ========================== peers begin ==========================
function getRecentPeers() {
const peers = [];
for (const [id, value] of Object.entries(getPeers())) {
if (!id) continue;
const tm = value['tm'];
const info = value['info'];
const cardInfo = {
id: id,
username: info['username'] || '',
hostname: info['hostname'] || '',
platform: info['platform'] || '',
alias: value.alias || '',
};
if (!tm || !cardInfo) continue;
peers.push([tm, id, cardInfo]);
}
return peers.sort().reverse().map(x => x[2]);
}
function loadRecentPeers() {
const peersRecent = getRecentPeers();
if (peersRecent) {
onRegisteredEvent(JSON.stringify({ name: 'load_recent_peers', peers: JSON.stringify(peersRecent) }));
}
}
function loadFavPeers() {
try {
const fav = localStorage.getItem('fav') ?? '[]';
const favs = JSON.parse(fav);
const peersFav = getRecentPeers().filter(x => favs.includes(x.id));
if (peersFav) {
onRegisteredEvent(JSON.stringify({ name: 'load_fav_peers', peers: JSON.stringify(peersFav) }));
}
} catch (e) {
console.error('Failed to load fav peers: ' + e.message);
}
}
export function queryOnlines(value) {
// TODO: implement this
}
// ========================== peers end ===========================
@ -587,6 +666,17 @@ function increasePort(host, offset) {
return host;
}
function getAlternativeCodecs() {
return JSON.stringify({
vp8: 1,
av1: 0,
h264: 1,
h265: 1,
});
}
// ========================== settings end ===========================
// ========================== server begin ==========================
function getApiServer() {
const api_server = localStorage.getItem('api-server');
if (api_server) {
@ -604,4 +694,15 @@ function getApiServer() {
}
return 'https://admin.rustdesk.com';
}
// ========================== settings end ===========================
function getAuditServer(typ) {
if (!localStorage.getItem("access_token")) {
return '';
}
const api_server = getApiServer();
if (!api_server || api_server.includes('rustdesk.com')) {
return '';
}
return api_server + '/api/audit/' + typ;
}
// ========================== server end ============================