use std::{
collections::{BTreeMap, HashMap},
fmt::Display,
io::{Read, Write},
};
use async_trait::async_trait;
use futures::{AsyncReadExt, AsyncWriteExt};
use p9::{wire_format, Tmessage, WireFormat};
use s2n_quic::stream::{BidirectionalStream, ReceiveStream, SendStream};
use tokio::{runtime::Runtime, sync::Mutex};
use crate::versions::{self, DEFAULT_MSIZE};
pub struct NinePClient<'a> {
msize: usize,
connection: s2n_quic::Connection,
rt: &'a Runtime,
tags: Mutex<BTreeMap<u16, NinePClientConnection<'a>>>,
}
pub struct Name(Vec<String>);
pub struct Owned(u16, Name);
pub struct File {
pub name: Name,
}
pub struct Dir {
pub name: Name,
}
pub struct DirEntry(Name);
impl genfs::DirEntry for DirEntry {
type Path = Name;
type PathOwned = Owned;
type Metadata = std::fs::Metadata;
type FileType = std::fs::FileType;
type Error = std::io::Error;
fn path(&self) -> Self::PathOwned {
todo!()
}
fn metadata(
&self,
) -> std::prelude::v1::Result<Self::Metadata, Self::Error> {
todo!()
}
fn file_type(
&self,
) -> std::prelude::v1::Result<Self::FileType, Self::Error> {
todo!()
}
fn file_name(&self) -> &Self::Path {
todo!()
}
}
impl Iterator for Dir {
type Item = Result<DirEntry, std::io::Error>;
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}
impl genfs::Dir<DirEntry, std::io::Error> for Dir {}
impl genfs::File for File {
type Error = std::io::Error;
fn read(
&self,
buf: &mut [u8],
) -> std::prelude::v1::Result<usize, Self::Error> {
todo!()
}
fn write(
&mut self,
buf: &[u8],
) -> std::prelude::v1::Result<usize, Self::Error> {
todo!()
}
fn flush(&mut self) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn seek(
&mut self,
pos: genfs::SeekFrom,
) -> std::prelude::v1::Result<u64, Self::Error> {
todo!()
}
}
impl<'a> genfs::Fs for NinePClient<'a> {
type Path = Name;
type PathOwned = Owned;
type File = File;
type Dir = Dir;
type DirEntry = DirEntry;
type Metadata = std::fs::Metadata;
type Permissions = std::fs::Permissions;
type Error = std::io::Error;
fn open(
&self,
path: &Self::Path,
options: &genfs::OpenOptions<Self::Permissions>,
) -> std::prelude::v1::Result<Self::File, Self::Error> {
todo!()
}
fn remove_file(
&mut self,
path: &Self::Path,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn metadata(
&self,
path: &Self::Path,
) -> std::prelude::v1::Result<Self::Metadata, Self::Error> {
todo!()
}
fn symlink_metadata(
&self,
path: &Self::Path,
) -> std::prelude::v1::Result<Self::Metadata, Self::Error> {
todo!()
}
fn rename(
&mut self,
from: &Self::Path,
to: &Self::Path,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn copy(
&mut self,
from: &Self::Path,
to: &Self::Path,
) -> std::prelude::v1::Result<u64, Self::Error> {
todo!()
}
fn hard_link(
&mut self,
src: &Self::Path,
dst: &Self::Path,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn symlink(
&mut self,
src: &Self::Path,
dst: &Self::Path,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn read_link(
&self,
path: &Self::Path,
) -> std::prelude::v1::Result<Self::PathOwned, Self::Error> {
todo!()
}
fn canonicalize(
&self,
path: &Self::Path,
) -> std::prelude::v1::Result<Self::PathOwned, Self::Error> {
todo!()
}
fn create_dir(
&mut self,
path: &Self::Path,
options: &genfs::DirOptions<Self::Permissions>,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn remove_dir(
&mut self,
path: &Self::Path,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn remove_dir_all(
&mut self,
path: &Self::Path,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
fn read_dir(
&self,
path: &Self::Path,
) -> std::prelude::v1::Result<Self::Dir, Self::Error> {
todo!()
}
fn set_permissions(
&mut self,
path: &Self::Path,
perm: Self::Permissions,
) -> std::prelude::v1::Result<(), Self::Error> {
todo!()
}
}
pub struct TStream<'a> {
rt: &'a tokio::runtime::Runtime,
stream: SendStream,
}
impl<'a> TStream<'a> {
pub fn new(rt: &'a Runtime, stream: SendStream) -> Self {
Self { rt, stream }
}
}
impl<'a> std::io::Write for TStream<'a> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let _guard = self.rt.enter();
self.rt.block_on(async {
match self.stream.write(buf).await {
std::io::Result::Ok(n) => Ok(n),
Err(err) => std::io::Result::Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("failed to write to stream: {}", err),
)),
}
})
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
pub struct RStream<'a> {
rt: &'a tokio::runtime::Runtime,
stream: ReceiveStream,
}
impl<'a> RStream<'a> {
pub fn new(rt: &'a Runtime, stream: ReceiveStream) -> Self {
Self { rt, stream }
}
}
impl<'a> std::io::Read for RStream<'a> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let _guard = self.rt.enter();
self.rt.block_on(async {
match self.stream.read(buf).await {
Ok(n) => match n {
0 => Err(std::io::Error::new(
std::io::ErrorKind::Other,
"stream closed",
)),
n => Ok(n),
},
Err(err) => Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("failed to read from stream: {}", err),
)),
}
})
}
}
impl<'a> NinePClient<'a> {
pub fn new(connection: s2n_quic::Connection, rt: &'a Runtime) -> Self {
Self {
rt,
msize: DEFAULT_MSIZE,
tags: Mutex::new(BTreeMap::new()),
connection,
}
}
}
pub struct NinePClientConnection<'a> {
fids: Mutex<HashMap<u32, u64>>,
tx: TStream<'a>,
rx: RStream<'a>,
turn: Turn,
}
impl<'a> NinePClient<'a> {
pub async fn attach(
&mut self,
tag: u16,
aname: &str,
) -> NinePClientConnection<'a> {
let bi_stream = self.connection.open_bidirectional_stream().await.unwrap();
let (recv, send) = bi_stream.split();
let mut conn = NinePClientConnection {
fids: Mutex::new(HashMap::new()),
tx: TStream::new(self.rt, send),
rx: RStream::new(self.rt, recv),
turn: Turn::Client,
};
let _ = conn.version(0, DEFAULT_MSIZE, versions::Version::V9P2024q9p.into()).await;
conn
}
}
enum Turn {
Client,
Server,
}
impl<'a> NinePClientConnection<'a> {
pub async fn attach(
&mut self,
tag: u16,
aname: &str,
uname: &str,
) -> std::prelude::v1::Result<(), std::io::Error> {
todo!()
}
pub async fn version(
&mut self,
tag: u16,
msize: usize,
version: &str,
) -> std::prelude::v1::Result<(), std::io::Error> {
todo!()
}
async fn write_message(
&mut self,
tag: u16,
msg: &Tmessage,
tx: &mut TStream<'a>,
) -> std::prelude::v1::Result<(), std::io::Error> {
let mut _guard = self.fids.lock().await;
let _ = match msg {
Tmessage::Version(version) => {
wire_format::WireFormat::encode(version, tx)
}
Tmessage::Flush(flush) => {
wire_format::WireFormat::encode(flush, tx)
}
Tmessage::Read(read) => wire_format::WireFormat::encode(read, tx),
Tmessage::Write(write) => {
wire_format::WireFormat::encode(write, tx)
}
Tmessage::Clunk(clunk) => {
wire_format::WireFormat::encode(clunk, tx)
}
Tmessage::Remove(remove) => {
wire_format::WireFormat::encode(remove, tx)
}
Tmessage::Attach(attach) => {
wire_format::WireFormat::encode(attach, tx)
}
Tmessage::Auth(auth) => wire_format::WireFormat::encode(auth, tx),
Tmessage::Statfs(statfs) => {
wire_format::WireFormat::encode(statfs, tx)
}
Tmessage::Lopen(lopen) => {
wire_format::WireFormat::encode(lopen, tx)
}
Tmessage::Lcreate(lcreate) => {
wire_format::WireFormat::encode(lcreate, tx)
}
Tmessage::Symlink(symlink) => {
wire_format::WireFormat::encode(symlink, tx)
}
Tmessage::Mknod(mknod) => {
wire_format::WireFormat::encode(mknod, tx)
}
Tmessage::Rename(rename) => {
wire_format::WireFormat::encode(rename, tx)
}
Tmessage::Readlink(readlink) => {
wire_format::WireFormat::encode(readlink, tx)
}
Tmessage::GetAttr(getattr) => {
wire_format::WireFormat::encode(getattr, tx)
}
Tmessage::SetAttr(setattr) => {
wire_format::WireFormat::encode(setattr, tx)
}
Tmessage::XattrWalk(xattrwalk) => {
wire_format::WireFormat::encode(xattrwalk, tx)
}
Tmessage::XattrCreate(xattrcreate) => {
wire_format::WireFormat::encode(xattrcreate, tx)
}
Tmessage::Readdir(readdir) => {
wire_format::WireFormat::encode(readdir, tx)
}
Tmessage::Fsync(fsync) => {
wire_format::WireFormat::encode(fsync, tx)
}
Tmessage::Lock(lock) => wire_format::WireFormat::encode(lock, tx),
Tmessage::GetLock(getlock) => {
wire_format::WireFormat::encode(getlock, tx)
}
Tmessage::Link(link) => wire_format::WireFormat::encode(link, tx),
Tmessage::Mkdir(mkdir) => {
wire_format::WireFormat::encode(mkdir, tx)
}
Tmessage::RenameAt(renameat) => {
wire_format::WireFormat::encode(renameat, tx)
}
Tmessage::UnlinkAt(unlinkat) => {
wire_format::WireFormat::encode(unlinkat, tx)
}
Tmessage::Walk(walk) => wire_format::WireFormat::encode(walk, tx),
};
Ok(())
}
}
mod client_tests;