Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
{
"identifier": "opener:allow-open-path",
"allow": [
{
"path": "$HOME/.codeforge/**"
},
{
"path": "$APPDATA/**"
},
{
"path": "$LOCALAPPDATA/**"
},
{
"path": "**"
}
Expand All @@ -20,9 +29,19 @@
"shell:allow-open",
"dialog:default",
"fs:allow-read-text-file",
"fs:allow-read-dir",
"fs:allow-read-file",
"fs:allow-write-file",
"fs:allow-write-text-file",
"fs:allow-remove",
"fs:allow-mkdir",
"fs:allow-exists",
{
"identifier": "fs:scope",
"allow": [
{
"path": "$HOME/.codeforge/**"
},
{
"path": "/var/folders/**"
},
Expand All @@ -32,6 +51,12 @@
{
"path": "/private/var/folders/**"
},
{
"path": "$APPDATA/**"
},
{
"path": "$LOCALAPPDATA/**"
},
{
"path": "**"
}
Expand Down
101 changes: 101 additions & 0 deletions src-tauri/src/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use log::info;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

#[derive(Debug, Serialize, Deserialize)]
pub struct CacheInfo {
pub plugins_cache_size: u64,
pub total_cache_size: u64,
}

// 获取缓存目录
fn get_cache_dir() -> Result<PathBuf, String> {
let home_dir = dirs::home_dir().ok_or("无法获取用户主目录")?;
Ok(home_dir.join(".codeforge").join("cache"))
}

// 获取插件缓存目录
fn get_plugins_cache_dir() -> Result<PathBuf, String> {
let cache_dir = get_cache_dir()?;
Ok(cache_dir.join("plugins"))
}

// 计算目录大小
fn calculate_dir_size(path: &PathBuf) -> u64 {
if !path.exists() {
return 0;
}

let mut total_size = 0u64;

if let Ok(entries) = fs::read_dir(path) {
for entry in entries.flatten() {
let path = entry.path();
if path.is_file() {
if let Ok(metadata) = fs::metadata(&path) {
total_size += metadata.len();
}
} else if path.is_dir() {
total_size += calculate_dir_size(&path);
}
}
}

total_size
}

// 获取缓存信息
#[tauri::command]
pub fn get_cache_info() -> Result<CacheInfo, String> {
info!("获取缓存信息");

let cache_dir = get_cache_dir()?;
let plugins_cache_dir = get_plugins_cache_dir()?;

let plugins_cache_size = calculate_dir_size(&plugins_cache_dir);
let total_cache_size = calculate_dir_size(&cache_dir);

Ok(CacheInfo {
plugins_cache_size,
total_cache_size,
})
}

// 清理插件缓存
#[tauri::command]
pub fn clear_plugins_cache() -> Result<(), String> {
info!("清理插件缓存");

let plugins_cache_dir = get_plugins_cache_dir()?;

if plugins_cache_dir.exists() {
fs::remove_dir_all(&plugins_cache_dir)
.map_err(|e| format!("删除插件缓存目录失败: {}", e))?;

// 重新创建空目录
fs::create_dir_all(&plugins_cache_dir)
.map_err(|e| format!("创建插件缓存目录失败: {}", e))?;
}

info!("插件缓存已清理");
Ok(())
}

// 清理所有缓存
#[tauri::command]
pub fn clear_all_cache() -> Result<(), String> {
info!("清理所有缓存");

let cache_dir = get_cache_dir()?;

if cache_dir.exists() {
fs::remove_dir_all(&cache_dir).map_err(|e| format!("删除缓存目录失败: {}", e))?;

// 重新创建空目录
fs::create_dir_all(&cache_dir).map_err(|e| format!("创建缓存目录失败: {}", e))?;
}

info!("所有缓存已清理");
Ok(())
}
2 changes: 1 addition & 1 deletion src-tauri/src/env_providers/clojure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl ClojureEnvironmentProvider {

fn get_default_install_dir() -> PathBuf {
let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
home_dir.join(".codeforge").join("clojure")
home_dir.join(".codeforge").join("plugins").join("clojure")
}

fn read_cache(&self) -> Option<Vec<GithubRelease>> {
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/env_providers/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub async fn fetch_metadata_from_cdn(language: &str) -> Result<Metadata, String>
.and_then(|m| m.base_url.as_ref())
.ok_or("CDN 地址未配置")?;

let metadata_url = format!("{}/{}/metadata.json", base_url, language);
let metadata_url = format!("{}/global/plugins/{}/metadata.json", base_url, language);
info!("从 CDN 获取 {} metadata: {}", language, metadata_url);

let client = reqwest::Client::builder()
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/env_providers/scala.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl ScalaEnvironmentProvider {

fn get_default_install_dir() -> PathBuf {
let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
home_dir.join(".codeforge").join("scala")
home_dir.join(".codeforge").join("plugins").join("scala")
}

// 从缓存读取版本列表
Expand Down
90 changes: 67 additions & 23 deletions src-tauri/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use log::{error, info, warn};
use std::collections::HashMap;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::sync::{Arc, OnceLock, mpsc};
use std::thread;
Expand Down Expand Up @@ -34,6 +35,39 @@ fn init_task_manager() -> TaskManager {
.clone()
}

// 获取 .codeforge 缓存目录
fn get_codeforge_cache_dir(language: &str) -> Result<PathBuf, String> {
let home_dir = dirs::home_dir().ok_or("无法获取用户主目录")?;
let cache_dir = home_dir
.join(".codeforge")
.join("cache")
.join("plugins")
.join(language);

// 确保目录存在
fs::create_dir_all(&cache_dir).map_err(|e| format!("创建缓存目录失败: {}", e))?;

Ok(cache_dir)
}

// 检查是否应该过滤 stderr 行
fn should_filter_stderr_line(language: &str, line: &str) -> bool {
match language {
"clojure" => {
// 过滤 Clojure 的常见警告信息
line.contains("WARNING: Implicit use of clojure.main")
|| line.contains("WARNING: name already refers to:")
}
"scala" => {
// 过滤 Scala 的编译信息
line.contains("[0m[0m[33mCompiling project")
|| line.contains("[0m[0m")
|| line.starts_with("\u{001b}")
}
_ => false,
}
}

// 停止执行命令
#[tauri::command]
pub async fn stop_execution(language: String) -> Result<bool, String> {
Expand Down Expand Up @@ -80,13 +114,17 @@ pub async fn execute_code(
.get_plugin(&request.language)
.ok_or_else(|| format!("Unsupported language: {}", request.language))?;

let temp_dir = std::env::temp_dir();
let file_name = format!(
"Codeforge_{}.{}",
request.language,
plugin.get_file_extension()
);
let file_path = temp_dir.join(file_name.clone());
// 使用 .codeforge/cache/plugin/<language> 目录
let temp_dir = get_codeforge_cache_dir(&request.language)?;
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let file_work = format!("Codeforge_{}_{}", request.language, timestamp);
let work_dir = temp_dir.join(&file_work);
fs::create_dir_all(&work_dir).map_err(|e| format!("创建工作目录失败: {}", e))?;
let file_name = format!("{}.{}", file_work, plugin.get_file_extension());
let file_path = work_dir.join(&file_name);

// 写入代码到临时文件
fs::write(&file_path, &request.code)
Expand Down Expand Up @@ -274,14 +312,17 @@ pub async fn execute_code(
// 读取并发送 stderr
while let Ok(line) = stderr_rx.try_recv() {
stderr_lines.push(line.clone());
let _ = app.emit(
"code-output",
serde_json::json!({
"type": "stderr",
"content": line,
"language": request.language
}),
);
// 过滤掉特定语言的警告信息
if !should_filter_stderr_line(&request.language, &line) {
let _ = app.emit(
"code-output",
serde_json::json!({
"type": "stderr",
"content": line,
"language": request.language
}),
);
}
}

// 检查进程是否结束
Expand All @@ -301,14 +342,17 @@ pub async fn execute_code(
}
while let Ok(line) = stderr_rx.try_recv() {
stderr_lines.push(line.clone());
let _ = app.emit(
"code-output",
serde_json::json!({
"type": "stderr",
"content": line,
"language": request.language
}),
);
// 过滤掉特定语言的警告信息
if !should_filter_stderr_line(&request.language, &line) {
let _ = app.emit(
"code-output",
serde_json::json!({
"type": "stderr",
"content": line,
"language": request.language
}),
);
}
}

let execution_time = start_time.elapsed().as_millis();
Expand Down
23 changes: 18 additions & 5 deletions src-tauri/src/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,24 @@ fn get_effective_log_directory(app: &AppHandle) -> PathBuf {
}

// 获取默认日志目录
fn get_default_log_directory(app: &AppHandle) -> PathBuf {
app.path()
.app_data_dir()
.expect("Failed to get app data dir")
.join("logs")
fn get_default_log_directory(_app: &AppHandle) -> PathBuf {
let home_dir = dirs::home_dir().expect("Failed to get home directory");
let log_dir = home_dir.join(".codeforge").join("logs");

// 确保目录存在
if !log_dir.exists() {
if let Err(e) = fs::create_dir_all(&log_dir) {
eprintln!("Failed to create log directory: {}", e);
// 如果创建失败,回退到应用数据目录
return _app
.path()
.app_data_dir()
.expect("Failed to get app data dir")
.join("logs");
}
}

log_dir
}

// 公共函数,供其他模块调用
Expand Down
6 changes: 6 additions & 0 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
windows_subsystem = "windows"
)]

mod cache;
mod config;
mod env_commands;
mod env_manager;
Expand All @@ -17,6 +18,7 @@ mod setup;
mod update;
mod utils;

use crate::cache::{clear_all_cache, clear_plugins_cache, get_cache_info};
use crate::env_commands::{
EnvironmentManagerState, download_and_install_version, get_environment_info,
get_supported_environment_languages, switch_environment_version, uninstall_environment_version,
Expand Down Expand Up @@ -107,6 +109,10 @@ fn main() {
get_app_config,
update_app_config,
get_config_path,
// 缓存相关命令
get_cache_info,
clear_plugins_cache,
clear_all_cache,
// 更新相关命令
check_for_updates,
start_update,
Expand Down
6 changes: 6 additions & 0 deletions src/components/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
<template #network>
<Network v-if="activeTab === 'network'" @settings-changed="handleNetworkSettingsChanged" @error="handleEditorError"/>
</template>

<!-- 缓存管理 -->
<template #cache>
<Cache v-if="activeTab === 'cache'"/>
</template>
</Tabs>
</Modal>
</template>
Expand All @@ -37,6 +42,7 @@ import General from './setting/General.vue'
import Language from './setting/Language.vue'
import Editor from './setting/Editor.vue'
import Network from './setting/Network.vue'
import Cache from './setting/Cache.vue'
import { useSettings } from '../composables/useSettings.ts'

const emit = defineEmits<{
Expand Down
Loading
Loading