Skip to content

Commit

Permalink
Refactor HocusPocus server configuration into its own file
Browse files Browse the repository at this point in the history
The HocusPocus server configuration and related database operations have been moved to a separate file, hocuspocus-server.js. This refactoring makes the main index.js more readable. Furthermore, in the frontend, the editor document is now initialized with a new Y.Doc().
  • Loading branch information
claygorman committed Dec 20, 2023
1 parent fe7f768 commit 9066c74
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 110 deletions.
111 changes: 2 additions & 109 deletions backend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ import processRequest from 'graphql-upload/processRequest.mjs';
import { minioClient } from './services/minio-client.js';
import fastifyIO from 'fastify-socket.io';
import { socketInit } from './socket/index.js';
import { Server } from '@hocuspocus/server';
import { fastifyWebsocket } from '@fastify/websocket';
import { Database } from '@hocuspocus/extension-database';
import hocuspocusServer from './services/hocuspocus-server.js';

const fastify = Fastify({
logger: ENABLE_FASTIFY_LOGGING,
Expand Down Expand Up @@ -76,115 +75,9 @@ fastify.register(fastifyWebsocket, {
options: { maxPayload: 1048576 },
});

const hocuspocusServer = Server.configure({
port: HTTP_PORT,
address: '0.0.0.0',
extensions: [
new Database({
fetch: ({ documentName }) => {
return new Promise(async (resolve, reject) => {
const [entityType, entityId, entityField] = documentName.split('.');
console.log({ action: 'Fetching tiptap document', documentName, entityType, entityId, entityField });

if (entityType === 'issue' && entityField === 'description') {
let issue = null;

try {
issue = await db.sequelize.models.Issue.findOne({
where: {
id: entityId,
},
});
} catch (e) {
reject(e);
}

if (!issue || !issue?.descriptionRaw) resolve(null);

const descriptionAsUnit8Array = new Uint8Array(issue.descriptionRaw);
console.log({ descriptionAsUnit8Array, issue });
resolve(descriptionAsUnit8Array.length === 0 ? null : descriptionAsUnit8Array);
}

if (entityType === 'issueComment' && entityField === 'comment') {
const comment = await db.sequelize.models.IssueComment.findOne({
where: {
id: entityId,
},
});

if (!comment) resolve(null);

const commentAsUnit8Array = new Uint8Array(comment.commentRaw);
resolve(commentAsUnit8Array.length === 0 ? null : commentAsUnit8Array);
}

resolve(null);
});
},
store: async ({ documentName, state }) => {
const [entityType, entityId, entityField] = documentName.split('.');

if (entityType === 'issue' && entityField === 'description') {
await db.sequelize.models.Issue.update(
{
descriptionRaw: state,
},
{
where: {
id: entityId,
},
}
);
}

if (entityType === 'issueComment' && entityField === 'comment') {
await db.sequelize.models.IssueComment.update(
{
commentRaw: state,
},
{
where: {
id: entityId,
},
}
);
}
},
}),
],
// async onAuthenticate(data) {
// const { token } = data;
//
// if (!token) {
// console.warn('Throwing exception to tiptap user');
// throw new Error('Not authorized!');
// }
//
// const {
// data: { provider, sub },
// } = await axios.get(`${FRONTEND_HOSTNAME}/api/verify-jwt`, {
// headers: { Authorization: `Bearer ${token}` },
// });
//
// const externalId = `${provider}__${sub}`;
//
// const user = await db.sequelize.models.User.findOne({ where: { externalId } });
//
// return {
// user,
// };
// },
});

fastify.register(async function (fastify) {
fastify.get('/collaboration', { websocket: true }, (connection /* SocketStream */, req /* FastifyRequest */) => {
const context = {
user: {
id: 1234,
name: 'Jane',
},
};
const context = {};

hocuspocusServer.handleConnection(connection.socket, req, context);
});
Expand Down
107 changes: 107 additions & 0 deletions backend/src/services/hocuspocus-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { Server } from '@hocuspocus/server';
import { HTTP_PORT } from './config.js';
import { Database } from '@hocuspocus/extension-database';
import { db } from '../db/index.js';

const hocuspocusServer = Server.configure({
port: HTTP_PORT,
address: '0.0.0.0',
extensions: [
new Database({
fetch: ({ documentName }) => {
return new Promise(async (resolve, reject) => {
const [entityType, entityId, entityField] = documentName.split('.');
console.log({ action: 'Fetching tiptap document', documentName, entityType, entityId, entityField });

if (entityType === 'issue' && entityField === 'description') {
let issue = null;

try {
issue = await db.sequelize.models.Issue.findOne({
where: {
id: entityId,
},
});
} catch (e) {
reject(e);
}

if (!issue || !issue?.descriptionRaw) resolve(null);

const descriptionAsUnit8Array = new Uint8Array(issue.descriptionRaw);
console.log({ descriptionAsUnit8Array, issue });
resolve(descriptionAsUnit8Array.length === 0 ? null : descriptionAsUnit8Array);
}

if (entityType === 'issueComment' && entityField === 'comment') {
const comment = await db.sequelize.models.IssueComment.findOne({
where: {
id: entityId,
},
});

if (!comment) resolve(null);

const commentAsUnit8Array = new Uint8Array(comment.commentRaw);
resolve(commentAsUnit8Array.length === 0 ? null : commentAsUnit8Array);
}

resolve(null);
});
},
store: async ({ documentName, state }) => {
const [entityType, entityId, entityField] = documentName.split('.');

if (entityType === 'issue' && entityField === 'description') {
await db.sequelize.models.Issue.update(
{
descriptionRaw: state,
},
{
where: {
id: entityId,
},
}
);
}

if (entityType === 'issueComment' && entityField === 'comment') {
await db.sequelize.models.IssueComment.update(
{
commentRaw: state,
},
{
where: {
id: entityId,
},
}
);
}
},
}),
],
// async onAuthenticate(data) {
// const { token } = data;
//
// if (!token) {
// console.warn('Throwing exception to tiptap user');
// throw new Error('Not authorized!');
// }
//
// const {
// data: { provider, sub },
// } = await axios.get(`${FRONTEND_HOSTNAME}/api/verify-jwt`, {
// headers: { Authorization: `Bearer ${token}` },
// });
//
// const externalId = `${provider}__${sub}`;
//
// const user = await db.sequelize.models.User.findOne({ where: { externalId } });
//
// return {
// user,
// };
// },
});

export default hocuspocusServer;
3 changes: 2 additions & 1 deletion frontend/components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { getUserColor } from '@/services/utils';
import { classNames } from '@/services/utils';
import axios from 'axios';
export * as EditorRenderOnly from './EditorRenderOnly';
import * as Y from 'yjs';

const getToken = async () => {
const { data } = await axios.get(`${PUBLIC_NEXTAUTH_URL}/api/get-jwt`);
Expand Down Expand Up @@ -86,7 +87,7 @@ const Editor = ({
: 'ws'
}://${new URL(`${NEXT_PUBLIC_API_URL}`).host}/collaboration`,
name: documentName ?? 'default-document',
// document: new Y.Doc(),
document: new Y.Doc(),
token: getToken,
onConnect: () => setConnected(true),
onDisconnect: () => setConnected(false),
Expand Down

0 comments on commit 9066c74

Please sign in to comment.