From 7ca32dd413f9321ef127b0bd786d9ec2f23210c9 Mon Sep 17 00:00:00 2001 From: Alex Zenla Date: Mon, 8 Jan 2024 15:04:06 -0800 Subject: [PATCH] implement transaction interface --- xsd/examples/list.rs | 2 +- xsd/src/bus.rs | 11 +++++ xsd/src/client.rs | 109 ++++++++++++++++++++++++++++++++++++++----- 3 files changed, 109 insertions(+), 13 deletions(-) diff --git a/xsd/examples/list.rs b/xsd/examples/list.rs index cec3ded..1ca9ed8 100644 --- a/xsd/examples/list.rs +++ b/xsd/examples/list.rs @@ -1,5 +1,5 @@ use xsd::bus::XsdBusError; -use xsd::client::XsdClient; +use xsd::client::{XsdClient, XsdInterface}; use xsd::sys::XSD_ERROR_EINVAL; fn list_recursive(client: &mut XsdClient, level: usize, path: &str) -> Result<(), XsdBusError> { diff --git a/xsd/src/bus.rs b/xsd/src/bus.rs index d740d6f..eb5696e 100644 --- a/xsd/src/bus.rs +++ b/xsd/src/bus.rs @@ -5,6 +5,7 @@ use std::fs::metadata; use std::io::{Read, Write}; use std::mem::size_of; use std::net::Shutdown; +use std::num::ParseIntError; use std::os::unix::net::UnixStream; use std::str::Utf8Error; use std::string::FromUtf8Error; @@ -76,6 +77,12 @@ impl From for XsdBusError { } } +impl From for XsdBusError { + fn from(_: ParseIntError) -> Self { + XsdBusError::new("Unable to coerce data into an integer.") + } +} + pub struct XsdSocket { handle: UnixStream, } @@ -87,6 +94,10 @@ pub struct XsdResponse { } impl XsdResponse { + pub fn parse_string(&self) -> Result { + Ok(String::from_utf8(self.payload.clone())?) + } + pub fn parse_string_vec(&self) -> Result, XsdBusError> { let mut strings: Vec = Vec::new(); let mut buffer: Vec = Vec::new(); diff --git a/xsd/src/client.rs b/xsd/src/client.rs index b728e89..f31577b 100644 --- a/xsd/src/client.rs +++ b/xsd/src/client.rs @@ -1,9 +1,20 @@ use crate::bus::{XsdBusError, XsdSocket}; -use crate::sys::{XSD_DIRECTORY, XSD_MKDIR, XSD_READ, XSD_RM, XSD_WRITE}; +use crate::sys::{ + XSD_DIRECTORY, XSD_MKDIR, XSD_READ, XSD_RM, XSD_TRANSACTION_END, XSD_TRANSACTION_START, + XSD_WRITE, +}; use std::ffi::CString; pub struct XsdClient { - socket: XsdSocket, + pub socket: XsdSocket, +} + +pub trait XsdInterface { + fn list(&mut self, path: &str) -> Result, XsdBusError>; + fn read(&mut self, path: &str) -> Result, XsdBusError>; + fn write(&mut self, path: &str, data: Vec) -> Result; + fn mkdir(&mut self, path: &str) -> Result; + fn rm(&mut self, path: &str) -> Result; } impl XsdClient { @@ -12,30 +23,104 @@ impl XsdClient { Ok(XsdClient { socket }) } - pub fn list(&mut self, path: &str) -> Result, XsdBusError> { - let response = self.socket.send_single(0, XSD_DIRECTORY, path)?; + fn list(&mut self, tx: u32, path: &str) -> Result, XsdBusError> { + let response = self.socket.send_single(tx, XSD_DIRECTORY, path)?; response.parse_string_vec() } - pub fn read(&mut self, path: &str) -> Result, XsdBusError> { - let response = self.socket.send_single(0, XSD_READ, path)?; + fn read(&mut self, tx: u32, path: &str) -> Result, XsdBusError> { + let response = self.socket.send_single(tx, XSD_READ, path)?; Ok(response.payload) } - pub fn write(&mut self, path: &str, data: Vec) -> Result { + fn write(&mut self, tx: u32, path: &str, data: Vec) -> Result { let mut buffer = Vec::new(); let path = CString::new(path)?; buffer.extend_from_slice(path.as_bytes_with_nul()); buffer.extend_from_slice(data.as_slice()); - let response = self.socket.send(0, XSD_WRITE, buffer.as_slice())?; + let response = self.socket.send(tx, XSD_WRITE, buffer.as_slice())?; response.parse_bool() } - pub fn mkdir(&mut self, path: &str) -> Result { - self.socket.send_single(0, XSD_MKDIR, path)?.parse_bool() + fn mkdir(&mut self, tx: u32, path: &str) -> Result { + self.socket.send_single(tx, XSD_MKDIR, path)?.parse_bool() } - pub fn rm(&mut self, path: &str) -> Result { - self.socket.send_single(0, XSD_RM, path)?.parse_bool() + fn rm(&mut self, tx: u32, path: &str) -> Result { + self.socket.send_single(tx, XSD_RM, path)?.parse_bool() + } + + pub fn transaction(&mut self) -> Result { + let response = self.socket.send(0, XSD_TRANSACTION_START, &[])?; + let tx = response.parse_string()?.parse::()?; + Ok(XsdTransaction { client: self, tx }) + } +} + +pub struct XsdTransaction<'a> { + client: &'a mut XsdClient, + tx: u32, +} + +impl XsdInterface for XsdClient { + fn list(&mut self, path: &str) -> Result, XsdBusError> { + self.list(0, path) + } + + fn read(&mut self, path: &str) -> Result, XsdBusError> { + self.read(0, path) + } + + fn write(&mut self, path: &str, data: Vec) -> Result { + self.write(0, path, data) + } + + fn mkdir(&mut self, path: &str) -> Result { + self.mkdir(0, path) + } + + fn rm(&mut self, path: &str) -> Result { + self.rm(0, path) + } +} + +impl XsdInterface for XsdTransaction<'_> { + fn list(&mut self, path: &str) -> Result, XsdBusError> { + self.client.list(self.tx, path) + } + + fn read(&mut self, path: &str) -> Result, XsdBusError> { + self.client.read(self.tx, path) + } + + fn write(&mut self, path: &str, data: Vec) -> Result { + self.client.write(self.tx, path, data) + } + + fn mkdir(&mut self, path: &str) -> Result { + self.client.mkdir(self.tx, path) + } + + fn rm(&mut self, path: &str) -> Result { + self.client.rm(self.tx, path) + } +} + +impl XsdTransaction<'_> { + pub fn end(&mut self, abort: bool) -> Result { + let abort_str = if abort { "F" } else { "T" }; + + self.client + .socket + .send_single(self.tx, XSD_TRANSACTION_END, abort_str)? + .parse_bool() + } + + pub fn commit(&mut self) -> Result { + self.end(false) + } + + pub fn abort(&mut self) -> Result { + self.end(true) } }