Skip to content

Commit

Permalink
update partykit server, persist to db
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerc99 committed Aug 12, 2024
1 parent ea98398 commit 4365620
Show file tree
Hide file tree
Showing 4 changed files with 374 additions and 206 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ dist-ssr

# dev persisted state
.partykit

# secrets
.env
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@
},
"dependencies": {
"@playhtml/react": "^0.3.2",
"@supabase/supabase-js": "^2.45.1",
"canvas-confetti": "^1.9.2",
"partykit": "0.0.79",
"partykit": "0.0.108",
"profane-words": "^1.5.11",
"randomcolor": "^0.6.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"y-partykit": "0.0.21"
"y-partykit": "0.0.31",
"yjs": "^13.6.18"
}
}
93 changes: 69 additions & 24 deletions partykit/party.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,84 @@
import type * as Party from "partykit/server";
import { onConnect } from "y-partykit";
import { createClient } from "@supabase/supabase-js";
import { Buffer } from "node:buffer";
import * as Y from "yjs";

export default class PlayServer implements Party.Server {
constructor(public room: Party.Room) {}
async onRequest(req: Party.Request) {
const parsedUrl = new URL(req.url);
if (req.method === "GET" && parsedUrl.searchParams.has("dump")) {
const data = await this.room.storage.list();
const items = [...data.entries()].map(([key, value]) => [
key,
// @ts-ignore
[...value],
]);
return new Response(JSON.stringify(items));
}
// Create a single supabase client for interacting with your database
const supabase = createClient(
process.env.SUPABASE_URL as string,
process.env.SUPABASE_KEY as string,
{ auth: { persistSession: false } }
);

return new Response("Not found");
}
export default class implements Party.Server {
constructor(public room: Party.Room) {}

onMessage(
async onMessage(
message: string | ArrayBuffer | ArrayBufferView,
sender: Party.Connection<unknown>
): void | Promise<void> {
): Promise<void> {
if (typeof message === "string") {
this.room.broadcast(message);
}
}
async onConnect(ws: Party.Connection<unknown>) {
// optionally look for events here to filter out valid ones?
return await onConnect(ws, this.room, {
persist: {
mode: "snapshot",

async onConnect(connection: Party.Connection) {
const room = this.room;

await onConnect(connection, this.room, {
async load() {
// This is called once per "room" when the first user connects

// Let's make a Yjs document
const doc = new Y.Doc();

// Load the document from the database
const { data, error } = await supabase
.from("documents")
.select("document")
.eq("name", room.id)
.maybeSingle();

if (error) {
throw new Error(error.message);
}

if (data) {
// If the document exists on the database,
// apply it to the Yjs document
Y.applyUpdate(
doc,
new Uint8Array(Buffer.from(data.document, "base64"))
);
}

// Return the Yjs document
return doc;
},
callback: {
handler: async (doc) => {
// This is called every few seconds if the document has changed

// convert the Yjs document to a Uint8Array
const content = Y.encodeStateAsUpdate(doc);

// Save the document to the database
const { data: _data, error } = await supabase
.from("documents")
.upsert(
{
name: room.id,
document: Buffer.from(content).toString("base64"),
},
{ onConflict: "name" }
);

if (error) {
console.error("failed to save:", error);
}
},
},
});
}
}

PlayServer satisfies Party.Worker;
Loading

0 comments on commit 4365620

Please sign in to comment.