diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java index f6194a06..4f3b90d5 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/ConfigController.java @@ -1,11 +1,9 @@ package com.reajason.javaweb.boot.controller; -import com.reajason.javaweb.boot.entity.Config; import com.reajason.javaweb.memshell.Packers; import com.reajason.javaweb.memshell.Server; import com.reajason.javaweb.memshell.ShellTool; import com.reajason.javaweb.memshell.server.AbstractShell; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -20,8 +18,28 @@ import java.util.*; @RequestMapping("/config") @CrossOrigin("*") public class ConfigController { + + @RequestMapping("/servers") + public Map> getServers() { + Map> servers = new LinkedHashMap<>(); + for (Server server : Server.values()) { + if (server.getShell() != null) { + Set supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes(); + servers.put(server.name(), supportedShellTypes.stream().toList()); + } + } + return servers; + } + + @RequestMapping("/packers") + public List getPackers() { + return Arrays.stream(Packers.values()) + .filter(packers -> packers.getParentPacker() == null) + .map(Packers::name).toList(); + } + @RequestMapping - public ResponseEntity config() { + public Map> config() { Map> coreMap = new HashMap<>(16); for (Server value : Server.values()) { AbstractShell shell = value.getShell(); @@ -38,21 +56,6 @@ public class ConfigController { } coreMap.put(value.name(), map); } - Config config = new Config(); - Map> servers = new LinkedHashMap<>(); - for (Server server : Server.values()) { - if (server.getShell() != null) { - Set supportedShellTypes = server.getShell().getShellInjectorMapping().getSupportedShellTypes(); - servers.put(server.name(), supportedShellTypes.stream().toList()); - } - } - config.setServers(servers); - config.setCore(coreMap); - config.setPackers( - Arrays.stream(Packers.values()) - .filter(packers -> packers.getParentPacker() == null) - .map(Packers::name).toList() - ); - return ResponseEntity.ok(config); + return coreMap; } } \ No newline at end of file diff --git a/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java b/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java index 4132e846..623d4a64 100644 --- a/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java +++ b/boot/src/main/java/com/reajason/javaweb/boot/controller/GeneratorController.java @@ -1,8 +1,8 @@ package com.reajason.javaweb.boot.controller; -import com.reajason.javaweb.memshell.MemShellGenerator; import com.reajason.javaweb.boot.dto.GenerateRequest; import com.reajason.javaweb.boot.dto.GenerateResponse; +import com.reajason.javaweb.memshell.MemShellGenerator; import com.reajason.javaweb.memshell.config.GenerateResult; import com.reajason.javaweb.memshell.config.InjectorConfig; import com.reajason.javaweb.memshell.config.ShellConfig; @@ -10,7 +10,6 @@ import com.reajason.javaweb.memshell.config.ShellToolConfig; import com.reajason.javaweb.memshell.packer.AggregatePacker; import com.reajason.javaweb.memshell.packer.Packer; import com.reajason.javaweb.memshell.packer.jar.JarPacker; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Base64; @@ -24,18 +23,18 @@ import java.util.Base64; @CrossOrigin("*") public class GeneratorController { @PostMapping - public ResponseEntity generate(@RequestBody GenerateRequest request) { + public GenerateResponse generate(@RequestBody GenerateRequest request) { ShellConfig shellConfig = request.getShellConfig(); ShellToolConfig shellToolConfig = request.parseShellToolConfig(); InjectorConfig injectorConfig = request.getInjectorConfig(); GenerateResult generateResult = MemShellGenerator.generate(shellConfig, injectorConfig, shellToolConfig); Packer packer = request.getPacker().getInstance(); if (packer instanceof JarPacker) { - return ResponseEntity.ok(new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult)))); + return new GenerateResponse(generateResult, Base64.getEncoder().encodeToString(((JarPacker) packer).packBytes(generateResult))); } else if (packer instanceof AggregatePacker) { - return ResponseEntity.ok(new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult))); + return new GenerateResponse(generateResult, ((AggregatePacker) packer).packAll(generateResult)); } else { - return ResponseEntity.ok(new GenerateResponse(generateResult, packer.pack(generateResult))); + return new GenerateResponse(generateResult, packer.pack(generateResult)); } } } \ No newline at end of file diff --git a/web/bun.lockb b/web/bun.lockb index c5770638..c580d2fa 100755 Binary files a/web/bun.lockb and b/web/bun.lockb differ diff --git a/web/package.json b/web/package.json index 8bacb9a9..b5ed3110 100644 --- a/web/package.json +++ b/web/package.json @@ -15,17 +15,16 @@ }, "devDependencies": { "@biomejs/biome": "1.9.4", - "@tanstack/router-plugin": "^1.114.32", - "@types/node": "^22.13.17", + "@types/node": "^22.14.0", "@types/react": "^19.1.0", "@types/react-copy-to-clipboard": "^5.0.7", "@types/react-dom": "^19.1.1", "@types/react-syntax-highlighter": "^15.5.13", "@vitejs/plugin-react": "^4.3.4", "rimraf": "^6.0.1", - "tailwindcss": "^4.1.1", - "typescript": "^5.8.2", - "vite": "^6.2.4", + "tailwindcss": "^4.1.3", + "typescript": "^5.8.3", + "vite": "^6.2.5", "vite-bundle-visualizer": "^1.2.1" }, "dependencies": { @@ -56,19 +55,15 @@ "@radix-ui/react-toggle": "^1.1.2", "@radix-ui/react-toggle-group": "^1.1.2", "@radix-ui/react-tooltip": "^1.1.8", - "@tailwindcss/vite": "^4.1.1", - "@tanstack/react-query": "^5.71.3", - "@tanstack/react-router": "^1.114.32", - "@tanstack/router-devtools": "^1.114.32", + "@tailwindcss/vite": "^4.1.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", - "embla-carousel-react": "^8.5.2", + "embla-carousel-react": "^8.6.0", "i18next": "^24.2.3", "input-otp": "^1.4.2", "lucide-react": "^0.487.0", - "next-themes": "^0.4.6", "react": "^19.1.0", "react-copy-to-clipboard": "^5.1.0", "react-day-picker": "9.6.4", @@ -76,8 +71,10 @@ "react-hook-form": "^7.55.0", "react-i18next": "^15.4.1", "react-resizable-panels": "^2.1.7", + "react-router": "^7.5.0", + "react-router-dom": "^7.5.0", "react-syntax-highlighter": "^15.6.1", - "recharts": "^2.15.1", + "recharts": "^2.15.2", "sonner": "^2.0.3", "tailwind-merge": "^3.1.0", "tailwind-scrollbar": "^4.0.2", diff --git a/web/src/routes/__root.tsx b/web/src/components/layouts/root-layout.tsx similarity index 86% rename from web/src/routes/__root.tsx rename to web/src/components/layouts/root-layout.tsx index 00b336b0..0e9c32b4 100644 --- a/web/src/routes/__root.tsx +++ b/web/src/components/layouts/root-layout.tsx @@ -1,17 +1,14 @@ import { LanguageSwitcher } from "@/components/language-switcher"; import { ModeToggle } from "@/components/mode-toggle.tsx"; import { ThemeProvider } from "@/components/theme-provider.tsx"; -import { Button } from "@/components/ui/button.tsx"; import { Toaster } from "@/components/ui/sonner"; import VersionBadge from "@/components/version-badge"; import { GitHubIcon } from "@/icon"; -import { Outlet, createRootRoute } from "@tanstack/react-router"; +import { Button } from "@/components/ui/button"; +import { Outlet } from "react-router-dom"; -export const Route = createRootRoute({ - component: RootComponent, -}); -function RootComponent() { +export default function RootLayout() { return ( @@ -42,4 +39,4 @@ function RootComponent() { ); -} +} \ No newline at end of file diff --git a/web/src/main.tsx b/web/src/main.tsx index 4a293442..1cfa2676 100644 --- a/web/src/main.tsx +++ b/web/src/main.tsx @@ -1,37 +1,23 @@ -import { RouterProvider, createRouter } from "@tanstack/react-router"; import ReactDOM from "react-dom/client"; -import { routeTree } from "./routeTree.gen"; import "./index.css"; import { TailwindIndicator } from "@/components/tailwind-indicator.tsx"; import { env } from "@/config.ts"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { I18nextProvider } from "react-i18next"; import i18n from "./i18n/i18n"; - -const queryClient = new QueryClient(); - -const router = createRouter({ - routeTree, - basepath: env.BASE_PATH, - defaultPreload: "intent", -}); - -declare module "@tanstack/react-router" { - interface Register { - router: typeof router; - } -} +import { RouterProvider } from "react-router-dom"; +import { router } from "./router"; +import { QueryProvider } from "./providers/query-client-provider"; const rootElement = document.getElementById("app") as HTMLElement; if (!rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement); root.render( - + {env.MODE !== "production" && } - , + ); } diff --git a/web/src/routes/index.tsx b/web/src/pages/index.tsx similarity index 59% rename from web/src/routes/index.tsx rename to web/src/pages/index.tsx index dffcd319..658e0614 100644 --- a/web/src/routes/index.tsx +++ b/web/src/pages/index.tsx @@ -10,41 +10,56 @@ import { ConfigResponseType, GenerateResponse, GenerateResult, + MainConfig, + PackerConfig, + ServerConfig, ShellToolType, } from "@/types/shell.ts"; -import { transformToPostData } from "@/utils/transformer.ts"; +import { customValidation, transformToPostData } from "@/utils/transformer.ts"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useQuery } from "@tanstack/react-query"; -import { createFileRoute } from "@tanstack/react-router"; import { LoaderCircle, WandSparklesIcon } from "lucide-react"; import { useState, useTransition } from "react"; import { useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { toast } from "sonner"; +import { useQuery } from "@tanstack/react-query"; -export const Route = createFileRoute("/")({ - component: IndexComponent, -}); +export default function IndexPage() { + const { data: serverConfig } = useQuery({ + queryKey: ["serverConfig"], + queryFn: async () => { + const response = await fetch(`${env.API_URL}/config/servers`); + return await response.json(); + }, + }); -function IndexComponent() { - const { data } = useQuery({ - queryKey: ["config"], + const { data: mainConfig } = useQuery({ + queryKey: ["mainConfig"], queryFn: async () => { const response = await fetch(`${env.API_URL}/config`); return await response.json(); }, }); + + const { data: packerConfig } = useQuery({ + queryKey: ["packerConfig"], + queryFn: async () => { + const response = await fetch(`${env.API_URL}/config/packers`); + return await response.json(); + }, + }); + const { t } = useTranslation(); const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { - server: "", + server: "Tomcat", targetJdkVersion: "50", debug: false, bypassJavaModule: false, shellClassName: "", shellTool: "Godzilla", - shellType: "", + shellType: "Listener", urlPattern: "/*", godzillaPass: "pass", godzillaKey: "key", @@ -64,40 +79,11 @@ function IndexComponent() { const [packMethod, setPackMethod] = useState(""); const [isActionPending, startTransition] = useTransition(); - function customValidation(values: FormSchema) { - if (values.shellType.endsWith("Servlet") && (values.urlPattern === "/*" || !values.urlPattern)) { - toast.warning(t("tips.servletUrlPattern")); - return false; - } - - if (values.shellType.endsWith("ControllerHandler") && (values.urlPattern === "/*" || !values.urlPattern)) { - toast.warning(t("tips.controllerUrlPattern")); - return false; - } - - if ( - (values.shellType === "HandlerMethod" || values.shellType === "HandlerFunction") && - (values.urlPattern === "/*" || !values.urlPattern) - ) { - toast.warning(t("tips.handlerUrlPattern")); - return false; - } - - if (values.shellTool === ShellToolType.Custom && !values.shellClassBase64) { - toast.warning(t("tips.customShellClass")); - return false; - } - return true; - } - - async function onSubmit(values: FormSchema) { + const onSubmit = async (data: FormSchema) => { startTransition(async () => { - if (!customValidation(values)) { - return; - } - - const postData = transformToPostData(values); try { + customValidation(t, data); + const postData = transformToPostData(data); const response = await fetch(`${env.API_URL}/generate`, { method: "POST", headers: { @@ -105,31 +91,30 @@ function IndexComponent() { }, body: JSON.stringify(postData), }); - await new Promise((resolve) => setTimeout(resolve, 200)); - if (response.ok) { - const json: GenerateResponse = await response.json(); - setPackResult(json.packResult); - setAllPackResults(json.allPackResults); - setGenerateResult(json.generateResult); - setPackMethod(values.packingMethod); - toast.success(t("success.generated")); - } else { + + if (!response.ok) { const json: APIErrorResponse = await response.json(); toast.error(t("errors.generationFailed", { error: json.error })); } - } catch (err) { - const error = err as Error; - toast.error(t("errors.generationFailed", { error: error.message })); + + const result = (await response.json()) as GenerateResponse; + setGenerateResult(result.generateResult); + setPackResult(result.packResult); + setAllPackResults(result.allPackResults); + setPackMethod(data.packingMethod); + toast.success(t("success.generated")); + } catch (error) { + toast.error(t("errors.generationFailed", { error: (error as Error).message })); } }); - } + }; return (
- +
- - + +