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 { EventEmitter } from "eventemitter3";
import { v4 as v4uuid } from "uuid"; import { v4 as v4uuid } from "uuid";
export const eventEmitter = new EventEmitter(); const eventEmitter = new EventEmitter();
export enum Task { export enum Task {
Move = "move", // 卡片移动 Move = "move", // 卡片移动
...@@ -13,7 +13,7 @@ export enum Task { ...@@ -13,7 +13,7 @@ export enum Task {
const getEnd = (task: Task) => `${task}-end`; const getEnd = (task: Task) => `${task}-end`;
/** 在组件之中注册方法 */ /** 在组件之中注册方法,注意注册的方法一旦执行成功,必须返回一个true */
const register = <T extends unknown[]>( const register = <T extends unknown[]>(
task: Task, task: Task,
fn: (...args: T) => Promise<boolean> fn: (...args: T) => Promise<boolean>
......
// Some implementation of infrastructure // Some implementation of infrastructure
/* eslint import/export: 0 */ import "./console";
export * from "./console";
export * from "./eventbus"; export * from "./eventbus";
export * from "./pfetch";
export * from "./sleep"; export * from "./sleep";
export * from "./stream"; 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"; ...@@ -9,6 +9,7 @@ import initSqlJs, { Database } from "sql.js";
import { CardData, CardMeta, CardText } from "@/api/cards"; import { CardData, CardMeta, CardText } from "@/api/cards";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { pfetch } from "@/infra";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
...@@ -26,6 +27,7 @@ export interface sqliteAction { ...@@ -26,6 +27,7 @@ export interface sqliteAction {
// 初始化DB需要业务方传入的数据 // 初始化DB需要业务方传入的数据
initInfo?: { initInfo?: {
dbUrl: string; dbUrl: string;
progressCallback?: (progress: number) => void; // 用于获取读取进度
}; };
// 需要读取卡牌数据的ID // 需要读取卡牌数据的ID
payload?: { payload?: {
...@@ -51,7 +53,9 @@ export default async function (action: sqliteAction): Promise<sqliteResult> { ...@@ -51,7 +53,9 @@ export default async function (action: sqliteAction): Promise<sqliteResult> {
case sqliteCmd.INIT: { case sqliteCmd.INIT: {
const info = action.initInfo; const info = action.initInfo;
if (info) { 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]); const [SQL, buffer] = await Promise.all([sqlPromise, dataPromise]);
YGODB = new SQL.Database(new Uint8Array(buffer)); YGODB = new SQL.Database(new Uint8Array(buffer));
......
...@@ -8,6 +8,7 @@ export const initStore = proxy({ ...@@ -8,6 +8,7 @@ export const initStore = proxy({
}, },
decks: false, decks: false,
i18n: false, i18n: false,
wasm: false,
// ... // ...
reset() {}, reset() {},
} satisfies NeosStore); } satisfies NeosStore);
...@@ -10,10 +10,20 @@ ...@@ -10,10 +10,20 @@
.logo-container { .logo-container {
align-items: center; align-items: center;
height: min-content; height: min-content;
padding: 5px 10px;
background-color: hsl(0, 0%, 100%, 0);
transition: 0.2s;
border-radius: 20px;
.logo { .logo {
width: 60px; width: 60px;
filter: brightness(1.5);
transform: translateY(1px); transform: translateY(1px);
transition: 0.2s;
}
&:hover {
background-color: hsl(0, 0%, 100%, 0.9);
.logo {
filter: invert(1);
}
} }
} }
......
import { Avatar } from "antd"; import { Avatar } from "antd";
import { useEffect } from "react";
import { import {
type LoaderFunction, type LoaderFunction,
NavLink, NavLink,
...@@ -7,30 +8,35 @@ import { ...@@ -7,30 +8,35 @@ import {
} from "react-router-dom"; } from "react-router-dom";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import { CookieKeys, getCookie } from "@/api";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { accountStore, deckStore, initStore, type User } from "@/stores"; import { accountStore } from "@/stores";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
import { initSqlite } from "./utils"; import {
getLoginStatus,
handleSSOLogin,
initDeck,
initSqlite,
initWASM,
} from "./utils";
const NeosConfig = useConfig(); const NeosConfig = useConfig();
export const loader: LoaderFunction = async () => { export const loader: LoaderFunction = async () => {
const user = getCookie<User>(CookieKeys.USER); getLoginStatus();
if (user) accountStore.login(user); initDeck();
// 加载卡组 initSqlite();
if (!initStore.decks) initWASM();
deckStore.initialize().then(() => (initStore.decks = true));
// 加载ygodb
if (!initStore.sqlite.progress) {
initSqlite().then(() => (initStore.sqlite.progress = 1));
initStore.sqlite.progress = 0.01;
}
return null; return null;
}; };
export const Component = () => { export const Component = () => {
// 捕获SSO登录
const location = useLocation();
useEffect(() => {
location.search && handleSSOLogin(location.search);
}, [location.search]);
// TODO 根据是否登录,显示内容 // TODO 根据是否登录,显示内容
const { pathname } = useLocation(); const { pathname } = useLocation();
const pathnamesHideHeader = ["/waitroom"]; const pathnamesHideHeader = ["/waitroom"];
...@@ -45,11 +51,6 @@ export const Component = () => { ...@@ -45,11 +51,6 @@ export const Component = () => {
alt="NEOS" alt="NEOS"
/> />
</div> </div>
{/* <img
className={styles.logo}
src={`${NeosConfig.assetsPath}/neos-logo.svg`}
alt="NEOS"
/> */}
<NavLink to="/">主页</NavLink> <NavLink to="/">主页</NavLink>
<NavLink to="/match">匹配</NavLink> <NavLink to="/match">匹配</NavLink>
<NavLink to="/build">组卡</NavLink> <NavLink to="/build">组卡</NavLink>
......
import rustInit from "rust-src";
import { CookieKeys, getCookie, setCookie } from "@/api";
import { useConfig } from "@/config"; import { useConfig } from "@/config";
import { useEnv } from "@/hook";
import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite"; import sqliteMiddleWare, { sqliteCmd } from "@/middleware/sqlite";
import { initStore } from "@/stores"; import { accountStore, deckStore, initStore, type User } from "@/stores";
const { cardsDbUrl } = useConfig(); const { cardsDbUrl } = useConfig();
const { BASE_URL } = useEnv();
/** 加载ygodb */
export const initSqlite = async () => { export const initSqlite = async () => {
const { sqlite } = initStore; if (!initStore.sqlite.progress) {
sqlite.progress = 0.01; const { sqlite } = initStore;
await sqliteMiddleWare({ const progressCallback = (progress: number) =>
cmd: sqliteCmd.INIT, (sqlite.progress = progress * 0.9);
initInfo: { dbUrl: cardsDbUrl }, sqlite.progress = 0.01;
}); await sqliteMiddleWare({
sqlite.progress = 1; 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 { EditFilled, SettingFilled } from "@ant-design/icons";
import { Space } from "antd"; import { Space } from "antd";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { type LoaderFunction, useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { useSnapshot } from "valtio"; import { useSnapshot } from "valtio";
import { CookieKeys, setCookie } from "@/api";
import { useConfig } from "@/config"; 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 { Background, IconFont, Select } from "@/ui/Shared";
import styles from "./index.module.scss"; import styles from "./index.module.scss";
...@@ -14,17 +13,6 @@ import { MatchModal, matchStore } from "./MatchModal"; ...@@ -14,17 +13,6 @@ import { MatchModal, matchStore } from "./MatchModal";
import { ReplayModal, replayOpen } from "./ReplayModal"; import { ReplayModal, replayOpen } from "./ReplayModal";
import { init } from "./util"; 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(); const NeosConfig = useConfig();
export const Component: React.FC = () => { export const Component: React.FC = () => {
...@@ -150,8 +138,3 @@ const Mode: React.FC<{ ...@@ -150,8 +138,3 @@ const Mode: React.FC<{
<div className={styles.desc}>{desc}</div> <div className={styles.desc}>{desc}</div>
</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