mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-16 04:29:05 +08:00
Merge branch 'rustdesk:master' into master
This commit is contained in:
commit
5af407d322
26
Cargo.lock
generated
26
Cargo.lock
generated
@ -1533,7 +1533,7 @@ dependencies = [
|
||||
"log",
|
||||
"objc",
|
||||
"pkg-config",
|
||||
"rdev",
|
||||
"rdev 0.5.0-2 (git+https://github.com/asur4s/rdev)",
|
||||
"serde 1.0.147",
|
||||
"serde_derive",
|
||||
"tfc",
|
||||
@ -4248,6 +4248,28 @@ dependencies = [
|
||||
"x11 2.20.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdev"
|
||||
version = "0.5.0-2"
|
||||
source = "git+https://github.com/rustdesk/rdev#25c29f61bfdf5d8ec50f0a8a7743bc1d85eb2c04"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"core-foundation 0.9.3",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"core-graphics 0.22.3",
|
||||
"enum-map",
|
||||
"epoll",
|
||||
"inotify",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"mio 0.8.5",
|
||||
"strum 0.24.1",
|
||||
"strum_macros 0.24.3",
|
||||
"widestring 1.0.2",
|
||||
"winapi 0.3.9",
|
||||
"x11 2.20.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rdrand"
|
||||
version = "0.4.0"
|
||||
@ -4518,7 +4540,7 @@ dependencies = [
|
||||
"num_cpus",
|
||||
"objc",
|
||||
"parity-tokio-ipc",
|
||||
"rdev",
|
||||
"rdev 0.5.0-2 (git+https://github.com/rustdesk/rdev)",
|
||||
"repng",
|
||||
"reqwest",
|
||||
"rpassword 7.1.0",
|
||||
|
@ -63,7 +63,7 @@ default-net = "0.11.0"
|
||||
wol-rs = "0.9.1"
|
||||
flutter_rust_bridge = { git = "https://github.com/SoLongAndThanksForAllThePizza/flutter_rust_bridge", optional = true }
|
||||
errno = "0.2.8"
|
||||
rdev = { git = "https://github.com/asur4s/rdev" }
|
||||
rdev = { git = "https://github.com/rustdesk/rdev" }
|
||||
url = { version = "2.1", features = ["serde"] }
|
||||
|
||||
reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false }
|
||||
@ -162,4 +162,4 @@ codegen-units = 1
|
||||
panic = 'abort'
|
||||
strip = true
|
||||
#opt-level = 'z' # only have smaller size after strip
|
||||
rpath = true
|
||||
rpath = true
|
||||
|
@ -1013,7 +1013,7 @@ class LastWindowPosition {
|
||||
return LastWindowPosition(m["width"], m["height"], m["offsetWidth"],
|
||||
m["offsetHeight"], m["isMaximized"]);
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
debugPrintStack(label: e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -1147,7 +1147,7 @@ Future<bool> restoreWindowPosition(WindowType type, {int? windowId}) async {
|
||||
final pos = bind.getLocalFlutterConfig(k: kWindowPrefix + type.name);
|
||||
var lpos = LastWindowPosition.loadFromString(pos);
|
||||
if (lpos == null) {
|
||||
debugPrint("window position saved, but cannot be parsed");
|
||||
debugPrint("no window position saved, ignoring position restoration");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1212,7 +1212,7 @@ Future<void> initUniLinks() async {
|
||||
}
|
||||
parseRustdeskUri(initialLink);
|
||||
} catch (err) {
|
||||
debugPrint("$err");
|
||||
debugPrintStack(label: "$err");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1422,7 +1422,7 @@ void onActiveWindowChanged() async {
|
||||
rustDeskWinManager.closeAllSubWindows()
|
||||
]);
|
||||
} catch (err) {
|
||||
debugPrint("$err");
|
||||
debugPrintStack(label: "$err");
|
||||
} finally {
|
||||
await windowManager.setPreventClose(false);
|
||||
await windowManager.close();
|
||||
|
@ -79,16 +79,19 @@ class _PeerTabPageState extends State<PeerTabPage>
|
||||
.toList()
|
||||
.obs;
|
||||
try {
|
||||
final json = jsonDecode(bind.getLocalFlutterConfig(k: 'peer-tab-order'));
|
||||
if (json is List) {
|
||||
final List<String> list = json.map((e) => e.toString()).toList();
|
||||
if (list.length == visibleOrderedTabs.length &&
|
||||
visibleOrderedTabs.every((e) => list.contains(e))) {
|
||||
visibleOrderedTabs.value = list;
|
||||
final conf = bind.getLocalFlutterConfig(k: 'peer-tab-order');
|
||||
if (conf.isNotEmpty) {
|
||||
final json = jsonDecode(conf);
|
||||
if (json is List) {
|
||||
final List<String> list = json.map((e) => e.toString()).toList();
|
||||
if (list.length == visibleOrderedTabs.length &&
|
||||
visibleOrderedTabs.every((e) => list.contains(e))) {
|
||||
visibleOrderedTabs.value = list;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('$e');
|
||||
debugPrintStack(label: '$e');
|
||||
}
|
||||
|
||||
adjustTab();
|
||||
|
@ -63,7 +63,7 @@ class DesktopSettingPage extends StatefulWidget {
|
||||
DesktopTabPage.onAddSetting(initialPage: page);
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('$e');
|
||||
debugPrintStack(label: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class DesktopTabPage extends StatefulWidget {
|
||||
initialPage: initialPage,
|
||||
)));
|
||||
} catch (e) {
|
||||
debugPrint('$e');
|
||||
debugPrintStack(label: '$e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ Future<bool> loginDialog() async {
|
||||
debugPrint('$resp');
|
||||
completer.complete(true);
|
||||
} catch (err) {
|
||||
debugPrint(err.toString());
|
||||
debugPrintStack(label: err.toString());
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
@ -564,7 +564,7 @@ void androidChannelInit() {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("MethodCallHandler err:$e");
|
||||
debugPrintStack(label: "MethodCallHandler err:$e");
|
||||
}
|
||||
return "";
|
||||
});
|
||||
|
@ -363,8 +363,6 @@ class FileModel extends ChangeNotifier {
|
||||
if (_currentRemoteDir.path.isEmpty) {
|
||||
openDirectory(_remoteOption.home, isLocal: false);
|
||||
}
|
||||
// load last transfer jobs
|
||||
await bind.sessionLoadLastTransferJobs(id: '${parent.target?.id}');
|
||||
}
|
||||
|
||||
Future<void> onClose() async {
|
||||
|
@ -126,7 +126,7 @@ class PlatformFFI {
|
||||
// no need to set home dir
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('initialize failed: $e');
|
||||
debugPrintStack(label: 'initialize failed: $e');
|
||||
}
|
||||
String id = 'NA';
|
||||
String name = 'Flutter';
|
||||
@ -151,9 +151,8 @@ class PlatformFFI {
|
||||
WindowsDeviceInfo winInfo = await deviceInfo.windowsInfo;
|
||||
name = winInfo.computerName;
|
||||
id = winInfo.computerName;
|
||||
} catch (e, stacktrace) {
|
||||
debugPrint("get windows device info failed: $e");
|
||||
debugPrintStack(stackTrace: stacktrace);
|
||||
} catch (e) {
|
||||
debugPrintStack(label: "get windows device info failed: $e");
|
||||
name = "unknown";
|
||||
id = "unknown";
|
||||
}
|
||||
@ -174,7 +173,7 @@ class PlatformFFI {
|
||||
await _ffiBind.mainSetHomeDir(home: _homeDir);
|
||||
await _ffiBind.mainInit(appDir: _dir);
|
||||
} catch (e) {
|
||||
debugPrint('initialize failed: $e');
|
||||
debugPrintStack(label: 'initialize failed: $e');
|
||||
}
|
||||
version = await getVersion();
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ pub fn get_display_server() -> String {
|
||||
}
|
||||
|
||||
fn get_display_server_of_session(session: &str) -> String {
|
||||
if let Ok(output) = run_loginctl(Some(vec!["show-session", "-p", "Type", session]))
|
||||
let mut display_server = if let Ok(output) =
|
||||
run_loginctl(Some(vec!["show-session", "-p", "Type", session]))
|
||||
// Check session type of the session
|
||||
{
|
||||
let display_server = String::from_utf8_lossy(&output.stdout)
|
||||
@ -64,28 +65,23 @@ fn get_display_server_of_session(session: &str) -> String {
|
||||
{
|
||||
if xorg_results.trim_end().to_string() != "" {
|
||||
// If it is, manually return "x11", otherwise return tty
|
||||
"x11".to_owned()
|
||||
} else {
|
||||
display_server
|
||||
return "x11".to_owned();
|
||||
}
|
||||
} else {
|
||||
// If any of these commands fail just fall back to the display server
|
||||
display_server
|
||||
}
|
||||
} else {
|
||||
display_server
|
||||
}
|
||||
} else {
|
||||
// loginctl has not given the expected output. try something else.
|
||||
if let Ok(sestype) = std::env::var("XDG_SESSION_TYPE") {
|
||||
return sestype.to_owned();
|
||||
}
|
||||
// If the session is not a tty, then just return the type as usual
|
||||
display_server
|
||||
}
|
||||
display_server
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
if display_server.is_empty() {
|
||||
// loginctl has not given the expected output. try something else.
|
||||
if let Ok(sestype) = std::env::var("XDG_SESSION_TYPE") {
|
||||
display_server = sestype;
|
||||
}
|
||||
}
|
||||
// If the session is not a tty, then just return the type as usual
|
||||
display_server
|
||||
}
|
||||
|
||||
pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
|
||||
@ -126,8 +122,7 @@ pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
|
||||
}
|
||||
|
||||
fn is_active(sid: &str) -> bool {
|
||||
if let Ok(output) = run_loginctl(Some(vec!["show-session", "-p", "State", sid]))
|
||||
{
|
||||
if let Ok(output) = run_loginctl(Some(vec!["show-session", "-p", "State", sid])) {
|
||||
String::from_utf8_lossy(&output.stdout).contains("active")
|
||||
} else {
|
||||
false
|
||||
|
@ -12,11 +12,10 @@ use hwcodec::mux::{MuxContext, Muxer};
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
io,
|
||||
time::Instant,
|
||||
};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
path::PathBuf,
|
||||
sync::mpsc::Sender,
|
||||
time::Instant,
|
||||
};
|
||||
use webm::mux::{self, Segment, Track, VideoTrack, Writer};
|
||||
|
||||
@ -31,12 +30,14 @@ pub enum RecordCodecID {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RecorderContext {
|
||||
pub server: bool,
|
||||
pub id: String,
|
||||
pub default_dir: String,
|
||||
pub filename: String,
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub codec_id: RecordCodecID,
|
||||
pub tx: Option<Sender<RecordState>>,
|
||||
}
|
||||
|
||||
impl RecorderContext {
|
||||
@ -52,7 +53,8 @@ impl RecorderContext {
|
||||
std::fs::create_dir_all(&dir)?;
|
||||
}
|
||||
}
|
||||
let file = self.id.clone()
|
||||
let file = if self.server { "s" } else { "c" }.to_string()
|
||||
+ &self.id.clone()
|
||||
+ &chrono::Local::now().format("_%Y%m%d%H%M%S").to_string()
|
||||
+ if self.codec_id == RecordCodecID::VP9 {
|
||||
".webm"
|
||||
@ -60,7 +62,7 @@ impl RecorderContext {
|
||||
".mp4"
|
||||
};
|
||||
self.filename = PathBuf::from(&dir).join(file).to_string_lossy().to_string();
|
||||
log::info!("video save to:{}", self.filename);
|
||||
log::info!("video will save to:{}", self.filename);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -75,6 +77,14 @@ pub trait RecorderApi {
|
||||
fn write_video(&mut self, frame: &EncodedVideoFrame) -> bool;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RecordState {
|
||||
NewFile(String),
|
||||
NewFrame,
|
||||
WriteTail,
|
||||
RemoveFile,
|
||||
}
|
||||
|
||||
pub struct Recorder {
|
||||
pub inner: Box<dyn RecorderApi>,
|
||||
ctx: RecorderContext,
|
||||
@ -110,6 +120,7 @@ impl Recorder {
|
||||
#[cfg(not(feature = "hwcodec"))]
|
||||
_ => bail!("unsupported codec type"),
|
||||
};
|
||||
recorder.send_state(RecordState::NewFile(recorder.ctx.filename.clone()));
|
||||
Ok(recorder)
|
||||
}
|
||||
|
||||
@ -123,6 +134,7 @@ impl Recorder {
|
||||
_ => bail!("unsupported codec type"),
|
||||
};
|
||||
self.ctx = ctx;
|
||||
self.send_state(RecordState::NewFile(self.ctx.filename.clone()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -171,8 +183,13 @@ impl Recorder {
|
||||
}
|
||||
_ => bail!("unsupported frame type"),
|
||||
}
|
||||
self.send_state(RecordState::NewFrame);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn send_state(&self, state: RecordState) {
|
||||
self.ctx.tx.as_ref().map(|tx| tx.send(state));
|
||||
}
|
||||
}
|
||||
|
||||
struct WebmRecorder {
|
||||
@ -237,9 +254,12 @@ impl RecorderApi for WebmRecorder {
|
||||
impl Drop for WebmRecorder {
|
||||
fn drop(&mut self) {
|
||||
std::mem::replace(&mut self.webm, None).map_or(false, |webm| webm.finalize(None));
|
||||
let mut state = RecordState::WriteTail;
|
||||
if !self.written || self.start.elapsed().as_secs() < MIN_SECS {
|
||||
std::fs::remove_file(&self.ctx.filename).ok();
|
||||
state = RecordState::RemoveFile;
|
||||
}
|
||||
self.ctx.tx.as_ref().map(|tx| tx.send(state));
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,8 +312,11 @@ impl RecorderApi for HwRecorder {
|
||||
impl Drop for HwRecorder {
|
||||
fn drop(&mut self) {
|
||||
self.muxer.write_tail().ok();
|
||||
let mut state = RecordState::WriteTail;
|
||||
if !self.written || self.start.elapsed().as_secs() < MIN_SECS {
|
||||
std::fs::remove_file(&self.ctx.filename).ok();
|
||||
state = RecordState::RemoveFile;
|
||||
}
|
||||
self.ctx.tx.as_ref().map(|tx| tx.send(state));
|
||||
}
|
||||
}
|
||||
|
@ -863,12 +863,14 @@ impl VideoHandler {
|
||||
self.record = false;
|
||||
if start {
|
||||
self.recorder = Recorder::new(RecorderContext {
|
||||
server: false,
|
||||
id,
|
||||
default_dir: crate::ui_interface::default_video_save_directory(),
|
||||
filename: "".to_owned(),
|
||||
width: w as _,
|
||||
height: h as _,
|
||||
codec_id: scrap::record::RecordCodecID::VP9,
|
||||
tx: None,
|
||||
})
|
||||
.map_or(Default::default(), |r| Arc::new(Mutex::new(Some(r))));
|
||||
} else {
|
||||
|
@ -936,7 +936,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
self.handle_job_status(d.id, d.file_num, err);
|
||||
}
|
||||
Some(file_response::Union::Error(e)) => {
|
||||
if let Some(job) = fs::get_job(e.id, &mut self.write_jobs) {
|
||||
if let Some(_job) = fs::get_job(e.id, &mut self.write_jobs) {
|
||||
fs::remove_job(e.id, &mut self.write_jobs);
|
||||
}
|
||||
self.handle_job_status(e.id, e.file_num, Some(e.error));
|
||||
|
@ -217,7 +217,7 @@ pub fn core_main() -> Option<Vec<String>> {
|
||||
if crate::platform::is_root() {
|
||||
crate::ipc::set_permanent_password(args[1].to_owned()).unwrap();
|
||||
} else {
|
||||
log::info!("Permission denied!");
|
||||
println!("Administrative privileges required!");
|
||||
}
|
||||
}
|
||||
return None;
|
||||
|
@ -4,6 +4,7 @@ use serde_json::{Map, Value};
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
pub mod account;
|
||||
pub mod record_upload;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HbbHttpResponse<T> {
|
||||
|
204
src/hbbs_http/record_upload.rs
Normal file
204
src/hbbs_http/record_upload.rs
Normal file
@ -0,0 +1,204 @@
|
||||
use bytes::Bytes;
|
||||
use hbb_common::{bail, config::Config, lazy_static, log, ResultType};
|
||||
use reqwest::blocking::{Body, Client};
|
||||
use scrap::record::RecordState;
|
||||
use serde::Serialize;
|
||||
use serde_json::Map;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{prelude::*, SeekFrom},
|
||||
sync::{mpsc::Receiver, Arc, Mutex},
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
const MAX_HEADER_LEN: usize = 1024;
|
||||
const SHOULD_SEND_TIME: Duration = Duration::from_secs(1);
|
||||
const SHOULD_SEND_SIZE: u64 = 1024 * 1024;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref ENABLE: Arc<Mutex<bool>> = Default::default();
|
||||
}
|
||||
|
||||
pub fn is_enable() -> bool {
|
||||
ENABLE.lock().unwrap().clone()
|
||||
}
|
||||
|
||||
pub fn run(rx: Receiver<RecordState>) {
|
||||
let mut uploader = RecordUploader {
|
||||
client: Client::new(),
|
||||
api_server: crate::get_api_server(
|
||||
Config::get_option("api-server"),
|
||||
Config::get_option("custom-rendezvous-server"),
|
||||
),
|
||||
filepath: Default::default(),
|
||||
filename: Default::default(),
|
||||
upload_size: Default::default(),
|
||||
running: Default::default(),
|
||||
last_send: Instant::now(),
|
||||
};
|
||||
std::thread::spawn(move || loop {
|
||||
if let Err(e) = match rx.recv() {
|
||||
Ok(state) => match state {
|
||||
RecordState::NewFile(filepath) => uploader.handle_new_file(filepath),
|
||||
RecordState::NewFrame => {
|
||||
if uploader.running {
|
||||
uploader.handle_frame(false)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
RecordState::WriteTail => {
|
||||
if uploader.running {
|
||||
uploader.handle_tail()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
RecordState::RemoveFile => {
|
||||
if uploader.running {
|
||||
uploader.handle_remove()
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::trace!("upload thread stop:{}", e);
|
||||
break;
|
||||
}
|
||||
} {
|
||||
uploader.running = false;
|
||||
log::error!("upload stop:{}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
struct RecordUploader {
|
||||
client: Client,
|
||||
api_server: String,
|
||||
filepath: String,
|
||||
filename: String,
|
||||
upload_size: u64,
|
||||
running: bool,
|
||||
last_send: Instant,
|
||||
}
|
||||
impl RecordUploader {
|
||||
fn send<Q, B>(&self, query: &Q, body: B) -> ResultType<()>
|
||||
where
|
||||
Q: Serialize + ?Sized,
|
||||
B: Into<Body>,
|
||||
{
|
||||
match self
|
||||
.client
|
||||
.post(format!("{}/api/record", self.api_server))
|
||||
.query(query)
|
||||
.body(body)
|
||||
.send()
|
||||
{
|
||||
Ok(resp) => {
|
||||
if let Ok(m) = resp.json::<Map<String, serde_json::Value>>() {
|
||||
if let Some(e) = m.get("error") {
|
||||
bail!(e.to_string());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => bail!(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_new_file(&mut self, filepath: String) -> ResultType<()> {
|
||||
match std::path::PathBuf::from(&filepath).file_name() {
|
||||
Some(filename) => match filename.to_owned().into_string() {
|
||||
Ok(filename) => {
|
||||
self.filename = filename.clone();
|
||||
self.filepath = filepath.clone();
|
||||
self.upload_size = 0;
|
||||
self.running = true;
|
||||
self.last_send = Instant::now();
|
||||
self.send(&[("type", "new"), ("file", &filename)], Bytes::new())?;
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => bail!("can't parse filename:{:?}", filename),
|
||||
},
|
||||
None => bail!("can't parse filepath:{}", filepath),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_frame(&mut self, flush: bool) -> ResultType<()> {
|
||||
if !flush && self.last_send.elapsed() < SHOULD_SEND_TIME {
|
||||
return Ok(());
|
||||
}
|
||||
match File::open(&self.filepath) {
|
||||
Ok(mut file) => match file.metadata() {
|
||||
Ok(m) => {
|
||||
let len = m.len();
|
||||
if len <= self.upload_size {
|
||||
return Ok(());
|
||||
}
|
||||
if !flush && len - self.upload_size < SHOULD_SEND_SIZE {
|
||||
return Ok(());
|
||||
}
|
||||
let mut buf = Vec::new();
|
||||
match file.seek(SeekFrom::Start(self.upload_size)) {
|
||||
Ok(_) => match file.read_to_end(&mut buf) {
|
||||
Ok(length) => {
|
||||
self.send(
|
||||
&[
|
||||
("type", "part"),
|
||||
("file", &self.filename),
|
||||
("offset", &self.upload_size.to_string()),
|
||||
("length", &length.to_string()),
|
||||
],
|
||||
buf,
|
||||
)?;
|
||||
self.upload_size = len;
|
||||
self.last_send = Instant::now();
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => bail!(e.to_string()),
|
||||
},
|
||||
Err(e) => bail!(e.to_string()),
|
||||
}
|
||||
}
|
||||
Err(e) => bail!(e.to_string()),
|
||||
},
|
||||
Err(e) => bail!(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_tail(&mut self) -> ResultType<()> {
|
||||
self.handle_frame(true)?;
|
||||
match File::open(&self.filepath) {
|
||||
Ok(mut file) => {
|
||||
let mut buf = vec![0u8; MAX_HEADER_LEN];
|
||||
match file.read(&mut buf) {
|
||||
Ok(length) => {
|
||||
buf.truncate(length);
|
||||
self.send(
|
||||
&[
|
||||
("type", "tail"),
|
||||
("file", &self.filename),
|
||||
("offset", "0"),
|
||||
("length", &length.to_string()),
|
||||
],
|
||||
buf,
|
||||
)?;
|
||||
log::info!("upload success, file:{}", self.filename);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => bail!(e.to_string()),
|
||||
}
|
||||
}
|
||||
Err(e) => bail!(e.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_remove(&mut self) -> ResultType<()> {
|
||||
self.send(
|
||||
&[("type", "remove"), ("file", &self.filename)],
|
||||
Bytes::new(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -399,6 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("hide_cm_tip", "Permitir ocultar solo si se aceptan sesiones a través de contraseña y usando contraseña permanente"),
|
||||
("wayland_experiment_tip", "El soporte para Wayland está en fase experimental, por favor, use X11 si necesita acceso desatendido."),
|
||||
("Right click to select tabs", "Clic derecho para seleccionar pestañas"),
|
||||
("Add to Address Book", ""),
|
||||
("Add to Address Book", "Añadir a la libreta de direcciones"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ const ADDR_CAPTURE_FRAME_COUNTER: usize = ADDR_CAPTURE_WOULDBLOCK + size_of::<i3
|
||||
const ADDR_CAPTURE_FRAME: usize =
|
||||
(ADDR_CAPTURE_FRAME_COUNTER + SIZE_COUNTER + FRAME_ALIGN - 1) / FRAME_ALIGN * FRAME_ALIGN;
|
||||
|
||||
const IPC_PROFIX: &str = "_portable_service";
|
||||
const IPC_SUFFIX: &str = "_portable_service";
|
||||
pub const SHMEM_NAME: &str = "_portable_service";
|
||||
const MAX_NACK: usize = 3;
|
||||
const MAX_DXGI_FAIL_TIME: usize = 5;
|
||||
@ -376,7 +376,7 @@ pub mod server {
|
||||
async fn run_ipc_client() {
|
||||
use DataPortableService::*;
|
||||
|
||||
let postfix = IPC_PROFIX;
|
||||
let postfix = IPC_SUFFIX;
|
||||
|
||||
match ipc::connect(1000, postfix).await {
|
||||
Ok(mut stream) => {
|
||||
@ -622,7 +622,7 @@ pub mod client {
|
||||
async fn start_ipc_server_async(rx: mpsc::UnboundedReceiver<Data>) {
|
||||
use DataPortableService::*;
|
||||
let rx = Arc::new(tokio::sync::Mutex::new(rx));
|
||||
let postfix = IPC_PROFIX;
|
||||
let postfix = IPC_SUFFIX;
|
||||
#[cfg(feature = "flutter")]
|
||||
let quick_support = {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
|
@ -21,8 +21,9 @@
|
||||
use super::{video_qos::VideoQoS, *};
|
||||
#[cfg(windows)]
|
||||
use crate::portable_service::client::PORTABLE_SERVICE_RUNNING;
|
||||
#[cfg(windows)]
|
||||
use hbb_common::get_version_number;
|
||||
use hbb_common::{
|
||||
get_version_number,
|
||||
tokio::sync::{
|
||||
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
|
||||
Mutex as TokioMutex,
|
||||
@ -481,22 +482,7 @@ fn run(sp: GenericService) -> ResultType<()> {
|
||||
#[cfg(windows)]
|
||||
log::info!("gdi: {}", c.is_gdi());
|
||||
let codec_name = Encoder::current_hw_encoder_name();
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
let recorder = if !Config::get_option("allow-auto-record-incoming").is_empty() {
|
||||
Recorder::new(RecorderContext {
|
||||
id: "local".to_owned(),
|
||||
default_dir: crate::ui_interface::default_video_save_directory(),
|
||||
filename: "".to_owned(),
|
||||
width: c.width,
|
||||
height: c.height,
|
||||
codec_id: scrap::record::RecordCodecID::VP9,
|
||||
})
|
||||
.map_or(Default::default(), |r| Arc::new(Mutex::new(Some(r))))
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
#[cfg(target_os = "ios")]
|
||||
let recorder: Arc<Mutex<Option<Recorder>>> = Default::default();
|
||||
let recorder = get_recorder(c.width, c.height, &codec_name);
|
||||
#[cfg(windows)]
|
||||
start_uac_elevation_check();
|
||||
|
||||
@ -673,6 +659,53 @@ fn run(sp: GenericService) -> ResultType<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_recorder(
|
||||
width: usize,
|
||||
height: usize,
|
||||
codec_name: &Option<String>,
|
||||
) -> Arc<Mutex<Option<Recorder>>> {
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
let recorder = if !Config::get_option("allow-auto-record-incoming").is_empty() {
|
||||
use crate::hbbs_http::record_upload;
|
||||
use scrap::record::RecordCodecID::*;
|
||||
|
||||
let tx = if record_upload::is_enable() {
|
||||
let (tx, rx) = std::sync::mpsc::channel();
|
||||
record_upload::run(rx);
|
||||
Some(tx)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let codec_id = match codec_name {
|
||||
Some(name) => {
|
||||
if name.contains("264") {
|
||||
H264
|
||||
} else {
|
||||
H265
|
||||
}
|
||||
}
|
||||
None => VP9,
|
||||
};
|
||||
Recorder::new(RecorderContext {
|
||||
server: true,
|
||||
id: Config::get_id(),
|
||||
default_dir: crate::ui_interface::default_video_save_directory(),
|
||||
filename: "".to_owned(),
|
||||
width,
|
||||
height,
|
||||
codec_id,
|
||||
tx,
|
||||
})
|
||||
.map_or(Default::default(), |r| Arc::new(Mutex::new(Some(r))))
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
#[cfg(target_os = "ios")]
|
||||
let recorder: Arc<Mutex<Option<Recorder>>> = Default::default();
|
||||
|
||||
recorder
|
||||
}
|
||||
|
||||
fn check_privacy_mode_changed(sp: &GenericService, privacy_mode_id: i32) -> ResultType<()> {
|
||||
let privacy_mode_id_2 = *PRIVACY_MODE_CONN_ID.lock().unwrap();
|
||||
if privacy_mode_id != privacy_mode_id_2 {
|
||||
|
@ -685,6 +685,7 @@ pub fn discover() {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "flutter")]
|
||||
pub fn peer_to_map(id: String, p: PeerConfig) -> HashMap<&'static str, String> {
|
||||
HashMap::<&str, String>::from_iter([
|
||||
("id", id),
|
||||
|
Loading…
Reference in New Issue
Block a user