Skip to content

Commit 5677a41

Browse files
authored
major refactor: on switching to a local cmd app (#560)
1 parent 2f93316 commit 5677a41

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+13511
-13048
lines changed

apps/desktop-api/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@
1111
"dependencies": {
1212
"@apollo/client": "^3.7.1",
1313
"@codepod/prisma": "workspace:*",
14+
"@codepod/yjs": "workspace:^",
1415
"@kubernetes/client-node": "^0.17.1",
1516
"@prisma/client": "4.3.1",
1617
"apollo-server": "^3.5.0",
1718
"apollo-server-core": "^3.10.3",
1819
"apollo-server-express": "3.10.2",
1920
"bcryptjs": "^2.4.3",
21+
"cors": "^2.8.5",
2022
"dockerode": "^3.3.1",
2123
"express": "^4.18.2",
2224
"google-auth-library": "^8.7.0",

apps/desktop-api/src/run.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
import { startServer } from "./server";
22

3-
startServer({ port: 4001 });
3+
startServer({ port: 4000 });

apps/desktop-api/src/server.ts

Lines changed: 32 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1,42 @@
11
import express from "express";
22
import http from "http";
3-
import fs from "fs";
3+
import { WebSocketServer } from "ws";
44

5-
import { ApolloServer, gql } from "apollo-server-express";
5+
import { createSetupWSConnection } from "@codepod/yjs";
6+
import { bindState, writeState } from "./yjs-blob";
67

7-
import { ApolloServerPluginLandingPageLocalDefault } from "apollo-server-core";
8-
9-
import { customAlphabet } from "nanoid/async";
10-
import { lowercase, numbers } from "nanoid-dictionary";
11-
12-
const nanoid = customAlphabet(lowercase + numbers, 20);
13-
14-
export const typeDefs = gql`
15-
type User {
16-
id: ID!
17-
username: String
18-
email: String!
19-
password: String!
20-
firstname: String!
21-
lastname: String!
22-
}
23-
24-
type Repo {
25-
id: ID!
26-
name: String
27-
userId: ID!
28-
stargazers: [User]
29-
collaborators: [User]
30-
public: Boolean
31-
createdAt: String
32-
updatedAt: String
33-
accessedAt: String
34-
}
35-
36-
type Query {
37-
hello: String
38-
me: User
39-
repo(id: String!): Repo
40-
getDashboardRepos: [Repo]
41-
}
42-
43-
type Mutation {
44-
world: String
45-
createRepo: Repo
46-
updateRepo(id: ID!, name: String!): Boolean
47-
deleteRepo(id: ID!): Boolean
48-
star(repoId: ID!): Boolean
49-
unstar(repoId: ID!): Boolean
50-
}
51-
`;
52-
53-
const CODEPOD_ROOT = "/var/codepod";
54-
const repoDirs = `${CODEPOD_ROOT}/repos`;
55-
56-
export const resolvers = {
57-
Query: {
58-
hello: () => {
59-
return "Hello world!";
60-
},
61-
// TODO Dummy Data
62-
me: () => {
63-
return {
64-
id: "localUser",
65-
username: "localUser",
66-
email: "",
67-
firstname: "Local",
68-
lastname: "User",
69-
};
70-
},
71-
getDashboardRepos: () => {
72-
if (!fs.existsSync(repoDirs)) fs.mkdirSync(repoDirs);
73-
// list folders in repoDirs
74-
const dirs = fs.readdirSync(repoDirs);
75-
// read meta data from dirs
76-
const repos = dirs.map((dir) => {
77-
const meta = JSON.parse(
78-
fs.readFileSync(`${repoDirs}/${dir}/meta.json`, "utf8")
79-
);
80-
return {
81-
id: meta.id,
82-
name: meta.name,
83-
userId: meta.userId,
84-
stargazers: (meta.stargazers || []).map((id) => ({ id })),
85-
collaborators: [],
86-
public: meta.public,
87-
createdAt: meta.createdAt,
88-
updatedAt: meta.updatedAt,
89-
accessedAt: meta.accessedAt,
90-
};
91-
});
92-
return repos;
93-
},
94-
repo: (_, { id }) => {
95-
// read meta data from dirs
96-
const meta = JSON.parse(
97-
fs.readFileSync(`${repoDirs}/${id}/meta.json`, "utf8")
98-
);
99-
// update the accessedAt time
100-
meta.accessedAt = new Date().getTime();
101-
fs.writeFileSync(`${repoDirs}/${id}/meta.json`, JSON.stringify(meta));
102-
return {
103-
id: meta.id,
104-
name: meta.name,
105-
userId: meta.userId,
106-
stargazers: (meta.stargazers || []).map((id) => ({ id })),
107-
collaborators: [],
108-
public: meta.public,
109-
createdAt: meta.createdAt,
110-
updatedAt: meta.updatedAt,
111-
accessedAt: meta.accessedAt,
112-
};
113-
},
114-
},
115-
Mutation: {
116-
world: () => {
117-
return "World!";
118-
},
119-
// TODO fill APIs
120-
createRepo: async () => {
121-
const id = await nanoid();
122-
// Integer representing the number of milliseconds that have elapsed since the Unix epoch.
123-
const time = new Date().getTime();
124-
const meta = {
125-
id,
126-
name: null,
127-
userId: "localUser",
128-
public: false,
129-
stargazers: [],
130-
collaborators: [],
131-
createdAt: time,
132-
updatedAt: time,
133-
accessedAt: time,
134-
};
135-
if (!fs.existsSync(repoDirs)) fs.mkdirSync(repoDirs);
136-
fs.mkdirSync(`${repoDirs}/${id}`);
137-
fs.writeFileSync(`${repoDirs}/${id}/meta.json`, JSON.stringify(meta));
138-
return meta;
139-
},
140-
updateRepo: (_, { id, name }) => {
141-
const meta = JSON.parse(
142-
fs.readFileSync(`${repoDirs}/${id}/meta.json`, "utf8")
143-
);
144-
meta.name = name;
145-
fs.writeFileSync(`${repoDirs}/${id}/meta.json`, JSON.stringify(meta));
146-
return true;
147-
},
148-
deleteRepo: (_, { id }) => {
149-
fs.rmdirSync(`${repoDirs}/${id}`, { recursive: true });
150-
return true;
151-
},
152-
star: (_, { repoId }) => {
153-
const meta = JSON.parse(
154-
fs.readFileSync(`${repoDirs}/${repoId}/meta.json`, "utf8")
155-
);
156-
meta.stargazers = ["localUser"];
157-
fs.writeFileSync(`${repoDirs}/${repoId}/meta.json`, JSON.stringify(meta));
158-
return true;
159-
},
160-
unstar: (_, { repoId }) => {
161-
const meta = JSON.parse(
162-
fs.readFileSync(`${repoDirs}/${repoId}/meta.json`, "utf8")
163-
);
164-
meta.stargazers = [];
165-
fs.writeFileSync(`${repoDirs}/${repoId}/meta.json`, JSON.stringify(meta));
166-
return true;
167-
},
168-
},
169-
};
8+
import cors from "cors";
1709

17110
export async function startServer({ port }) {
172-
const apollo = new ApolloServer({
173-
typeDefs,
174-
resolvers,
175-
plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })],
11+
const app = express();
12+
app.use(express.json({ limit: "20mb" }));
13+
// support cors
14+
app.use(cors());
15+
// serve static files generated from UI
16+
app.use(express.static("../../packages/ui/dist"));
17+
18+
const http_server = http.createServer(app);
19+
20+
// Yjs websocket
21+
const wss = new WebSocketServer({ noServer: true });
22+
23+
wss.on("connection", (...args) =>
24+
createSetupWSConnection(bindState, writeState)(...args)
25+
);
26+
27+
http_server.on("upgrade", async (request, socket, head) => {
28+
// You may check auth of request here..
29+
// See https://github.com/websockets/ws#client-authentication
30+
if (request.url) {
31+
wss.handleUpgrade(request, socket, head, function done(ws) {
32+
wss.emit("connection", ws, request, { readOnly: false });
33+
});
34+
return;
35+
}
36+
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
37+
socket.destroy();
38+
return;
17639
});
177-
const expapp = express();
178-
expapp.use(express.json({ limit: "20mb" }));
179-
const http_server = http.createServer(expapp);
180-
181-
await apollo.start();
182-
apollo.applyMiddleware({ app: expapp });
18340

18441
http_server.listen({ port }, () => {
18542
console.log(`🚀 Server ready at http://localhost:${port}`);

apps/desktop-yjs/src/yjs-blob.ts renamed to apps/desktop-api/src/yjs-blob.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import fs from "fs";
2121
import Y from "yjs";
22-
import { Node as ReactflowNode, Edge as ReactflowEdge } from "reactflow";
2322

2423
import debounce from "lodash/debounce";
2524

@@ -51,18 +50,12 @@ function getDebouncedCallback(key) {
5150
return debounceRegistry.get(key);
5251
}
5352

54-
type NodeData = {
55-
level: number;
56-
name?: string;
57-
};
58-
59-
const CODEPOD_ROOT = "/var/codepod";
60-
const repoDirs = `${CODEPOD_ROOT}/repos`;
53+
// FIXME hard-coded path.
54+
const blobDir = "/tmp/example-repo";
6155

6256
async function handleSaveBlob({ repoId, yDocBlob }) {
6357
console.log("save blob", repoId, yDocBlob.length);
6458
// create the yjs-blob folder if not exists
65-
const blobDir = `${repoDirs}/${repoId}`;
6659
if (!fs.existsSync(blobDir)) {
6760
fs.mkdirSync(blobDir);
6861
}
@@ -93,9 +86,9 @@ function setupObserversToDB(ydoc: Y.Doc, repoId: string) {
9386
});
9487
}
9588
const rootMap = ydoc.getMap("rootMap");
96-
const nodesMap = rootMap.get("nodesMap") as Y.Map<ReactflowNode<NodeData>>;
89+
const nodesMap = rootMap.get("nodesMap") as Y.Map<any>;
9790
nodesMap.observe(observer);
98-
const edgesMap = rootMap.get("edgesMap") as Y.Map<ReactflowEdge>;
91+
const edgesMap = rootMap.get("edgesMap") as Y.Map<any>;
9992
edgesMap.observe(observer);
10093
const codeMap = rootMap.get("codeMap") as Y.Map<Y.Text>;
10194
codeMap.observeDeep(observer);
@@ -112,16 +105,15 @@ async function loadFromFS(ydoc: Y.Doc, repoId: string) {
112105
// load from the database and write to the ydoc
113106
console.log("=== loadFromFS");
114107
// read the blob from file system
115-
const blobDir = `${repoDirs}/${repoId}`;
116108
const binFile = `${blobDir}/yjs.bin`;
117109
if (fs.existsSync(binFile)) {
118110
const yDocBlob = fs.readFileSync(binFile);
119111
Y.applyUpdate(ydoc, yDocBlob);
120112
} else {
121113
// init the ydoc
122114
const rootMap = ydoc.getMap("rootMap");
123-
rootMap.set("nodesMap", new Y.Map<ReactflowNode<NodeData>>());
124-
rootMap.set("edgesMap", new Y.Map<ReactflowEdge>());
115+
rootMap.set("nodesMap", new Y.Map<any>());
116+
rootMap.set("edgesMap", new Y.Map<any>());
125117
rootMap.set("codeMap", new Y.Map<Y.Text>());
126118
rootMap.set("richMap", new Y.Map<Y.XmlFragment>());
127119
rootMap.set("resultMap", new Y.Map<any>());

apps/desktop-ui/.eslintrc.cjs

Lines changed: 0 additions & 18 deletions
This file was deleted.

apps/desktop-ui/.gitignore

Lines changed: 0 additions & 24 deletions
This file was deleted.

apps/desktop-ui/README.md

Lines changed: 0 additions & 27 deletions
This file was deleted.

apps/desktop-ui/index.html

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)