Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 0 additions & 29 deletions browser/websocket/_codeBlock.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import { Change, Socket, wrap } from "../../deps/socket.ts";
import { Page } from "../../deps/scrapbox-rest.ts";
import { TinyCodeBlock } from "../../rest/getCodeBlocks.ts";
import { getProjectId, getUserId } from "./id.ts";
import { pushWithRetry } from "./_fetch.ts";

/** コードブロックのタイトル行の情報を保持しておくためのinterface */
export interface CodeTitle {
Expand All @@ -11,31 +7,6 @@ export interface CodeTitle {
indent: number;
}

/** コミットを送信する一連の処理 */
export const applyCommit = async (
commits: Change[],
page: Page,
projectName: string,
pageTitle: string,
socket: Socket,
userId?: string,
): ReturnType<typeof pushWithRetry> => {
const [projectId, userId_] = await Promise.all([
getProjectId(projectName),
userId ?? getUserId(),
]);
const { request } = wrap(socket);
return await pushWithRetry(request, commits, {
parentId: page.commitId,
projectId: projectId,
pageId: page.id,
userId: userId_,
project: projectName,
title: pageTitle,
retry: 3,
});
};

/** コードブロックのタイトル行から各種プロパティを抽出する
*
* @param lineText {string} 行テキスト
Expand Down
97 changes: 0 additions & 97 deletions browser/websocket/_fetch.ts

This file was deleted.

52 changes: 12 additions & 40 deletions browser/websocket/deletePage.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,22 @@
import { Socket, socketIO, wrap } from "../../deps/socket.ts";
import { connect, disconnect } from "./socket.ts";
import { getProjectId, getUserId } from "./id.ts";
import { pull } from "./pull.ts";
import { pushWithRetry } from "./_fetch.ts";
import { push, PushOptions, RetryError } from "./push.ts";
import { Result } from "../../rest/util.ts";

export interface DeletePageOptions {
socket?: Socket;
}
export type DeletePageOptions = PushOptions;

/** 指定したページを削除する
*
* @param project 削除したいページのproject
* @param title 削除したいページのタイトル
* @param options 使用したいSocketがあれば指定する
* @param options
*/
export const deletePage = async (
export const deletePage = (
project: string,
title: string,
options?: DeletePageOptions,
): Promise<void> => {
const [
{ id: pageId, commitId: parentId, persistent },
projectId,
userId,
] = await Promise.all([
pull(project, title),
getProjectId(project),
getUserId(),
]);

if (!persistent) return;

const injectedSocket = options?.socket;
const socket = injectedSocket ?? await socketIO();
await connect(socket);
const { request } = wrap(socket);
try {
await pushWithRetry(request, [{ deleted: true }], {
projectId,
pageId,
parentId,
userId,
project,
title,
});
} finally {
if (!injectedSocket) await disconnect(socket);
}
};
): Promise<Result<string, RetryError>> =>
push(
project,
title,
(page) => page.persistent ? [{ deleted: true }] : [],
options,
);
5 changes: 2 additions & 3 deletions browser/websocket/makeChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import type { Change } from "../../deps/socket.ts";
import { toTitleLc } from "../../title.ts";
import { parseYoutube } from "../../parser/youtube.ts";

export interface Init {
export interface Init extends Page {
userId: string;
page: Page;
}
export function* makeChanges(
left: Pick<Line, "text" | "id">[],
right: string[],
{ userId, page }: Init,
{ userId, ...page }: Init,
): Generator<Change, void, unknown> {
// 改行文字が入るのを防ぐ
const right_ = right.flatMap((text) => text.split("\n"));
Expand Down
101 changes: 26 additions & 75 deletions browser/websocket/patch.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
import { Socket, socketIO, wrap } from "../../deps/socket.ts";
import { connect, disconnect } from "./socket.ts";
import { getProjectId, getUserId } from "./id.ts";
import { Change, DeletePageChange, PinChange } from "../../deps/socket.ts";
import { makeChanges } from "./makeChanges.ts";
import { pull } from "./pull.ts";
import { Line, Page } from "../../deps/scrapbox-rest.ts";
import { pushCommit, pushWithRetry } from "./_fetch.ts";
import { push, PushOptions, RetryError } from "./push.ts";
import { suggestUnDupTitle } from "./suggestUnDupTitle.ts";
import { Result } from "../../rest/util.ts";

export interface PatchOptions {
socket?: Socket;
}
export type PatchOptions = PushOptions;

export interface PatchMetadata extends Page {
/** 書き換えを再試行した回数
*
* 初回は`0`で、再試行するたびに増える
*/
retry: number;
attempts: number;
}

/** ページ全体を書き換える
Expand All @@ -27,77 +24,31 @@ export interface PatchMetadata extends Page {
* @param update 書き換え後の本文を作成する函数。引数には現在の本文が渡される。空配列を返すとページが削除される。undefinedを返すと書き換えを中断する
* @param options 使用したいSocketがあれば指定する
*/
export const patch = async (
export const patch = (
project: string,
title: string,
update: (
lines: Line[],
metadata: PatchMetadata,
) => string[] | undefined | Promise<string[] | undefined>,
options?: PatchOptions,
): Promise<void> => {
const [
page_,
projectId,
userId,
] = await Promise.all([
pull(project, title),
getProjectId(project),
getUserId(),
]);

let page = page_;

const injectedSocket = options?.socket;
const socket = injectedSocket ?? await socketIO();
await connect(socket);
try {
const { request } = wrap(socket);

// 3回retryする
for (let retry = 0; retry < 3; retry++) {
try {
const pending = update(page.lines, { ...page, retry });
const newLines = pending instanceof Promise ? await pending : pending;

if (!newLines) return;

if (newLines.length === 0) {
await pushWithRetry(request, [{ deleted: true }], {
projectId,
pageId: page.id,
parentId: page.commitId,
userId,
project,
title,
});
}

const changes = [
...makeChanges(page.lines, newLines, { userId, page }),
];
await pushCommit(request, changes, {
parentId: page.commitId,
projectId,
pageId: page.id,
userId,
});
break;
} catch (_e: unknown) {
if (retry === 2) {
throw Error("Faild to retry pushing.");
}
console.log(
"Faild to push a commit. Retry after pulling new commits",
);
try {
page = await pull(project, title);
} catch (e: unknown) {
throw e;
}
): Promise<Result<string, RetryError>> =>
push(
project,
title,
async (page, attempts, prev, reason) => {
if (reason === "DuplicateTitleError") {
const fallbackTitle = suggestUnDupTitle(title);
return prev.map((change) => {
if ("title" in change) change.title = fallbackTitle;
return change;
}) as Change[] | [DeletePageChange] | [PinChange];
}
}
} finally {
if (!injectedSocket) await disconnect(socket);
}
};
const pending = update(page.lines, { ...page, attempts });
const newLines = pending instanceof Promise ? await pending : pending;
if (newLines === undefined) return [];
if (newLines.length === 0) return [{ deleted: true }];
return [...makeChanges(page.lines, newLines, page)];
},
options,
);
Loading