rockbed 0.1.0

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.
Files changed (62) hide show
  1. package/README.md +143 -0
  2. package/dist/assert/index.d.ts +6 -0
  3. package/dist/assert/index.js +27 -0
  4. package/dist/assert/index.js.map +1 -0
  5. package/dist/async/index.d.ts +105 -0
  6. package/dist/async/index.js +380 -0
  7. package/dist/async/index.js.map +1 -0
  8. package/dist/dispose/index.d.ts +47 -0
  9. package/dist/dispose/index.js +166 -0
  10. package/dist/dispose/index.js.map +1 -0
  11. package/dist/dispose-base-CAeXDpjg.d.ts +6 -0
  12. package/dist/error/index.d.ts +46 -0
  13. package/dist/error/index.js +150 -0
  14. package/dist/error/index.js.map +1 -0
  15. package/dist/error-base-BWuBlS2k.d.ts +28 -0
  16. package/dist/event/index.d.ts +57 -0
  17. package/dist/event/index.js +167 -0
  18. package/dist/event/index.js.map +1 -0
  19. package/dist/index.d.ts +10 -0
  20. package/dist/index.js +989 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/json/index.d.ts +4 -0
  23. package/dist/json/index.js +20 -0
  24. package/dist/json/index.js.map +1 -0
  25. package/dist/lock/index.d.ts +106 -0
  26. package/dist/lock/index.js +404 -0
  27. package/dist/lock/index.js.map +1 -0
  28. package/dist/response/index.d.ts +17 -0
  29. package/dist/response/index.js +19 -0
  30. package/dist/response/index.js.map +1 -0
  31. package/package.json +80 -0
  32. package/src/assert/assert.ts +24 -0
  33. package/src/assert/index.ts +2 -0
  34. package/src/async/barrier.ts +47 -0
  35. package/src/async/index.ts +8 -0
  36. package/src/async/promise.ts +316 -0
  37. package/src/async/wait.ts +7 -0
  38. package/src/dispose/disposable-store.ts +68 -0
  39. package/src/dispose/disposable-t.ts +85 -0
  40. package/src/dispose/disposable-utils.ts +13 -0
  41. package/src/dispose/dispose-base.ts +9 -0
  42. package/src/dispose/index.ts +8 -0
  43. package/src/dispose/logger.ts +41 -0
  44. package/src/error/error-base.ts +39 -0
  45. package/src/error/error-code.ts +48 -0
  46. package/src/error/error-const.ts +16 -0
  47. package/src/error/error-or.ts +2 -0
  48. package/src/error/error-t.ts +93 -0
  49. package/src/error/index.ts +5 -0
  50. package/src/event/emitter.ts +193 -0
  51. package/src/event/index.ts +10 -0
  52. package/src/index.ts +8 -0
  53. package/src/json/index.ts +1 -0
  54. package/src/json/json.ts +15 -0
  55. package/src/lock/README.md +11 -0
  56. package/src/lock/capability.ts +89 -0
  57. package/src/lock/index.ts +2 -0
  58. package/src/lock/semaphore.ts +21 -0
  59. package/src/lock/shared-mutex.ts +256 -0
  60. package/src/response/index.ts +1 -0
  61. package/src/response/response.ts +27 -0
  62. package/tsconfig.json +23 -0
