1use crate::prelude::{SessionSource, SessionSourceConfig};
7use eyre::Result;
8use foundry_evm::core::evm::FoundryEvmNetwork;
9use serde::{Deserialize, Serialize};
10use std::path::Path;
11use time::{OffsetDateTime, format_description};
12
13#[derive(Debug, Serialize, Deserialize)]
15#[serde(bound = "")]
16pub struct ChiselSession<FEN: FoundryEvmNetwork> {
17 pub source: SessionSource<FEN>,
19 pub id: Option<String>,
21}
22
23impl<FEN: FoundryEvmNetwork> ChiselSession<FEN> {
25 pub fn new(config: SessionSourceConfig<FEN>) -> Result<Self> {
35 Ok(Self { source: SessionSource::new(config)?, id: None })
37 }
38
39 pub fn contract_source(&self) -> String {
50 self.source.to_repl_source()
51 }
52
53 pub fn clear_cache() -> Result<()> {
60 let cache_dir = Self::cache_dir()?;
61 for entry in std::fs::read_dir(cache_dir)? {
62 let entry = entry?;
63 let path = entry.path();
64 if path.is_dir() {
65 std::fs::remove_dir_all(path)?;
66 } else {
67 std::fs::remove_file(path)?;
68 }
69 }
70 Ok(())
71 }
72
73 pub fn remove_cached_session(id: &str) -> Result<()> {
75 let cache_file = format!("{}chisel-{id}.json", Self::cache_dir()?);
76 match std::fs::remove_file(cache_file) {
77 Ok(()) => Ok(()),
78 Err(error) if error.kind() == std::io::ErrorKind::NotFound => Ok(()),
79 Err(error) => Err(error.into()),
80 }
81 }
82
83 pub fn write(&mut self) -> Result<String> {
89 let cache_dir = Self::cache_dir()?;
91 std::fs::create_dir_all(&cache_dir)?;
92
93 let cache_file_name = match self.id.as_ref() {
94 Some(id) => {
95 format!("{cache_dir}chisel-{id}.json")
97 }
98 None => {
99 let (id, file_name) = Self::next_cached_session()?;
101 self.id = Some(id);
103 file_name
105 }
106 };
107
108 let serialized_contents = serde_json::to_string_pretty(self)?;
110 std::fs::write(&cache_file_name, serialized_contents)?;
111
112 Ok(cache_file_name)
115 }
116
117 pub fn next_cached_session() -> Result<(String, String)> {
123 let cache_dir = Self::cache_dir()?;
124 let entries = std::fs::read_dir(&cache_dir)?;
125 let session_num = entries.filter(Result::is_ok).count();
126
127 Ok((format!("{session_num}"), format!("{cache_dir}chisel-{session_num}.json")))
128 }
129
130 pub fn cache_dir() -> Result<String> {
136 let home_dir =
137 dirs::home_dir().ok_or_else(|| eyre::eyre!("Failed to grab home directory"))?;
138 let home_dir_str = home_dir
139 .to_str()
140 .ok_or_else(|| eyre::eyre!("Failed to convert home directory to string"))?;
141 Ok(format!("{home_dir_str}/.foundry/cache/chisel/"))
142 }
143
144 pub fn create_cache_dir() -> Result<()> {
150 let cache_dir = Self::cache_dir()?;
151 if !Path::new(&cache_dir).exists() {
152 std::fs::create_dir_all(&cache_dir)?;
153 }
154 Ok(())
155 }
156
157 pub fn get_sessions() -> Result<Vec<(String, String)>> {
159 let cache_dir = Self::cache_dir()?;
161 let entries = std::fs::read_dir(cache_dir)?;
162
163 let mut sessions = Vec::new();
165 for entry in entries {
166 let entry = entry?;
167 let modified_time = entry.metadata()?.modified()?;
168 let file_name = entry.file_name();
169 let file_name = file_name
170 .into_string()
171 .map_err(|e| eyre::eyre!(format!("{}", e.to_string_lossy())))?;
172 sessions.push((
173 systemtime_strftime(modified_time, "[year]-[month]-[day] [hour]:[minute]:[second]")
174 .unwrap(),
175 file_name,
176 ));
177 }
178 Ok(sessions)
179 }
180
181 pub fn load(id: &str) -> Result<Self> {
191 let cache_dir = Self::cache_dir()?;
192 let contents = std::fs::read_to_string(Path::new(&format!("{cache_dir}chisel-{id}.json")))?;
193 let chisel_env: Self = serde_json::from_str(&contents)?;
194 Ok(chisel_env)
195 }
196
197 pub fn latest_cached_session() -> Result<String> {
203 let cache_dir = Self::cache_dir()?;
204 let mut entries = std::fs::read_dir(cache_dir)?;
205 let mut latest = entries.next().ok_or_else(|| eyre::eyre!("No entries found!"))??;
206 for entry in entries {
207 let entry = entry?;
208 if entry.metadata()?.modified()? > latest.metadata()?.modified()? {
209 latest = entry;
210 }
211 }
212 Ok(latest
213 .path()
214 .to_str()
215 .ok_or_else(|| eyre::eyre!("Failed to get session path!"))?
216 .to_string())
217 }
218
219 pub fn latest() -> Result<Self> {
225 let last_session = Self::latest_cached_session()?;
226 let last_session_contents = std::fs::read_to_string(Path::new(&last_session))?;
227 let chisel_env: Self = serde_json::from_str(&last_session_contents)?;
228 Ok(chisel_env)
229 }
230}
231
232fn systemtime_strftime<T>(dt: T, format: &str) -> Result<String>
235where
236 T: Into<OffsetDateTime>,
237{
238 Ok(dt.into().format(&format_description::parse(format)?)?)
239}