Commit c53d5c21 authored by timel's avatar timel

optimize: init

parent 21b2db98
Pipeline #23006 passed with stages
in 14 minutes and 10 seconds
import { EventEmitter } from "eventemitter3";
import { v4 as v4uuid } from "uuid";
export const eventEmitter = new EventEmitter();
const eventEmitter = new EventEmitter();
export enum Task {
Move = "move", // 卡片移动
......@@ -13,7 +13,7 @@ export enum Task {
const getEnd = (task: Task) => `${task}-end`;
/** 在组件之中注册方法 */
/** 在组件之中注册方法,注意注册的方法一旦执行成功,必须返回一个true */
const register = <T extends unknown[]>(
task: Task,
fn: (...args: T) => Promise<boolean>
......
// Some implementation of infrastructure
/* eslint import/export: 0 */
export * from "./console";
import "./console";
export * from "./eventbus";
export * from "./pfetch";
export * from "./sleep";
export * from "./stream";
/** 在fetch的基础上,封装一个pfetch。增加一个可选的新参数,这个参数是一个回调函数,从而让外界可以感知fetch的进度(0->1),比如下载进度。 */
export async function pfetch(
input: RequestInfo,
options?: {
init?: RequestInit;
progressCallback?: (progress: number) => void;
}
): Promise<Response> {
const response = await fetch(input, options?.init);
const clonedResponse = response.clone(); // Clone the response to create a new body stream
if (typeof options?.progressCallback === "function") {
const contentLength = parseInt(
response.headers.get("content-length") || "0",
10
);
let bytesRead = 0;
const reader = clonedResponse.body!.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
bytesRead += value.length;
const progress = (bytesRead / contentLength) * 100;
options?.progressCallback(progress);
}
}
return response;
}
......@@ -9,6 +9,7 @@ import initSqlJs, { Database } from "sql.js";
import { CardData, CardMeta, CardText } from "@/api/cards";
import { useConfig } from "@/config";
import { pfetch } from "@/infra";
const NeosConfig = useConfig();
......@@ -26,6 +27,7 @@ export interface sqliteAction {
// 初始化DB需要业务方传入的数据
initInfo?: {
dbUrl: string;
progressCallback?: (progress: number) => void; // 用于获取读取进度
};
// 需要读取卡牌数据的ID
payload?: {
......@@ -51,7 +53,9 @@ export default async function (action: sqliteAction): Promise<sqliteResult> {
case sqliteCmd.INIT: {
const info = action.initInfo;
if (info) {
const dataPromise = fetch(info.dbUrl).then((res) => res.arrayBuffer()); // TODO: i18n
const dataPromise = pfetch(info.dbUrl, {
progressCallback: action.initInfo?.progressCallback,
}).then((res) => res.arrayBuffer()); // TODO: i18n
const [SQL, buffer] = await Promise.all([sqlPromise, dataPromise]);
YGODB = new SQL.Database(new Uint8Array(buffer));
......
......@@ -8,6 +8,7 @@ export const initStore = proxy({
},
decks: false,
i18n: false,
wasm: false,
// ...
reset() {},
} satisfies NeosStore);
......@@ -10,10 +10,20 @@
.logo-container {
align-items: center;
height: min-content;
padding: 5px 10px;
background-color: hsl(0, 0%, 100%, 0);
transition: 0.2s;
border-radius: 20px;
.logo {
width: 60px;
filter: brightness(1.5);
transform: translateY(1px);
transition: 0.2s;
}
&:hover {
background-color: hsl(0, 0%, 100%, 0.9);
.logo {
filter: invert(1);
}
}
}
......
import { Avatar } from "antd";
import { useEffect } from "react";
import {
type LoaderFunction,
NavLink,
......@@ -7,30 +8,35 @@ import {
} from "react-router-dom";
import { useSnapshot } from "valtio";
import { CookieKeys, getCookie } from "@/api";
import { useConfig } from "@/config";
import { accountStore, deckStore, initStore, type User } from "@/stores";
import { accountStore } from "@/stores";
import styles from "./index.module.scss";
import { initSqlite } from "./utils";
import {
getLoginStatus,
handleSSOLogin,
initDeck,
initSqlite,
initWASM,
} from "./utils";
const NeosConfig = useConfig();
export const loader: LoaderFunction = async () => {
const user = getCookie<User>(CookieKeys.USER);
if (user) accountStore.login(user);
// 加载卡组
if (!initStore.decks)
deckStore.initialize().then(() => (initStore.decks = true));
// 加载ygodb
if (!initStore.sqlite.progress) {
initSqlite().then(() => (initStore.sqlite.progress = 1));
initStore.sqlite.progress = 0.01;
}
getLoginStatus();
initDeck();
initSqlite();
initWASM();
return null;
};
export const Component = () => {
// 捕获SSO登录
const location = useLocation();
useEffect(() => {
location.search && handleSSOLogin(location.search);
}, [location.search]);
// TODO 根据是否登录,显示内容
const { pathname } = useLocation();
const pathnamesHideHeader = ["/waitroom"];
......@@ -45,11 +51,6 @@ export const Component = () => {
alt="NEOS"
/>
</div>
{/* <img
className={styles.logo}
src={`${NeosConfig.assetsPath}/neos-logo.svg`}
alt="NEOS"
/> */}
<NavLink to="/">主页</NavLink>
<NavLink to="/match">匹配</NavLink>
<NavLink to="/build">组卡</NavLink>
......
import rustInit from "rust-src";
import { CookieKeys, getCookie, setCookie } from "@/api";
import { useConfig } from "@/config";
import { useEnv } from "@/hook";
import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite";
import { initStore } from "@/stores";
import { accountStore, deckStore, initStore, type User } from "@/stores";
const { cardsDbUrl } = useConfig();
const { BASE_URL } = useEnv();
/** 加载ygodb */
export const initSqlite = async () => {
const { sqlite } = initStore;
sqlite.progress = 0.01;
await sqliteMiddleWare({
cmd: sqliteCmd.INIT,
initInfo: { dbUrl: cardsDbUrl },
});
sqlite.progress = 1;
if (!initStore.sqlite.progress) {
const { sqlite } = initStore;
const progressCallback = (progress: number) =>
(sqlite.progress = progress * 0.9);
sqlite.progress = 0.01;
await sqliteMiddleWare({
cmd: sqliteCmd.INIT,
initInfo: { dbUrl: cardsDbUrl, progressCallback },
});
sqlite.progress = 1;
}
};
/** 加载卡组 */
export const initDeck = async () => {
if (!initStore.decks) {
await deckStore.initialize();
initStore.decks = true;
}
};
/** 加载WASM */
export const initWASM = async () => {
const url =
BASE_URL === "/"
? undefined
: new URL("rust_src_bg.wasm", `${BASE_URL}assets/`);
await rustInit(url);
initStore.wasm = true;
};
/** sso登录跳转回来 */
export const handleSSOLogin = async (search: string) => {
/** 从SSO跳转回的URL之中,解析用户信息 */
function getSSOUser(searchParams: URLSearchParams): User {
return Object.fromEntries(searchParams) as unknown as User;
}
const sso = new URLSearchParams(search).get("sso");
const user = sso ? getSSOUser(new URLSearchParams(atob(sso))) : undefined;
if (user) {
accountStore.login(user);
setCookie(CookieKeys.USER, JSON.stringify(user));
// TODO: toast显示登录成功
}
};
/** 从cookie获取登录态 */
export const getLoginStatus = async () => {
const user = getCookie<User>(CookieKeys.USER);
if (user) accountStore.login(user);
};
import { EditFilled, SettingFilled } from "@ant-design/icons";
import { Space } from "antd";
import { useEffect, useState } from "react";
import { type LoaderFunction, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { useSnapshot } from "valtio";
import { CookieKeys, setCookie } from "@/api";
import { useConfig } from "@/config";
import { accountStore, deckStore, IDeck, roomStore, type User } from "@/stores";
import { accountStore, deckStore, IDeck, roomStore } from "@/stores";
import { Background, IconFont, Select } from "@/ui/Shared";
import styles from "./index.module.scss";
......@@ -14,17 +13,6 @@ import { MatchModal, matchStore } from "./MatchModal";
import { ReplayModal, replayOpen } from "./ReplayModal";
import { init } from "./util";
export const loader: LoaderFunction = () => {
const sso = new URLSearchParams(location.search).get("sso");
const user = sso ? getSSOUser(new URLSearchParams(atob(sso))) : undefined;
if (user) {
accountStore.login(user);
setCookie(CookieKeys.USER, JSON.stringify(user));
// TODO: toast显示登录成功
}
return null;
};
const NeosConfig = useConfig();
export const Component: React.FC = () => {
......@@ -150,8 +138,3 @@ const Mode: React.FC<{
<div className={styles.desc}>{desc}</div>
</div>
);
/** 从SSO跳转回的URL之中,解析用户信息 */
function getSSOUser(searchParams: URLSearchParams): User {
return Object.fromEntries(searchParams) as unknown as User;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment