Skip to content

Commit

Permalink
🦄 refactor: Merge InnerTty into WrapperTty
Browse files Browse the repository at this point in the history
  • Loading branch information
wychlw committed Sep 22, 2024
1 parent 787cef4 commit 59eb644
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 79 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# autotester

部分文档见 [doc](./doc)
Python 部分文档见 [doc](./doc)
Rust 部分代码包含 rustdoc

## 文件夹释义

Expand All @@ -10,8 +11,13 @@
- tests:应用测试及示例
- apps:Python 实际测试脚本

## fin
## 目前完成状况

Python:
- Shell、Serial、SSH
- os-autoinst cli api 部分
Rust CLI: 基本稳定,已完成的 API 不会有大的改动,可能会有新增中间处理层
Rust CLI Exec:稳定,不太可能有更多变动(其它兼容/功能请在 FFI/外部实现)

Rust GUI:不稳定,API 不太可能有太大变动不过
Rust GUI Exec:不稳定,API 变动可能(根据新功能实验更改)

Rust Python Api:我保证它能用…… **计划改动,我尽量做到不破坏现有 API**
UI:~~一团空气~~
8 changes: 8 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

- [ ] **可维护性:想办法把那个 PyTty 缩小掉……**

- [ ] CLI
- [ ] 获取内层某个层级的 ref/mut 然后更改?不知道会不会破坏借用检查器不过…会的话可能得从 Box 换成 Rc 了

- [ ] 更多的连接方式
- [x] 更完善的 SSH
- [ ] 通过 tunnel 连接
Expand All @@ -31,8 +34,13 @@
- [?] 从 dyn Tty 中区分出这个巨型 wrapper,并分开实现(可以在每次开头前都试一试?)
- [ ]
- [x] 执行器
- [ ] Python API 多个层级之间不太能互通…(inner_ref 和 inner_mut 不能直接用)需要想个办法处理下

- [ ] 与下一步测试软件的进一步集成
- [ ] GUI 部分框架
- [ ] UI 部分
- [ ] UI 设计
- 目前考虑多窗口,然后在上面放上一个编辑器和执行器什么的…这样可以实时编辑、打 needle 啥的?
- 然后由于 Wrapper 的层级越来越高…要不要写个啥展示下当前层级的样子呢(思考)

