添加初始提交

1. 编译已经通过
2. 添加好了rpc客户端的基本实现
3. 添加好了fuser的架子,内容等待实现
This commit is contained in:
Ekko.bao 2024-07-16 07:55:44 +08:00
parent 71505636ec
commit 24573524a6
8 changed files with 1599 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

1233
Cargo.lock generated Executable file

File diff suppressed because it is too large Load Diff

19
Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "lws_client"
version = "0.1.0"
edition = "2021"
[[bin]] # Bin to run the HelloWorld gRPC client
name = "lws-client"
path = "src/client.rs"
[dependencies]
tonic = "0.11"
prost = "0.12"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
fuser = "0.14.0"
[build-dependencies]
tonic-build = "0.11"

4
build.rs Executable file
View File

@ -0,0 +1,4 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::compile_protos("proto/lws.proto")?;
Ok(())
}

211
proto/lws.proto Normal file
View File

@ -0,0 +1,211 @@
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package lws_vfs;
service LwsVfs {
// Sends a greeting
rpc SayHello(HelloRequest) returns (HelloReply) {}
rpc fgetattr(getattr) returns (getattr) {}
rpc fsetxattr(setxattr) returns (setxattr) {}
rpc faccess(access) returns (access) {}
rpc freaddir(readdir) returns (readdir) {}
rpc fread(read) returns (read) {}
rpc fopen(open) returns (open) {}
rpc fwrite(write) returns (write) {}
rpc fgetxattr(getxattr) returns (getxattr) {}
rpc ftruncate(truncate) returns (truncate) {}
rpc futimens(utimens) returns (utimens) {}
rpc fchown(chown) returns (chown) {}
rpc frelease(release) returns (release) {}
rpc fmkdir(mkdir) returns (mkdir) {}
rpc frmdir(rmdir) returns (rmdir) {}
rpc fflush(flush) returns (flush) {}
rpc fopendir(opendir) returns (opendir) {}
rpc freleasedir(releasedir) returns (releasedir) {}
rpc fcreate(create) returns (create) {}
rpc funlink(unlink) returns (unlink) {}
rpc frename(rename) returns (rename) {}
}
// The request message containing the user's name.
message HelloRequest { string name = 1; }
// The response message containing the greetings
message HelloReply { string message = 1; }
message file_info {
int32 flags = 1;
uint32 fh_old = 2;
bool direct_io = 3;
uint64 fh = 10;
uint64 lock_owner = 11;
}
message fstat {
uint64 fst_mode = 1;
uint64 fst_ino = 2;
uint64 fst_dev = 3;
uint64 fst_rdev = 4;
uint64 fst_nlink = 5;
uint64 fst_uid = 6;
uint64 fst_gid = 7;
uint64 fst_size = 8;
uint64 fst_atime = 9;
uint64 fst_mtime = 10;
uint64 fst_ctime = 11;
uint64 fst_blksize = 12;
uint64 fst_blocks = 13;
}
// fuse api function message define:
message getattr {
string path = 1;
fstat stat = 2;
int32 ret = 15;
}
message setxattr {
string path = 1;
string name = 2;
bytes value = 3;
int64 size = 4;
uint32 flags = 5;
int32 ret = 15;
}
message getxattr {
string path = 1;
string name = 2;
bytes value = 3;
int64 size = 4;
int32 ret = 15;
}
message access {
string path = 1;
uint32 mask = 2;
int32 ret = 15;
}
message readdir {
string path = 1;
repeated string dirs = 2;
uint32 offset = 3;
file_info fi = 4;
int32 ret = 15;
}
message open {
string path = 1;
file_info fi = 2;
int32 ret = 15;
}
message read {
string path = 1;
bytes buff = 2;
int64 size = 3;
int64 offset = 4;
file_info fi = 5;
int32 ret = 15;
}
message write {
string path = 1;
bytes buff = 2;
int64 size = 3;
int64 offset = 4;
file_info fi = 5;
int32 ret = 15;
}
message truncate {
string path = 1;
int64 size = 3;
int32 ret = 15;
}
message timespec {
int32 tv_sec = 1;
int64 tv_nsec = 2;
}
message utimens {
string path = 1;
repeated timespec ts = 2; // const struct timespec ts[2]
int32 ret = 15;
}
message chown {
string path = 1;
int32 uid = 2;
int32 gid = 3;
int32 ret = 15;
}
message release {
string path = 1;
file_info fi = 2;
int32 ret = 15;
}
message mkdir {
string path = 1;
file_info fi = 2;
uint32 mode = 3;
int32 ret = 15;
}
message rmdir {
string path = 1;
int32 ret = 15;
}
message flush {
string path = 1;
file_info fi = 2;
int32 ret = 15;
}
message opendir {
string path = 1;
file_info fi = 2;
int32 ret = 15;
}
message releasedir {
string path = 1;
file_info fi = 2;
int32 ret = 15;
}
message create {
string path = 1;
uint32 mode = 2;
file_info fi = 3;
int32 ret = 15;
}
message unlink {
string path = 1;
int32 ret = 15;
}
message rename {
string path = 1;
string new = 2;
int32 ret = 15;
}

