unikvs 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +1553 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4032 -0
- package/dist/index.js.map +1 -0
- package/package.json +34 -34
- package/src/_contexts.ts +1089 -0
- package/src/_logger.ts +5 -3
- package/src/_middleware.ts +207 -0
- package/src/_pipeline-graph.helpers.ts +183 -0
- package/src/_pipeline-graph.ts +1307 -0
- package/src/_pipeline-graph.types.ts +303 -0
- package/src/_pipeline-leaf-resolver.ts +70 -0
- package/src/_plugin-lifecycle.ts +201 -0
- package/src/_storage.ts +169 -115
- package/src/_streams.schemas.ts +21 -0
- package/src/_streams.ts +32 -6
- package/src/_to-value-stream.ts +22 -11
- package/src/_types.ts +237 -0
- package/src/_unikvs-branch.ts +94 -0
- package/src/_unikvs.schemas.ts +451 -0
- package/src/_valibot.ts +17 -6
- package/src/_value-schemas.ts +36 -206
- package/src/_value-validation.ts +57 -0
- package/src/errors.ts +391 -148
- package/src/index.ts +46 -25
- package/src/{value-stream.types.ts → types.ts} +1 -1
- package/src/unikvs-branch.ts +445 -0
- package/src/unikvs-builder.ts +706 -0
- package/src/unikvs.ts +1423 -1007
- package/src/unikvs.types.ts +194 -0
- package/src/value-schemas.ts +98 -0
- package/dist/src/_logger.d.ts +0 -3
- package/dist/src/_logger.d.ts.map +0 -1
- package/dist/src/_logger.js +0 -3
- package/dist/src/_merge-variables.d.ts +0 -13
- package/dist/src/_merge-variables.d.ts.map +0 -1
- package/dist/src/_merge-variables.js +0 -12
- package/dist/src/_storage.d.ts +0 -18
- package/dist/src/_storage.d.ts.map +0 -1
- package/dist/src/_storage.js +0 -103
- package/dist/src/_streams.d.ts +0 -20
- package/dist/src/_streams.d.ts.map +0 -1
- package/dist/src/_streams.js +0 -36
- package/dist/src/_to-value-stream.d.ts +0 -12
- package/dist/src/_to-value-stream.d.ts.map +0 -1
- package/dist/src/_to-value-stream.js +0 -102
- package/dist/src/_transformer.d.ts +0 -13
- package/dist/src/_transformer.d.ts.map +0 -1
- package/dist/src/_transformer.js +0 -60
- package/dist/src/_valibot.d.ts +0 -15
- package/dist/src/_valibot.d.ts.map +0 -1
- package/dist/src/_valibot.js +0 -23
- package/dist/src/_value-schemas.d.ts +0 -179
- package/dist/src/_value-schemas.d.ts.map +0 -1
- package/dist/src/_value-schemas.js +0 -150
- package/dist/src/errors.d.ts +0 -306
- package/dist/src/errors.d.ts.map +0 -1
- package/dist/src/errors.js +0 -234
- package/dist/src/index.d.ts +0 -10
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -3
- package/dist/src/unikvs-config.d.ts +0 -174
- package/dist/src/unikvs-config.d.ts.map +0 -1
- package/dist/src/unikvs-config.js +0 -100
- package/dist/src/unikvs.d.ts +0 -272
- package/dist/src/unikvs.d.ts.map +0 -1
- package/dist/src/unikvs.js +0 -928
- package/dist/src/utils.types.d.ts +0 -5
- package/dist/src/utils.types.d.ts.map +0 -1
- package/dist/src/utils.types.js +0 -1
- package/dist/src/value-stream.types.d.ts +0 -10
- package/dist/src/value-stream.types.d.ts.map +0 -1
- package/dist/src/value-stream.types.js +0 -1
- package/dist/src/variables.types.d.ts +0 -11
- package/dist/src/variables.types.d.ts.map +0 -1
- package/dist/src/variables.types.js +0 -1
- package/src/_merge-variables.ts +0 -19
- package/src/_transformer.ts +0 -89
- package/src/unikvs-config.ts +0 -401
- package/src/utils.types.ts +0 -4
- package/src/variables.types.ts +0 -13
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import type { IReadableStream } from "@unikvs/core";
|
|
2
|
+
|
|
3
|
+
import type { VariablesStore } from "./_contexts.js";
|
|
4
|
+
import type UniKvsMiddleware from "./_middleware.js";
|
|
5
|
+
import type UniKvsStorage from "./_storage.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* パイプラインの葉となる宛先です。
|
|
9
|
+
*/
|
|
10
|
+
export type PipelineLeaf = {
|
|
11
|
+
/**
|
|
12
|
+
* データの永続化先です。
|
|
13
|
+
*/
|
|
14
|
+
readonly storage: UniKvsStorage;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 宛先の登録順 (0 起点) です。
|
|
18
|
+
*/
|
|
19
|
+
readonly index: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* ストレージ名のキャッシュです。
|
|
23
|
+
*/
|
|
24
|
+
readonly name: string;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 経路上に `AllowRepair` が存在するかどうかです。
|
|
28
|
+
*/
|
|
29
|
+
readonly canRepair: boolean;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 葉 1 件分の凍結された名前空間です。
|
|
33
|
+
*/
|
|
34
|
+
readonly nameNames: readonly string[];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 根直下から葉の直前までのノード列です。
|
|
38
|
+
* グラフ自身の走査と内部単体テスト専用です。
|
|
39
|
+
*
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
readonly path: readonly PipelineNode[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* パイプラインの節となるミドルウェアです。
|
|
47
|
+
*/
|
|
48
|
+
export type PipelineNode = {
|
|
49
|
+
/**
|
|
50
|
+
* 節を構成するミドルウェアです。
|
|
51
|
+
*/
|
|
52
|
+
readonly middleware: UniKvsMiddleware;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* この節で終端する葉です。
|
|
56
|
+
* 登録順に保持します。
|
|
57
|
+
*/
|
|
58
|
+
readonly leaves: readonly PipelineLeaf[];
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* 子の節です。
|
|
62
|
+
* 登録順に保持します。
|
|
63
|
+
*/
|
|
64
|
+
readonly children: readonly PipelineNode[];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 直下の葉と節を登録順に列挙した静的な項目列です。
|
|
68
|
+
*/
|
|
69
|
+
readonly entries: readonly PipelineEntry[];
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 部分木の全葉です。
|
|
73
|
+
* 登録順に保持します。
|
|
74
|
+
*/
|
|
75
|
+
readonly allLeaves: readonly PipelineLeaf[];
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 部分木の全葉名です。
|
|
79
|
+
* 凍結されています。
|
|
80
|
+
*/
|
|
81
|
+
readonly leafNames: readonly string[];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 節または葉を登録順に列挙するための項目です。
|
|
86
|
+
*/
|
|
87
|
+
export type PipelineEntry =
|
|
88
|
+
| {
|
|
89
|
+
/**
|
|
90
|
+
* 葉であることを示します。
|
|
91
|
+
*/
|
|
92
|
+
readonly kind: "leaf";
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 対象の葉です。
|
|
96
|
+
*/
|
|
97
|
+
readonly leaf: PipelineLeaf;
|
|
98
|
+
}
|
|
99
|
+
| {
|
|
100
|
+
/**
|
|
101
|
+
* 節であることを示します。
|
|
102
|
+
*/
|
|
103
|
+
readonly kind: "node";
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 対象の節です。
|
|
107
|
+
*/
|
|
108
|
+
readonly node: PipelineNode;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* コンパイル前の宛先定義です。
|
|
113
|
+
*/
|
|
114
|
+
export type PipelineDestination = {
|
|
115
|
+
/**
|
|
116
|
+
* データの永続化先です。
|
|
117
|
+
*/
|
|
118
|
+
readonly storage: UniKvsStorage;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 適用順のミドルウェア列です。末尾未使用分は含みません。
|
|
122
|
+
*/
|
|
123
|
+
readonly middlewares: readonly UniKvsMiddleware[];
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 葉へ書き込むためのエンコード結果です。
|
|
128
|
+
*/
|
|
129
|
+
export type EncodeTarget = {
|
|
130
|
+
/**
|
|
131
|
+
* 対象の葉です。
|
|
132
|
+
*/
|
|
133
|
+
readonly leaf: PipelineLeaf;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* エンコード済みのデータです。
|
|
137
|
+
*/
|
|
138
|
+
readonly data: unknown;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 写像済みのキーです。
|
|
142
|
+
*/
|
|
143
|
+
readonly key: string;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 解決済みの葉です。
|
|
148
|
+
*/
|
|
149
|
+
export type ResolvedLeaf = {
|
|
150
|
+
/**
|
|
151
|
+
* 対象の葉です。
|
|
152
|
+
*/
|
|
153
|
+
readonly leaf: PipelineLeaf;
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 写像済みのキーです。
|
|
157
|
+
*/
|
|
158
|
+
readonly key: string;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* ストリームのエンコード先となる葉です。
|
|
163
|
+
*/
|
|
164
|
+
export type StreamEncodeTarget = {
|
|
165
|
+
/**
|
|
166
|
+
* 対象の葉です。
|
|
167
|
+
*/
|
|
168
|
+
readonly leaf: PipelineLeaf;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* 葉へ書き込むストリームです。
|
|
172
|
+
*/
|
|
173
|
+
readonly stream: IReadableStream;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* 写像済みのキーです。
|
|
177
|
+
*/
|
|
178
|
+
readonly key: string;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 構築済みのストリームエンコード木です。
|
|
183
|
+
*/
|
|
184
|
+
export type StreamEncodeTree = {
|
|
185
|
+
/**
|
|
186
|
+
* 登録順の書き込み対象です。
|
|
187
|
+
*/
|
|
188
|
+
readonly targets: StreamEncodeTarget[];
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 読み取り側へ渡すストリームです。`splitRead` を指定したときだけ分岐後の読み取り側になります。
|
|
192
|
+
*/
|
|
193
|
+
readonly readStream: IReadableStream;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* 書き込み対象とする葉を判定する関数です。
|
|
198
|
+
*/
|
|
199
|
+
export interface IActiveLeafChecker {
|
|
200
|
+
/**
|
|
201
|
+
* 書き込み対象とする葉を判定します。
|
|
202
|
+
*
|
|
203
|
+
* @param leaf 対象の葉です。
|
|
204
|
+
*
|
|
205
|
+
* @returns 判定結果です。
|
|
206
|
+
*/
|
|
207
|
+
(leaf: PipelineLeaf): boolean;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* 節の `encodeStream` または `mapKey` が失敗したときの処理を行う関数です。
|
|
212
|
+
*/
|
|
213
|
+
export interface IEncodeNodeErrorHandler {
|
|
214
|
+
/**
|
|
215
|
+
* 節のセットアップ失敗時の処理です。
|
|
216
|
+
*
|
|
217
|
+
* `true` を返すと節の部分木をスキップします。
|
|
218
|
+
* 例外を投げた場合はそのまま伝播します。
|
|
219
|
+
*
|
|
220
|
+
* @param ex 節の取得または写像で発生した例外です。
|
|
221
|
+
* @param activeLeaves 節の配下で対象となる葉です。
|
|
222
|
+
*
|
|
223
|
+
* @returns 部分木をスキップする場合は `true` を返します。
|
|
224
|
+
*/
|
|
225
|
+
(ex: unknown, activeLeaves: readonly PipelineLeaf[]): boolean;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* ストリームエンコード木の構築オプションです。
|
|
230
|
+
*/
|
|
231
|
+
export type BuildEncodeTreeOptions = {
|
|
232
|
+
/**
|
|
233
|
+
* 書き込み対象とする葉を判定します。省略時は全葉が対象です。
|
|
234
|
+
*/
|
|
235
|
+
readonly isActive?: IActiveLeafChecker | undefined;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* 読み取り側と書き込み側を分岐するかどうかです。書き戻しで使用します。
|
|
239
|
+
*/
|
|
240
|
+
readonly splitRead?: boolean | undefined;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* 節のセットアップ失敗を分類します。省略時は生の例外として伝播します。
|
|
244
|
+
*/
|
|
245
|
+
readonly onNodeError?: IEncodeNodeErrorHandler | undefined;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* 操作共通の実行時情報です。
|
|
250
|
+
*
|
|
251
|
+
* `store` は操作内の全コンテキストで共有され、下流の `set` が上流の `get` に見えます。
|
|
252
|
+
*/
|
|
253
|
+
export type OperationScope = {
|
|
254
|
+
/**
|
|
255
|
+
* 操作対象の論理キーです。
|
|
256
|
+
*/
|
|
257
|
+
readonly key: string;
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* 中断シグナルです。
|
|
261
|
+
*/
|
|
262
|
+
readonly signal: AbortSignal;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 操作内で共有される変数ストアです。
|
|
266
|
+
*/
|
|
267
|
+
readonly store: VariablesStore;
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* コンパイル中の節です。フィールドは finalize で確定します。
|
|
272
|
+
*/
|
|
273
|
+
export type MutableNode = {
|
|
274
|
+
/**
|
|
275
|
+
* 節を構成するミドルウェアです。
|
|
276
|
+
*/
|
|
277
|
+
readonly middleware: UniKvsMiddleware;
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* この節で終端する葉です。登録順に保持します。
|
|
281
|
+
*/
|
|
282
|
+
readonly leaves: PipelineLeaf[];
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* 子の節です。登録順に保持します。
|
|
286
|
+
*/
|
|
287
|
+
readonly children: MutableNode[];
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 直下の葉と節を登録順に列挙した項目列です。finalize で確定します。
|
|
291
|
+
*/
|
|
292
|
+
entries: readonly PipelineEntry[];
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* 部分木の全葉です。登録順に保持します。finalize で確定します。
|
|
296
|
+
*/
|
|
297
|
+
allLeaves: readonly PipelineLeaf[];
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* 部分木の全葉名です。finalize で確定します。
|
|
301
|
+
*/
|
|
302
|
+
leafNames: readonly string[];
|
|
303
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { applyMapKey } from "./_pipeline-graph.helpers.js";
|
|
2
|
+
import type {
|
|
3
|
+
PipelineLeaf,
|
|
4
|
+
PipelineNode,
|
|
5
|
+
ResolvedLeaf,
|
|
6
|
+
OperationScope,
|
|
7
|
+
} from "./_pipeline-graph.types.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 単一操作のスコープで葉の写像キーを解決します。
|
|
11
|
+
*
|
|
12
|
+
* 新 `mapKey` は同期的であり、中断シグナルも受け付けないため、共有節の写像は操作内で 1 回だけ実行され、結果を使い回します。
|
|
13
|
+
* 並行解決でも `Map` キャッシュにより重複しません (`resolve` 自体が同期的であるため、競合しません)。
|
|
14
|
+
*/
|
|
15
|
+
export class LeafResolver {
|
|
16
|
+
/**
|
|
17
|
+
* 根のキーです。
|
|
18
|
+
*/
|
|
19
|
+
readonly #rootKey: string;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 操作共通の実行時情報です (共有ストアを含みます)。
|
|
23
|
+
*/
|
|
24
|
+
readonly #scope: OperationScope;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 節ごとの解決結果のキャッシュです。
|
|
28
|
+
*/
|
|
29
|
+
readonly #nodeCache: Map<PipelineNode, string>;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 通常は `PipelineGraph.createResolver` から生成します。
|
|
33
|
+
*
|
|
34
|
+
* @param scope 操作共通の実行時情報です。
|
|
35
|
+
*/
|
|
36
|
+
public constructor(scope: OperationScope) {
|
|
37
|
+
this.#rootKey = scope.key;
|
|
38
|
+
this.#scope = scope;
|
|
39
|
+
this.#nodeCache = new Map();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 葉の写像キーを解決します。
|
|
44
|
+
*
|
|
45
|
+
* @param leaf 解決する葉です。
|
|
46
|
+
*
|
|
47
|
+
* @returns 解決済みの葉を返します。
|
|
48
|
+
*/
|
|
49
|
+
public resolve(leaf: PipelineLeaf): ResolvedLeaf {
|
|
50
|
+
let key = this.#rootKey;
|
|
51
|
+
|
|
52
|
+
for (const node of leaf.path) {
|
|
53
|
+
const cached = this.#nodeCache.get(node);
|
|
54
|
+
|
|
55
|
+
if (cached !== undefined) {
|
|
56
|
+
key = cached;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const mapped = applyMapKey(node.middleware, key, this.#scope);
|
|
61
|
+
this.#nodeCache.set(node, mapped);
|
|
62
|
+
key = mapped;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
key,
|
|
67
|
+
leaf,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import type { MaybePromise } from "maypromise";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 参照カウントで管理するプラグインの操作対象です。
|
|
5
|
+
*
|
|
6
|
+
* @template TOpenContext オープンコンテキストの型です。
|
|
7
|
+
* @template TCloseContext クローズコンテキストの型です。
|
|
8
|
+
*/
|
|
9
|
+
interface IPlugin<TOpenContext, TCloseContext> {
|
|
10
|
+
/**
|
|
11
|
+
* プラグインが開かれているかどうかです。
|
|
12
|
+
*/
|
|
13
|
+
get isOpen(): boolean;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* プラグインを開く関数です。未定義のときは `open` を持たないものとして扱います。
|
|
17
|
+
*/
|
|
18
|
+
open?(c: TOpenContext): MaybePromise<void>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* プラグインを閉じる関数です。未定義のときは `close` を持たないものとして扱います。
|
|
22
|
+
*/
|
|
23
|
+
close?(c: TCloseContext): MaybePromise<void>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 共有プラグインの参照カウントと実 `close` の再試行を管理します。
|
|
28
|
+
*
|
|
29
|
+
* 同じプラグインを共有する利用者のうち、最初の `open` だけが実際に開き、最後の `close` だけが実際に閉じます。
|
|
30
|
+
* 実 `close` に失敗したときは所有権を残し、次の `close` で再試行できるようにします。
|
|
31
|
+
*
|
|
32
|
+
* @template TOpenContext オープンコンテキストの型です。
|
|
33
|
+
* @template TCloseContext クローズコンテキストの型です。
|
|
34
|
+
*/
|
|
35
|
+
export class PluginLifecycle<TOpenContext, TCloseContext> {
|
|
36
|
+
/**
|
|
37
|
+
* 参照カウントの対象です。
|
|
38
|
+
*/
|
|
39
|
+
readonly #plugin: IPlugin<TOpenContext, TCloseContext>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* `open` した利用者の数です。最初の `open` だけが実際に開き、最後の `close` だけが実際に閉じます。
|
|
43
|
+
* `close` を持たないプラグインは閉じられないため数えません。
|
|
44
|
+
*/
|
|
45
|
+
#references: number;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 実 `close` に失敗したまま利用者の数が 0 になったかどうかです。
|
|
49
|
+
*
|
|
50
|
+
* このフラグが立っている間は、外部で開かれたプラグインではなく、閉じきれていない所有権が残っています。
|
|
51
|
+
* 次の `open` が所有権を引き継ぎ、次の `close` が実 `close` を再試行します。
|
|
52
|
+
*/
|
|
53
|
+
#closeFailed: boolean;
|
|
54
|
+
|
|
55
|
+
public constructor(plugin: IPlugin<TOpenContext, TCloseContext>) {
|
|
56
|
+
this.#plugin = plugin;
|
|
57
|
+
this.#references = 0;
|
|
58
|
+
this.#closeFailed = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* プラグインを開きます。
|
|
63
|
+
*
|
|
64
|
+
* 同じプラグインを共有する利用者のうち、最初の 1 回だけ実際の `open` を呼びます。
|
|
65
|
+
* この管理対象外で既に開かれているプラグインは open/close の対象外にします。
|
|
66
|
+
* 参照が残っていても実体が閉じられているときは、既存の参照を失わずに実 open へフォールバックします。
|
|
67
|
+
* `close` を持たないプラグインは閉じられないため、参照を数えません。
|
|
68
|
+
*
|
|
69
|
+
* @param c オープンコンテキストです。
|
|
70
|
+
*/
|
|
71
|
+
public async open(c: TOpenContext): Promise<void> {
|
|
72
|
+
if (this.#plugin.open === undefined) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// `close` を持たないプラグインは開いたままにしかできないため、参照を数えず、未 open のときだけ実 open します。
|
|
77
|
+
if (this.#plugin.close === undefined) {
|
|
78
|
+
if (this.#plugin.isOpen) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await this.#plugin.open(c);
|
|
83
|
+
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// この管理対象外の外部 open は対象外です。
|
|
88
|
+
// 直前の close に失敗した所有権 (#closeFailed) がある間は、外部 open とみなしません。
|
|
89
|
+
if (this.#plugin.isOpen && this.#references === 0 && !this.#closeFailed) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (this.#references > 0 || this.#closeFailed) {
|
|
94
|
+
if (this.#plugin.isOpen) {
|
|
95
|
+
// 既存の参照を失わずに加算します。close 失敗分の所有権もここで引き継ぎます。
|
|
96
|
+
this.#references += 1;
|
|
97
|
+
this.#closeFailed = false;
|
|
98
|
+
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 参照があるのに実体が閉じられているときは、実 open にフォールバックし、既存の参照を失わずに加算します。
|
|
103
|
+
await this.#plugin.open(c);
|
|
104
|
+
this.#references += 1;
|
|
105
|
+
this.#closeFailed = false;
|
|
106
|
+
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await this.#plugin.open(c);
|
|
111
|
+
this.#references += 1;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* プラグインを閉じます。
|
|
116
|
+
*
|
|
117
|
+
* 同じプラグインを共有する利用者のうち、最後の 1 回だけ実際の `close` を呼びます。
|
|
118
|
+
* 各呼び出しで参照を 1 つ減らし、実 `close` は全参照が解放されたときにだけ呼びます。
|
|
119
|
+
* 実 `close` に失敗したときは所有権を残し、次の `close` で再試行できるようにします。
|
|
120
|
+
* `close` を持たないプラグインは open で参照を数えないため、ここでは何もしません。
|
|
121
|
+
* 実 `close` へ渡すコンテキストは最後に閉じる利用者のものであり、最初に開いた利用者の vars/signal は保持しません。
|
|
122
|
+
*
|
|
123
|
+
* @param c クローズコンテキストです。
|
|
124
|
+
*/
|
|
125
|
+
public async close(c: TCloseContext): Promise<void> {
|
|
126
|
+
if (this.#plugin.close === undefined) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (this.#references === 0 && !this.#closeFailed) {
|
|
131
|
+
// この管理対象外のプラグインは閉じません。
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (this.#references > 0) {
|
|
136
|
+
this.#references -= 1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (this.#references > 0) {
|
|
140
|
+
// まだ利用者が残っているため、実体は閉じません。
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!this.#plugin.isOpen) {
|
|
145
|
+
// 既に外部で閉じられているため、未解放の所有権を解消します。
|
|
146
|
+
this.#closeFailed = false;
|
|
147
|
+
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
await this.#closeReal(c);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 失敗した実 `close` だけを再試行します。
|
|
156
|
+
*
|
|
157
|
+
* 通常の `close` と違い参照を減らしません。close 失敗後に新しい `open` が所有権を引き継いでいる場合は何もしません。
|
|
158
|
+
* 実体が既に閉じられているときは失敗状態だけを解消します。
|
|
159
|
+
*
|
|
160
|
+
* @param c クローズコンテキストです。
|
|
161
|
+
*/
|
|
162
|
+
public async retryClose(c: TCloseContext): Promise<void> {
|
|
163
|
+
if (this.#plugin.close === undefined) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 新しい open が所有権を引き継いでいる場合は、その参照を解放しないよう何もしません。
|
|
168
|
+
if (!this.#closeFailed || this.#references > 0) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!this.#plugin.isOpen) {
|
|
173
|
+
// 既に外部で閉じられているため、未解放の所有権を解消します。
|
|
174
|
+
this.#closeFailed = false;
|
|
175
|
+
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
await this.#closeReal(c);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 実 `close` を実行し、失敗したかどうかを記録します。
|
|
184
|
+
*
|
|
185
|
+
* @param c クローズコンテキストです。
|
|
186
|
+
*/
|
|
187
|
+
async #closeReal(c: TCloseContext): Promise<void> {
|
|
188
|
+
if (this.#plugin.close === undefined) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
await this.#plugin.close(c);
|
|
194
|
+
this.#closeFailed = false;
|
|
195
|
+
} catch (ex) {
|
|
196
|
+
// 閉じるのに失敗したときは未解放として記録し、次の close で再試行できるようにします。
|
|
197
|
+
this.#closeFailed = true;
|
|
198
|
+
throw ex;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|