- [ ] 实际应用
141 changes: 95 additions & 46 deletions src/cli/asciicast.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
//! Asciicast recorder.
//!
//!
//! The Asciicast recorder is a recorder that records the terminal output
//! in the asciicast v2 format.
use std::{
any::Any,
collections::HashMap,
error::Error,
mem::replace,
sync::{Arc, Mutex},
thread::{sleep, spawn, JoinHandle},
time::{Duration, SystemTime},
Expand All @@ -15,19 +16,16 @@ use std::{
use asciicast::{Entry, EventType, Header};
use serde_json::to_string;

use crate::{
consts::DURATION,
info,
util::anybase::AnyBase,
};
use crate::{consts::DURATION, info, util::anybase::AnyBase};

use super::{
recorder::Recorder,
tty::{DynTty, Tty, WrapperTty},
};

pub struct Asciicast {
inner: Arc<Mutex<Option<DynTty>>>,
inner: Arc<Mutex<DynTty>>,
inner_took: Arc<Mutex<bool>>,
head: Header,
data: Arc<Mutex<Vec<u8>>>,
logged: Arc<Mutex<Vec<Entry>>>,
Expand All @@ -38,10 +36,11 @@ pub struct Asciicast {

impl Asciicast {
pub fn build(inner: DynTty) -> Asciicast {
let inner = Arc::new(Mutex::new(Some(inner)));
let inner = Arc::new(Mutex::new(inner));

let mut res = Asciicast {
inner: inner.clone(),
inner_took: Arc::new(Mutex::new(false)),
head: Header {
version: 2,
width: 80,
Expand All @@ -64,38 +63,47 @@ impl Asciicast {
};

let inner = inner.clone();
let inner_took = res.inner_took.clone();
let data = res.data.clone();
let logged = res.logged.clone();
let begin = res.begin.clone();
let begin_time = res.begin_time.clone();
let process = move || loop {
sleep(Duration::from_millis(DURATION));
let mut inner = inner.lock().unwrap();
if inner.is_none() {
return;
}
let inner = inner.as_mut().unwrap();
let new_data = inner.read();
if new_data.is_err() {
return;
{
let inner_took = inner_took.lock().unwrap();
if *inner_took {
return;
}
}
let new_data = new_data.unwrap();

let begin = begin.lock().unwrap();
if *begin && !new_data.is_empty() {
let time = begin_time.lock().unwrap().elapsed().unwrap();
let timestamp = time.as_millis();
let timestamp = timestamp as f64 / 1000.0;
let mut logged = logged.lock().unwrap();
logged.push(Entry {
time: timestamp,
event_type: EventType::Output,
event_data: String::from_utf8(new_data.clone()).unwrap_or_default(),
});
let new_data = {
let mut inner = inner.lock().unwrap();
let new_data = inner.read();
if new_data.is_err() {
return;
}
new_data.unwrap()
};

{
let begin = begin.lock().unwrap();
if *begin && !new_data.is_empty() {
let time = begin_time.lock().unwrap().elapsed().unwrap();
let timestamp = time.as_millis();
let timestamp = timestamp as f64 / 1000.0;
let mut logged = logged.lock().unwrap();
logged.push(Entry {
time: timestamp,
event_type: EventType::Output,
event_data: String::from_utf8(new_data.clone()).unwrap_or_default(),
});
}
}

let mut data = data.lock().unwrap();
data.extend(new_data);
{
let mut data = data.lock().unwrap();
data.extend(new_data);
}
};

let thread = spawn(process);
Expand Down Expand Up @@ -149,21 +157,60 @@ impl Tty for Asciicast {
Ok(res)
}
fn write(&mut self, data: &[u8]) -> Result<(), Box<dyn Error>> {
let inner = self.inner.clone();
let mut inner = inner.lock().unwrap();
if inner.is_none() {
return Err(Box::<dyn Error>::from("You've already exited."));
{
let inner_took = self.inner_took.lock().unwrap();
if *inner_took {
return Err(Box::<dyn Error>::from("You've already exited."));
}
}
{
let inner = self.inner.clone();
let mut inner = inner.lock().unwrap();
inner.write(data)
}
let inner = inner.as_mut().unwrap();
inner.write(data)
}
}

struct DummyTty {}
impl AnyBase for DummyTty {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
}
impl Tty for DummyTty {
fn read(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(Vec::new())
}
fn read_line(&mut self) -> Result<Vec<u8>, Box<dyn Error>> {
Ok(Vec::new())
}
fn write(&mut self, _data: &[u8]) -> Result<(), Box<dyn Error>> {
Ok(())
}
}

impl WrapperTty for Asciicast {
fn exit(self) -> DynTty {
let inner = self.inner.clone();
let mut inner = inner.lock().unwrap();
inner.take().unwrap()
fn exit(mut self) -> DynTty {
{
let mut inner_took = self.inner_took.lock().unwrap();
*inner_took = true;
}
let dummy = DummyTty {};
self.swap(Box::new(dummy)).unwrap()
}

fn inner_mut(&mut self) -> &mut DynTty {
panic!("Asciicast recorder does not support inner_mut method... I have no idea how to implement it.");
}

fn inner_ref(&self) -> &DynTty {
panic!("Asciicast recorder does not support inner_mut method... I have no idea how to implement it.");
}
}

Expand Down Expand Up @@ -262,13 +309,15 @@ impl Recorder for Asciicast {

fn swap(&mut self, target: DynTty) -> Result<DynTty, Box<dyn Error>> {
sleep(Duration::from_micros(DURATION));
{
let inner_took = self.inner_took.lock().unwrap();
if *inner_took {
return Err(Box::<dyn Error>::from("You've already exited."));
}
}
let inner = self.inner.clone();
let mut inner = inner.lock().unwrap();
if inner.is_none() {
return Err(Box::<dyn Error>::from("You've already exited."));
}
let res = inner.take().unwrap();
*inner = Some(target);
let res = replace(&mut *inner, target);
Ok(res)
}
}
9 changes: 8 additions & 1 deletion src/cli/deansi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,15 @@ impl Tty for DeANSI {
}

impl WrapperTty for DeANSI {
/// Exit the Tty and return the inner Tty
fn exit(self) -> DynTty {
self.inner
}

fn inner_ref(&self) -> &DynTty {
&self.inner
}

fn inner_mut(&mut self) -> &mut DynTty {
&mut self.inner
}
}
3 changes: 1 addition & 2 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
//! functionality, or do some pre-processing before passing the data to
//! the inner [`Tty`].
//!
//! Sometimes, we may need to modify the config **inside** a [`WrapperTty`].
//! That's where the [`InnerTty`] trait comes in. It allows us to access the
//! Sometimes, we may need to modify the config **inside** a [`WrapperTty`]. It allows us to access the
//! inner [`Tty`] of a [`WrapperTty`] (by ref or mut, ofcourse).
//!
//! Then, based on this concept, we can build a lot of useful tools, such as
Expand Down
10 changes: 9 additions & 1 deletion src/cli/recorder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{any::Any, error::Error, mem::replace};

use crate::{info, cli::tty::Tty, util::anybase::AnyBase};
use crate::{cli::tty::Tty, info, util::anybase::AnyBase};

use super::tty::{DynTty, WrapperTty};

Expand Down Expand Up @@ -75,6 +75,14 @@ impl WrapperTty for SimpleRecorder {
fn exit(self) -> DynTty {
self.inner
}

fn inner_ref(&self) -> &DynTty {
&self.inner
}

fn inner_mut(&mut self) -> &mut DynTty {
&mut self.inner
}
}

impl Recorder for SimpleRecorder
Expand Down
11 changes: 9 additions & 2 deletions src/cli/tee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,15 @@ impl Tty for Tee {
}

impl WrapperTty for Tee {
fn exit(mut self) -> DynTty {
self.file.flush().unwrap();
fn exit(self) -> DynTty {
self.inner
}

fn inner_ref(&self) -> &DynTty {
&self.inner
}

fn inner_mut(&mut self) -> &mut DynTty {
&mut self.inner
}
}
4 changes: 0 additions & 4 deletions src/cli/tty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@ pub trait WrapperTty: Tty {

/// Exit the Tty and return the inner Tty
fn exit(self) -> DynTty;
}

/// A trait for accessing the inner `Tty` of a `WrapperTty`
pub trait InnerTty: WrapperTty {

/// Get a reference to the inner Tty
fn inner_ref(&self) -> &DynTty;
Expand Down
4 changes: 2 additions & 2 deletions src/exec/cli_api.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::error::Error;

use crate::cli::tty::InnerTty;
use crate::cli::tty::WrapperTty;

pub trait CliTestApi: InnerTty {
pub trait CliTestApi: WrapperTty {
///
///
/// You may found this func includes assert_script_run and script_output
Expand Down
11 changes: 3 additions & 8 deletions src/exec/cli_exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use std::{
};

use crate::{
cli::tty::{DynTty, InnerTty, Tty, WrapperTty},
consts::DURATION,
err, info,
util::{anybase::AnyBase, util::rand_string},
cli::tty::{DynTty, Tty, WrapperTty}, consts::DURATION, err, info, util::{anybase::AnyBase, util::rand_string}
};

use super::cli_api::{CliTestApi, SudoCliTestApi};
Expand Down Expand Up @@ -63,12 +60,11 @@ impl WrapperTty for CliTester {
fn exit(self) -> DynTty {
self.inner
}
}

impl InnerTty for CliTester {
fn inner_ref(&self) -> &DynTty {
&self.inner
}

fn inner_mut(&mut self) -> &mut DynTty {
&mut self.inner
}
Expand Down Expand Up @@ -189,12 +185,11 @@ impl WrapperTty for SudoCliTester {
fn exit(self) -> DynTty {
self.inner.exit()
}
}

impl InnerTty for SudoCliTester {
fn inner_ref(&self) -> &DynTty {
self.inner.inner_ref()
}

fn inner_mut(&mut self) -> &mut DynTty {
self.inner.inner_mut()
}
Expand Down
Loading

0 comments on commit 59eb644

Please sign in to comment.