19
src/client.rs Executable file
View File

@ -0,0 +1,19 @@
use lws_client::LwsVfsIns;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut lws_ins = match LwsVfsIns::new("config.json").await{
Ok(ins) => ins,
Err(e) => {
println!("Error creating lws server instance: {:?}", e);
return Err(e);
}
};
match lws_ins.hello().await{
Err(e) => {
println!("lws client instance hello err {:?}", e);
return Err(e);
},
_ =>{},
}
LwsVfsIns::mount(lws_ins)
}

109
src/lib.rs Normal file
View File

@ -0,0 +1,109 @@
use lws_client::HelloRequest;
use std::{io::Read as _};
use std::fs::File;
use std::error::Error;
use std::collections::HashMap;
use serde_json::{self, Value};
use lws_client::lws_vfs_client::LwsVfsClient;
use std::os::raw::c_int;
use fuser::{
KernelConfig, FileAttr, FileType, Filesystem, MountOption, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry,
Request,
};
pub mod lws_client {
tonic::include_proto!("lws_vfs"); //导入lws vfs proto buffer
}
#[derive(Debug, Default)]
pub struct Config {
port: u16,
addr: String,
mount_map: HashMap<String, String>,
}
impl Config {
pub fn new(json: &str) -> Result<Config, Box<dyn Error>> {
let mut file = File::open(json)?;
let mut buffer = String::new();
file.read_to_string(&mut buffer)?;
let json: Value = serde_json::from_str(buffer.as_ref())?;
let port: u16 = match json.get("port") {
Some(port) => port.as_u64().expect("expect port is a number but its not") as u16,
None => 5001,
};
let addr: String = match json.get("addr") {
Some(addr) => addr.as_str().expect("expect addr is a String but its not").to_string(),
None => "localhost".to_string(),
};
let mounts = match json.get("mount") {
Some(mounts) => mounts.as_object().unwrap(),
None => {
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::Other,
"no mount map",
)))
}
};
let mount_map = mounts
.iter()
.map(|(key, value)| {
(
key.as_str().to_string(),
value.as_str().unwrap().to_string(),
)
})
.collect();
Ok(Config { port, addr, mount_map })
}
pub fn get_port(&self) -> u16 {
self.port
}
pub fn get_addr(&self) -> &String {
&self.addr
}
}
pub struct LwsVfsIns {
pub config: Config,
rpc: LwsVfsClient<tonic::transport::Channel>
}
impl Filesystem for LwsVfsIns {
fn init(&mut self, _req: &Request, #[allow(unused_variables)] config: &mut KernelConfig,
) -> Result<(), c_int> {
Ok(())
}
}
impl LwsVfsIns {
pub async fn new(json: &str) -> Result<LwsVfsIns, Box<dyn Error>> {
let config = Config::new(json)?;
let addr = format!("http://{}:{}", config.get_addr(), config.get_port());
//connect to server
let rpc = LwsVfsClient::connect(addr).await?;
Ok(LwsVfsIns {
config,
rpc,
})
}
pub async fn hello(&mut self) -> Result<(), Box<dyn Error>> {
let request = tonic::Request::new(HelloRequest {
name: "Ekko lws hello".into(),
});
let response = &self.rpc.say_hello(request).await?;
println!("RESPONSE={:?}", response);
Ok(())
}
pub fn mount<FS:Filesystem>(file_system:FS) -> Result<(), Box<dyn Error>> {
let mountpoint = "/mnt";
let options = vec![MountOption::RO, MountOption::FSName("lws_fs".to_string())];
fuser::mount2(file_system, mountpoint, &options).unwrap();
Ok(())
}
}

3
src/main.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}