@@ -0,0 +1,89 @@
1
+ import { lvAssert } from '../assert';
2
+ import { Emitter, type Event } from '../event';
3
+
4
+ //
5
+ // 资源对应的是标准库中的 unsigned state 以及相关的位运算
6
+ // 我们用两个具体的Capability结构实现(Capability命名来源于标准库)
7
+ //
8
+
9
+ /**
10
+ * 资源状态
11
+ */
12
+ export enum CapabilityStatus {
13
+ Unlocked,
14
+ Locked,
15
+ }
16
+
17
+ /**
18
+ * 独享的资源
19
+ *
20
+ * acquire 获取控制权
21
+ * release 释放控制权
22
+ */
23
+ export class Capability {
24
+ public onUnlocked: Event<[]>;
25
+
26
+ private readonly _onUnlocked = new Emitter<[]>();
27
+ private _status = CapabilityStatus.Unlocked;
28
+
29
+ constructor() {
30
+ this.onUnlocked = this._onUnlocked.event;
31
+ }
32
+
33
+ get status(): CapabilityStatus {
34
+ return this._status;
35
+ }
36
+
37
+ public acquire(): void {
38
+ lvAssert(this._status === CapabilityStatus.Unlocked);
39
+ this._status = CapabilityStatus.Locked;
40
+ }
41
+
42
+ public release(): void {
43
+ lvAssert(this._status === CapabilityStatus.Locked);
44
+ this._status = CapabilityStatus.Unlocked;
45
+ this._onUnlocked.fire();
46
+ }
47
+ }
48
+
49
+ /**
50
+ * 共享的资源
51
+ *
52
+ * acquire 获取控制权
53
+ * release 释放控制权
54
+ */
55
+ export class SharedCapability {
56
+ public onUnlocked: Event<[]>;
57
+
58
+ private readonly _onUnlocked = new Emitter<[]>();
59
+ private _status = CapabilityStatus.Unlocked;
60
+ private _counter = 0;
61
+
62
+ constructor() {
63
+ this.onUnlocked = this._onUnlocked.event;
64
+ }
65
+
66
+ get status(): CapabilityStatus {
67
+ return this._status;
68
+ }
69
+
70
+ get counter(): number {
71
+ return this._counter;
72
+ }
73
+
74
+ public acquire() {
75
+ if (this._status === CapabilityStatus.Unlocked) {
76
+ this._status = CapabilityStatus.Locked;
77
+ }
78
+ this._counter++;
79
+ }
80
+
81
+ public release() {
82
+ lvAssert(this._counter > 0);
83
+ this._counter--;
84
+ if (this._counter === 0) {
85
+ this._status = CapabilityStatus.Unlocked;
86
+ this._onUnlocked.fire();
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,2 @@
1
+ // 读写能力的互斥量,实现读写锁的能力
2
+ export { SharedMutex } from './shared-mutex';
@@ -0,0 +1,21 @@
1
+ import type { Event } from '../event';
2
+ import { Emitter } from '../event';
3
+
4
+ /**
5
+ * 信号
6
+ *
7
+ * 用来模拟标准库的condition_variable
8
+ * 提供监听某个信号被激活的能力
9
+ */
10
+ export class Semaphore {
11
+ public onActive: Event<[]>;
12
+ private readonly _onActive = new Emitter<[]>();
13
+
14
+ constructor() {
15
+ this.onActive = this._onActive.event;
16
+ }
17
+
18
+ public notify(): void {
19
+ this._onActive.fire();
20
+ }
21
+ }
@@ -0,0 +1,256 @@
1
+ import { lvAssert, lvAssertNotNil } from '../assert';
2
+ import { listenOnce } from '../event';
3
+ import { SharedCapability, Capability, CapabilityStatus } from './capability';
4
+ import { Semaphore } from './semaphore';
5
+
6
+ /**
7
+ * 提供读写能力的共享互斥量
8
+ *
9
+ * 参考C++17标准库双门思想实现
10
+ * 接口也与标准库保持一致
11
+ * 方法内部禁止promise,只可以对外暴露promise
12
+ *
13
+ * 核心
14
+ * - 写写互斥,读写互斥,读读可重入
15
+ *
16
+ * 使用举例:
17
+ * class Foo {
18
+ * private _mutex = new SharedMutex();
19
+ *
20
+ * async add() {
21
+ * // 上写锁
22
+ * await this._mutex.lock();
23
+ * // ...write something
24
+ * this._mutex.unlock();
25
+ * }
26
+ *
27
+ * async getSomething1() {
28
+ * // 上读锁
29
+ * await this._mutex.lockShared();
30
+ * try {
31
+ * return xxx;
32
+ * } finally {
33
+ * this._mutex.unlockShared();
34
+ * }
35
+ * }
36
+ *
37
+ * async getSomething2() {
38
+ * // 上读锁
39
+ * await this._mutex.lockShared();
40
+ * try {
41
+ * return xxx;
42
+ * } finally {
43
+ * this._mutex.unlockShared();
44
+ * }
45
+ * }
46
+ * }
47
+ */
48
+ export class SharedMutex {
49
+ // 在第一道门外等待的写者
50
+ private readonly _waitingWriters: Semaphore[] = [];
51
+
52
+ // 已经通过了第一道门的写者
53
+ // 如果在第二道门外等待,状态为sharedLocked
54
+ // 如果已经进入到第二道门内拿到了锁,状态为locked
55
+ private _writer?: Capability;
56
+
57
+ // 在第一道门外等待的读者
58
+ private _waitingReader?: Semaphore;
59
+
60
+ // 拿到锁的读者
61
+ private _reader?: SharedCapability;
62
+
63
+ /**
64
+ * 是否被锁住
65
+ */
66
+ public isLocked(): boolean {
67
+ return Boolean(this._writer) || this._readerCount !== 0;
68
+ }
69
+
70
+ /**
71
+ * 等待并获取写锁
72
+ */
73
+ public lock(): Promise<void> {
74
+ return new Promise<void>((resolve) => {
75
+ // 第一道门
76
+ if (this._writer) {
77
+ // 如果已经有写者进入了,其他写者等待
78
+ const token = new Semaphore();
79
+ this._waitingWriters.push(token);
80
+ token.onActive(() => {
81
+ this._writerEnterGate1(resolve);
82
+ });
83
+ } else {
84
+ this._writerEnterGate1(resolve);
85
+ }
86
+ });
87
+ }
88
+
89
+ /**
90
+ * 尝试获取写锁,立刻返回结果
91
+ */
92
+ public tryLock(): boolean {
93
+ if (this._writer || this._readerCount > 0) {
94
+ return false;
95
+ }
96
+ // 这里不需要await,一定可以上锁
97
+ this.lock();
98
+ return true;
99
+ }
100
+
101
+ /**
102
+ * 解除写锁
103
+ */
104
+ public unLock(): void {
105
+ lvAssertNotNil(this._writer);
106
+
107
+ // 打开第一道门
108
+ this._writer.release();
109
+ }
110
+
111
+ /**
112
+ * 解除写锁。`unLock` 的常规拼写别名。
113
+ */
114
+ public unlock(): void {
115
+ this.unLock();
116
+ }
117
+
118
+ /**
119
+ * 等待并获取读锁
120
+ */
121
+ public lockShared(): Promise<void> {
122
+ return new Promise<void>((resolve) => {
123
+ // 读者只需要进第一道门
124
+ if (this._writer) {
125
+ // 如果有写者已经进入了第一道门,读者等待
126
+ if (!this._waitingReader) {
127
+ this._waitingReader = new Semaphore();
128
+ }
129
+ this._waitingReader.onActive(() => {
130
+ this._readerEnterGate1(resolve);
131
+ });
132
+ } else {
133
+ this._readerEnterGate1(resolve);
134
+ }
135
+ });
136
+ }
137
+
138
+ /**
139
+ * 尝试获取读锁,立刻返回结果
140
+ */
141
+ public tryLockShared(): boolean {
142
+ if (this._writer) {
143
+ return false;
144
+ }
145
+ // 不需要await,一定可以上锁
146
+ this.lockShared();
147
+ return true;
148
+ }
149
+
150
+ /**
151
+ * 解除读锁
152
+ */
153
+ public unLockShared(): void {
154
+ lvAssertNotNil(this._reader);
155
+ if (this._writer) {
156
+ // TODO(niurouwan): 暂时保留,方便验证,稳定后可以去掉
157
+ lvAssert(this._writer.status === CapabilityStatus.Unlocked);
158
+ }
159
+
160
+ this._reader.release();
161
+ }
162
+
163
+ /**
164
+ * 解除读锁。`unLockShared` 的常规拼写别名。
165
+ */
166
+ public unlockShared(): void {
167
+ this.unLockShared();
168
+ }
169
+
170
+ /**
171
+ * 获取当前读者数量
172
+ */
173
+ private get _readerCount(): number {
174
+ return this._reader ? this._reader.counter : 0;
175
+ }
176
+
177
+ /**
178
+ * 写者进入第一道门
179
+ */
180
+ private _writerEnterGate1(resolve: () => void): void {
181
+ lvAssert(!this._writer);
182
+ // 确定写者,关第一道门
183
+ this._writer = new Capability();
184
+
185
+ // 第二道门
186
+ // 等待所有读者出去
187
+ if (this._readerCount > 0) {
188
+ listenOnce(this._reader!.onUnlocked)(() => {
189
+ this._writerEnterGate2(resolve);
190
+ });
191
+ } else {
192
+ this._writerEnterGate2(resolve);
193
+ }
194
+ }
195
+
196
+ /**
197
+ * 写者进入第二道门
198
+ */
199
+ private _writerEnterGate2(resolve: () => void): void {
200
+ lvAssertNotNil(this._writer);
201
+ lvAssert(this._readerCount === 0);
202
+
203
+ // 成功加锁
204
+ this._writer.acquire();
205
+ listenOnce(this._writer.onUnlocked)(() => {
206
+ lvAssertNotNil(this._writer);
207
+ // 不再持有
208
+ this._writer = undefined;
209
+ this._moveForward();
210
+ });
211
+ resolve();
212
+ }
213
+
214
+ /**
215
+ * 读者进入第一道门
216
+ */
217
+ private _readerEnterGate1(resolve: () => void): void {
218
+ lvAssert(!this._writer);
219
+
220
+ // 门外等待的读者清除
221
+ this._waitingReader = undefined;
222
+
223
+ if (!this._reader) {
224
+ this._reader = new SharedCapability();
225
+ this._reader.acquire();
226
+ listenOnce(this._reader.onUnlocked)(() => {
227
+ this._moveForward();
228
+ });
229
+ } else {
230
+ this._reader.acquire();
231
+ }
232
+ resolve();
233
+ }
234
+
235
+ /**
236
+ * 锁释放时推进流程
237
+ */
238
+ private _moveForward(): void {
239
+ // 如果有写者在等待在第二道门前面,那么此时推进的一定是读锁释放,直接return即可
240
+ if (this._writer) {
241
+ return;
242
+ }
243
+
244
+ // 写者优先,优先通知在第一道门前面的写者
245
+ if (this._waitingWriters.length > 0) {
246
+ const semaphore = this._waitingWriters.shift()!;
247
+ semaphore.notify();
248
+ return;
249
+ }
250
+
251
+ // 最后通知第一道门前面的读者
252
+ if (this._waitingReader) {
253
+ this._waitingReader.notify();
254
+ }
255
+ }
256
+ }
@@ -0,0 +1 @@
1
+ export * from './response';
@@ -0,0 +1,27 @@
1
+ export interface ISuccessResponse<T = any> {
2
+ code: 0;
3
+ data: T;
4
+ msg: string;
5
+ }
6
+
7
+ export interface IErrorResponse {
8
+ code: Exclude<number, 0>;
9
+ msg: string;
10
+ }
11
+
12
+ export type IResponse<T = any> = ISuccessResponse<T> | IErrorResponse;
13
+
14
+ export function makeSuccessResponse<T = any>(data: T): ISuccessResponse<T> {
15
+ return {
16
+ code: 0,
17
+ data,
18
+ msg: 'success',
19
+ };
20
+ }
21
+
22
+ export function makeErrorResponse(code: number, msg: string) {
23
+ return {
24
+ code,
25
+ msg,
26
+ };
27
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2022",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022", "DOM"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "declaration": true,
12
+ "declarationMap": true,
13
+ "sourceMap": true,
14
+ "noUnusedLocals": false,
15
+ "noUnusedParameters": false,
16
+ "noImplicitReturns": true,
17
+ "noFallthroughCasesInSwitch": true,
18
+ "isolatedModules": true,
19
+ "types": ["node"]
20
+ },
21
+ "include": ["src/**/*"],
22
+ "exclude": ["node_modules", "dist"]
23
+ }