V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  hamsterbase  ›  全部回复第 7 页 / 共 18 页
回复总数  341
1 ... 3  4  5  6  7  8  9  10  11  12 ... 18  
18 。 帮我为 IMemoTalkCore 编写集成单元测试。 使用 jest


```ts
/**
* MemoTalkCore 核心为一个 Y.Doc 对象
* 保存的时候 encode 为字符串
* 可以合并别的 MemoTalkCore, 入参为字符串
*/
export interface IMemoTalkCore {
createMemoTalk(content: string): string;

getMemoTalkById(id: string): MemoTalk;

getMemoTalkList(): MemoTalk[];

deleteMemoTalkById(id: string): void;

/**
* 把整个数据库序列化为字符串
*/
encode(): string;

merge(data: string): void;
}
```
17. 在 copilot 的帮助下,完成了核心逻辑的实现


const enum YDocKey {
/**
* 避免 id 重复
*/
id = "id",
memoTalks = "memoTalks",
}

export class MemoTalkCore implements IMemoTalkCore {
private ydoc: Y.Doc;
constructor() {
this.ydoc = new Y.Doc();
}

createMemoTalk(content: string): string {
if (typeof content !== "string") {
throw new Error("content must be string");
}
const idMap = this.ydoc.getMap(YDocKey.id);
let id: string = nanoid();
while (idMap.has(id)) {
id = nanoid();
}
const memoTalksArray = this.ydoc.getArray<string>(YDocKey.memoTalks);

const memoTalk = this.ydoc.getMap(id);
memoTalk.set("content", content ?? "");
memoTalk.set("createTime", Date.now());
memoTalksArray.push([id]);
return id;
}

getMemoTalkById(id: string): MemoTalk {
const memoTalk = this.ydoc.getMap(id);
return {
id,
content: memoTalk.get("content") as string,
createTime: memoTalk.get("createTime") as number,
};
}

getMemoTalkList(): MemoTalk[] {
const memoTalksArray = this.ydoc.getArray<string>(YDocKey.memoTalks);
return memoTalksArray.map((id) => this.getMemoTalkById(id));
}

deleteMemoTalkById(id: string): void {
const memoTalksArray = this.ydoc.getArray<string>(YDocKey.memoTalks);
memoTalksArray.delete(memoTalksArray.toArray().indexOf(id));
}

encode(): string {
return fromUint8Array(Y.encodeStateAsUpdate(this.ydoc));
}

merge(data: string): void {
Y.applyUpdate(this.ydoc, toUint8Array(data));
}
}
16. 设计一下核心的数据结构。 这个是我自己设计的


export interface MemoTalk {
id: string;
content: string;
createTime: number;
}

/**
* MemoTalkCore 核心为一个 Y.Doc 对象
* 保存的时候 encode 为字符串
* 可以合并别的 MemoTalkCore, 入参为字符串
*/
export interface MemoTalkCore {
createMemoTalk(content: string): string;

getMemoTalkById(id: string): MemoTalk;

getMemoTalkList(): MemoTalk[];

deleteMemoTalkById(id: string): void;

/**
* 把整个数据库序列化为字符串
*/
encode(): string;

merge(data: string): void;
}
15.

Q: 帮我设计一个 ts interface. NoteCore

1. 新建笔记,返回 ID
2. 根据 ID 返回笔记内容。
3. 获取笔记列表.
4. 根据 ID 删除笔记
14. 前端上线啦,可以访问了。 开始写前端逻辑

https://memo-talk-web.onrender.com/
13. 使用 vite 的 ts + react 模板,数据核心准备使用 yjs
11. 帮我想一下 memo-talk 前端仓库的名字

以下是一些可能的 Memo-Talk 前端仓库的名字:

- memo-talk-frontend:一个简单而明确的仓库名称,指示该仓库包含 Memo-Talk 的前端代码。
- memo-talk-web:一个更简洁的仓库名称,指示该仓库包含 Memo-Talk 的 Web 界面代码。
- memo-talk-ui:一个仓库名称,指示该仓库包含 Memo-Talk 的用户界面部分。
- memo-talk-client:一个仓库名称,指示该仓库包含 Memo-Talk 的客户端代码。
- memo-talk-portal:一个仓库名称,指示该仓库包含 Memo-Talk 的 Web 门户代码。
你可以根据你的喜好和项目的具体需求选择其中任何一个名称。无论你选择哪个名称,都需要确保它能够准确地描述该仓库的内容,并且易于理解和记忆。此外,你可能还需要考虑使用标准的命名约定和格式,以便其他开发人员能够轻松地找到和使用你的仓库。
10. 白嫖 render.com , 服务器上线了 https://memo-talk.onrender.com
9 。chatgpt 没有写文件名校验逻辑,让他单独写一个
帮我用 ts 写一个字符串检测函数。 字符串长度必须为 64 个字符,每个字符是 0-9 和 A-F 之间的一个 16 进制数字.
忽略大小写。 最终输出转换为小写后的结果。 如果不满足,则抛错。
8. koa-router 好像没有类型,换 @koa/router. 初始化项目,把 chatgpt 回答拷贝一下

https://github.com/hamsterbase/memo-talk/commit/2cc9318a7255e2dafef2716e78b2e844953042cc
7. 之后不贴 chatgpt 的回答了,复制粘贴太麻烦啦。

Q:

我希望你能帮我编写一下服务端的代码。

参数命名规则为 folder , file , content 。

需要有以下 4 个接口为。

1. 获取 folder 获取文件列表。

