Skip to content

Commit

Permalink
made feed ordering better
Browse files Browse the repository at this point in the history
  • Loading branch information
DeepDoge committed Nov 18, 2024
1 parent 523d6fe commit 0b9c7b0
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 53 deletions.
10 changes: 5 additions & 5 deletions project/app/src/features/feed/Feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export namespace Feed {
limit: number;
indexers: Feed.Indexer[];
};
export type Direction = {
export type Order = {
indexIterator(length: bigint): Iterator<bigint, void, unknown>;
isCandidateOfOtherSourceBetter(candidatePost: Post, selectedPost: Post): boolean;
};
Expand Down Expand Up @@ -64,9 +64,9 @@ export class Feed {

public async *iter(params: {
config: Config;
direction: Feed.Direction;
order: Feed.Order;
}): AsyncIterator<Post[], void, unknown> {
const { config, direction } = params;
const { config, order } = params;

const sources = await Promise.allSettled(
this.indexers.map(async (indexer) => {
Expand All @@ -81,7 +81,7 @@ export class Feed {
provider,
indexerContract,
length,
indexIterator: direction.indexIterator(length),
indexIterator: order.indexIterator(length),
queue: [] as Post[],
};
}),
Expand Down Expand Up @@ -143,7 +143,7 @@ export class Feed {
continue;
}

if (direction.isCandidateOfOtherSourceBetter(candidatePost, selectedPost)) {
if (order.isCandidateOfOtherSourceBetter(candidatePost, selectedPost)) {
selectedSource = candidateSource;
continue;
}
Expand Down
10 changes: 7 additions & 3 deletions project/app/src/features/feed/components/FeedScroller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { computed, fragment, ref, tags } from "@purifyjs/core";
import { Feed } from "~/features/feed/Feed";
import { randomNoAlloc } from "~/features/feed/feedDirections";
import { PostView } from "~/features/post/PostView";
import { config } from "~/shared/config";
import { ArrowDownSvg } from "~/shared/svgs/ArrowDownSvg";
Expand All @@ -10,7 +9,9 @@ import { useOnVisible } from "~/shared/utils/effects/useOnVisible";

const { ul, li, section, button } = tags;

export function FeedScroller(feed: Feed) {
export function FeedScroller(params: { feed: Feed; preferDirection: Feed.Order }) {
const { feed, preferDirection } = params;

const host = section()
.effect(useScope(FeedScrollerCss))
.effect(() => {
Expand Down Expand Up @@ -69,7 +70,10 @@ export function FeedScroller(feed: Feed) {

try {
refresing.val = true;
nextGenerator = feed.iter({ config: config.val, direction: randomNoAlloc("newer") });
nextGenerator = feed.iter({
config: config.val,
order: preferDirection,
});
await loadNext({ clear: true });
} catch (error) {
console.error(error);
Expand Down
6 changes: 5 additions & 1 deletion project/app/src/features/feed/components/PostThread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { tags } from "@purifyjs/core";
import { FeedForm } from "~/features/feed/components/FeedForm";
import { FeedScroller } from "~/features/feed/components/FeedScroller";
import { Feed } from "~/features/feed/Feed";
import { orderRandom } from "~/features/feed/feedDirections";
import { Post } from "~/features/post/Post";
import { PostView } from "~/features/post/PostView";
import { config } from "~/shared/config";
Expand All @@ -21,7 +22,10 @@ export function PostThread(post: Post) {
.children(
strong().textContent("Replies"),
repliesFeed.derive((repliesFeed) =>
FeedScroller(repliesFeed).effect(usePart("scroller")),
FeedScroller({
feed: repliesFeed,
preferDirection: orderRandom("newer"),
}).effect(usePart("scroller")),
),
),
repliesFeed.derive((repliesFeed) => FeedForm([repliesFeed.id]).effect(usePart("form"))),
Expand Down
47 changes: 4 additions & 43 deletions project/app/src/features/feed/feedDirections.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Feed } from "~/features/feed/Feed";
import { fractalHash } from "~/shared/math/fractalHash";

export function asc(): Feed.Direction {
export function orderOlder(): Feed.Order {
return {
*indexIterator(length) {
for (let n = 0n; n < length; n++) {
Expand All @@ -13,7 +14,7 @@ export function asc(): Feed.Direction {
};
}

export function desc(): Feed.Direction {
export function orderNewer(): Feed.Order {
return {
*indexIterator(length) {
for (let n = 0n; n < length; n++) {
Expand All @@ -26,47 +27,7 @@ export function desc(): Feed.Direction {
};
}

export function random(prefer: "newer" | "older"): Feed.Direction {
return {
*indexIterator(length) {
// create the pool of indices
const pool = Array.from({ length: Number(length) }, (_, i) => BigInt(i));

// Fisher-Yates shuffle to randomize the pool
for (let i = pool.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[pool[i]!, pool[j]!] = [pool[j]!, pool[i]!];
}

// yield indices from the shuffled pool
for (const index of pool) {
yield index;
}
},
isCandidateOfOtherSourceBetter(candidatePost, selectedPost) {
if (prefer === "newer") {
return candidatePost.createdAt < selectedPost.createdAt;
}

if (prefer === "older") {
return candidatePost.createdAt > selectedPost.createdAt;
}

prefer satisfies never;
throw new Error(`Unknown 'prefer' option: ${prefer}`);
},
};
}

export function randomNoAlloc(prefer: "newer" | "older"): Feed.Direction {
// Simple hash function to apply deterministic randomness using only bigint
function fractalHash(n: bigint, seed: bigint) {
let x = n ^ seed; // XOR the seed with the index (as a bigint)
x = (x * 0x517cc1b727220a95n) & 0xffffffffffffffffn; // Multiply and truncate, still as bigint
x = (x ^ (x >> 32n)) & 0xffffffffffffffffn; // XOR and shift for more randomness
return x;
}

export function orderRandom(prefer: "newer" | "older"): Feed.Order {
return {
*indexIterator(length) {
const seed = BigInt(crypto.getRandomValues(new Uint32Array(1))[0]!);
Expand Down
5 changes: 4 additions & 1 deletion project/app/src/features/profile/ProfileView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { tags } from "@purifyjs/core";
import { FeedForm } from "~/features/feed/components/FeedForm";
import { FeedScroller } from "~/features/feed/components/FeedScroller";
import { Feed } from "~/features/feed/Feed";
import { orderNewer } from "~/features/feed/feedDirections";
import { Address } from "~/shared/schemas/primatives";
import { css, useScope } from "~/shared/utils/css";
import { usePart } from "~/shared/utils/effects/usePart";
Expand All @@ -14,7 +15,9 @@ export function ProfileView(params: { address: Address; postsFeed: Feed }) {
return div()
.effect(useScope(ProfileViewCss))
.children(
div({ class: "content" }).children(FeedScroller(postsFeed)),
div({ class: "content" }).children(
FeedScroller({ feed: postsFeed, preferDirection: orderNewer() }),
),
FeedForm([postsFeed.id]).effect(usePart("form")),
);
}
Expand Down
6 changes: 6 additions & 0 deletions project/app/src/shared/math/fractalHash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function fractalHash(n: bigint, seed: bigint) {
let x = n ^ seed; // XOR the seed with the index (as a bigint)
x = (x * 0x517cc1b727220a95n) & 0xffffffffffffffffn; // Multiply and truncate, still as bigint
x = (x ^ (x >> 32n)) & 0xffffffffffffffffn; // XOR and shift for more randomness
return x;
}

0 comments on commit 0b9c7b0

Please sign in to comment.