2025-07-22 19:48:46 +07:00
|
|
|
import { useEffect, useRef, useState } from "react";
|
2025-07-24 11:43:01 +07:00
|
|
|
import { FaDownload } from "react-icons/fa";
|
|
|
|
import { toast } from "sonner";
|
|
|
|
import Container from "../Container";
|
|
|
|
import NavBar from "../NavBar";
|
2025-04-28 14:35:53 -04:00
|
|
|
|
|
|
|
function Cache() {
|
2025-07-22 17:45:48 +07:00
|
|
|
const [searchQuery, setSearchQuery] = useState("");
|
2025-04-28 14:35:53 -04:00
|
|
|
const [cacheData, setCacheData] = useState([]);
|
2025-07-24 11:43:01 +07:00
|
|
|
const [keyCount, setKeyCount] = useState(0);
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const [hasSearched, setHasSearched] = useState(false);
|
|
|
|
|
2025-04-28 14:35:53 -04:00
|
|
|
const debounceTimeout = useRef(null);
|
|
|
|
|
|
|
|
// Fetch the key count when the component mounts
|
|
|
|
useEffect(() => {
|
|
|
|
const fetchKeyCount = async () => {
|
|
|
|
try {
|
2025-07-22 17:45:48 +07:00
|
|
|
const response = await fetch("/api/cache/keycount");
|
2025-04-28 14:35:53 -04:00
|
|
|
const data = await response.json();
|
|
|
|
setKeyCount(data.count); // Update key count
|
|
|
|
} catch (error) {
|
2025-07-22 17:45:48 +07:00
|
|
|
console.error("Error fetching key count:", error);
|
2025-04-28 14:35:53 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
fetchKeyCount();
|
|
|
|
}, []); // Run only once when the component mounts
|
|
|
|
|
|
|
|
const handleInputChange = (event) => {
|
|
|
|
const query = event.target.value;
|
2025-07-24 11:43:01 +07:00
|
|
|
setSearchQuery(query);
|
2025-07-22 17:45:48 +07:00
|
|
|
|
2025-04-28 14:35:53 -04:00
|
|
|
if (debounceTimeout.current) {
|
|
|
|
clearTimeout(debounceTimeout.current);
|
|
|
|
}
|
|
|
|
|
2025-07-24 11:43:01 +07:00
|
|
|
if (query.trim() !== "") {
|
|
|
|
setLoading(true); // Show spinner immediately
|
|
|
|
debounceTimeout.current = setTimeout(() => {
|
|
|
|
sendApiCall(query);
|
|
|
|
}, 1000);
|
|
|
|
} else {
|
|
|
|
setHasSearched(false); // Reset state when input is cleared
|
|
|
|
setCacheData([]);
|
|
|
|
}
|
2025-04-28 14:35:53 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
const sendApiCall = (text) => {
|
2025-07-24 11:43:01 +07:00
|
|
|
setLoading(true);
|
2025-07-22 17:45:48 +07:00
|
|
|
fetch("/api/cache/search", {
|
|
|
|
method: "POST",
|
|
|
|
headers: { "Content-Type": "application/json" },
|
2025-04-28 14:35:53 -04:00
|
|
|
body: JSON.stringify({ input: text }),
|
|
|
|
})
|
|
|
|
.then((response) => response.json())
|
2025-07-24 11:43:01 +07:00
|
|
|
.then((data) => {
|
|
|
|
setCacheData(data);
|
|
|
|
setHasSearched(true);
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
toast.error(`Error: ${error.message}`);
|
|
|
|
console.error("Error:", error);
|
|
|
|
})
|
|
|
|
.finally(() => setLoading(false));
|
2025-04-28 14:35:53 -04:00
|
|
|
};
|
|
|
|
|
2025-07-22 19:48:46 +07:00
|
|
|
useEffect(() => {
|
|
|
|
document.title = "Cache | CDRM-Project";
|
|
|
|
}, []);
|
|
|
|
|
2025-04-28 14:35:53 -04:00
|
|
|
return (
|
2025-07-24 11:43:01 +07:00
|
|
|
<>
|
|
|
|
<NavBar />
|
|
|
|
<Container>
|
|
|
|
<div className="my-4 flex w-full flex-col items-center justify-center gap-2 lg:flex-row">
|
|
|
|
<fieldset className="fieldset w-full max-w-2xl">
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
value={searchQuery}
|
|
|
|
onChange={handleInputChange}
|
|
|
|
placeholder={`Search ${keyCount} keys...`}
|
|
|
|
className="input w-full max-w-2xl font-mono"
|
|
|
|
/>
|
|
|
|
</fieldset>
|
|
|
|
<button
|
|
|
|
className="btn btn-success"
|
|
|
|
onClick={() => {
|
|
|
|
window.location.href = "/api/cache/download";
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<FaDownload />
|
|
|
|
Download keys cache
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{loading ? (
|
|
|
|
<div className="flex justify-center py-16">
|
|
|
|
<span className="loading loading-spinner loading-md me-2"></span>
|
|
|
|
Searching...
|
|
|
|
</div>
|
|
|
|
) : cacheData.length > 0 ? (
|
|
|
|
<div className="my-4 flex justify-center">
|
|
|
|
<div className="overflow-x-auto">
|
|
|
|
<table className="table">
|
|
|
|
<thead>
|
|
|
|
<tr>
|
|
|
|
<th></th>
|
|
|
|
<th className="text-center">PSSH</th>
|
|
|
|
<th className="text-center">key ID:key pair</th>
|
|
|
|
</tr>
|
|
|
|
</thead>
|
|
|
|
<tbody>
|
|
|
|
{cacheData.map((item, index) => (
|
|
|
|
<tr key={index}>
|
|
|
|
<th>{index + 1}</th>
|
|
|
|
<td className="font-mono">{item.PSSH}</td>
|
|
|
|
<td className="font-mono">
|
|
|
|
{item.KID}:{item.Key}
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
))}
|
|
|
|
</tbody>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
) : hasSearched ? (
|
|
|
|
<div className="flex justify-center py-16">
|
|
|
|
<div className="text-center">No data found in the database</div>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div className="flex justify-center py-16">
|
|
|
|
<div className="text-center">Enter a search query to see results</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</Container>
|
|
|
|
</>
|
2025-04-28 14:35:53 -04:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export default Cache;
|