当前位置: 首页 > news >正文

【Tauri2】027——plugin(三)——fs

前言

前面使用了fs这个插件,这篇就来简单看看关于fs内部的东西

正文

init方法

先来看看init方法

函数签名

pub fn init<R: Runtime>() -> TauriPlugin<R, Option<config::Config>> 

 返回TauriPlugin,

看看Config 又是什么

#[derive(Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Config {pub require_literal_leading_dot: Option<bool>,
}

是个结构体,只是一个字段require_literal_leading_dot,根据意思,可以知道

一个可选的布尔字段,表示是否要求路径中以点(.)开头的组件必须显式匹配

实现了trait  Deserialize,这是PluginBuilder的trait要求

pub struct Builder<R: Runtime, C: DeserializeOwned = ()> 

 new方法

 PluginBuilder::<R, Option<config::Config>>::new("fs").invoke_handler(tauri::generate_handler![commands::create,...])

传入fs作为插件的名字,后面接着调用invoke_handler,用于注册通信函数

setup方法

 .setup(|app, api| {let scope = Scope {require_literal_leading_dot: api.config().as_ref().and_then(|c| c.require_literal_leading_dot),scope: tauri::fs::Scope::new(app, &FsScope::default())?,};#[cfg(target_os = "android")]{let fs = mobile::init(app, api)?;app.manage(fs);}#[cfg(not(target_os = "android"))]app.manage(Fs(app.clone()));app.manage(scope);Ok(())})
pub(crate) struct Scope {pub(crate) scope: tauri::fs::Scope,pub(crate) require_literal_leading_dot: Option<bool>,
}

Scope是个结构体,里面有scope和require_literal_leading_dot字段

先初始化这个Scope

然后,注册了两个State,一个是Fs,另一个就是初始化后的scope

简单使用require_literal_leading_dot——读取.gitignore文件

在配置文件tauri.conf.json中,进行如下配置

  "plugins":{"fs": {"requireLiteralLeadingDot": false}},

因为.gitignore文件的路径在D:/start/.gitignore

但是tauri.conf.json的路径D:/start/src-tauri/tauri.conf.json

因此resources如下

 "resources": {..."../.gitignore": "public/.gitignore"},

要往后退一个目录才能找到。

当然,也可以写绝对路径

编译后,debug目录下

成功

读取.gitignore

关键代码如下

    let rf=await readTextFile("public/.gitignore",{baseDir})console.log(rf)

结果如下

没问题

on_event

        .on_event(|app, event| {if let RunEvent::WindowEvent {label: _,event: WindowEvent::DragDrop(DragDropEvent::Drop { paths, position: _ }),..} = event{let scope = app.fs_scope();for path in paths {if path.is_file() {dbg!(&path);let _ = scope.allow_file(path);} else {let _ = scope.allow_directory(path, true);}}}})

很明显,这里面就是监控window事件的,来试试

使用拖拽事件DragDrop

在尝试过程中,笔者发现一件事情

如果在Cargo文件,在依赖tauri中,设置了features=["unstable"],笔者发现无法触发这个DragDrop事件和Focus事件。

但是如果不设置feature=["unstable"],在前面文章中使用的一些东西WindowBuilder,就使用不了。

笔者在这里删除unstable,为了触发DragDrop

在源代码中,添加打印语句

                let scope = app.fs_scope();println!("DragDropEvent::Drop {:#?}", paths);println!("DragDropEvent::Drop {:#?}", scope);

总之,代码如下

fn use_window_event(window: &Window,event: &WindowEvent,
){match event {WindowEvent::DragDrop(drag)=>{match drag {tauri::DragDropEvent::Drop {paths,position,..}=>{println!("{:?}",paths);},_=> {println!("DragDrop {:?}", drag);}}}_ => {println!("Other event {:?}", event);}}
}

 主项目的main函数中

 .on_window_event(use_window_event)

笔者多次尝试,打印的结果如下

DragDropEvent::Drop Scope {allowed_patterns: ["C:\\Users\\26644\\Desktop\\f10c2ffebc1a933389a5390179c5cd13.png","C:\\Users\\26644\\Desktop\\hello.asm","\\\\[?]\\C:\\Users\\26644\\Desktop\\hello.asm","\\\\[?]\\C:\\Users\\26644\\Desktop\\f10c2ffebc1a933389a5390179c5cd13.png",],forbidden_patterns: [],
}

好像拖拽了之后,会把文件路经添加到allowed_patterns。

最后调用build方法

.build()

返回TauriPlugin<R, Option<config::Config>>

总之,干了四件事

1、添加一个配置

2、注册通信函数

3、注册了两个State

4、事件处理

看看通信函数create

#[tauri::command]
pub fn create<R: Runtime>(webview: Webview<R>,global_scope: GlobalScope<Entry>,command_scope: CommandScope<Entry>,path: SafeFilePath,options: Option<BaseOptions>,
) -> CommandResult<ResourceId> {let resolved_path = resolve_path(&webview,&global_scope,&command_scope,path,options.and_then(|o| o.base_dir),)?;let file = File::create(&resolved_path).map_err(|e| {format!("failed to create file at path: {} with error: {e}",resolved_path.display())})?;let rid = webview.resources_table().add(StdFileResource::new(file));Ok(rid)
}

前三个参数都是能直接获取的,不必细说。

需要传path和options两个参数。

看看resolve_path方法

pub fn resolve_path<R: Runtime>(webview: &Webview<R>,global_scope: &GlobalScope<Entry>,command_scope: &CommandScope<Entry>,path: SafeFilePath,base_dir: Option<BaseDirectory>,
) -> CommandResult<PathBuf> {let path = path.into_path()?;let path = if let Some(base_dir) = base_dir {webview.path().resolve(&path, base_dir)?} else {path};let fs_scope = ...let scope =...let require_literal_leading_dot = ...if is_forbidden(&fs_scope.scope, &path, require_literal_leading_dot)...if fs_scope.scope.is_allowed(&path) || scope.is_allowed(&path) {Ok(path)} else {Err(CommandError::Plugin(Error::PathForbidden(path)))}
}

大致的过程

1、路径拼接

webview.path().resolve(&path, base_dir)?

webview实现了Manager,调用path方法,返回&PathResolve,使用

resolve拼接路径

2、判断是否被禁止

3、判断是否满足允许的条件

最后返回需要的路径

 File::create

调用Rust标志库std::fs::File中的方法来创建文件

resources_table

 fn resources_table(&self) -> MutexGuard<'_, ResourceTable> 

返回一个锁,里面是ResourceTable

#[derive(Default)]
pub struct ResourceTable {index: BTreeMap<ResourceId, Arc<dyn Resource>>,
}

ResourceTable 是个结构体,内部只有一个字段,index。类型是BTreeMap

BTreeMap in std::collections - Rusthttps://doc.rust-lang.org/std/collections/struct.BTreeMap.html

简单地说,BTreeMap 是一种基于 B树 的有序键值存储结构

1、有序存储

2、高效的查找、插入和删除

3、适用于内存和磁盘存储

键是ResourceId,值是Arc<dyn Resource>,动态分发trait Resource

pub type ResourceId = u32;

 ResourceId是u32的别名

看看这个StdFileResouzhe

struct StdFileResource(Mutex<File>);impl StdFileResource {fn new(file: File) -> Self {Self(Mutex::new(file))}fn with_lock<R, F: FnMut(&File) -> R>(&self, mut f: F) -> R {let file = self.0.lock().unwrap();f(&file)}
}
impl Resource for StdFileResource {}

这是一个结构体,实现了 trait Resource 

 看看其中的add方法

  pub fn add<T: Resource>(&mut self, resource: T) -> ResourceId {self.add_arc(Arc::new(resource))}

返回了ResourceId 

一直往里面走,发现add_arc_dyn

  pub fn add_arc_dyn(&mut self, resource: Arc<dyn Resource>) -> ResourceId {let mut rid = Self::new_random_rid();while self.index.contains_key(&rid) {rid = Self::new_random_rid();}let removed_resource = self.index.insert(rid, resource);assert!(removed_resource.is_none());rid}

大致过程

1、随机创造一个的ResourceId

  fn new_random_rid() -> u32 {let mut bytes = [0_u8; 4];getrandom::getrandom(&mut bytes).expect("failed to get random bytes");u32::from_ne_bytes(bytes)}

2、在BtreeMap中判断是否包含这个随机的ResourceId如果存在,重新生成一个随机的 ResourceId,直到生成一个唯一的 ResourceId。

3、BtreeMap的insert方法,插入ResourceId和对应的resource,比如文件。

insert 方法的返回值是 Option<V>,表示插入操作是否覆盖了原有的值:
如果键已经存在,返回 Some(旧值)。
如果键不存在,返回 None

4、断言插入操作没有覆盖任何已有的资源

5、返回ResourceId

总结

在create中,先判断是否满足权限,再将资源插入到BtreeMap中,返回ResourceId

其他方法就不必细看了,都是围绕标准库std::fs和BtreeMap,进行展开。

比如说write,就是先通过BtreeMap获取rid,然后使用fs中的方法。

http://www.xdnf.cn/news/47881.html

相关文章:

  • 出差像是旅游?
  • 2025-04-20 李沐深度学习4 —— 自动求导
  • 中级软件设计师 - 知识点(附真题)目录大全
  • Matplotlib的应用
  • springboot起步依赖的原理是什么?
  • “小坝” 策略:始发站 buffer 控制与优化
  • 专题讨论:BST树上的添加与删除
  • mysql的5.7版本与8.0版本的差异与兼容性
  • Flink介绍——实时计算核心论文之MillWheel论文详解
  • 计算机视觉7——齐次坐标与相机内外参
  • transformer注意力机制
  • 集合框架拓展--stream流的使用
  • 理解 React 的 useEffect
  • 代理模式(Proxy Pattern)
  • 返回内容协商,@ResponseBody 注解
  • C++面试题集合(附答案)
  • [Windows]_[VS2017]_[如何进行远程调试程序]
  • 计算机视觉与深度学习 | 工业视觉缺陷检测如何检小缺陷?背景概述,原理,检测难点,常用的检测算法,算法评估指标,新项目算法选择,算法部署
  • 【Oracle专栏】Oracle中的虚拟列
  • Linux文件时间戳详解:Access、Modify、Change时间的区别与作用
  • PCA——主成分分析数学原理及代码
  • 小迪抓包技术算法加密(6-9天)
  • Dify部署内网时遇到的代理问题及解决办法
  • 【Python爬虫详解】第一篇:Python爬虫入门指南
  • B+树节点与插入操作
  • git清理--解决.git文件过大问题
  • 基于蒙特卡洛模拟与时间序列分析的美的集团财务预测模型研究
  • DeepSeek 助力 Vue 开发:打造丝滑的二维码生成(QR Code)
  • 常用的验证验证 onnxruntime-gpu安装的命令
  • WIN10重启开机不用登录,直接进入桌面