Fixed batching problem

main
jaxoncreed 2 years ago
parent 5acfea4c43
commit c0c8eb6afb
  1. 4
      packages/demo-react/src/App.tsx
  2. 10
      packages/demo-react/src/Header.tsx
  3. 41
      packages/demo-react/src/Layout.tsx
  4. 34
      packages/demo-react/src/profile/Profile.tsx
  5. 8
      packages/solid/src/requester/LeafRequester.ts
  6. 20
      packages/solid/src/requester/requests/updateDataResource.ts
  7. 9
      packages/solid/src/util/RequestBatcher.ts

@ -1,12 +1,12 @@
import type { FunctionComponent } from "react";
import React from "react";
import { Layout } from "./Layout";
import { Router } from "./Layout";
import { BrowserSolidLdoProvider } from "@ldo/solid-react";
const ProfileApp: FunctionComponent = () => {
return (
<BrowserSolidLdoProvider>
<Layout />
<Router />
</BrowserSolidLdoProvider>
);
};

@ -3,6 +3,7 @@ import type { FunctionComponent } from "react";
import React from "react";
import { useResource, useSolidAuth, useSubject } from "@ldo/solid-react";
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes";
import { Link } from "react-router-dom";
const DEFAULT_ISSUER = "https://solidweb.me";
@ -27,7 +28,8 @@ export const Header: FunctionComponent = () => {
const [issuer, setIssuer] = useState(DEFAULT_ISSUER);
const { login, signUp, session } = useSolidAuth();
return (
<header style={{ display: "flex" }}>
<header>
<div style={{ display: "flex" }}>
{session.isLoggedIn ? (
<LoggedInHeader webId={session.webId!} />
) : (
@ -41,6 +43,12 @@ export const Header: FunctionComponent = () => {
<button onClick={() => signUp(issuer)}>Sign Up</button>
</>
)}
</div>
<p>
<Link to="/">Blog</Link>
{" "}
<Link to="/profile">Profile</Link>
</p>
</header>
);
};

@ -1,13 +1,30 @@
import { useSolidAuth } from "@ldo/solid-react";
import React from "react";
import React, { Fragment } from "react";
import type { FunctionComponent } from "react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { createBrowserRouter, Outlet, RouterProvider } from "react-router-dom";
import { Blog } from "./blog/Blog";
import { PostPage } from "./post/PostPage";
import { Header } from "./Header";
import { MainContainerProvider } from "./MainContainerProvider";
import { Profile } from "./profile/Profile";
export const Layout: FunctionComponent = () => {
const { session } = useSolidAuth();
return (
<div>
<Header />
<hr />
<MainContainerProvider>
{session.isLoggedIn ? <Outlet /> : <Fragment />}
</MainContainerProvider>
</div>
);
};
const router = createBrowserRouter([
{
element: <Layout />,
children: [
{
path: "/",
element: <Blog />,
@ -16,20 +33,18 @@ const router = createBrowserRouter([
path: "/media/:uri",
element: <PostPage />,
},
{
path: "/profile",
element: <Profile />,
},
],
},
]);
export const Layout: FunctionComponent = () => {
const { session, ranInitialAuthCheck } = useSolidAuth();
export const Router: FunctionComponent = () => {
const { ranInitialAuthCheck } = useSolidAuth();
if (!ranInitialAuthCheck) {
return <p>Loading</p>;
}
return (
<div>
<Header />
<hr />
<MainContainerProvider>
{session.isLoggedIn ? <RouterProvider router={router} /> : undefined}
</MainContainerProvider>
</div>
);
return <RouterProvider router={router} />;
};

@ -0,0 +1,34 @@
import {
useLdo,
useResource,
useSolidAuth,
useSubject,
} from "@ldo/solid-react";
import type { ChangeEvent } from "react";
import React, { useCallback, type FunctionComponent } from "react";
import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes";
export const Profile: FunctionComponent = () => {
const { session } = useSolidAuth();
const profile = useSubject(SolidProfileShapeShapeType, session.webId);
const webIdResource = useResource(session.webId);
const { changeData, commitData } = useLdo();
const onNameChange = useCallback(
async (e: ChangeEvent<HTMLInputElement>) => {
if (profile && webIdResource) {
const cProfile = changeData(profile, webIdResource);
cProfile.fn = e.target.value;
await commitData(cProfile);
}
},
[profile, webIdResource],
);
return (
<>
<label>Name</label>
<input type="text" value={profile?.fn || ""} onChange={onNameChange} />
</>
);
};

@ -56,12 +56,18 @@ export class LeafRequester extends Requester {
async updateDataResource(
changes: DatasetChanges<Quad>,
): Promise<UpdateResult> {
const transaction = this.context.solidLdoDataset.startTransaction();
transaction.addAll(changes.added || []);
changes.removed?.forEach((quad) => transaction.delete(quad));
// Commit data optimistically
transaction.commit();
const result = await this.requestBatcher.queueProcess({
name: UPDATE_KEY,
args: [
this.uri,
changes,
{ fetch: this.context.fetch, dataset: this.context.solidLdoDataset },
{ fetch: this.context.fetch, onRollback: () => transaction.rollback() },
],
perform: updateDataResource,
modifyQueue: (queue, isLoading, [, changes]) => {

@ -1,9 +1,5 @@
import type { DatasetChanges } from "@ldo/rdf-utils";
import { changesToSparqlUpdate } from "@ldo/rdf-utils";
import type {
SubscribableDataset,
TransactionalDataset,
} from "@ldo/subscribable-dataset";
import type { Quad } from "@rdfjs/types";
import { guaranteeFetch } from "../../util/guaranteeFetch";
import type { LeafUri } from "../../util/uriTypes";
@ -19,19 +15,11 @@ export type UpdateResultError = HttpErrorResultType | UnexpectedResourceError;
export async function updateDataResource(
uri: LeafUri,
datasetChanges: DatasetChanges<Quad>,
options?: BasicRequestOptions & { dataset?: SubscribableDataset<Quad> },
options?: BasicRequestOptions & { onRollback?: () => void },
): Promise<UpdateResult> {
try {
const fetch = guaranteeFetch(options?.fetch);
// Put Changes in transactional dataset
let transaction: TransactionalDataset<Quad> | undefined;
if (options?.dataset) {
transaction = options.dataset.startTransaction();
transaction.addAll(datasetChanges.added || []);
datasetChanges.removed?.forEach((quad) => transaction!.delete(quad));
// Commit data optimistically
transaction.commit();
}
// Make request
const sparqlUpdate = await changesToSparqlUpdate(datasetChanges);
const response = await fetch(uri, {
@ -44,8 +32,8 @@ export async function updateDataResource(
const httpError = HttpErrorResult.checkResponse(uri, response);
if (httpError) {
// Handle error rollback
if (transaction) {
transaction.rollback();
if (options?.onRollback) {
options.onRollback();
}
return httpError;
}

@ -66,11 +66,14 @@ export class RequestBatcher {
const timeSinceLastTrigger = Date.now() - lastRequestTimestamp;
const triggerProcess = async () => {
this.isWaiting = false;
if (this.isWaiting) {
return;
}
this.lastRequestTimestampMap[processName] = Date.now();
this.lastRequestTimestampMap[ANY_KEY] = Date.now();
const processToTrigger = this.processQueue.shift();
if (processToTrigger) {
this.isWaiting = true;
try {
const returnValue = await processToTrigger.perform(
...processToTrigger.args,
@ -83,6 +86,7 @@ export class RequestBatcher {
callback(err);
});
}
this.isWaiting = false;
// Reset loading
if (
@ -101,8 +105,7 @@ export class RequestBatcher {
}
};
if (timeSinceLastTrigger < this.batchMillis && !this.isWaiting) {
this.isWaiting = true;
if (timeSinceLastTrigger < this.batchMillis) {
setTimeout(triggerProcess, this.batchMillis - timeSinceLastTrigger);
} else {
triggerProcess();

Loading…
Cancel
Save