Skip to content

Commit 9e981a7

Browse files
committed
✨ Enable to run patch() with an existing socket
1 parent 9bc8667 commit 9e981a7

File tree

3 files changed

+96
-82
lines changed

3 files changed

+96
-82
lines changed

browser/websocket/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./room.ts";
22
export * from "./shortcuts.ts";
3+
export * from "./patch.ts";
34
export * from "./stream.ts";

browser/websocket/patch.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Socket, socketIO, wrap } from "../../deps/socket.ts";
2+
import { connect, disconnect } from "./socket.ts";
3+
import { getProjectId, getUserId } from "./id.ts";
4+
import { makeChanges } from "./makeChanges.ts";
5+
import { HeadData, pull } from "./pull.ts";
6+
import type { Line } from "../../deps/scrapbox.ts";
7+
import { pushCommit, pushWithRetry } from "./_fetch.ts";
8+
9+
export interface PatchOptions {
10+
socket?: Socket;
11+
}
12+
13+
/** ページ全体を書き換える
14+
*
15+
* serverには書き換え前後の差分だけを送信する
16+
*
17+
* @param project 書き換えたいページのproject
18+
* @param title 書き換えたいページのタイトル
19+
* @param update 書き換え後の本文を作成する函数。引数には現在の本文が渡される。空配列を返すとページが削除される。undefinedを返すと書き換えを中断する
20+
* @param options 使用したいSocketがあれば指定する
21+
*/
22+
export async function patch(
23+
project: string,
24+
title: string,
25+
update: (
26+
lines: Line[],
27+
metadata: HeadData,
28+
) => string[] | undefined | Promise<string[] | undefined>,
29+
options?: PatchOptions,
30+
): Promise<void> {
31+
const [
32+
head_,
33+
projectId,
34+
userId,
35+
] = await Promise.all([
36+
pull(project, title),
37+
getProjectId(project),
38+
getUserId(),
39+
]);
40+
41+
let head = head_;
42+
43+
const injectedSocket = options?.socket;
44+
const socket = injectedSocket ?? await socketIO();
45+
await connect(socket);
46+
try {
47+
const { request } = wrap(socket);
48+
49+
// 3回retryする
50+
for (let i = 0; i < 3; i++) {
51+
try {
52+
const pending = update(head.lines, head);
53+
const newLines = pending instanceof Promise ? await pending : pending;
54+
55+
if (!newLines) return;
56+
57+
if (newLines.length === 0) {
58+
await pushWithRetry(request, [{ deleted: true }], {
59+
projectId,
60+
pageId: head.pageId,
61+
parentId: head.commitId,
62+
userId,
63+
project,
64+
title,
65+
});
66+
}
67+
68+
const changes = makeChanges(head.lines, newLines, { userId, head });
69+
await pushCommit(request, changes, {
70+
parentId: head.commitId,
71+
projectId,
72+
pageId: head.pageId,
73+
userId,
74+
});
75+
break;
76+
} catch (_e: unknown) {
77+
if (i === 2) {
78+
throw Error("Faild to retry pushing.");
79+
}
80+
console.log(
81+
"Faild to push a commit. Retry after pulling new commits",
82+
);
83+
try {
84+
head = await pull(project, title);
85+
} catch (e: unknown) {
86+
throw e;
87+
}
88+
}
89+
}
90+
} finally {
91+
if (!injectedSocket) await disconnect(socket);
92+
}
93+
}

browser/websocket/shortcuts.ts

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { socketIO, wrap } from "../../deps/socket.ts";
22
import { getProjectId, getUserId } from "./id.ts";
3-
import { makeChanges } from "./makeChanges.ts";
4-
import { HeadData, pull } from "./pull.ts";
3+
import { pull } from "./pull.ts";
54
import { pinNumber } from "./pin.ts";
6-
import type { Line } from "../../deps/scrapbox.ts";
7-
import { pushCommit, pushWithRetry } from "./_fetch.ts";
5+
import { pushWithRetry } from "./_fetch.ts";
86

97
/** 指定したページを削除する
108
*
@@ -44,84 +42,6 @@ export async function deletePage(
4442
}
4543
}
4644

47-
/** ページ全体を書き換える
48-
*
49-
* serverには書き換え前後の差分だけを送信する
50-
*
51-
* @param project 書き換えたいページのproject
52-
* @param title 書き換えたいページのタイトル
53-
* @param update 書き換え後の本文を作成する函数。引数には現在の本文が渡される。空配列を返すとページが削除される。undefinedを返すと書き換えを中断する
54-
*/
55-
export async function patch(
56-
project: string,
57-
title: string,
58-
update: (
59-
lines: Line[],
60-
metadata: HeadData,
61-
) => string[] | undefined | Promise<string[] | undefined>,
62-
): Promise<void> {
63-
const [
64-
head_,
65-
projectId,
66-
userId,
67-
] = await Promise.all([
68-
pull(project, title),
69-
getProjectId(project),
70-
getUserId(),
71-
]);
72-
73-
let head = head_;
74-
75-
const io = await socketIO();
76-
try {
77-
const { request } = wrap(io);
78-
79-
// 3回retryする
80-
for (let i = 0; i < 3; i++) {
81-
try {
82-
const pending = update(head.lines, head);
83-
const newLines = pending instanceof Promise ? await pending : pending;
84-
85-
if (!newLines) return;
86-
87-
if (newLines.length === 0) {
88-
await pushWithRetry(request, [{ deleted: true }], {
89-
projectId,
90-
pageId: head.pageId,
91-
parentId: head.commitId,
92-
userId,
93-
project,
94-
title,
95-
});
96-
}
97-
98-
const changes = makeChanges(head.lines, newLines, { userId, head });
99-
await pushCommit(request, changes, {
100-
parentId: head.commitId,
101-
projectId,
102-
pageId: head.pageId,
103-
userId,
104-
});
105-
break;
106-
} catch (_e: unknown) {
107-
if (i === 2) {
108-
throw Error("Faild to retry pushing.");
109-
}
110-
console.log(
111-
"Faild to push a commit. Retry after pulling new commits",
112-
);
113-
try {
114-
head = await pull(project, title);
115-
} catch (e: unknown) {
116-
throw e;
117-
}
118-
}
119-
}
120-
} finally {
121-
io.disconnect();
122-
}
123-
}
124-
12545
export interface PinOption {
12646
/** ピン留め対象のページが存在しないときの振る舞いを変えるoption
12747
*

0 commit comments

Comments
 (0)