@demobook/server
Version:
## Setup
250 lines (204 loc) • 6.08 kB
text/typescript
import { Request, Response } from 'express';
import { createDir, moveFiles, deleteDir } from '../deploy';
import { getComments, postCommentToPR, editComment } from '../bot';
import { generateOutput } from '../output';
import { Redis } from '../Redis';
export interface Item {
dir: string;
url: string;
prNum: number | null;
projectName: string;
dateNum: number;
totalSize: number;
}
const redis = new Redis();
redis.subscribeExpired(async (keyEvent, key) => {
try {
await deleteDir(key);
} catch (e) {
throw e;
}
});
// TODO: use websocket
export async function getTimeSequence(req: Request, res: Response) {
const keys = await redis.getKeys('*');
const demos = [];
for (const item of keys) {
const demo = await redis.get(item);
const [, owner, repo, hash] = item.split('/');
demos.push({
...demo,
owner,
key: hash,
repo,
url: `${process.env.URL}/demos/${owner}/${repo}/${hash}`,
});
}
const schema = demos.sort((a, b) => b.dateNum - a.dateNum);
return res.json(schema);
}
type Owner = {
name: string;
url: string;
updatedAt: number;
demosNum: number;
totalSize: number;
};
export async function getOwners(req: Request, res: Response) {
const keys = await redis.getKeys('*');
const schema: Record<string, Omit<Owner, 'name'>> = {};
for (const item of keys) {
const demo = await redis.get(item);
const [, owner, ,] = item.split('/');
if (!schema[owner]) {
schema[owner] = {
url: `${process.env.GITHUB_URL}/${owner}`,
updatedAt: -1,
demosNum: 0,
totalSize: 0,
};
}
schema[owner]['demosNum']++;
schema[owner]['totalSize'] += demo.totalSize;
if (schema[owner]['updatedAt'] < demo.dateNum) schema[owner]['updatedAt'] = demo.dateNum;
}
return res.json(schema);
}
type Repo = {
key: string;
prUrl: string;
totalSize: number;
dateNum: number;
};
// repo url
export async function getRepos(req: Request, res: Response) {
const { owner: name } = req.params;
const keys = await redis.getKeys(`${process.env.OUTPUT_DIR}/${name}/*`);
const schema: {
owner: Owner;
repos: Record<string, Repo[]>;
} = {
owner: {
url: `${process.env.GITHUB_URL}/${name}`,
name,
demosNum: keys.length,
totalSize: 0,
updatedAt: -1,
},
repos: {},
};
for (const item of keys) {
const demo = await redis.get(item);
const [, owner, repo, hash] = item.split('/');
if (!schema['repos'][repo]) schema['repos'][repo] = [];
const prUrl = demo.prNum
? `${process.env.GITHUB_URL}/${owner}/${repo}/pull/${demo.prNum}`
: null;
schema['repos'][repo].push({
...demo,
key: hash,
prUrl,
});
schema['owner']['totalSize'] += demo.totalSize;
if (schema['owner']['updatedAt'] < demo.dateNum) schema['owner']['updatedAt'] = demo.dateNum;
}
Object.entries(schema['repos']).forEach(([key, value]) => {
// @ts-expect-error
schema['repos'][key] = (value as Array<Item>).sort((a, b) => b.dateNum - a.dateNum);
});
return res.json(schema);
}
export async function getDemos(req: Request, res: Response) {}
export async function getAll(req: Request, res: Response) {
const keys = await redis.getKeys('*');
const schema: Record<string, Record<string, Repo[]>> = {};
for (const item of keys) {
const r = await redis.get(item);
const [, owner, repo, hash] = item.split('/');
if (!schema[owner]) schema[owner] = {};
if (!schema[owner][repo]) schema[owner][repo] = [];
schema[owner][repo].push({
key: hash,
...r,
});
}
return res.json(schema);
}
interface PostDemos extends Request {
body: {
file_path: Array<{
name: string;
}>;
name: string;
pr_num: string;
};
}
export async function post(req: PostDemos, res: Response) {
try {
const { owner, repo } = req.params;
// @ts-expect-error
const dir = await createDir(req.params);
let projectName,
prNum,
files,
totalSize = 0;
if (typeof req.body['file_path'] === 'string') {
projectName = req.body['name'] || 'main';
prNum = req.body['pr_num'] ? Number(req.body['pr_num']) : null;
// @ts-expect-error
const info = req.files[0];
files = [
{
name: req.body['file_path'],
buffer: info.buffer,
},
];
totalSize = info.buffer.byteLength;
} else {
projectName =
req.body['name'] && Array.isArray(req.body['name']) ? req.body['name'][0] : 'main';
prNum =
req.body['pr_num'] && Array.isArray(req.body['pr_num'])
? Number(req.body['pr_num'][0])
: null;
files = req.body['file_path'].map((name, i) => {
// @ts-expect-error
const info = req.files[i];
totalSize += info.buffer.byteLength;
return {
name: name,
buffer: info.buffer,
};
});
}
await moveFiles(files, dir);
const url = `${process.env.URL}/${dir}`.replace(process.env.OUTPUT_DIR || '', 'demos');
const item = {
dir,
url,
prNum,
projectName,
dateNum: Date.now(),
totalSize,
};
await redis.set(item);
if (prNum) {
const comments = await getComments({ owner, repo, number: prNum });
// if bot exists, overwrite the comment
// const existedComment = comments.data.find((comment: GetCommentsForRepoResponseItem) => {
const existedComment = comments.data.find((comment: any) => {
if (comment.user.login === process.env.GITHUB_USER_NAME) return true;
return false;
});
const body = generateOutput(item, existedComment?.body ?? null);
if (existedComment) {
await editComment({ owner, repo, body, id: String(existedComment.id) });
} else {
await postCommentToPR({ owner, repo, number: prNum, body });
}
}
return res.json({ url });
} catch (e) {
return res.status(500).json({ message: (e as Error).message });
}
}