fib-pool 1.6.0 → 1.6.2

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/.travis.yml CHANGED
@@ -26,6 +26,15 @@ matrix:
26
26
  - os: linux
27
27
  env:
28
28
  - VERSION=0.27.0
29
+ - os: linux
30
+ env:
31
+ - VERSION=0.28.0
32
+ - os: linux
33
+ env:
34
+ - VERSION=0.29.0
35
+ - os: linux
36
+ env:
37
+ - VERSION=0.30.0
29
38
  - os: osx
30
39
  osx_image: xcode9
31
40
  env:
@@ -58,6 +67,18 @@ matrix:
58
67
  osx_image: xcode9
59
68
  env:
60
69
  - VERSION=0.27.0
70
+ - os: osx
71
+ osx_image: xcode9
72
+ env:
73
+ - VERSION=0.28.0
74
+ - os: osx
75
+ osx_image: xcode9
76
+ env:
77
+ - VERSION=0.29.0
78
+ - os: osx
79
+ osx_image: xcode9
80
+ env:
81
+ - VERSION=0.30.0
61
82
  before_install:
62
83
  - OS=linux
63
84
  - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
@@ -103,6 +103,45 @@ var res = p("test", (conn) => {
103
103
 
104
104
  ```
105
105
 
106
+ ## Strict mode (default: enabled)
107
+
108
+ By default, the pool uses strict mode to prevent accessing pooled objects outside of the callback function. This helps prevent resource leaks and ensures proper resource management.
109
+
110
+ ```js
111
+ var Pool = require("fib-pool");
112
+
113
+ var p = Pool({
114
+ create: () => {
115
+ return { value: 1, getValue: function() { return this.value; } };
116
+ }
117
+ });
118
+
119
+ var leaked;
120
+ p((obj) => {
121
+ leaked = obj;
122
+ // This works inside the pool callback
123
+ console.log(obj.getValue()); // OK
124
+ });
125
+
126
+ // This will throw an error: "access object outside of pool scope"
127
+ leaked.getValue(); // Error!
128
+ ```
129
+
130
+ When strict mode is enabled, it also prevents:
131
+ - Setting properties on pooled objects
132
+ - Calling `close()`, `destroy()`, or `dispose()` methods directly
133
+
134
+ To disable strict mode:
135
+
136
+ ```js
137
+ var p = Pool({
138
+ create: () => {
139
+ return { value: 1 };
140
+ },
141
+ strict: false
142
+ });
143
+ ```
144
+
106
145
  ## Clear a pool
107
146
 
108
147
  Simple example.
package/appveyor.yml CHANGED
@@ -9,6 +9,9 @@ environment:
9
9
  - VERSION: 0.26.0
10
10
  - VERSION: 0.26.1
11
11
  - VERSION: 0.27.0
12
+ - VERSION: 0.28.0
13
+ - VERSION: 0.29.0
14
+ - VERSION: 0.30.0
12
15
 
13
16
  install:
14
17
  - ps: Install-Product node $env:nodejs_version
package/lib/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ "use strict";
1
2
  const coroutine = require("coroutine");
2
3
  const util = require("util");
3
4
  function ensureError(e) {
@@ -5,7 +6,7 @@ function ensureError(e) {
5
6
  e = new Error(e);
6
7
  return e;
7
8
  }
8
- const GetPool = function (_opt, maxsize, timeout) {
9
+ module.exports = function GetPool(_opt, maxsize, timeout) {
9
10
  let opt = _opt;
10
11
  if (util.isFunction(_opt)) {
11
12
  opt = {
@@ -160,4 +161,3 @@ const GetPool = function (_opt, maxsize, timeout) {
160
161
  };
161
162
  return pool;
162
163
  };
163
- module.exports = GetPool;
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "fib-pool",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "description": "Generic resource pooling for fibjs",
5
- "main": "./lib",
6
- "types": "@types/index.d.ts",
5
+ "main": "./src",
6
+ "types": "typings/index.d.ts",
7
+ "type": "module",
7
8
  "repository": "git://github.com/fibjs/fib-pool.git",
8
9
  "author": "Liu Hu <lion@9465.net>",
9
10
  "contributors": [
@@ -20,15 +21,15 @@
20
21
  "fibjs"
21
22
  ],
22
23
  "scripts": {
23
- "build": "fib-typify src -o lib",
24
24
  "test": "fibjs test",
25
- "ci": "npm run build && npm run test",
26
- "prepublishOnly": "npm run build"
25
+ "typecheck": "tsc --noEmit",
26
+ "ci": "npm run typecheck && npm run test"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@fibjs/ci": "^2.3.0",
30
30
  "@fibjs/types": "^0.27.1",
31
- "fib-typify": "^0.6.0"
31
+ "fib-typify": "^0.8.4",
32
+ "typescript": "^5.9.3"
32
33
  },
33
34
  "ci": {
34
35
  "type": "travis, appveyor",
@@ -40,7 +41,10 @@
40
41
  "0.25.0",
41
42
  "0.26.0",
42
43
  "0.26.1",
43
- "0.27.0"
44
+ "0.27.0",
45
+ "0.28.0",
46
+ "0.29.0",
47
+ "0.30.0"
44
48
  ]
45
49
  }
46
50
  }
package/src/index.ts ADDED
@@ -0,0 +1,287 @@
1
+ import * as coroutine from 'coroutine';
2
+ import * as util from 'util';
3
+
4
+ declare namespace FibPoolNS {
5
+ type FirstParameter<T> = T extends (arg: infer T, ...args: any[]) => any ? T : never;
6
+
7
+ interface DippedItemStruct {
8
+ close?: FibPoolOptionResult['destroy'];
9
+ destroy?: FibPoolOptionResult['destroy'];
10
+ dispose?: FibPoolOptionResult['destroy'];
11
+ }
12
+
13
+ interface FibPoolOptionArgs<T extends DippedItemStruct = {}> {
14
+ create: (name: string) => T
15
+ destroy?: (item?: T) => any;
16
+ maxsize?: number
17
+ timeout?: number
18
+ retry?: number | boolean
19
+ strict?: boolean
20
+ }
21
+ interface FibPoolOptionResult<T extends DippedItemStruct = {}> {
22
+ create: FibPoolOptionArgs<T>['create']
23
+ destroy: FibPoolOptionArgs<T>['destroy']
24
+ maxsize: FibPoolOptionArgs<T>['maxsize']
25
+ timeout: FibPoolOptionArgs<T>['timeout']
26
+ retry: FibPoolOptionArgs<T>['retry']
27
+ strict: FibPoolOptionArgs<T>['strict']
28
+ }
29
+
30
+ interface FibPoolDipperFn<T_CREATED_ITEM, T_POOL_FUNC_RETURN = any> {
31
+ (o: T_CREATED_ITEM): T_POOL_FUNC_RETURN
32
+ }
33
+
34
+ type FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN = any> = {
35
+ <T_RETURN = T_POOL_FUNC_RETURN>(name: string, func: FibPoolDipperFn<T_CREATED_ITEM, T_RETURN>): T_RETURN
36
+ <T_RETURN = T_POOL_FUNC_RETURN>(func: FibPoolDipperFn<T_CREATED_ITEM, T_RETURN>): T_RETURN
37
+ } & {
38
+ connections?(): number;
39
+ info?(): {
40
+ maxsize: number;
41
+ count: number;
42
+ running: number;
43
+ wait: number;
44
+ timeout: number;
45
+ };
46
+ clear?(): void;
47
+ }
48
+ }
49
+
50
+ function ensureError (e: string | Error) {
51
+ if (typeof e === 'string')
52
+ e = new Error(e)
53
+
54
+ return e
55
+ }
56
+
57
+ export default function GetPool<
58
+ T_CREATED_ITEM extends FibPoolNS.DippedItemStruct,
59
+ T_POOL_FUNC_RETURN
60
+ > (
61
+ _opt: FibPoolNS.FibPoolOptionArgs<T_CREATED_ITEM> | FibPoolNS.FibPoolOptionArgs<T_CREATED_ITEM>['create'],
62
+ maxsize?: number,
63
+ timeout?: number
64
+ ): FibPoolNS.FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN> {
65
+ /* clean input arguments :start */
66
+ let opt = <FibPoolNS.FibPoolOptionResult<T_CREATED_ITEM>>_opt;
67
+ if (util.isFunction(_opt)) {
68
+ opt = <FibPoolNS.FibPoolOptionResult<T_CREATED_ITEM>>{
69
+ create: _opt,
70
+ maxsize: maxsize,
71
+ timeout: timeout
72
+ };
73
+ }
74
+
75
+ const create = opt.create;
76
+ const destroy = opt.destroy || ((o: {
77
+ close?: FibPoolNS.FibPoolOptionResult<T_CREATED_ITEM>['destroy'];
78
+ destroy?: FibPoolNS.FibPoolOptionResult<T_CREATED_ITEM>['destroy'];
79
+ dispose?: FibPoolNS.FibPoolOptionResult<T_CREATED_ITEM>['destroy'];
80
+ }) => {
81
+ if (util.isFunction(o.close)) o.close();
82
+ if (util.isFunction(o.destroy)) o.destroy();
83
+ if (util.isFunction(o.dispose)) o.dispose();
84
+ });
85
+
86
+ maxsize = opt.maxsize || 10;
87
+ timeout = opt.timeout || 60000;
88
+ let tm = timeout / 10;
89
+ if (tm < 10)
90
+ tm = 10;
91
+
92
+ const retry = opt.retry || 1;
93
+ const _strict = opt.strict === undefined ? true : opt.strict;
94
+ /* clean input arguments :end */
95
+
96
+ let pools = <{
97
+ o: T_CREATED_ITEM;
98
+ name: string;
99
+ time: Date;
100
+ }[]>[];
101
+
102
+ const jobs = <{
103
+ name: string;
104
+ ev: Class_Event;
105
+ o?: T_CREATED_ITEM;
106
+ e?: Error;
107
+ }[]>[];
108
+
109
+ let count = 0;
110
+ let running = 0;
111
+
112
+ const sem = new coroutine.Semaphore(maxsize);
113
+ let clearTimer: Class_Timer;
114
+
115
+ function clearPool() {
116
+ let c: typeof pools[any];
117
+ const d = new Date().getTime();
118
+
119
+ while (count) {
120
+ c = pools[0];
121
+
122
+ if (d - c.time.getTime() > timeout) {
123
+ pools = pools.slice(1);
124
+ count--;
125
+
126
+ if (c.o !== undefined)
127
+ coroutine.start(destroy, c.o);
128
+ } else
129
+ break;
130
+ }
131
+
132
+ if (!count) {
133
+ if (clearTimer) {
134
+ clearTimer.clear();
135
+ clearTimer = null;
136
+ }
137
+ } else if (!clearTimer) {
138
+ clearTimer = setInterval(clearPool, tm);
139
+ if (clearTimer && typeof clearTimer.unref === 'function')
140
+ clearTimer.unref();
141
+ }
142
+ }
143
+
144
+ function putback(
145
+ name: typeof jobs[any]['name'],
146
+ o: T_CREATED_ITEM,
147
+ e?: Error
148
+ ) {
149
+ e = ensureError(e);
150
+ for (let i = 0; i < jobs.length; i++) {
151
+ const job = jobs[i];
152
+ if (job.name === name) {
153
+ jobs.splice(i, 1);
154
+ job.o = o;
155
+ job.e = e;
156
+ job.ev.set();
157
+ return;
158
+ }
159
+ }
160
+
161
+ if (e === undefined)
162
+ pools[count++] = {
163
+ o: o,
164
+ name: name,
165
+ time: new Date()
166
+ };
167
+ }
168
+
169
+ function connect(name: string) {
170
+ let o: T_CREATED_ITEM;
171
+ let cn = 0;
172
+ let err: Error;
173
+
174
+ while (true) {
175
+ try {
176
+ o = create(name);
177
+ break;
178
+ } catch (e) {
179
+ if (++cn >= (retry as number)) {
180
+ err = e;
181
+ break;
182
+ }
183
+ }
184
+ }
185
+
186
+ putback(name, o, err);
187
+ }
188
+
189
+ const pool: FibPoolNS.FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN> = (
190
+ name: string | FibPoolNS.FibPoolDipperFn<T_CREATED_ITEM, T_POOL_FUNC_RETURN>,
191
+ func?: FibPoolNS.FibPoolDipperFn<T_CREATED_ITEM, T_POOL_FUNC_RETURN>
192
+ ) => {
193
+ if (typeof name === 'function') {
194
+ func = name as any;
195
+ name = "";
196
+ }
197
+
198
+ let r: T_POOL_FUNC_RETURN;
199
+ let o: typeof jobs[any]['o'];
200
+ let p = false;
201
+
202
+ clearPool();
203
+ sem.acquire();
204
+
205
+ if (count) {
206
+ for (let i = count - 1; i >= 0; i--)
207
+ if (pools[i].name === name) {
208
+ p = true
209
+ o = pools[i].o;
210
+ pools.splice(i, 1);
211
+ count--;
212
+ break;
213
+ }
214
+ }
215
+
216
+ if (!p) {
217
+ coroutine.start(connect, name);
218
+
219
+ const job = <typeof jobs[any]>{
220
+ name: name,
221
+ ev: new coroutine.Event()
222
+ };
223
+ jobs.push(job);
224
+
225
+ job.ev.wait();
226
+ if (job.e) {
227
+ sem.post();
228
+ throw ensureError(job.e);
229
+ }
230
+ o = job.o;
231
+ }
232
+
233
+ running++;
234
+ try {
235
+ const po = (_strict && typeof o === 'object') ? new Proxy({}, {
236
+ get: function (target, prop) {
237
+ if (prop === 'close' || prop === 'destroy' || prop === 'dispose')
238
+ throw new Error("Cannot close/destroy/dispose");
239
+ if (o === undefined)
240
+ throw new Error("access object outside of pool scope");
241
+ const value = o[prop];
242
+ if (typeof value === 'function') {
243
+ return function () {
244
+ return value.apply(o, arguments);
245
+ }
246
+ }
247
+ return value;
248
+ },
249
+ set: function (target, prop, value) {
250
+ throw new Error("Cannot set property");
251
+ }
252
+ }) as any : o;
253
+
254
+ r = func(po as T_CREATED_ITEM);
255
+ putback(name, o);
256
+ o = undefined;
257
+ } catch (e) {
258
+ if (o !== undefined)
259
+ coroutine.start(destroy, o);
260
+ o = undefined;
261
+ throw ensureError(e);
262
+ } finally {
263
+ running--;
264
+ sem.post();
265
+ clearPool();
266
+ }
267
+
268
+ return r;
269
+ };
270
+
271
+ pool.connections = () => count
272
+
273
+ pool.info = () => ({
274
+ maxsize: maxsize,
275
+ count: count,
276
+ running: running,
277
+ wait: sem.count(),
278
+ timeout: timeout
279
+ })
280
+
281
+ pool.clear = () => {
282
+ timeout = -1;
283
+ clearPool();
284
+ }
285
+
286
+ return pool;
287
+ }
package/tsconfig.json CHANGED
@@ -4,9 +4,14 @@
4
4
  "module": "commonjs",
5
5
  "alwaysStrict": false,
6
6
  "removeComments": true,
7
- "typeRoots": [
8
- "node_modules",
9
- "types"
7
+ "noEmit": true,
8
+ "types": [
9
+ "@fibjs/types"
10
10
  ]
11
- }
11
+ },
12
+ "exclude": [
13
+ "test",
14
+ "typings",
15
+ "node_modules"
16
+ ]
12
17
  }
@@ -0,0 +1,43 @@
1
+ declare namespace FibPoolNS {
2
+ type FirstParameter<T> = T extends (arg: infer T, ...args: any[]) => any ? T : never;
3
+ interface DippedItemStruct {
4
+ close?: FibPoolOptionResult['destroy'];
5
+ destroy?: FibPoolOptionResult['destroy'];
6
+ dispose?: FibPoolOptionResult['destroy'];
7
+ }
8
+ interface FibPoolOptionArgs<T extends DippedItemStruct = {}> {
9
+ create: (name: string) => T;
10
+ destroy?: (item?: T) => any;
11
+ maxsize?: number;
12
+ timeout?: number;
13
+ retry?: number | boolean;
14
+ strict?: boolean;
15
+ }
16
+ interface FibPoolOptionResult<T extends DippedItemStruct = {}> {
17
+ create: FibPoolOptionArgs<T>['create'];
18
+ destroy: FibPoolOptionArgs<T>['destroy'];
19
+ maxsize: FibPoolOptionArgs<T>['maxsize'];
20
+ timeout: FibPoolOptionArgs<T>['timeout'];
21
+ retry: FibPoolOptionArgs<T>['retry'];
22
+ strict: FibPoolOptionArgs<T>['strict'];
23
+ }
24
+ interface FibPoolDipperFn<T_CREATED_ITEM, T_POOL_FUNC_RETURN = any> {
25
+ (o: T_CREATED_ITEM): T_POOL_FUNC_RETURN;
26
+ }
27
+ type FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN = any> = {
28
+ <T_RETURN = T_POOL_FUNC_RETURN>(name: string, func: FibPoolDipperFn<T_CREATED_ITEM, T_RETURN>): T_RETURN;
29
+ <T_RETURN = T_POOL_FUNC_RETURN>(func: FibPoolDipperFn<T_CREATED_ITEM, T_RETURN>): T_RETURN;
30
+ } & {
31
+ connections?(): number;
32
+ info?(): {
33
+ maxsize: number;
34
+ count: number;
35
+ running: number;
36
+ wait: number;
37
+ timeout: number;
38
+ };
39
+ clear?(): void;
40
+ };
41
+ }
42
+ declare const _default: <T_CREATED_ITEM extends FibPoolNS.DippedItemStruct, T_POOL_FUNC_RETURN>(_opt: FibPoolNS.FibPoolOptionArgs<T_CREATED_ITEM> | ((name: string) => T_CREATED_ITEM), maxsize?: number, timeout?: number) => FibPoolNS.FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN>;
43
+ export = _default;
package/@types/index.d.ts DELETED
@@ -1,3 +0,0 @@
1
- /// <reference path="type.d.ts" />
2
-
3
- export = FibPoolNS.FibPoolGenerator
package/@types/type.d.ts DELETED
@@ -1,58 +0,0 @@
1
- /// <reference types="@fibjs/types" />
2
-
3
- declare namespace FibPoolNS {
4
- type FirstParameter<T> = T extends (arg: infer T, ...args: any[]) => any ? T : never;
5
-
6
- interface DippedItemStruct {
7
- close?: FibPoolOptionResult['destroy'];
8
- destroy?: FibPoolOptionResult['destroy'];
9
- dispose?: FibPoolOptionResult['destroy'];
10
- }
11
-
12
- interface FibPoolOptionArgs<T extends DippedItemStruct = Fibjs.AnyObject> {
13
- create: (name: string) => T
14
- destroy?: (item?: T) => any;
15
- maxsize?: number
16
- timeout?: number
17
- retry?: number | boolean
18
- }
19
- interface FibPoolOptionResult<T extends DippedItemStruct = Fibjs.AnyObject> {
20
- create: FibPoolOptionArgs<T>['create']
21
- destroy: FibPoolOptionArgs<T>['destroy']
22
- maxsize: FibPoolOptionArgs<T>['maxsize']
23
- timeout: FibPoolOptionArgs<T>['timeout']
24
- retry: FibPoolOptionArgs<T>['retry']
25
- }
26
-
27
- interface FibPoolDipperFn<T_CREATED_ITEM, T_POOL_FUNC_RETURN = any> {
28
- (o: T_CREATED_ITEM): T_POOL_FUNC_RETURN
29
- }
30
-
31
- type FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN = any> = {
32
- <T_RETURN = T_POOL_FUNC_RETURN>(name: string, func: FibPoolDipperFn<T_CREATED_ITEM, T_RETURN>): T_RETURN
33
- <T_RETURN = T_POOL_FUNC_RETURN>(func: FibPoolDipperFn<T_CREATED_ITEM, T_RETURN>): T_RETURN
34
- } & {
35
- connections?(): number;
36
- info?(): {
37
- maxsize: number;
38
- count: number;
39
- running: number;
40
- wait: number;
41
- timeout: number;
42
- };
43
- clear?(): void;
44
- }
45
-
46
- function FibPoolGenerator<
47
- T_CREATED_ITEM extends DippedItemStruct = Fibjs.AnyObject,
48
- T_POOL_FUNC_RETURN = any
49
- > (
50
- opt: FibPoolOptionArgs<T_CREATED_ITEM> | FibPoolOptionArgs<T_CREATED_ITEM>['create'],
51
- maxsize?: number,
52
- timeout?: number
53
- ): FibPool<T_CREATED_ITEM, T_POOL_FUNC_RETURN>;
54
- }
55
-
56
- declare module "fib-pool" {
57
- export = FibPoolNS.FibPoolGenerator
58
- }