2. 根据 folder ,file 获取 content

3. 根据 folder ,file 删除文件

4. 根据 folder ,file, content 写入文件

要求。

1. 基于 koa 编写,使用 typescript 编写
2. folder , file 必须为 64 个字符,每个字符是 0-9 和 A-F 之间的一个 16 进制数字.
3. 我希望你能用 koa-router 编写
4. 文件希望写入到本地的 data 文件夹下
5. 规则为 /data/folder/file
6. API 必须以 public/api/v1 开头
7. content 限制最大 1mb
8. folder, file, content 都通过 body 获取,不要用 query,path 获取。
6. 他没把文件写到本地,所以改一下 prompt

Q:

我希望你能帮我编写一下服务端的代码。

需要有以下四个接口接口为

1. 获取文件夹列表

2. 根据文件夹名字,文件名获取文件内容

3. 根据文件夹名字,文件名删除文件

4. 根据文件夹名字,文件名删除文件

要求。

1. 基于 koa 编写
2. 使用 typescript 编写
3. 文件名,文件名必须为 64 个字符,每个字符是 0-9 和 A-F 之间的一个 16 进制数字
4. 文件夹名和文件名,文件内容都通过 body 传递。
5. 我希望你能用 koa-router 编写
6. 文件希望写入到本地的 data 文件夹下
7. API 必须以 public/api/v1 开头

Q:

```ts
import Koa from "koa";
import Router from "koa-router";
import fs from "fs/promises";
import path from "path";

const app = new Koa();
const router = new Router();

const DATA_FOLDER = "data";

// 获取文件夹列表
router.get("/public/api/v1/folders", async (ctx) => {
try {
const folders = await fs.readdir(DATA_FOLDER);
ctx.body = folders;
} catch (err) {
ctx.status = 500;
ctx.body = "Internal Server Error";
console.error(err);
}
});

// 根据文件夹名字,文件名获取文件内容
router.get(
"/public/api/v1/folders/:folderName/files/:fileName",
async (ctx) => {
const { folderName, fileName } = ctx.params;
const filePath = path.join(DATA_FOLDER, folderName, fileName);
try {
const fileContent = await fs.readFile(filePath, "utf-8");
ctx.body = fileContent;
} catch (err) {
if (err.code === "ENOENT") {
ctx.status = 404;
ctx.body = "File Not Found";
} else {
ctx.status = 500;
ctx.body = "Internal Server Error";
console.error(err);
}
}
}
);

// 根据文件夹名字,文件名删除文件
router.del(
"/public/api/v1/folders/:folderName/files/:fileName",
async (ctx) => {
const { folderName, fileName } = ctx.params;
const filePath = path.join(DATA_FOLDER, folderName, fileName);
try {
await fs.unlink(filePath);
ctx.body = "File Deleted";
} catch (err) {
if (err.code === "ENOENT") {
ctx.status = 404;
ctx.body = "File Not Found";
} else {
ctx.status = 500;
ctx.body = "Internal Server Error";
console.error(err);
}
}
}
);

// 根据文件夹名字,文件名删除文件
router.post(
"/public/api/v1/folders/:folderName/files/:fileName",
async (ctx) => {
const { folderName, fileName } = ctx.params;
const filePath = path.join(DATA_FOLDER, folderName, fileName);
try {
await fs.mkdir(path.join(DATA_FOLDER, folderName), { recursive: true });
await fs.writeFile(filePath, ctx.request.body);
ctx.body = "File Created";
} catch (err) {
ctx.status = 500;
ctx.body = "Internal Server Error";
console.error(err);
}
}
);

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => {
console.log("Server listening on port 3000");
});
```

接口说明:

获取文件夹列表:GET /public/api/v1/folders
根据文件夹名字,文件名获取文件内容:GET /public/api/v1/folders/:folderName/files/:fileName
根据文件夹名字,文件名删除文件:DELETE /public/api/v1/folders/:folderName/files/:fileName
根据文件夹名字,文件名删除文件:POST /public/api/v1/folders/:folderName/files/:fileName
其中,文件名和文件夹名都是 64 个字符的 16 进制数字字符串。文件内容通过 Request Body 传递,文件保存在本地的 data 文件夹下。如果出现错误,会返回适当的 HTTP 状态码和错误信息。
@aitianci 基于 crdt ,不会丢数据的
@x308989414q

暂时不支持,未来会支持。
@DemonQ 请问你是用 1.2 版本吗?

填完 token 以后,刷新页面试试看?
@ggmood 同步指的是什么意思?数
用的是 notion api ,数据都在 notion
@jaredyam release 不能合并其他的 release 分支。


只有 master -初始化-> release 和 release -发布-> master

如果公共代码,可以分别 PR 到 release A 和 release B
1. master 为基线,只包含上次发布的代码
2. release/a.b.c 为迭代分支,迭代分支只包含当前代码。
3. 每个迭代可以单独的部署,提测前需要合并最新的 master 基线。
4. 平时开发流程为 创建分支,往迭代合并。 不允许直接合并 master
5. 迭代发布后打 tag, va.b.c 。
2023-06-03 11:28:50 +08:00
回复了 rivercherdeeeeee 创建的主题 程序员 emby 服务的问题
安装 tailscale 就行了。emby 服务器和手机都安装 tailscale
1 ... 3  4  5  6  7  8  9  10  11  12 ... 18  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1747 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 18ms · UTC 16:32 · PVG 00:32 · LAX 08:32 · JFK 11:32
Developed with CodeLauncher
♥ Do have faith in what you're doing.