Skip to content

Commit 1635e9e

Browse files
committed
[FEATURE] Basic infrastructure management via terminal created.
1 parent de2e12f commit 1635e9e

File tree

9 files changed

+298
-1
lines changed

9 files changed

+298
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use super::terminal_cursor::TerminalCursor;
2+
3+
pub trait IManager: Clone {
4+
fn manage(&self, option: String) -> TerminalCursor<Self> where Self: Sized;
5+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use super::{i_manager::IManager, terminal_option::TerminalOption};
2+
3+
#[derive(Clone)]
4+
pub struct TerminalCursor<T: IManager> {
5+
header: String,
6+
options: Vec<TerminalOption<T>>,
7+
cursor: usize,
8+
}
9+
10+
impl <T: IManager> TerminalCursor<T> {
11+
12+
pub fn new(header: &str) -> Self {
13+
TerminalCursor {
14+
header: String::from(header),
15+
options: Vec::new(),
16+
cursor: 0
17+
}
18+
}
19+
20+
pub fn header(&self) -> String {
21+
self.header.clone()
22+
}
23+
24+
pub fn options(&mut self) -> Vec<TerminalOption<T>> {
25+
if self.cursor > self.options.len() {
26+
self.cursor = 0;
27+
}
28+
29+
for option in self.options.iter_mut().enumerate() {
30+
option.1.unfocused();
31+
if option.0 == self.cursor {
32+
option.1.focused();
33+
}
34+
}
35+
36+
self.options.clone()
37+
}
38+
39+
pub fn option(&mut self) -> Option<&mut TerminalOption<T>> {
40+
for option in self.options.iter_mut().enumerate() {
41+
if option.0 == self.cursor {
42+
return Some(option.1);
43+
}
44+
}
45+
None
46+
}
47+
48+
pub fn increase(&mut self) -> &Self {
49+
if self.options.len() > 0 && self.cursor < self.options.len() - 1 {
50+
self.cursor = self.cursor + 1;
51+
}
52+
self
53+
}
54+
55+
pub fn decrease(&mut self) -> &Self {
56+
if self.cursor > 0 {
57+
self.cursor = self.cursor - 1;
58+
}
59+
self
60+
}
61+
62+
pub fn push(&mut self, option: TerminalOption<T>) -> &Self {
63+
self.options.push(option);
64+
self
65+
}
66+
67+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use crate::{infrastructure::repository::i_db_repository::IDBRepository, service::service::Service};
2+
3+
use super::{i_manager::IManager, terminal_cursor::TerminalCursor, terminal_manager::TerminalManager, terminal_option::TerminalOption};
4+
5+
const STATUS: &'static str = "STATUS";
6+
const SHOW_DATABASES: &'static str = "SHOW_DATABASES";
7+
8+
#[derive(Clone)]
9+
pub struct TerminalDatabase<T: IDBRepository> {
10+
service: Service<T>,
11+
}
12+
13+
impl <T: IDBRepository> IManager for TerminalDatabase<T> {
14+
15+
fn manage(&self, option: String) -> TerminalCursor<Self> where Self: Sized {
16+
match option.as_str() {
17+
STATUS => self.clone().status(),
18+
SHOW_DATABASES => self.clone().show_databases(),
19+
_ => todo!(),
20+
}
21+
}
22+
23+
}
24+
25+
impl <T: IDBRepository> TerminalDatabase<T> {
26+
27+
pub fn new(service: Service<T>) -> TerminalDatabase<T> {
28+
TerminalDatabase { service: service }
29+
}
30+
31+
pub fn launch(&mut self) -> &Self {
32+
let cursor = self.base_cursor();
33+
let _ = TerminalManager::new(cursor).launch();
34+
return self;
35+
}
36+
37+
fn base_cursor(&self) -> TerminalCursor<Self> {
38+
let mut cursor: TerminalCursor<Self> = TerminalCursor::new("Select any option: ");
39+
cursor.push(TerminalOption::from(String::from("Status"), STATUS, self.clone()));
40+
cursor.push(TerminalOption::from(String::from("Show databases"), SHOW_DATABASES, self.clone()));
41+
cursor
42+
}
43+
44+
fn status(self) -> TerminalCursor<Self> {
45+
let cursor = TerminalCursor::new("//TODO:");
46+
cursor
47+
}
48+
49+
fn show_databases(self) -> TerminalCursor<Self> {
50+
let cursor = TerminalCursor::new("//TODO:");
51+
cursor
52+
}
53+
54+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
use std::io::{self, Write};
2+
3+
use crossterm::event::{read, Event, KeyCode, KeyEventKind};
4+
5+
use super::{i_manager::IManager, terminal_cursor::TerminalCursor};
6+
7+
const ANSI_COLOR_RESET: &'static str = "\x1b[0m";
8+
const ANSI_BACKGROUND_WHITE: &'static str = "\x1b[47m";
9+
10+
#[derive(Clone)]
11+
pub struct TerminalManager<T: IManager> {
12+
cursor: TerminalCursor<T>,
13+
}
14+
15+
impl <T: IManager> TerminalManager<T> {
16+
17+
pub fn new(cursor: TerminalCursor<T>) -> TerminalManager<T> {
18+
return TerminalManager {cursor};
19+
}
20+
21+
pub fn launch(&mut self) -> io::Result<()> {
22+
23+
self.hide_cursor();
24+
25+
loop {
26+
27+
self.clear_screen();
28+
29+
self.print();
30+
31+
let key_event = match read()? {
32+
Event::Key(event) => event,
33+
_ => continue, // Skip non-key events
34+
};
35+
36+
if key_event.kind == KeyEventKind::Press {
37+
match key_event.code {
38+
KeyCode::Up => {self.cursor.decrease();},
39+
KeyCode::Down => {self.cursor.increase();},
40+
KeyCode::Enter => {
41+
println!("Enter");
42+
43+
let update = self.manage();
44+
if update.is_none() {
45+
println!("Something goes wrong!");
46+
break;
47+
}
48+
49+
self.cursor = update.unwrap();
50+
51+
},
52+
KeyCode::Esc => {
53+
println!("Exit");
54+
break;
55+
}
56+
_ => println!("Wrong key!"),
57+
}
58+
}
59+
}
60+
61+
Ok(())
62+
63+
}
64+
65+
fn clear_screen(&self) {
66+
print!("\x1b[2J\x1b[1;1H");
67+
}
68+
69+
fn hide_cursor(&self) {
70+
print!("\x1b[?25l");
71+
}
72+
73+
fn show_cursor(&self) {
74+
print!("\x1b[?25h");
75+
}
76+
77+
fn print(&mut self) {
78+
79+
print!("{}\n\n", self.cursor.header());
80+
81+
for cursor in self.cursor.options().iter_mut().enumerate() {
82+
let index = cursor.0;
83+
let position = cursor.1;
84+
85+
let mut title = position.title();
86+
if position.is_focused() {
87+
title = format!("{}{}{}", ANSI_BACKGROUND_WHITE, title, ANSI_COLOR_RESET);
88+
}
89+
print!("{}.- {}.\n", index + 1, title);
90+
}
91+
92+
let _ = io::stdout().flush();
93+
94+
}
95+
96+
fn manage(&mut self) -> Option<TerminalCursor<T>> {
97+
let o_option = self.cursor.option();
98+
if o_option.is_some() {
99+
let option = o_option.unwrap();
100+
return Some(option.execute());
101+
}
102+
None
103+
}
104+
105+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use super::{i_manager::IManager, terminal_cursor::TerminalCursor};
2+
3+
#[derive(Clone)]
4+
pub struct TerminalOption<T: IManager> {
5+
option: String,
6+
focus: bool,
7+
title: String,
8+
manager: T,
9+
}
10+
11+
impl <T: IManager> TerminalOption<T> {
12+
13+
pub fn from(title: String, option: &str, manager: T) -> TerminalOption<T> {
14+
TerminalOption {
15+
option: String::from(option),
16+
focus: false,
17+
title: title,
18+
manager: manager
19+
}
20+
}
21+
22+
pub fn is_focused(&self) -> bool {
23+
return self.focus;
24+
}
25+
26+
pub fn title(&self) -> String {
27+
return self.title.clone();
28+
}
29+
30+
pub fn focused(&mut self) -> &Self {
31+
self.focus = true;
32+
return self;
33+
}
34+
35+
pub fn unfocused(&mut self) -> &Self {
36+
self.focus = false;
37+
return self;
38+
}
39+
40+
pub fn execute(&mut self) -> TerminalCursor<T> {
41+
return self.manager.manage(self.option.clone());
42+
}
43+
44+
}

src/infrastructure/repository/i_db_repository.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use async_trait::async_trait;
33
use crate::{commons::exception::connect_exception::ConnectException, domain::filter::data_base_query::DataBaseQuery};
44

55
#[async_trait]
6-
pub trait IDBRepository {
6+
pub trait IDBRepository: Clone {
77
//TODO: Replace bytes vector returns with specific entities.
88
async fn status(self) -> Result<(), ConnectException>;
99
async fn list_data_bases(self) -> Result<Vec<String>, ConnectException>;

src/infrastructure/repository/mongo_db_repository.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::{
1111

1212
use super::i_db_repository::IDBRepository;
1313

14+
#[derive(Clone)]
1415
pub struct MongoDbRepository {
1516
client: Client
1617
}

src/main.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
use crate::{domain::connection_data::ConnectionData, infrastructure::{manager::terminal::terminal_database::TerminalDatabase, repository::mongo_db_repository::MongoDbRepository}, service::service::Service};
2+
13
mod commons {
24
pub mod exception {
35
pub mod connect_exception;
46
}
57
pub mod utils;
68
}
79
mod infrastructure {
10+
pub mod manager {
11+
pub mod terminal {
12+
pub mod i_manager;
13+
pub mod terminal_option;
14+
pub mod terminal_database;
15+
pub mod terminal_cursor;
16+
pub mod terminal_manager;
17+
}
18+
}
819
pub mod repository {
920
pub mod i_db_repository;
1021
pub mod mongo_db_repository;
@@ -25,5 +36,14 @@ mod service {
2536

2637
#[tokio::main]
2738
async fn main() {
39+
40+
let data = ConnectionData::new(String::from("mongodb://root:example@localhost:27017"));
41+
let repository = MongoDbRepository::new(data).await.ok().unwrap();
42+
43+
let service = Service::from(repository);
44+
let mut terminal = TerminalDatabase::new(service);
45+
46+
terminal.launch();
47+
2848
println!("rust-db-manager!");
2949
}

src/service/service.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::{commons::exception::connect_exception::ConnectException, domain::filter::data_base_query::DataBaseQuery, infrastructure::repository::i_db_repository::IDBRepository};
22

3+
#[derive(Clone)]
34
pub struct Service<T: IDBRepository> {
45
repository: T,
56
}

0 commit comments

Comments
 (0)