Improve marking performance

This commit is contained in:
Kuba Orlik 2021-11-21 23:00:55 +01:00
parent 25cd2c2a0c
commit 3eb5dc6f9d
3 changed files with 69 additions and 29 deletions

View File

@ -1,8 +1,13 @@
import React from "react"; import React from "react";
import { getMemory } from "../memory"; import { getMemory } from "../memory";
import { MergedStolenDataEntry, Sources } from "../stolen-data-entry"; import { RequestCluster } from "../request-cluster";
import {
MergedStolenDataEntry,
Sources,
StolenDataEntry,
} from "../stolen-data-entry";
import { hyphenate } from "../util"; import { hyphenate, useEmitter } from "../util";
const MAX_STRING_VALUE_LENGTH = 100; const MAX_STRING_VALUE_LENGTH = 100;
@ -51,6 +56,7 @@ function StolenDataValue({
entry: MergedStolenDataEntry; entry: MergedStolenDataEntry;
prefixKey?: string; prefixKey?: string;
}) { }) {
const [version] = useEmitter(entry);
const value = entry.getParsedValues(prefixKey)[0]; const value = entry.getParsedValues(prefixKey)[0];
let body = null; let body = null;
if (!value) { if (!value) {
@ -64,6 +70,7 @@ function StolenDataValue({
? "2px solid red" ? "2px solid red"
: "2px solid transparent", : "2px solid transparent",
}} }}
data-version={version}
> >
{content.slice(0, MAX_STRING_VALUE_LENGTH)}{" "} {content.slice(0, MAX_STRING_VALUE_LENGTH)}{" "}
{content.length > MAX_STRING_VALUE_LENGTH ? "(...)" : ""} {content.length > MAX_STRING_VALUE_LENGTH ? "(...)" : ""}
@ -92,6 +99,38 @@ const icons: Record<Sources, string> = {
header: "H", header: "H",
}; };
function StolenDataRow({
entry,
cluster,
}: {
entry: MergedStolenDataEntry;
cluster: RequestCluster;
}) {
const [version] = useEmitter(entry);
return (
<tr
key={origin + cluster.id + entry.getUniqueKey()}
data-key={origin + cluster.id + entry.getUniqueKey()}
data-version={version}
>
<th
style={{
width: "100px",
overflowWrap: "anywhere",
border: entry.hasMark("") ? "2px solid red" : "2px solid transparent",
}}
onClick={() => entry.toggleMark("")}
>
{entry.getNames().map(hyphenate).join(", ")}
</th>
<td>{entry.getSources().map((source) => icons[source])}</td>
<td style={{ wordWrap: "anywhere" as any }}>
<StolenDataValue entry={entry} />
</td>
</tr>
);
}
export default function StolenDataCluster({ export default function StolenDataCluster({
origin, origin,
shorthost, shorthost,
@ -130,27 +169,13 @@ export default function StolenDataCluster({
{cluster {cluster
.getStolenData({ minValueLength, cookiesOnly, cookiesOrOriginOnly }) .getStolenData({ minValueLength, cookiesOnly, cookiesOrOriginOnly })
.map((entry) => ( .map((entry) => (
<tr <StolenDataRow
key={origin + cluster.id + entry.getUniqueKey()} {...{
data-key={origin + cluster.id + entry.getUniqueKey()} entry,
> cluster,
<th key: origin + cluster.id + entry.getUniqueKey(),
style={{
width: "100px",
overflowWrap: "anywhere",
border: entry.hasMark("")
? "2px solid red"
: "2px solid transparent",
}} }}
onClick={() => entry.toggleMark("")} />
>
{entry.getNames().map(hyphenate).join(", ")}
</th>
<td>{entry.getSources().map((source) => icons[source])}</td>
<td style={{ wordWrap: "anywhere" as any }}>
<StolenDataValue entry={entry} />
</td>
</tr>
))} ))}
</tbody> </tbody>
</table> </table>

View File

@ -1,7 +1,7 @@
import { TCModel } from "@iabtcf/core"; import { TCModel } from "@iabtcf/core";
import { EventEmitter } from "events";
import ExtendedRequest, { HAREntry } from "./extended-request"; import ExtendedRequest, { HAREntry } from "./extended-request";
import Mark from "./mark"; import Mark from "./mark";
import { getMemory } from "./memory";
import { import {
getshorthost, getshorthost,
isJSONObject, isJSONObject,
@ -29,7 +29,7 @@ const id = (function* id() {
} }
})(); })();
export class StolenDataEntry { export class StolenDataEntry extends EventEmitter {
public isIAB = false; public isIAB = false;
public iab: TCModel | null = null; public iab: TCModel | null = null;
public id: number; public id: number;
@ -47,6 +47,7 @@ export class StolenDataEntry {
// // console.log(this.iab); // // console.log(this.iab);
// this.isIAB = true; // this.isIAB = true;
// } catch (e) {} // } catch (e) {}
super();
this.id = id.next().value as number; this.id = id.next().value as number;
this.classification = this.classify(); this.classification = this.classify();
} }
@ -127,7 +128,7 @@ export class StolenDataEntry {
addMark(key: string) { addMark(key: string) {
this.marks.push(new Mark(this, key)); this.marks.push(new Mark(this, key));
getMemory().emit("change", true); // to trigger rerender this.emit("change");
} }
hasMark(key?: string) { hasMark(key?: string) {
@ -140,7 +141,7 @@ export class StolenDataEntry {
removeMark(key: string) { removeMark(key: string) {
this.marks = this.marks.filter((mark) => mark.key != key); this.marks = this.marks.filter((mark) => mark.key != key);
getMemory().emit("change", true); // to trigger rerender this.emit("change");
} }
toggleMark(key: string) { toggleMark(key: string) {
@ -194,8 +195,9 @@ export class StolenDataEntry {
} }
} }
export class MergedStolenDataEntry { export class MergedStolenDataEntry extends EventEmitter {
constructor(public entries: StolenDataEntry[]) { constructor(public entries: StolenDataEntry[]) {
super();
const all_marks = unique( const all_marks = unique(
entries.map((entry) => entry.marks).reduce(reduceConcat, []) entries.map((entry) => entry.marks).reduce(reduceConcat, [])
); );
@ -205,6 +207,20 @@ export class MergedStolenDataEntry {
// getMemory().emit("change"); // to trigger render // getMemory().emit("change"); // to trigger render
} }
on(event: string, listener: () => void) {
for (const entry of this.entries) {
entry.on(event, listener);
}
return this;
}
removeListener(event: string, listener: () => void) {
for (const entry of this.entries) {
entry.removeListener(event, listener);
}
return this;
}
hasValue(value: string) { hasValue(value: string) {
return this.entries.some((entry) => entry.value === value); return this.entries.some((entry) => entry.value === value);
} }

View File

@ -1,6 +1,5 @@
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { Dispatch, SetStateAction, useEffect, useState } from "react";
import Memory from "./memory";
export type Unpromisify<T> = T extends Promise<infer R> ? R : T; export type Unpromisify<T> = T extends Promise<infer R> ? R : T;
export type Unarray<T> = T extends Array<infer R> ? R : T; export type Unarray<T> = T extends Array<infer R> ? R : T;