diff --git a/Cargo.toml b/Cargo.toml index 1bef12a1..c7ec1f8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,8 +57,8 @@ sha256 = "1.5" futures = "0.3.30" futures-util = "0.3.30" go-defer = "0.1.0" -russh = "0.44.0" -russh-keys = "0.44.0" +russh = "0.45.0" +russh-keys = "0.45.0" axum = "0.7.5" axum-extra = "0.9.3" tower-http = "0.5.2" diff --git a/lunar/src-tauri/build.rs b/lunar/src-tauri/build.rs index 11484bb2..9d5b5ce4 100644 --- a/lunar/src-tauri/build.rs +++ b/lunar/src-tauri/build.rs @@ -37,7 +37,7 @@ fn main() { "release" }; - std::fs::copy(format!("../../target/{}/mega", debug_path), sidecar_path) + std::fs::copy(format!("../../target/{}/mega{}", debug_path, extension), sidecar_path) .expect("Run Cargo build for mega first"); // Copy libpipy due to target os diff --git a/lunar/src-tauri/src/main.rs b/lunar/src-tauri/src/main.rs index 0188ae9b..a6cea675 100644 --- a/lunar/src-tauri/src/main.rs +++ b/lunar/src-tauri/src/main.rs @@ -2,37 +2,33 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] use std::env; -use std::str::FromStr; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use serde::Deserialize; use tauri::api::process::{Command, CommandChild, CommandEvent}; -use tauri::State; -use tokio::sync::Mutex; +use tauri::{Manager, State}; #[derive(Default)] struct ServiceState { child: Option, } -#[derive(Debug, Deserialize, Clone)] -struct MegaStartParams { - pub bootstrap_node: String, -} -impl Default for MegaStartParams { - fn default() -> Self { - Self { - bootstrap_node: String::from_str("http://34.84.172.121/relay").unwrap(), +impl Drop for ServiceState { + fn drop(&mut self) { + if let Some(child_process) = self.child.take() { + child_process + .kill() + .expect("Failed to kill sidecar process"); } } } -#[tauri::command] -async fn start_mega_service( - handle: tauri::AppHandle, - state: State<'_, Arc>>, - params: MegaStartParams, -) -> Result { +#[derive(Debug, Deserialize, Clone, Default)] +struct MegaStartParams { + pub bootstrap_node: Option, +} + +fn set_up_lib(handle: tauri::AppHandle) { let resource_path = handle .path_resolver() .resource_dir() @@ -46,21 +42,34 @@ async fn start_mega_service( std::env::set_var("LD_LIBRARY_PATH", libs_dir.to_str().unwrap()); #[cfg(target_os = "windows")] - std::env::set_var("PATH", format!("{};{}", libs_dir.to_str().unwrap(), std::env::var("PATH").unwrap())); + std::env::set_var( + "PATH", + format!( + "{};{}", + libs_dir.to_str().unwrap(), + std::env::var("PATH").unwrap() + ), + ); +} - let mut service_state = state.lock().await; +#[tauri::command] +fn start_mega_service( + state: State<'_, Arc>>, + params: MegaStartParams, +) -> Result<(), String> { + let mut service_state = state.lock().unwrap(); if service_state.child.is_some() { return Err("Service is already running".into()); } + let args = if let Some(ref addr) = params.bootstrap_node { + vec!["service", "http", "--bootstrap-node", addr] + } else { + vec!["service", "http"] + }; let (mut rx, child) = Command::new_sidecar("mega") .expect("Failed to create `mega` binary command") - .args([ - "service", - "http", - "--bootstrap-node", - ¶ms.bootstrap_node, - ]) + .args(args) .spawn() .expect("Failed to spawn `Mega service`"); @@ -87,7 +96,7 @@ async fn start_mega_service( eprintln!("Sidecar terminated by signal: {}", signal); } // update ServiceState child - let mut service_state = cloned_state.lock().await; + let mut service_state = cloned_state.lock().unwrap(); service_state.child = None; break; } @@ -95,12 +104,12 @@ async fn start_mega_service( } } }); - Ok(resource_path.to_str().unwrap().to_string()) + Ok(()) } #[tauri::command] -async fn stop_mega_service(state: State<'_, Arc>>) -> Result<(), String> { - let mut service_state = state.lock().await; +fn stop_mega_service(state: State<'_, Arc>>) -> Result<(), String> { + let mut service_state = state.lock().unwrap(); if let Some(child) = service_state.child.take() { child.kill().map_err(|e| e.to_string())?; } else { @@ -110,23 +119,23 @@ async fn stop_mega_service(state: State<'_, Arc>>) -> Result } #[tauri::command] -async fn restart_mega_service( - handle: tauri::AppHandle, +fn restart_mega_service( state: State<'_, Arc>>, params: MegaStartParams, -) -> Result { - stop_mega_service(state.clone()).await?; - start_mega_service(handle, state, params).await +) -> Result<(), String> { + stop_mega_service(state.clone())?; + start_mega_service(state, params)?; + Ok(()) } #[tauri::command] async fn mega_service_status(state: State<'_, Arc>>) -> Result { - let service_state = state.lock().await; + let service_state = state.lock().unwrap(); Ok(service_state.child.is_some()) } fn main() { - // let params = MegaStartParams::default(); + let params = MegaStartParams::default(); tauri::Builder::default() .manage(Arc::new(Mutex::new(ServiceState::default()))) .invoke_handler(tauri::generate_handler![ @@ -135,16 +144,15 @@ fn main() { restart_mega_service, mega_service_status ]) - .setup(|_| { - // let app_handle = app.handle(); - // let state = app.state::>>().clone(); - // tauri::async_runtime::spawn(async move { - // if let Err(e) = start_mega_service(state, params).await { - // eprintln!("Failed to restart rust_service: {}", e); - // } else { - // println!("Rust service restarted successfully"); - // } - // }); + .setup(|app| { + let app_handle = app.handle().clone(); + set_up_lib(app_handle); + let state = app.state::>>().clone(); + if let Err(e) = start_mega_service(state, params) { + eprintln!("Failed to restart rust_service: {}", e); + } else { + println!("Rust service restarted successfully"); + } Ok(()) }) .run(tauri::generate_context!()) diff --git a/lunar/src/app/api/fetcher.ts b/lunar/src/app/api/fetcher.ts index 843a884e..f94f7dc5 100644 --- a/lunar/src/app/api/fetcher.ts +++ b/lunar/src/app/api/fetcher.ts @@ -28,7 +28,7 @@ const fetcher = async url => { export function useTreeCommitInfo(path) { const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mono/tree/commit-info?path=${path}`, fetcher, { - dedupingInterval: 1000, + dedupingInterval: 30000, }) return { tree: data, @@ -48,6 +48,39 @@ export function useBlobContent(path) { } } +export function useMRList(status) { + const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mono/mr/list?status=${status}`, fetcher, { + dedupingInterval: 60000, + }) + return { + mrList: data, + isMRLoading: isLoading, + isMRError: error, + } +} + +export function useMRDetail(id) { + const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mono/mr/${id}/detail`, fetcher, { + dedupingInterval: 60000, + }) + return { + mrDetail: data, + isMRLoading: isLoading, + isMRError: error, + } +} + +export function useMRFiles(id) { + const { data, error, isLoading } = useSWR(`${endpoint}/api/v1/mono/mr/${id}/files`, fetcher, { + dedupingInterval: 60000, + }) + return { + mrFiles: data, + isMRLoading: isLoading, + isMRError: error, + } +} + export function useRepoList() { const { data, error, isLoading } = useSWR(`${relay}/relay/api/v1/repo_list`, fetcher, { dedupingInterval: 30000, diff --git a/lunar/src/app/blob/page.tsx b/lunar/src/app/blob/page.tsx index d84432f5..87dce465 100644 --- a/lunar/src/app/blob/page.tsx +++ b/lunar/src/app/blob/page.tsx @@ -4,9 +4,18 @@ import Bread from '@/components/BreadCrumb'; import { useSearchParams } from 'next/navigation'; import { useBlobContent } from '../api/fetcher'; import { Skeleton } from "antd/lib"; +import { Suspense } from 'react' export default function BlobPage() { + return ( + + + + ) +} + +function Blob() { const searchParams = useSearchParams(); const path = searchParams.get('path'); diff --git a/lunar/src/app/mr/page.tsx b/lunar/src/app/mr/page.tsx new file mode 100644 index 00000000..a09d8d28 --- /dev/null +++ b/lunar/src/app/mr/page.tsx @@ -0,0 +1,27 @@ +'use client' +import MergeDetail from "@/components/MergeDetail"; +import { useMRDetail } from "../api/fetcher"; +import { Skeleton } from "antd/lib"; +import { useSearchParams } from "next/navigation"; +import { Suspense } from 'react' + +export default function Page() { + return ( + + + + ); +} + +function MRDetailPage() { + const searchParams = useSearchParams(); + const id = searchParams.get('id'); + const { mrDetail, isMRLoading, isMRError } = useMRDetail(id); + if (isMRLoading) return ; + + return ( +
+ +
+ ) +} diff --git a/lunar/src/app/page.tsx b/lunar/src/app/page.tsx index 0a1dc10b..0c687bbf 100644 --- a/lunar/src/app/page.tsx +++ b/lunar/src/app/page.tsx @@ -1,10 +1,9 @@ 'use client' -import { Flex, Layout } from 'antd'; -import { Skeleton, Button, Result } from "antd/lib"; +import { Flex, Layout, Skeleton, Alert } from "antd/lib"; import CodeTable from '@/components/CodeTable'; import MergeList from '@/components/MergeList'; -import { useTreeCommitInfo, useBlobContent, useMegaStatus } from '@/app/api/fetcher'; +import { useTreeCommitInfo, useBlobContent, useMRList } from '@/app/api/fetcher'; const { Content } = Layout; @@ -16,74 +15,55 @@ const contentStyle: React.CSSProperties = { backgroundColor: '#fff', }; -const layoutStyle = { - minHeight: 500, +const rightStyle = { + minHeight: 768, + borderRadius: 8, + overflow: 'hidden', + width: 'calc(40% - 8px)', + maxWidth: 'calc(40% - 8px)', + background: '#fff' +}; + + +const leftStyle = { + minHeight: '100%', borderRadius: 8, overflow: 'hidden', - width: 'calc(50% - 8px)', - maxWidth: 'calc(50% - 8px)', + width: 'calc(60% - 8px)', + maxWidth: 'calc(70% - 8px)', background: '#fff' }; -const mrList = [ - { - "id": 2278111790530821, - "title": "", - "status": "open", - "open_timestamp": 1721181311, - "merge_timestamp": null - }, - { - "id": 2277296526688517, - "title": "", - "status": "merged", - "open_timestamp": 1721131551, - "merge_timestamp": 1721131565 - }, - { - "id": 2276683620876549, - "title": "", - "status": "merged", - "open_timestamp": 1721094142, - "merge_timestamp": 1721117874 - } -]; export default function HomePage() { const { tree, isTreeLoading, isTreeError } = useTreeCommitInfo("/"); const { blob, isBlobLoading, isBlobError } = useBlobContent("/README.md"); - const { status, isLoading, isError } = useMegaStatus(); + const { mrList, isMRLoading, isMRError } = useMRList(""); - if (isTreeLoading || isBlobLoading || isLoading) return ; + if (isTreeLoading || isBlobLoading || isMRLoading) return ; return (
- {!status && - < Result - status="warning" - title="Set relay server address first to start mega server" - extra={ - - } - /> - } + { - status && - + { (tree && blob) && } - + {(isTreeLoading || isBlobLoading) && } {(!isTreeLoading && !isBlobLoading) && - + } {/* */} diff --git a/lunar/src/app/settings/page.tsx b/lunar/src/app/settings/page.tsx index 163098b4..529a3f9f 100644 --- a/lunar/src/app/settings/page.tsx +++ b/lunar/src/app/settings/page.tsx @@ -75,6 +75,20 @@ export default function Settings() { +
+
+ ZTM Agent Peer Id +
+
+ +
+
+ + + +
+ ), }, diff --git a/lunar/src/components/MergeDetail.tsx b/lunar/src/components/MergeDetail.tsx new file mode 100644 index 00000000..97f5501e --- /dev/null +++ b/lunar/src/components/MergeDetail.tsx @@ -0,0 +1,95 @@ +'use client' +import React, { useEffect, useState } from 'react'; +import { Card, Button, List } from 'antd/lib'; +import { useRouter } from 'next/navigation'; +import { useMRFiles } from '@/app/api/fetcher'; + +const endpoint = process.env.NEXT_PUBLIC_API_URL; + + +const MRDetailPage = ({ mrDetail }) => { + const router = useRouter(); + const [filedata, setFileData] = useState([]); + const [loadings, setLoadings] = useState([]); + const [error, setError] = useState(null); + + const { mrFiles, isMRLoading, isMRError } = useMRFiles(mrDetail.id); + + useEffect(() => { + if (isMRLoading) { + set_to_loading(2) + } + if (mrFiles) { + setFileData(mrFiles.data); + cancel_loading(2) + } + }, [mrDetail, mrFiles]); + + + const set_to_loading = (index: number) => { + setLoadings((prevLoadings) => { + const newLoadings = [...prevLoadings]; + newLoadings[index] = true; + return newLoadings; + }); + } + + const cancel_loading = (index: number) => { + setLoadings((prevLoadings) => { + const newLoadings = [...prevLoadings]; + newLoadings[index] = false; + return newLoadings; + }); + } + + const approve_mr = async (index: number, id: number) => { + set_to_loading(index); + const res = await fetch(`${endpoint}/api/v1/mono/mr/${id}/merge`,{ + method: 'POST', + }); + if (res) { + cancel_loading(index); + } + + if (res.ok) { + router.refresh(); + } + }; + + + return ( + + {mrDetail.status === "open" && + + } + + More} + > + Change File List
} + bordered + dataSource={filedata} + loading = {loadings[2]} + renderItem={(item) => ( + + {item} + + )} + /> + + + ) +} + +export default MRDetailPage; \ No newline at end of file diff --git a/lunar/src/components/MergeList.tsx b/lunar/src/components/MergeList.tsx index 4c16d1ba..737a204f 100644 --- a/lunar/src/components/MergeList.tsx +++ b/lunar/src/components/MergeList.tsx @@ -46,7 +46,7 @@ const MergeList: React.FC = ({ mrList }) => { return ( ( @@ -55,7 +55,7 @@ const MergeList: React.FC = ({ mrList }) => { avatar={ } - title={{`MR ${item.id} open by Mega automacticlly${item.title}`}{getStatusTag(item.status)}} + title={{`MR ${item.id} open by Mega automacticlly${item.title}`}{getStatusTag(item.status)}} description={getDescription(item)} /> diff --git a/mono/Cargo.toml b/mono/Cargo.toml index 9c121154..dd140475 100644 --- a/mono/Cargo.toml +++ b/mono/Cargo.toml @@ -15,10 +15,7 @@ path = "src/main.rs" [dependencies] common = { workspace = true } jupiter = { workspace = true } -callisto = { workspace = true } ceres = { workspace = true } -vault = { workspace = true } -mercury = { workspace = true } taurus = { workspace = true } anyhow = { workspace = true }