web3browser.io/src/components/Browser.tsx

191 lines
4.5 KiB
TypeScript
Raw Normal View History

2023-10-11 13:46:46 +00:00
import {
createContext,
createRef,
forwardRef,
2023-10-16 21:43:13 +00:00
useCallback,
2023-10-11 13:46:46 +00:00
useContext,
useEffect,
useState,
} from "react";
import {
dnsClient,
ethClient,
handshakeClient,
ipfsClient,
networkRegistryClient,
peerDiscoveryClient,
swarmClient,
} from "@/clients.ts";
import * as kernel from "@lumeweb/libkernel/kernel";
import { kernelLoaded } from "@lumeweb/libkernel/kernel";
import Arrow from "@/components/Arrow.tsx";
import type React from "react";
import { Input } from "@/components/ui/input.tsx";
import { Button } from "@/components/ui/button.tsx";
2023-10-16 19:20:00 +00:00
import {
type AuthContextType,
type LumeStatusContextType,
useAuth,
useLumeStatus,
} from "@lumeweb/sdk";
2023-10-11 13:46:46 +00:00
let BOOT_FUNCTIONS: (() => Promise<any>)[] = [];
interface BrowserContextType {
url: string;
setUrl: React.Dispatch<React.SetStateAction<string>>;
}
const BrowserStateContext = createContext<BrowserContextType | undefined>(
undefined,
);
export function BrowserStateProvider({
children,
}: {
children: React.ReactElement;
}) {
const [url, setUrl] = useState("about:blank");
return (
<BrowserStateContext.Provider value={{ url, setUrl }}>
{children}
</BrowserStateContext.Provider>
);
}
export function useBrowserState() {
const context = useContext(BrowserStateContext);
if (!context) {
throw new Error(
"useBrowserState must be used within a BrowserStateProvider",
);
}
return context;
}
2023-10-16 19:20:00 +00:00
async function boot(status: LumeStatusContextType, auth: AuthContextType) {
2023-10-11 13:46:46 +00:00
const reg = await navigator.serviceWorker.register("/sw.js");
await reg.update();
await kernel.serviceWorkerReady();
kernel.init().then(() => {
2023-10-16 19:20:00 +00:00
status.setInited(true);
});
2023-10-11 13:46:46 +00:00
await kernelLoaded();
2023-10-16 19:20:00 +00:00
auth.setIsLoggedIn(true);
2023-10-12 17:20:46 +00:00
2023-10-11 13:46:46 +00:00
BOOT_FUNCTIONS.push(
async () =>
await swarmClient.addRelay(
"2d7ae1517caf4aae4de73c6d6f400765d2dd00b69d65277a29151437ef1c7d1d",
),
);
// IRC
BOOT_FUNCTIONS.push(
async () =>
await peerDiscoveryClient.register(
2023-10-13 09:37:44 +00:00
"zrjHTx8tSQFWnmZ9JzK7XmJirqJQi2WRBLYp3fASaL2AfBQ",
2023-10-11 13:46:46 +00:00
),
);
BOOT_FUNCTIONS.push(
async () => await networkRegistryClient.registerType("content"),
);
BOOT_FUNCTIONS.push(
async () => await networkRegistryClient.registerType("blockchain"),
);
BOOT_FUNCTIONS.push(async () => await handshakeClient.register());
BOOT_FUNCTIONS.push(async () => await ethClient.register());
BOOT_FUNCTIONS.push(async () => await ipfsClient.register());
2023-10-16 19:20:00 +00:00
BOOT_FUNCTIONS.push(async () => status.setReady(true));
2023-10-11 13:46:46 +00:00
const resolvers = [
2023-10-12 14:04:14 +00:00
"zrjCnUBqmBqXXcc2yPnq517sXQtNcfZ2BHgnVTcbhSYxko7", // CID
"zrjEYq154PS7boERAbRAKMyRGzAR6CTHVRG6mfi5FV4q9FA", // ENS
2023-10-11 13:46:46 +00:00
"zrjEH3iojPLr7986o7iCn9THBmJmHiuDWmS1G6oT8DnfuFM", // HNS
];
for (const resolver of resolvers) {
BOOT_FUNCTIONS.push(async () => dnsClient.registerResolver(resolver));
}
await bootup();
await Promise.all([
ethClient.ready(),
handshakeClient.ready(),
ipfsClient.ready(),
]);
}
async function bootup() {
for (const entry of Object.entries(BOOT_FUNCTIONS)) {
2023-10-13 06:51:11 +00:00
console.log(entry[1].toString());
2023-10-11 13:46:46 +00:00
await entry[1]();
}
}
export function Navigator() {
const { url: contextUrl, setUrl } = useBrowserState();
2023-10-16 19:20:00 +00:00
const { isLoggedIn } = useAuth();
const [inputValue, setInputValue] = useState(contextUrl); // Local state for the input value
2023-10-11 13:46:46 +00:00
2023-10-16 21:43:13 +00:00
const browse = useCallback(() => {
let input = contextUrl.trim();
2023-10-11 13:46:46 +00:00
// If the input doesn't contain a protocol, assume it's http
if (!input?.match(/^https?:\/\//)) {
input = `http://${input}`;
}
try {
// Try to parse it as a URL
const url = new URL(input);
setUrl(
`/browse/${url.hostname}${url.pathname}${url.search}${url.hash}` ||
"about:blank",
);
} catch (e) {
// Handle invalid URLs here, if needed
console.error("Invalid URL:", e);
}
}, [contextUrl, setUrl]);
2023-10-11 13:46:46 +00:00
const NavInput = forwardRef((props: any, ref) => (
<Input ref={ref} {...props}></Input>
));
2023-10-16 21:15:23 +00:00
console.log("Navigator mounted");
2023-10-11 13:46:46 +00:00
return (
<>
<NavInput
value={inputValue}
onChange={(e: any) => setInputValue(e.target.value)}
disabled={!isLoggedIn}
/>
<Button onClick={browse} disabled={!isLoggedIn}>
2023-10-11 13:46:46 +00:00
Navigate
<Arrow />
</Button>
</>
);
}
export function Browser() {
const { url } = useBrowserState();
2023-10-16 19:20:00 +00:00
const status = useLumeStatus();
const auth = useAuth();
2023-10-11 13:46:46 +00:00
useEffect(() => {
2023-10-16 19:20:00 +00:00
boot(status, auth);
2023-10-11 13:46:46 +00:00
}, []);
return <iframe src={url} className="w-full h-full"></iframe>;
}