Skip to content

Commit ac9cb7d

Browse files
committed
Initial Commit
0 parents  commit ac9cb7d

File tree

116 files changed

+9641
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+9641
-0
lines changed

.babelrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["es2015", "stage-2"]
3+
}

.eslintrc

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"extends": "eslint:recommended",
3+
"parser": "babel-eslint",
4+
"env": {
5+
"browser": true,
6+
"node": true,
7+
"es6": true
8+
},
9+
"rules": {
10+
"no-unused-vars": ["error", { "args": "none" }]
11+
}
12+
}

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
/dist
3+
.idea
4+
npm-debug.log
5+
yarn-error.log

.npmignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test
2+
yarn-error.log
3+
yarn.lock

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 jcdelmas
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
the Software, and to permit persons to whom the Software is furnished to do so,
10+
subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
# pp-stream
3+
4+
High-level stream library with back-pressure support. Inspired by [Akka Stream](http://doc.akka.io/docs/akka/2.5.4/scala/stream/index.html).

ROADMAP.md

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
# Roadmap
3+
4+
## Sources
5+
6+
* failed
7+
* fromFile
8+
* fromQueue
9+
10+
## Sinks
11+
12+
* cancelled
13+
* toFile
14+
* foldAsync
15+
16+
## Flows
17+
18+
* takeWithin
19+
* dropWithin
20+
* groupedWithin
21+
* recoverWith
22+
* detach
23+
* initialDelay
24+
* batch
25+
* prepend
26+
* fromSinkAndSource
27+
28+
## Fan out
29+
30+
* unzip
31+
* unzipWith
32+
* route (not in akka stream)
33+
34+
## Misc
35+
36+
* NodeJS stream converter
37+
38+
## Testing
39+
40+
* Concurrent test execution

package.json

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
{
2+
"name": "pp-stream",
3+
"version": "0.1.0",
4+
"description": "High-level stream library with back-pressure support.",
5+
"main": "./dist/index.js",
6+
"directories": {
7+
"test": "test"
8+
},
9+
"dependencies": {
10+
"@types/chai": "^4.1.4",
11+
"@types/chai-as-promised": "^7.1.0",
12+
"@types/lodash": "^4.14.106",
13+
"@types/node": "^9.6.0",
14+
"@types/should": "^13.0.0",
15+
"bluebird": "^3.5.0",
16+
"lodash": "^4.17.4"
17+
},
18+
"devDependencies": {
19+
"@types/jest": "^22.2.2",
20+
"babel-cli": "^6.5.1",
21+
"babel-core": "^6.5.2",
22+
"babel-eslint": "^7.2.3",
23+
"babel-polyfill": "^6.5.0",
24+
"babel-preset-es2015": "^6.5.0",
25+
"babel-preset-stage-2": "^6.24.1",
26+
"babel-register": "^6.5.2",
27+
"chai": "^4.1.2",
28+
"chai-as-promised": "^7.1.1",
29+
"eslint": "^4.6.1",
30+
"eslint-plugin-import": "^2.7.0",
31+
"jest": "^20.0.4",
32+
"npm-run-all": "^4.1.1",
33+
"rimraf": "^2.6.2",
34+
"should": "^11.2.1",
35+
"should-promised": "^0.3.1",
36+
"ts-jest": "^22.4.2",
37+
"typescript": "^2.7.2"
38+
},
39+
"scripts": {
40+
"clean": "rimraf dist",
41+
"test": "jest",
42+
"lint": "eslint src test",
43+
"check": "run-s lint test",
44+
"build": "babel src --out-dir dist",
45+
"release": "run-s clean check build",
46+
"typescript": "tsc --outDir dist --project ."
47+
},
48+
"repository": {
49+
"type": "git",
50+
"url": "git+https://github.com/jcdelmas/pp-stream.git"
51+
},
52+
"jest": {
53+
"transform": {
54+
"^.+\\.tsx?$": "ts-jest",
55+
"^.+\\.jsx?$": "babel-jest"
56+
},
57+
"testRegex": "\\.spec\\.(js|ts)$",
58+
"testPathIgnorePatterns": [
59+
"/dist/",
60+
"/node_modules/"
61+
],
62+
"moduleFileExtensions": [
63+
"ts",
64+
"tsx",
65+
"js",
66+
"jsx",
67+
"json",
68+
"node"
69+
],
70+
"modulePaths": [
71+
"./src"
72+
]
73+
},
74+
"keywords": [
75+
"Stream",
76+
"Back",
77+
"Pressure"
78+
],
79+
"author": "jc.delmas@gmail.com",
80+
"license": "ISC",
81+
"bugs": {
82+
"url": "https://github.com/jcdelmas/pp-stream/issues"
83+
},
84+
"homepage": "https://github.com/jcdelmas/pp-stream#readme"
85+
}

src/core/buffer.ts

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
2+
export enum OverflowStrategy {
3+
DROP_BUFFER = "DROP_BUFFER",
4+
DROP_HEAD = "DROP_HEAD",
5+
DROP_NEW = "DROP_NEW",
6+
DROP_TAIL = "DROP_TAIL",
7+
FAIL = "FAIL",
8+
BACK_PRESSURE = "BACK_PRESSURE",
9+
}
10+
11+
export default class Buffer<A> {
12+
13+
buf: A[] = []
14+
15+
constructor(
16+
private readonly maxSize: number = 16,
17+
private readonly overflowStrategy: OverflowStrategy = OverflowStrategy.FAIL,
18+
private readonly dropCallback: (x: A) => void = () => {}) {
19+
}
20+
21+
size(): number {
22+
return this.buf.length;
23+
}
24+
25+
isEmpty(): boolean {
26+
return this.buf.length === 0;
27+
}
28+
29+
isFull(): boolean {
30+
return this.buf.length === this.maxSize;
31+
}
32+
33+
push(x: A): void {
34+
if (this.isFull()) {
35+
switch (this.overflowStrategy) {
36+
case OverflowStrategy.FAIL:
37+
this.buf.forEach(this.dropCallback);
38+
throw new Error('Buffer overflow');
39+
case OverflowStrategy.DROP_BUFFER:
40+
this.buf.forEach(this.dropCallback);
41+
this.buf = [];
42+
break;
43+
case OverflowStrategy.DROP_HEAD:
44+
this.dropCallback(this.buf.shift());
45+
break;
46+
case OverflowStrategy.DROP_NEW:
47+
this.dropCallback(x);
48+
return;
49+
case OverflowStrategy.DROP_TAIL:
50+
this.dropCallback(this.buf.pop());
51+
break;
52+
default:
53+
throw new Error('Not supported strategy: ' + this.overflowStrategy)
54+
}
55+
}
56+
this.buf.push(x);
57+
}
58+
59+
pull(): A {
60+
if (this.isEmpty()) {
61+
throw new Error('Empty buffer');
62+
}
63+
return this.buf.shift() as A
64+
}
65+
66+
head(): A {
67+
if (this.isEmpty()) {
68+
throw new Error('Empty buffer');
69+
}
70+
return this.buf[0];
71+
}
72+
73+
drain(): A[] {
74+
const buf = this.buf;
75+
this.buf = [];
76+
return buf;
77+
}
78+
}

src/core/fan-in.ts

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { DownstreamHandler, Inlet, Outlet, Shape, SingleOutputStage } from './stage'
2+
import { range } from 'lodash'
3+
import { complexFlow, Flow, FlowShape } from './flow'
4+
import { Graph } from './graph'
5+
import { Source } from './source'
6+
7+
export abstract class FanInShape<O> implements Shape {
8+
9+
outputs: Outlet<O>[]
10+
inputs: Inlet<any>[]
11+
12+
constructor(public output: Outlet<O>) {
13+
this.outputs = [output]
14+
}
15+
}
16+
17+
export class FanInShape2<I1, I2, O> implements Shape {
18+
19+
outputs: Outlet<O>[]
20+
inputs: Inlet<any>[]
21+
22+
constructor(public in1: Inlet<I1>, public in2: Inlet<I2>, public output: Outlet<O>) {
23+
this.inputs = [in1, in2]
24+
this.outputs = [output]
25+
}
26+
}
27+
28+
export class FanInShape3<I1, I2, I3, O> implements Shape {
29+
30+
outputs: Outlet<O>[]
31+
inputs: Inlet<any>[]
32+
33+
constructor(public in1: Inlet<I1>,
34+
public in2: Inlet<I2>,
35+
public in3: Inlet<I3>,
36+
public output: Outlet<O>) {
37+
this.inputs = [in1, in2, in3]
38+
this.outputs = [output]
39+
}
40+
}
41+
42+
export class UniformFanInShape<I, O> implements FanInShape<O> {
43+
44+
outputs: Outlet<any>[]
45+
46+
constructor(public inputs: Inlet<I>[], public output: Outlet<O>) {
47+
this.outputs = [output]
48+
}
49+
}
50+
51+
export function fanInFlow<A>(source: Source<A>, graphFactory: (size: number) => Graph<UniformFanInShape<A, A>, void>): Flow<A, A> {
52+
return complexFlow(b => {
53+
const s = b.add(source)
54+
const merge = b.add(graphFactory(2))
55+
s.output.wire(merge.inputs[1])
56+
return new FlowShape(merge.inputs[0], merge.output)
57+
})
58+
}
59+
60+
export abstract class FanInStage<O, S extends FanInShape<O>> extends SingleOutputStage<O, S> {
61+
62+
finish(): void {
63+
this.cancel()
64+
this.complete()
65+
}
66+
67+
onCancel(): void {
68+
this.cancel()
69+
}
70+
71+
cancel(): void {
72+
this.shape.inputs.forEach(input => {
73+
if (!input.isClosed()) {
74+
input.cancel()
75+
}
76+
})
77+
}
78+
}
79+
80+
export abstract class UniformFanInStage<I, O> extends FanInStage<O, UniformFanInShape<I, O>> {
81+
82+
shape: UniformFanInShape<I, O>
83+
84+
constructor(protected inCount: number) {
85+
super()
86+
const inputs = range(0, inCount).map(i => new Inlet<I>(this.createDownstreamHandler(i)))
87+
this.shape = new UniformFanInShape(inputs, new Outlet<O>(this))
88+
}
89+
90+
protected input(i: number): Inlet<I> {
91+
return this.shape.inputs[i]
92+
}
93+
94+
abstract createDownstreamHandler(index: number): DownstreamHandler
95+
}

0 commit comments

Comments
 (0)