Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(websockets): introducing @marblejs/websockets package and bunch more additional core features #89

Merged
merged 54 commits into from Jan 4, 2019

Conversation

Projects
1 participant
@JozefFlakus
Copy link
Member

commented Dec 28, 2018

Sorry for so huge PR but I wanted to introduce everything what I wanted in one big feature. 馃檲

PR Type

What kind of change does this PR introduce?

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Build related changes
[ ] CI related changes
[ ] Documentation content changes
[ ] Other... Please describe:

What is the new behavior?

Introducing @marblejs/websockets - a RxJS implementation for WebSocket protocol.

  • WebSocket listener definition:
export const webSocketServer = webSocketListener({
  middlewares: [ ... ],
  effects: [ ... ],
  error: error$,                     // optional
  connection: connection$,           // optional
  eventTransformer: jsonTransformer, // optional
});

The WebSocket listener API contains well known middlewares, effects and error props like we currently have in case of httpListener.

The connection prop is used as a stream of incoming WS connections - it can be used for validation related purposes, eg:

const connection$: WebSocketConnectionEffect = req$ =>
  req$.pipe(
    mergeMap(req => iif(
      () => !isTokenValid(req.headers.authorization),
      throwError(new WebSocketConnectionError('Unauthorized', 4000)),
      of(req),
    )),
  );

Because WebSocket protocol can be used not only for JSON based events, the API allows to pass an optional eventTransformer function that conforms to EventTransformer interface which exposes decode and encode methods used for incoming and outgoing events. If it is not defined, the listener will use a default jsonTransformer.

  • WebSocket effects definition
    Lets do some Rx fun 鈿★笍
export const sum$: WebSocketEffect = event$ =>
  event$.pipe(
    matchType('SUM')
  );

export const add$: WebSocketEffect = (event$, client) =>
  event$.pipe(
    matchType('ADD'),
    buffer(sum$(event$, client)),
    map(events => events as WebSocketEvent<number>[]),
    map(events => events.reduce((a, e) => e.payload + a, 0)),
    map(payload => ({ type: 'SUM_RESULT', payload })),
  );

The code above defines two Effects. Lets demonstrate its behavior via incoming events:

{ type: 'ADD', payload: 3 }
{ type: 'ADD', payload: 2 }
{ type: 'SUM' }

received client result:

{ type: 'SUM_RESULT', payload: 5 }

Cool, isn't it? 馃構

  • WebSocket server bootstrapping
    In order to achieve a consistent API for defining additional http-based servers (like WebSockets). We are introducing marble({ ... }) function which purpose is to bootstrap a HTTP server, expose server events as Observable streams and define additional dependencies. Closes #80
import { httpServer } from './http.listener';
import { webSocketServer } from './webSockets.listener';

marble({
  hostname: '127.0.0.1',
  port: 1337,
  httpListener: httpServer,   // httpListener output
  httpEventsHandler: events$, // server related events exposed as a Observable stream
  dependencies: [
    bind(WebSocketsToken).to(webSocketServer), // webSocketListener output
  ]
});

The passed object to marble function can contain a list of additional dependencies that can be connected directly to http server (eg. WebSockets). The @marblejs/core package implements a dedicated "Dependency Injection like" mechanism for http server related dependencies. Thanks to DI we can inject a defined WebSockets server into normal HTTP based Effect and send a broadcast message to all connected clients. Agin - Cool, isn't it? 馃構

For more details how the DI can be used in Marble.js environment please visit /packages/@integration/src. The example shows how the WebSocket server can be attached to specific REST API route.

If you have any detailed question please do not hesitate to put some comments. I will try to explain more deeply how the particular scenario can be implemented :)

P.S. - An eventual attributes naming can be changed before the final release.

Does this PR introduce a breaking change?

[ ] Yes
[x] No

JozefFlakus added some commits Dec 13, 2018

@JozefFlakus JozefFlakus added this to the 2.0.0 milestone Dec 28, 2018

@JozefFlakus JozefFlakus self-assigned this Dec 28, 2018

@JozefFlakus JozefFlakus added this to In progress in @marblejs/next via automation Dec 28, 2018

@JozefFlakus JozefFlakus force-pushed the feat/next/websockets branch 2 times, most recently from 2820dcb to 02e4709 Dec 28, 2018

@JozefFlakus JozefFlakus force-pushed the feat/next/websockets branch from 02e4709 to 9956a6b Dec 28, 2018

@codecov

This comment has been minimized.

Copy link

commented Dec 28, 2018

Codecov Report

Merging #89 into next will not change coverage.
The diff coverage is 100%.

Impacted file tree graph

@@         Coverage Diff          @@
##           next    #89    +/-   ##
====================================
  Coverage   100%   100%            
====================================
  Files        44     63    +19     
  Lines       498    782   +284     
  Branches     62     80    +18     
====================================
+ Hits        498    782   +284
Impacted Files Coverage 螖
packages/websockets/src/error/ws-error.handler.ts 100% <100%> (酶)
packages/websockets/src/operators/index.ts 100% <100%> (酶)
packages/core/src/error/error.effect.ts 100% <100%> (酶) 猬嗭笍
packages/core/src/+internal/utils/string.util.ts 100% <100%> (酶)
packages/core/src/http.interface.ts 100% <100%> (酶) 猬嗭笍
packages/core/src/server/server.injector.ts 100% <100%> (酶)
.../src/operators/mapToServer/mapToServer.operator.ts 100% <100%> (酶)
packages/websockets/src/error/ws-error.model.ts 100% <100%> (酶)
...ages/websockets/src/listener/websocket.listener.ts 100% <100%> (酶)
packages/websockets/src/error/ws-error.effect.ts 100% <100%> (酶)
... and 39 more

Continue to review full report at Codecov.

Legend - Click here to learn more
螖 = absolute <relative> (impact), 酶 = not affected, ? = missing data
Powered by Codecov. Last update 4cef1f0...4cc7ee6. Read the comment docs.

@JozefFlakus JozefFlakus force-pushed the feat/next/websockets branch from 85a0427 to d1ac807 Dec 31, 2018

@JozefFlakus JozefFlakus merged commit ee3249e into next Jan 4, 2019

2 checks passed

Travis CI - Pull Request Build Passed
Details
codecov/patch 100% of diff hit (target 100%)
Details

@marblejs/next automation moved this from In progress to Done Jan 4, 2019

@JozefFlakus JozefFlakus deleted the feat/next/websockets branch Jan 4, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can鈥檛 perform that action at this time.