Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update system #613

Merged
merged 1 commit into from
Dec 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 63 additions & 76 deletions src/hooks/useLocalProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ import { useProjectMetadata } from '@containers';
import { ProjectFieldsFragment, ProjectsOrderBy } from '@subql/network-query';
import { useGetProjectsLazyQuery } from '@subql/react-hooks';
import { notEmpty } from '@utils';
import { filterSuccessPromoiseSettledResult } from '@utils';
import { makeCacheKey } from '@utils/limitation';
import { waitForSomething } from '@utils/waitForSomething';
import { useInterval, useMount } from 'ahooks';
import { useMount } from 'ahooks';
import localforage from 'localforage';
import { uniqWith } from 'lodash-es';
import { cloneDeep } from 'lodash-es';

const cacheKey = makeCacheKey('localProjectWithMetadata');

type ProjectWithMetadata = { description: string; versionDescription: string; name: string } & ProjectFieldsFragment;

export const useLocalProjects = () => {
// this hooks want to do these things:
// 1. Get all projects order by order
Expand All @@ -35,66 +37,80 @@ export const useLocalProjects = () => {
});
const { getMetadataFromCid } = useProjectMetadata();

const projects = useRef<
({ description: string; versionDescription: string; name: string } & ProjectFieldsFragment)[]
>([]);
const projects = useRef<ProjectWithMetadata[]>([]);

const fetchAllProjects = async (length = 0) => {
try {
loading.current = true;
const fetchAllProjects = async (cachedProjects?: ProjectWithMetadata[], withLoading = true) => {
const innerFetch: (fetchedProjects: ProjectWithMetadata[]) => Promise<ProjectWithMetadata[]> = async (
fetchedProjects,
) => {
let tempProjects = cloneDeep(fetchedProjects) || [];

const res = await getProjects({
variables: {
offset: length,
orderBy: [ProjectsOrderBy.ID_ASC],
ids: [],
},
defaultOptions: {
fetchPolicy: 'network-only',
},
});

if (res.data?.projects?.nodes) {
const nonEmptyProjects = res.data.projects?.nodes.filter(notEmpty);
const allMetadata = await Promise.allSettled(nonEmptyProjects.map((i) => getMetadataFromCid(i.metadata)));
const projectsWithMetadata = nonEmptyProjects.map((project, index) => {
const rawMetadata = allMetadata[index];
const metadata =
rawMetadata.status === 'fulfilled'
? rawMetadata.value
: { name: '', description: '', versionDescription: '' };
return {
...project,
...metadata,
};
});
const mergered = uniqWith([...projects.current, ...projectsWithMetadata], (x, y) => x.id === y.id);
projects.current = mergered;
await localforage.setItem(cacheKey, mergered);
if (mergered.length >= res.data.projects.totalCount) {
loading.current = false;
return;
try {
if (withLoading) {
loading.current = true;
}

window.requestIdleCallback(() => fetchAllProjects(mergered.length));
const res = await getProjects({
variables: {
offset: tempProjects.length,
orderBy: [ProjectsOrderBy.ID_ASC],
ids: [],
},
defaultOptions: {
fetchPolicy: 'network-only',
},
});

if (res.data?.projects?.nodes) {
const nonEmptyProjects = res.data.projects?.nodes.filter(notEmpty);
const allMetadata = await Promise.allSettled(nonEmptyProjects.map((i) => getMetadataFromCid(i.metadata)));
const projectsWithMetadata = nonEmptyProjects.map((project, index) => {
const rawMetadata = allMetadata[index];
const metadata =
rawMetadata.status === 'fulfilled'
? rawMetadata.value
: { name: '', description: '', versionDescription: '' };
return {
...project,
...metadata,
};
});
const mergered = uniqWith([...tempProjects, ...projectsWithMetadata], (x, y) => x.id === y.id);
tempProjects = mergered;
if (mergered.length >= res.data.projects.totalCount) {
loading.current = false;
return tempProjects;
}

return await innerFetch(tempProjects);
}
} catch (e) {
setError(e);
loading.current = false;
return tempProjects;
}
} catch (e) {
setError(e);
loading.current = false;
}

return tempProjects;
};

const res = await innerFetch(cachedProjects || []);

projects.current = res;
await localforage.setItem(cacheKey, res);
};

const init = async () => {
// When first estiblish the local cache. We need to fetch all of it.
// See fetchAllProject. It's a low-priority(requestsIdleCallback) fetch
// if there have cache, just add & update metadata.
// if there have cache, use cache first, and then fetch from initial to update.
const cached = await localforage.getItem<
({ description: string; versionDescription: string; name: string } & ProjectFieldsFragment)[]
>(cacheKey);

if (cached) {
projects.current = cached;
fetchAllProjects(cached.length);
await fetchAllProjects(cached);
// update for next search
window.requestIdleCallback(() => fetchAllProjects([], false));
return;
}
fetchAllProjects();
Expand All @@ -119,39 +135,10 @@ export const useLocalProjects = () => {
};
};

const updateExistMetadata = async () => {
await waitForSomething({ func: () => !loading.current });
// IPFS can be cache. So fetch all of it would ok.
const allMetadata = await Promise.allSettled(
projects.current.map(async (i) => {
const data = await getMetadataFromCid(i.metadata);
return {
[i.id]: data,
};
}),
);
const successData = allMetadata.filter(filterSuccessPromoiseSettledResult);

const newProjectsData = projects.current.map((i) => {
const find = successData.find((x) => x.value[i.id]);
return {
...i,
...find,
};
});
await localforage.setItem(cacheKey, newProjectsData);

projects.current = newProjectsData;
};

useMount(() => {
window.requestIdleCallback(() => init());
});

useInterval(() => {
window.requestIdleCallback(() => updateExistMetadata());
}, 60000);

return {
loading,
error,
Expand Down
Loading