├── .prettierignore ├── .npmignore ├── packages ├── api │ ├── src │ │ ├── discovery │ │ │ ├── Item.ts │ │ │ ├── ServiceDiscoveryEvent.ts │ │ │ └── index.ts │ │ ├── common │ │ │ ├── index.ts │ │ │ └── Address.ts │ │ ├── cluster │ │ │ ├── tests │ │ │ │ └── README.md │ │ │ ├── MemberMap.ts │ │ │ ├── index.ts │ │ │ ├── ClusterEvent.ts │ │ │ └── Cluster.ts │ │ ├── transport │ │ │ └── index.ts │ │ ├── index.ts │ │ └── microservice │ │ │ ├── Message.ts │ │ │ ├── AsyncModel.ts │ │ │ ├── ServiceDefinition.ts │ │ │ ├── LookUp.ts │ │ │ ├── Service.ts │ │ │ ├── Router.ts │ │ │ ├── ServiceReference.ts │ │ │ ├── index.ts │ │ │ ├── CreateProxy.ts │ │ │ ├── Endpoint.ts │ │ │ └── CreateServiceCall.ts │ ├── .gitignore │ ├── tsconfig.json │ ├── README.md │ └── package.json ├── cluster-nodejs │ ├── src │ │ ├── index.ts │ │ └── helpers │ │ │ └── types.ts │ ├── .gitignore │ ├── jest.config.js │ ├── tsconfig.json │ ├── rollup.config.js │ ├── package.json │ └── README.md ├── node │ ├── .gitignore │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── rollup.cjs.config.js │ └── package.json ├── routers │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ ├── Default │ │ │ └── default.ts │ │ ├── Retry │ │ │ └── retry.ts │ │ └── RoundRobin │ │ │ └── roundRobin.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── rollup.config.js │ ├── README.md │ ├── tests │ │ ├── defaul.spec.ts │ │ └── retry.spec.ts │ └── package.json ├── utils │ ├── .gitignore │ ├── src │ │ ├── qualifier.ts │ │ ├── checkEnvironemnt.ts │ │ ├── mocks │ │ │ └── PostMessageWithTransferPolyfill.ts │ │ ├── index.ts │ │ ├── logs.ts │ │ ├── serviceDefinition.ts │ │ └── constants.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── rollup.config.js │ ├── README.md │ └── package.json ├── addressable │ ├── src │ │ ├── types.ts │ │ ├── utils │ │ │ ├── map.ts │ │ │ ├── join.ts │ │ │ ├── Subject.ts │ │ │ └── eachDelta.ts │ │ ├── api.ts │ │ ├── const.ts │ │ ├── index.ts │ │ ├── boostrap.ts │ │ └── Node.ts │ ├── e2eSetup.js │ ├── tests │ │ ├── messageChannelMock.ts │ │ ├── postMessageMock.ts │ │ ├── fixtures │ │ │ └── pingPong │ │ │ │ ├── iframe.html │ │ │ │ ├── index.html │ │ │ │ └── pingPong.ts │ │ └── e2e.browser.ts │ ├── e2eTeardown.js │ ├── e2eStart.js │ ├── jest-puppeteer.config.js │ ├── jest.config.js │ ├── tsconfig.json │ ├── rollup.cjs.config.js │ └── rollup.iife.config.js ├── rsocket-adapter │ ├── .gitignore │ ├── src │ │ ├── helpers │ │ │ ├── constants.ts │ │ │ ├── validation.ts │ │ │ ├── types.ts │ │ │ └── defaultConfiguration.ts │ │ ├── index.ts │ │ ├── Client │ │ │ ├── connectionManager.ts │ │ │ └── clientConnection.ts │ │ ├── Server │ │ │ └── createServer.ts │ │ └── api │ │ │ └── Provider.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── README.md │ ├── rollup.config.js │ ├── package.json │ └── tests │ │ └── validation.spec.ts ├── transport-browser │ ├── .gitignore │ ├── tests │ │ ├── messageChannelMock.ts │ │ └── transport.spec.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── README.md │ ├── rollup.config.js │ ├── src │ │ └── index.ts │ └── package.json ├── transport-nodejs │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ └── Provider │ │ │ ├── Provider.ts │ │ │ ├── ProviderServer.ts │ │ │ └── ProviderClient.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── README.md │ ├── rollup.config.js │ └── package.json ├── cluster-browser │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ └── Cluster │ │ │ └── connection.ts │ ├── tests │ │ ├── messageChannelMock.ts │ │ └── cluster.spec.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── rollup.config.js │ ├── package.json │ └── README.md ├── rsocket-ws-gateway │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ ├── api │ │ │ ├── types.ts │ │ │ └── Gateway.ts │ │ ├── helpers │ │ │ ├── constants.ts │ │ │ └── validation.ts │ │ ├── requestResponse.ts │ │ └── requestStream.ts │ ├── tests │ │ ├── messageChannelMock.ts │ │ ├── multi-proxy.spec.ts │ │ └── stop.spec.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── rollup.config.js │ └── package.json ├── scalecube-discovery │ ├── tests │ │ ├── messageChannelMock.ts │ │ ├── mockEnv.ts │ │ ├── mockDiscovery.ts │ │ ├── helper.ts │ │ └── integration │ │ │ └── destroy.spec.ts │ ├── src │ │ ├── index.ts │ │ └── helpers │ │ │ └── constants.ts │ ├── .gitignore │ ├── jest.config-node.js │ ├── jest.config-dom.js │ ├── tsconfig.json │ ├── rollup.cjs.config.js │ ├── README.md │ └── package.json ├── rsocket-ws-gateway-client │ ├── src │ │ └── index.ts │ ├── jest.config.js │ ├── tsconfig.json │ ├── package.json │ ├── README.md │ ├── rollup.cjs.config.js │ └── rollup.iife.config.js ├── scalecube-microservice │ ├── tests │ │ ├── messageChannelMock.ts │ │ ├── mockEnv.ts │ │ ├── helper.ts │ │ ├── mocks │ │ │ ├── microserviceFactory.ts │ │ │ └── GreetingService.ts │ │ ├── unit │ │ │ └── Microservices │ │ │ │ └── endpointsUtil.spec.ts │ │ └── integration │ │ │ └── retryRouter.spec.ts │ ├── .gitignore │ ├── src │ │ ├── index.ts │ │ ├── helpers │ │ │ ├── logger.ts │ │ │ └── serviceData.ts │ │ ├── ServiceCall │ │ │ └── ServiceCallUtils.ts │ │ ├── Proxy │ │ │ ├── createProxy.ts │ │ │ └── Proxy.ts │ │ └── Microservices │ │ │ ├── Destroy.ts │ │ │ └── endpointsUtil.ts │ ├── jest.config-node.js │ ├── tsconfig.json │ ├── jest.config-dom.js │ ├── rollup.es.config.js │ └── rollup.cjs.config.js ├── browser │ ├── .gitignore │ ├── tsconfig.json │ ├── src │ │ └── index.ts │ ├── rollup.cjs.config.js │ ├── rollup.iife.config.js │ └── package.json └── examples │ ├── .gitignore │ ├── k8s │ ├── Dockerfile │ ├── stop │ ├── package.json │ ├── helm-scalecube-ex │ │ ├── values.yaml │ │ ├── .helmignore │ │ ├── templates │ │ │ ├── seed.yaml │ │ │ ├── greeting-pod.yaml │ │ │ └── consumer-pod.yaml │ │ └── Chart.yaml │ ├── cluster.yml │ ├── seed.js │ ├── greeting.js │ ├── start │ └── consumer.js │ ├── iife │ ├── webWorkerExample2 │ │ ├── reactiveStream.js │ │ ├── definitions.js │ │ ├── index.html │ │ ├── worker2.js │ │ └── worker1.js │ ├── distributedEnvironmentExample │ │ ├── reactiveStream.js │ │ ├── worker2.js │ │ ├── definitions.js │ │ └── worker1.js │ ├── remoteCallExample │ │ ├── definitions.js │ │ ├── remoteCall.html │ │ ├── remoteCall.js │ │ └── remoteService.js │ ├── iframe │ │ ├── worker1.js │ │ ├── index.html │ │ ├── iframe.html │ │ ├── index.js │ │ └── definitions.js │ ├── webWorkerExample │ │ ├── worker1.js │ │ ├── worker2.js │ │ ├── definitions.js │ │ ├── index.html │ │ └── bubbleSortService.js │ └── HTMLElementExample │ │ └── example-html.html │ ├── node │ ├── seedService.js │ ├── index.js │ ├── helpers │ │ └── retryRouterWithLogs.js │ ├── helloService.js │ └── greetMePlzService.js │ ├── tsconfig.json │ ├── jest.config.js │ ├── Dockerfile │ ├── bundles │ ├── parcel.html │ ├── rollup.html │ └── src │ │ ├── service │ │ └── GreetingService.ts │ │ └── index.ts │ ├── rollup.iife.config.js │ └── tests │ └── greeting.spec.ts ├── .remarkrc ├── lerna.json ├── .gitignore ├── .prettierrc.js ├── scripts └── verify.sh ├── tslint.json └── .github ├── workflows └── ci.yml └── ISSUE_TEMPLATE └── bug_report.md /.prettierignore: -------------------------------------------------------------------------------- 1 | *.md 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmrc 2 | .npmignore 3 | .* -------------------------------------------------------------------------------- /packages/api/src/discovery/Item.ts: -------------------------------------------------------------------------------- 1 | export type Item = any; 2 | -------------------------------------------------------------------------------- /packages/api/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | -------------------------------------------------------------------------------- /.remarkrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "remark-preset-lint-recommended" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/src/index.ts: -------------------------------------------------------------------------------- 1 | export { joinCluster } from './Cluster/JoinCluster'; 2 | -------------------------------------------------------------------------------- /packages/node/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | 6 | report.cjs.html 7 | -------------------------------------------------------------------------------- /packages/api/src/common/index.ts: -------------------------------------------------------------------------------- 1 | import Address from './Address'; 2 | 3 | export { Address }; 4 | -------------------------------------------------------------------------------- /packages/routers/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | es/ 5 | cjs/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/utils/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | es/ 5 | cjs/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/addressable/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface Peer { 2 | [id: string]: MessagePort; 3 | } 4 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | es/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | es/ 5 | cjs/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/transport-browser/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | es/ 5 | cjs/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/transport-nodejs/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | es/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/cluster-browser/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | es/ 5 | cjs/ 6 | 7 | 8 | report.html 9 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | es/ 6 | 7 | report.html 8 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Gateway } from './Gateway'; 2 | 3 | export default Gateway; 4 | -------------------------------------------------------------------------------- /packages/api/src/cluster/tests/README.md: -------------------------------------------------------------------------------- 1 | # Cluster tests 2 | 3 | Valid cluster implementation must pass this test suite 4 | -------------------------------------------------------------------------------- /packages/cluster-browser/src/index.ts: -------------------------------------------------------------------------------- 1 | import { joinCluster } from './Cluster/joinCluster'; 2 | 3 | export { joinCluster }; 4 | -------------------------------------------------------------------------------- /packages/addressable/e2eSetup.js: -------------------------------------------------------------------------------- 1 | require('./e2eStart'); 2 | 3 | module.exports = require('jest-environment-puppeteer').setup; 4 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/api/types.ts: -------------------------------------------------------------------------------- 1 | export interface RsocketEventsPayload { 2 | data: any; 3 | metadata: any; 4 | } 5 | -------------------------------------------------------------------------------- /packages/addressable/tests/messageChannelMock.ts: -------------------------------------------------------------------------------- 1 | import { mockMessageChannel } from '@scalecube/utils'; 2 | 3 | mockMessageChannel(); 4 | -------------------------------------------------------------------------------- /packages/cluster-browser/tests/messageChannelMock.ts: -------------------------------------------------------------------------------- 1 | import { mockMessageChannel } from '@scalecube/utils'; 2 | 3 | mockMessageChannel(); 4 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/tests/messageChannelMock.ts: -------------------------------------------------------------------------------- 1 | import { mockMessageChannel } from '@scalecube/utils'; 2 | 3 | mockMessageChannel(); 4 | -------------------------------------------------------------------------------- /packages/transport-browser/tests/messageChannelMock.ts: -------------------------------------------------------------------------------- 1 | import { mockMessageChannel } from '@scalecube/utils'; 2 | 3 | mockMessageChannel(); 4 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createGatewayProxy } from './createGatewayProxy'; 2 | 3 | export { createGatewayProxy }; 4 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/messageChannelMock.ts: -------------------------------------------------------------------------------- 1 | import { mockMessageChannel } from '@scalecube/utils'; 2 | 3 | mockMessageChannel(); 4 | -------------------------------------------------------------------------------- /packages/browser/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | dist/ 6 | 7 | report.iffe.html 8 | report.cjs.html 9 | report.es.html 10 | -------------------------------------------------------------------------------- /packages/addressable/e2eTeardown.js: -------------------------------------------------------------------------------- 1 | const p = require('./e2eStart'); 2 | p.start.kill('SIGQUIT'); 3 | module.exports = require('jest-environment-puppeteer').teardown; 4 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/tests/mockEnv.ts: -------------------------------------------------------------------------------- 1 | jest.unmock('@scalecube/utils'); 2 | import utils = require('@scalecube/utils'); 3 | utils.isNodejs = jest.fn(() => false); 4 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/mockEnv.ts: -------------------------------------------------------------------------------- 1 | jest.unmock('@scalecube/utils'); 2 | import utils = require('@scalecube/utils'); 3 | utils.isNodejs = jest.fn(() => false); 4 | -------------------------------------------------------------------------------- /packages/examples/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .idea/ 3 | node_modules/ 4 | flow-typed/ 5 | coverage/ 6 | .npmrc 7 | yarn-error.log 8 | .DS_Store 9 | 10 | parcel/ 11 | rollup/ 12 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createDiscovery } from './Discovery/Discovery'; 2 | 3 | export { createDiscovery }; 4 | 5 | export default createDiscovery; 6 | -------------------------------------------------------------------------------- /packages/examples/k8s/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-alpine3.11 2 | RUN apk add python make g++ 3 | COPY . /var/app 4 | WORKDIR /var/app 5 | RUN yarn 6 | RUN cat yarn.lock 7 | 8 | CMD /bin/sh -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/tests/messageChannelMock.ts: -------------------------------------------------------------------------------- 1 | import { mockMessageChannel } from '@scalecube/utils'; 2 | import 'regenerator-runtime/runtime'; 3 | 4 | mockMessageChannel(); 5 | -------------------------------------------------------------------------------- /packages/utils/src/qualifier.ts: -------------------------------------------------------------------------------- 1 | export const getQualifier = ({ serviceName, methodName }: { serviceName: string; methodName: string }): string => 2 | `${serviceName}/${methodName}`; 3 | -------------------------------------------------------------------------------- /packages/addressable/e2eStart.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | 3 | const start = exec('yarn start', { cwd: '../../' }); 4 | 5 | module.exports = { 6 | start, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/addressable/tests/postMessageMock.ts: -------------------------------------------------------------------------------- 1 | import { applyPostMessagePolyfill } from '@scalecube/utils/src/mocks/PostMessageWithTransferPolyfill'; 2 | 3 | applyPostMessagePolyfill(); 4 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | node_modules 3 | 4 | lib/ 5 | es/ 6 | dist-min/ 7 | dist/ 8 | 9 | report.iffe.html 10 | report.cjs.html 11 | report.es.html 12 | -------------------------------------------------------------------------------- /packages/examples/k8s/stop: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker stop $(docker ps -q --filter name=scalecube-example-control-plane) 4 | kind delete cluster --name scalecube-example 5 | 6 | echo "STOPPED" 7 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/helpers/constants.ts: -------------------------------------------------------------------------------- 1 | export const SERVER_NOT_IMPL = 'Server provider is not implemented'; 2 | export const CLIENT_NOT_IMPL = 'Client provider is not implemented'; 3 | -------------------------------------------------------------------------------- /packages/api/src/cluster/MemberMap.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * information of the other members. 3 | * 4 | */ 5 | export interface MembersData { 6 | [member: string]: any; 7 | } 8 | -------------------------------------------------------------------------------- /packages/addressable/jest-puppeteer.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testRegex: '(\\.|/)browser\\.ts$', 3 | preset: 'jest-puppeteer', 4 | globalSetup: './e2eSetup.js', 5 | globalTeardown: './e2eTeardown.js', 6 | }; 7 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "yarn", 3 | "useWorkspaces": true, 4 | "packages": ["packages/*"], 5 | "command": { 6 | "version": { 7 | "exact": true 8 | } 9 | }, 10 | "version": "0.2.11" 11 | } 12 | -------------------------------------------------------------------------------- /packages/utils/src/checkEnvironemnt.ts: -------------------------------------------------------------------------------- 1 | export const isNodejs = () => { 2 | try { 3 | // common api for main threat or worker in the browser 4 | return !navigator; 5 | } catch (e) { 6 | return false; 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createMicroservice } from './Microservices/Microservices'; 2 | import { ASYNC_MODEL_TYPES } from './helpers/constants'; 3 | 4 | export { createMicroservice, ASYNC_MODEL_TYPES }; 5 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .idea/ 3 | node_modules/ 4 | flow-typed/ 5 | coverage/ 6 | .npmrc 7 | yarn-error.log 8 | .DS_Store 9 | 10 | es/ 11 | cjs/ 12 | 13 | 14 | report.cjs.html 15 | report.es.html 16 | -------------------------------------------------------------------------------- /packages/api/src/discovery/ServiceDiscoveryEvent.ts: -------------------------------------------------------------------------------- 1 | import { Item } from '.'; 2 | 3 | export interface ServiceDiscoveryEvent { 4 | type: Type; 5 | items: Item[]; 6 | } 7 | 8 | export type Type = 'REGISTERED' | 'UNREGISTERED' | 'IDLE'; 9 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample2/reactiveStream.js: -------------------------------------------------------------------------------- 1 | importScripts('https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js'); 2 | 3 | reactiveStreamExample = { 4 | getInterval: (time) => rxjs.interval(time || 2000), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/examples/k8s/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "k8s", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "private": false, 7 | "dependencies": { 8 | "@scalecube/node": "snapshot" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/routers/src/index.ts: -------------------------------------------------------------------------------- 1 | import { defaultRouter } from './Default/default'; 2 | import { roundRobin } from './RoundRobin/roundRobin'; 3 | import { retryRouter } from './Retry/retry'; 4 | 5 | export { defaultRouter, roundRobin, retryRouter }; 6 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/index.ts: -------------------------------------------------------------------------------- 1 | export { setupServer } from './Server/startServer'; 2 | export { setupClient } from './Client/startClient'; 3 | 4 | export { Provider, ProviderFactory, PayloadSerializers, ProviderSetup } from './api/Provider'; 5 | -------------------------------------------------------------------------------- /packages/examples/iife/distributedEnvironmentExample/reactiveStream.js: -------------------------------------------------------------------------------- 1 | importScripts('https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.4.0/rxjs.umd.min.js'); 2 | 3 | reactiveStreamExample = { 4 | getInterval: (time) => rxjs.timer(0, time || 1000), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/examples/k8s/helm-scalecube-ex/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for helm-scalecube-ex. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | image: 6 | name: scalecube-example:k8s 7 | pullPolicy: Never 8 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/helpers/logger.ts: -------------------------------------------------------------------------------- 1 | import { saveToLogs } from '@scalecube/utils'; 2 | 3 | export const loggerUtil = (whoAmI: string, debug: boolean) => (msg: any, type: 'log' | 'warn') => { 4 | saveToLogs(whoAmI, msg, {}, debug, type); 5 | }; 6 | -------------------------------------------------------------------------------- /packages/examples/k8s/cluster.yml: -------------------------------------------------------------------------------- 1 | kind: Cluster 2 | apiVersion: kind.x-k8s.io/v1alpha4 3 | nodes: 4 | - role: control-plane 5 | kubeadmConfigPatches: 6 | extraPortMappings: 7 | - containerPort: 30080 8 | hostPort: 8080 9 | protocol: TCP 10 | -------------------------------------------------------------------------------- /packages/addressable/tests/fixtures/pingPong/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ping Pong test 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/api/src/transport/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | ServerTransportOptions, 3 | ClientTransportOptions, 4 | Invoker, 5 | Transport, 6 | ServerStop, 7 | ClientTransport, 8 | ServerTransport, 9 | TDestroy, 10 | TLogger, 11 | TDestroyOptions, 12 | } from './Transport'; 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .idea/ 3 | node_modules/ 4 | es/ 5 | es-bundle/ 6 | lib/ 7 | dist/ 8 | cjs/ 9 | flow-typed/ 10 | doc/ 11 | coverage/ 12 | .npmrc 13 | yarn-error.log 14 | .DS_Store 15 | report.html 16 | /packages/addressable/report.cjs.html 17 | /packages/addressable/report.iffe.html 18 | -------------------------------------------------------------------------------- /packages/api/src/cluster/index.ts: -------------------------------------------------------------------------------- 1 | import { ClusterEvent, MemberEventType } from './ClusterEvent'; 2 | import { Cluster, JoinCluster, ClusterOptions } from './Cluster'; 3 | import { MembersData } from './MemberMap'; 4 | 5 | export { ClusterEvent, Cluster, JoinCluster, ClusterOptions, MembersData, MemberEventType }; 6 | -------------------------------------------------------------------------------- /packages/api/src/discovery/index.ts: -------------------------------------------------------------------------------- 1 | import { Discovery, DiscoveryOptions, CreateDiscovery } from './Discovery'; 2 | import { ServiceDiscoveryEvent, Type } from './ServiceDiscoveryEvent'; 3 | import { Item } from './Item'; 4 | 5 | export { Discovery, DiscoveryOptions, Item, CreateDiscovery, ServiceDiscoveryEvent, Type }; 6 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/helper.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter = require('events'); 2 | // @ts-ignore 3 | const myEmitter = new EventEmitter(); 4 | 5 | // @ts-ignore 6 | global.addEventListener = myEmitter.addListener.bind(myEmitter); 7 | // @ts-ignore 8 | global.removeEventListener = myEmitter.removeListener.bind(myEmitter); 9 | -------------------------------------------------------------------------------- /packages/transport-nodejs/src/index.ts: -------------------------------------------------------------------------------- 1 | import { setupServer, setupClient } from '@scalecube/rsocket-adapter'; 2 | import { clientProvider, serverProvider } from './Provider/Provider'; 3 | 4 | export const transport = { 5 | clientTransport: setupClient(clientProvider), 6 | serverTransport: setupServer(serverProvider), 7 | }; 8 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/src/helpers/types.ts: -------------------------------------------------------------------------------- 1 | export interface SwimEvent { 2 | host: string; 3 | meta: any; 4 | state: SwimEventAlive | SwimEventSuspect | SwimEventFaulty; 5 | incarnation: number; 6 | } 7 | 8 | export type SwimEventAlive = 0; 9 | export type SwimEventSuspect = 1; 10 | export type SwimEventFaulty = 2; 11 | -------------------------------------------------------------------------------- /packages/api/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as TransportApi from './transport'; 2 | import { Address } from './common'; 3 | import * as DiscoveryApi from './discovery'; 4 | import * as MicroserviceApi from './microservice'; 5 | import * as ClusterApi from './cluster'; 6 | 7 | export { TransportApi, Address, DiscoveryApi, MicroserviceApi, ClusterApi }; 8 | -------------------------------------------------------------------------------- /packages/addressable/src/utils/map.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from './Subject'; 2 | 3 | export function map(mapFn: (arg: any) => any, sbj: Pick) { 4 | return { 5 | subscribe: (fn: (arg: any) => void) => { 6 | return sbj.subscribe((val) => { 7 | fn(mapFn(val)); 8 | }); 9 | }, 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/tests/mockDiscovery.ts: -------------------------------------------------------------------------------- 1 | import { createDiscovery as discovery } from '../src'; 2 | import { joinCluster } from '@scalecube/cluster-browser'; 3 | 4 | export const createDiscovery = (config: any) => { 5 | return discovery({ 6 | cluster: joinCluster, 7 | ...config, 8 | debug: true, 9 | }); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/jest.config-node.js: -------------------------------------------------------------------------------- 1 | const jestConfig = require('./jest.config-dom'); 2 | 3 | jestConfig.testEnvironment = 'node'; 4 | jestConfig.globals = { 5 | isNodeEvn: true, 6 | }; 7 | jestConfig.setupFilesAfterEnv = ['/tests/helper.ts', ...(jestConfig.setupFilesAfterEnv || [])]; 8 | 9 | module.exports = jestConfig; 10 | -------------------------------------------------------------------------------- /packages/addressable/src/api.ts: -------------------------------------------------------------------------------- 1 | type ListenerFn = (msg: any, port: MessagePort) => void; 2 | export interface Listener extends ListenerFn { 3 | cleanFns?: Array<() => void>; 4 | } 5 | type remove = () => void; 6 | export type listen = (addr: string, fn: Listener) => remove; 7 | export type connect = (addr: string, timeout?: number) => Promise; 8 | -------------------------------------------------------------------------------- /packages/examples/node/seedService.js: -------------------------------------------------------------------------------- 1 | const { createMicroservice, ASYNC_MODEL_TYPES } = require('@scalecube/node'); 2 | 3 | process.on('message', () => { 4 | createMicroservice({ 5 | address: { 6 | protocol: 'ws', 7 | host: 'localhost', 8 | port: 6111, 9 | path: '', 10 | }, 11 | debug: true, 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/routers/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/jest.config-node.js: -------------------------------------------------------------------------------- 1 | const jestConfig = require('./jest.config-dom'); 2 | 3 | jestConfig.testEnvironment = 'node'; 4 | jestConfig.globals = { 5 | isNodeEvn: true, 6 | }; 7 | jestConfig.setupFilesAfterEnv = ['/tests/helper.ts', ...(jestConfig.setupFilesAfterEnv || [])]; 8 | 9 | module.exports = jestConfig; 10 | -------------------------------------------------------------------------------- /packages/utils/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/transport-nodejs/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)(test|spec)\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/examples/k8s/seed.js: -------------------------------------------------------------------------------- 1 | const { createMicroservice } = require('@scalecube/node'); 2 | 3 | console.log('seed', process.env.SEED_SERVICE_HOST); 4 | console.log('address', process.env.ADDRESS); 5 | 6 | createMicroservice({ 7 | address: { 8 | protocol: 'ws', 9 | host: process.env.ADDRESS, 10 | port: 7001, 11 | path: '', 12 | }, 13 | debug: true, 14 | }); 15 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | printWidth: 120, 3 | tabWidth: 2, 4 | useTabs: false, 5 | semi: true, 6 | singleQuote: true, 7 | trailingComma: 'es5', 8 | bracketSpacing: true, 9 | arrowParens: 'always', 10 | overrides: [ 11 | { 12 | files: '**/*.yaml', 13 | options: { 14 | bracketSpacing: false, 15 | }, 16 | }, 17 | ], 18 | }; 19 | -------------------------------------------------------------------------------- /packages/examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "lib": ["dom", "es6"], 6 | "declaration": false, 7 | "strict": true, 8 | "noUnusedLocals": true, 9 | "moduleResolution": "node", 10 | "baseUrl": "./bundles/src", 11 | "skipLibCheck": true 12 | }, 13 | "include": ["bundles/src/**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/api/src/microservice/Message.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @interface Message 3 | * ServiceCall data 4 | */ 5 | export interface Message { 6 | /** 7 | * @property 8 | * The combination of serviceName and methodName: 9 | */ 10 | qualifier: string; 11 | /** 12 | * @property 13 | * Arguments of the invoked function 14 | */ 15 | data: any[]; 16 | } 17 | -------------------------------------------------------------------------------- /packages/examples/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'node'], 8 | moduleDirectories: ['node_modules', '/src', '/node_modules/'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/addressable/src/const.ts: -------------------------------------------------------------------------------- 1 | export const DEBUG = false; 2 | 3 | export const EVENT = { 4 | addChannel: 'addChannel', 5 | channelInit: 'channelInit', 6 | registerAddress: 'registerAddress', 7 | unregisterAddress: 'unregisterAddress', 8 | connect: 'connect', 9 | incomingServerConnection: 'incomingServerConnection', 10 | incomingClientConnection: 'incomingClientConnection', 11 | }; 12 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js', 'node'], 8 | moduleDirectories: ['node_modules', '/src', '/node_modules/'], 9 | }; 10 | -------------------------------------------------------------------------------- /packages/examples/iife/remoteCallExample/definitions.js: -------------------------------------------------------------------------------- 1 | var definitions = (function() { 2 | var remoteServiceDefinition = { 3 | serviceName: 'RemoteService', 4 | methods: { 5 | hello: { 6 | asyncModel: 'requestResponse', 7 | }, 8 | greet$: { 9 | asyncModel: 'requestStream', 10 | }, 11 | }, 12 | }; 13 | 14 | return remoteServiceDefinition; 15 | })(); 16 | -------------------------------------------------------------------------------- /scripts/verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | VERSION=$1 4 | if [ "$VERSION" = "" ] ; then 5 | echo "Please specify a version to verify" 6 | exit 1 7 | fi 8 | DIR=$(pwd) 9 | cd $DIR/packages/examples/k8s 10 | npx json -I -f package.json -e "this.dependencies['@scalecube/node']='$VERSION'" 11 | cd $DIR/packages/examples/ 12 | yarn run test:e2e 13 | docker build . -t scalecube-example:bundle --build-arg VERSION=$VERSION 14 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/tests/helper.ts: -------------------------------------------------------------------------------- 1 | import EventEmitter = require('events'); 2 | const myEmitter = new EventEmitter(); 3 | 4 | // @ts-ignore 5 | global.addEventListener = myEmitter.addListener.bind(myEmitter); 6 | // @ts-ignore 7 | global.removeEventListener = myEmitter.removeListener.bind(myEmitter); 8 | 9 | global.console.log = (...s: any[]) => { 10 | process.stdout.write(s.join(' , ') + '\n'); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/examples/node/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const { fork } = require('child_process'); 4 | 5 | const mockServers = [ 6 | 'node/helloService.js', 7 | 'node/personService.js', 8 | 'node/greetMePlzService.js', 9 | 'node/seedService.js', 10 | ]; 11 | 12 | // load services 13 | mockServers.forEach((filePath) => { 14 | const ms = fork(path.resolve('.', filePath)); 15 | ms.send(''); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/transport-browser/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | setupFilesAfterEnv: ['/tests/messageChannelMock.ts'], 10 | }; 11 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/helpers/constants.ts: -------------------------------------------------------------------------------- 1 | export const SERVICE_CALL_MUST_BE_OBJECT = 'service call must be an object'; 2 | export const REQUEST_STREAM_MUST_BE_FUNCTION = 'requestStream must be a function'; 3 | export const REQUEST_RESPONSE_MUST_BE_FUNCTION = 'requestResponse must be a function'; 4 | 5 | export const getInvalidRequestHandler = (name: string, type) => 6 | `invalid custom ${name}, receive ${type} instead of Function`; 7 | -------------------------------------------------------------------------------- /packages/examples/iife/iframe/worker1.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/browser/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | 4 | sc.createMicroservice({ 5 | services: [ 6 | { 7 | definition: definitions.remoteServiceDefinition4, 8 | reference: { 9 | ack4: () => Promise.resolve('ack'), 10 | }, 11 | }, 12 | ], 13 | address: 'worker', 14 | seedAddress: 'main', 15 | }); 16 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)(test|spec)\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | setupFilesAfterEnv: ['/tests/messageChannelMock.ts'], 10 | }; 11 | -------------------------------------------------------------------------------- /packages/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "strict": true, 9 | "moduleResolution": "node", 10 | "baseUrl": "./src", 11 | "esModuleInterop": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules", "**/*.spec.*"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/api/src/microservice/AsyncModel.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Defines Stream asyncModel ( Observable, Flowable , etc.. ) 3 | */ 4 | export type RequestStreamAsyncModel = 'requestStream'; 5 | 6 | /** 7 | * Defines Async asyncModel ( Promise ) 8 | */ 9 | export type RequestResponseAsyncModel = 'requestResponse'; 10 | 11 | /** 12 | * Definition of the method's response type 13 | */ 14 | export type AsyncModel = RequestStreamAsyncModel | RequestResponseAsyncModel; 15 | -------------------------------------------------------------------------------- /packages/browser/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "strict": true, 9 | "moduleResolution": "node", 10 | "baseUrl": "./src", 11 | "esModuleInterop": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules", "**/*.spec.*"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample/worker1.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/scalecube-microservice/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | importScripts('./bubbleSortService.js'); 4 | 5 | sc.createMicroservice({ 6 | services: [ 7 | { 8 | reference: remoteBubbleSortService, 9 | definition: definitions.remoteServiceDefinition, 10 | }, 11 | ], 12 | address: 'worker', 13 | seedAddress: 'main', 14 | }); 15 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample/worker2.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/scalecube-microservice/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | importScripts('./bubbleSortService.js'); 4 | 5 | sc.createMicroservice({ 6 | services: [ 7 | { 8 | reference: remoteBubbleSortService, 9 | definition: definitions.remoteServiceDefinition2, 10 | }, 11 | ], 12 | address: 'worker2', 13 | seedAddress: 'main', 14 | }); 15 | -------------------------------------------------------------------------------- /packages/addressable/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'src'], 9 | globals: { 10 | isNodeEvn: false, 11 | }, 12 | setupFilesAfterEnv: ['/tests/messageChannelMock.ts'], 13 | }; 14 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "strict": true, 9 | "moduleResolution": "node", 10 | "baseUrl": "./src", 11 | "esModuleInterop": true 12 | }, 13 | "include": ["src/**/*"], 14 | "exclude": ["node_modules", "**/*.spec.*"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/examples/iife/HTMLElementExample/example-html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scalecube HTML Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/cluster-browser/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | globals: { 10 | isNodeEvn: false, 11 | }, 12 | setupFilesAfterEnv: ['/tests/messageChannelMock.ts'], 13 | }; 14 | -------------------------------------------------------------------------------- /packages/examples/k8s/helm-scalecube-ex/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /packages/addressable/tests/fixtures/pingPong/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ping Pong test 6 | 7 | 8 |

Open console, check for 9 messages "x got pong from y"

9 | 10 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./dist", 8 | "outDir": "./dist", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true 13 | }, 14 | "include": ["src/**/*"], 15 | "exclude": ["node_modules", "**/*.spec.*"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/transport-nodejs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./dist", 8 | "outDir": "./dist", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true 13 | }, 14 | "include": ["src/**/*"], 15 | "exclude": ["node_modules", "**/*.spec.*"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/addressable/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "outDir": "./es", 8 | "strict": true, 9 | "moduleResolution": "node", 10 | "baseUrl": "./src", 11 | "skipLibCheck": true, 12 | "esModuleInterop": true 13 | }, 14 | "include": ["src/**/*"], 15 | "exclude": ["node_modules", "../../node_modules", "**/*.spec.*"] 16 | } 17 | -------------------------------------------------------------------------------- /packages/examples/Dockerfile: -------------------------------------------------------------------------------- 1 | # this docker is using us to verify published version 2 | FROM node:lts-alpine3.11 3 | RUN apk add python make g++ 4 | COPY . /var/app 5 | WORKDIR /var/app 6 | ARG VERSION=next 7 | RUN yarn add \ 8 | @scalecube/browser@${VERSION} \ 9 | @scalecube/node@${VERSION} \ 10 | @scalecube/routers@${VERSION} \ 11 | @scalecube/transport-nodejs@${VERSION} \ 12 | @scalecube/utils@${VERSION} \ 13 | @scalecube/api@${VERSION} 14 | 15 | RUN yarn build 16 | 17 | CMD /bin/sh 18 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-config-prettier"], 3 | "rules": { 4 | "forin": false, 5 | "interface-name": false, 6 | "no-empty-interface": false, 7 | "object-literal-sort-keys": false, 8 | "ordered-imports": false, 9 | "no-unused-expression": [true, "allow-fast-null-checks", "allow-new"], 10 | "no-empty": [true, "allow-empty-functions"], 11 | "no-console": [true, "log"], 12 | "max-classes-per-file": false 13 | }, 14 | "jsRules": true 15 | } 16 | -------------------------------------------------------------------------------- /packages/api/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./lib", 8 | "outDir": "./lib", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/jest.config-dom.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | globals: { 10 | isNodeEvn: false, 11 | }, 12 | setupFilesAfterEnv: ['/tests/mockEnv.ts', '/tests/messageChannelMock.ts'], 13 | }; 14 | -------------------------------------------------------------------------------- /packages/routers/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./es", 8 | "outDir": "./es", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/jest.config-dom.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | '.(ts|tsx)': 'ts-jest', 4 | }, 5 | testRegex: '(\\.|/)spec\\.ts$', 6 | testPathIgnorePatterns: ['/es/', '/lib/', '/node_modules/'], 7 | moduleFileExtensions: ['ts', 'tsx', 'js'], 8 | moduleDirectories: ['node_modules', 'app/src'], 9 | globals: { 10 | isNodeEvn: false, 11 | }, 12 | setupFilesAfterEnv: ['/tests/mockEnv.ts', '/tests/messageChannelMock.ts'], 13 | }; 14 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./es", 8 | "outDir": "./es", 9 | "strict": true, 10 | "moduleResolution": "Node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./es", 8 | "outDir": "./es", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/cluster-browser/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./es", 8 | "outDir": "./es", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./es", 8 | "outDir": "./es", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/transport-browser/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./es", 8 | "outDir": "./es", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "skipLibCheck": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/examples/node/helpers/retryRouterWithLogs.js: -------------------------------------------------------------------------------- 1 | const { retryRouter } = require('@scalecube/routers'); 2 | 3 | const retryRouterWithLogs = (serviceName) => (...data) => 4 | new Promise((resolve) => { 5 | const progress = setInterval(() => { 6 | console.log(`${serviceName} waiting...`); 7 | }, 1000); 8 | 9 | retryRouter({ period: 10 })(...data).then((response) => { 10 | clearInterval(progress); 11 | resolve(response); 12 | }); 13 | }); 14 | 15 | module.exports = { 16 | retryRouterWithLogs, 17 | }; 18 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./dist", 8 | "outDir": "./dist", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "noImplicitAny": false 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "**/*.spec.*"] 17 | } 18 | -------------------------------------------------------------------------------- /packages/addressable/src/utils/join.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from './Subject'; 2 | 3 | export function join(s1: Pick, s2: Pick) { 4 | return { 5 | subscribe: (fn: (arg: any) => void) => { 6 | const s = new Subject(); 7 | const uns1 = s1.subscribe((i) => s.next(i)); 8 | const uns2 = s2.subscribe((i) => s.next(i)); 9 | const uns = s.subscribe(fn); 10 | 11 | return () => { 12 | uns1(); 13 | uns2(); 14 | uns(); 15 | }; 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # rsocke-transport 7 | 8 | This package serves as RSocket Transport provider 9 | -------------------------------------------------------------------------------- /packages/api/src/microservice/ServiceDefinition.ts: -------------------------------------------------------------------------------- 1 | import { AsyncModel } from '.'; 2 | 3 | /** 4 | * @interface ServiceDefinition 5 | * Service metadata 6 | */ 7 | export interface ServiceDefinition { 8 | /** 9 | * @property 10 | * The name of a service 11 | */ 12 | serviceName: string; 13 | /** 14 | * @property 15 | * The map of methods, that exist in the service, with the corresponding asyncModel of each of them 16 | */ 17 | methods: { 18 | [methodName: string]: { 19 | asyncModel: AsyncModel; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /packages/addressable/src/index.ts: -------------------------------------------------------------------------------- 1 | import { bootstrap } from './boostrap'; 2 | import * as api from './api'; 3 | 4 | let win; 5 | let worker; 6 | // @ts-ignore 7 | if (typeof window !== 'undefined') { 8 | // @ts-ignore 9 | win = window; 10 | } 11 | // @ts-ignore 12 | if (typeof WorkerGlobalScope !== 'undefined') { 13 | // @ts-ignore 14 | worker = self; 15 | } 16 | const client = bootstrap(win, worker); 17 | 18 | export const connect: api.connect = client.connect; 19 | export const listen: api.listen = client.listen; 20 | export type listener = api.Listener; 21 | -------------------------------------------------------------------------------- /packages/api/src/cluster/ClusterEvent.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @interface ClusterEvent 3 | * Notification from Cluster to the subscriber 4 | */ 5 | export interface ClusterEvent { 6 | /** 7 | * @property 8 | * 'ADDED' | 'REMOVED' | 'INIT' 9 | */ 10 | type: MemberEventType; 11 | /** 12 | * @property 13 | * data that pass between members 14 | */ 15 | items: any[]; 16 | /** 17 | * @property 18 | * from which member the information arrived 19 | */ 20 | from: string; 21 | } 22 | 23 | export type MemberEventType = 'ADDED' | 'REMOVED' | 'INIT'; 24 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "es6", 5 | "lib": ["dom", "es2015", "es2017.object", "es5", "es6", "es2016"], 6 | "declaration": true, 7 | "declarationDir": "./dist", 8 | "outDir": "./dist", 9 | "strict": true, 10 | "moduleResolution": "node", 11 | "baseUrl": "./src", 12 | "esModuleInterop": true, 13 | "noImplicitAny": false, 14 | "skipLibCheck": true 15 | }, 16 | "include": ["src/**/*"], 17 | "exclude": ["node_modules", "**/*.spec.*"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/transport-nodejs/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # transport-nodejs 7 | 8 | This package serves as RSocket Transport provider for running on NodeJS 9 | -------------------------------------------------------------------------------- /packages/api/src/microservice/LookUp.ts: -------------------------------------------------------------------------------- 1 | import { Endpoint } from '.'; 2 | 3 | /** 4 | * @function LookUp 5 | * The function that finds all the appropriate endpoints for a given criteria 6 | */ 7 | export type LookUp = (options: LookupOptions) => Endpoint[] | []; 8 | 9 | /** 10 | * @interface LookupOptions 11 | * The criteria, that is used to get endpoints from a registry 12 | */ 13 | export interface LookupOptions { 14 | /** 15 | * @property 16 | * The combination of serviceName and methodName: 17 | */ 18 | qualifier: string; 19 | } 20 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/helpers/validation.ts: -------------------------------------------------------------------------------- 1 | import { check } from '@scalecube/utils'; 2 | 3 | export const validateClientProvider = (provider: any) => validateProvider(provider, 'RsocketClient'); 4 | export const validateServerProvider = (provider: any) => validateProvider(provider, 'RsocketServer'); 5 | 6 | export const validateProvider = (provider: any, name: string) => { 7 | check.assertDefined(provider, `Must provide ${name} provider`); 8 | 9 | check.assertFunction(provider, `${name} provider invalid, expect a function be receive ${typeof provider}`); 10 | }; 11 | -------------------------------------------------------------------------------- /packages/transport-browser/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # transport-browser 7 | 8 | This package serves as RSocket Transport provider for running on browser 9 | -------------------------------------------------------------------------------- /packages/examples/bundles/parcel.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scalecube ESModule Example 6 | 7 | 8 |
9 | results : 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/examples/bundles/rollup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scalecube ESModule Example 6 | 7 | 8 |
9 | results : 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /packages/routers/src/Default/default.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | 3 | export const defaultRouter: MicroserviceApi.Router = (options: MicroserviceApi.RouterOptions) => { 4 | const { message, lookUp } = options; 5 | const { qualifier } = message; 6 | return new Promise((resolve, reject) => { 7 | const endpoints = lookUp({ qualifier }); 8 | if (!(endpoints && Array.isArray(endpoints) && endpoints.length > 0)) { 9 | reject(null); 10 | } else { 11 | resolve(endpoints[0]); 12 | } 13 | }); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample/definitions.js: -------------------------------------------------------------------------------- 1 | definitions = (function() { 2 | var remoteServiceDefinition = { 3 | serviceName: 'RemoteService1', 4 | methods: { 5 | bubbleSortTime: { 6 | asyncModel: 'requestResponse', 7 | }, 8 | }, 9 | }; 10 | 11 | var remoteServiceDefinition2 = { 12 | serviceName: 'RemoteService2', 13 | methods: { 14 | bubbleSortTime: { 15 | asyncModel: 'requestResponse', 16 | }, 17 | }, 18 | }; 19 | 20 | return { 21 | remoteServiceDefinition, 22 | remoteServiceDefinition2, 23 | }; 24 | })(); 25 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/ServiceCall/ServiceCallUtils.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceContext } from '../helpers/types'; 2 | import { saveToLogs } from '@scalecube/utils'; 3 | 4 | export const serviceCallError = ({ 5 | errorMessage, 6 | microserviceContext, 7 | }: { 8 | errorMessage: string; 9 | microserviceContext: MicroserviceContext | null; 10 | }) => { 11 | const error = new Error(errorMessage); 12 | if (microserviceContext) { 13 | const { whoAmI, debug } = microserviceContext; 14 | saveToLogs(whoAmI, errorMessage, {}, debug, 'warn'); 15 | } 16 | return error; 17 | }; 18 | -------------------------------------------------------------------------------- /packages/transport-nodejs/src/Provider/Provider.ts: -------------------------------------------------------------------------------- 1 | import { Provider } from '@scalecube/rsocket-adapter'; 2 | 3 | // @ts-ignore 4 | import { JsonSerializers } from 'rsocket-core'; 5 | import { clientFactory } from './ProviderClient'; 6 | import { serverFactory } from './ProviderServer'; 7 | 8 | const serializers = JsonSerializers; 9 | 10 | export const clientProvider: Provider = { 11 | providerFactory: clientFactory, 12 | serializers, 13 | factoryOptions: null, 14 | }; 15 | 16 | export const serverProvider: Provider = { 17 | providerFactory: serverFactory, 18 | serializers, 19 | factoryOptions: null, 20 | }; 21 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/helpers/types.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { ReactiveSocket } from 'rsocket-types'; 3 | 4 | export type CreateConnectionManager = () => ConnectionManager; 5 | 6 | export interface ConnectionManager { 7 | getConnection: (connectionAddress: string) => Promise; 8 | getAllConnections: () => { [key: string]: Promise }; 9 | setConnection: (connectionAddress: string, value: Promise) => void; 10 | removeConnection: (connectionAddress: string) => void; 11 | } 12 | 13 | export interface RsocketEventsPayload { 14 | data: any; 15 | metadata: any; 16 | } 17 | -------------------------------------------------------------------------------- /packages/api/src/common/Address.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @interface Address 3 | * URI address 4 | */ 5 | export default interface Address { 6 | /** 7 | * @property 8 | * unique identifier that allows other computers to access it. 9 | */ 10 | host: string; 11 | /** 12 | * @property 13 | * determine on which port number the server will receive the data 14 | */ 15 | port: number; 16 | /** 17 | * @property 18 | * rules for communication between server and client 19 | * ws | pm | tcp 20 | */ 21 | protocol: string; 22 | /** 23 | * @property 24 | * relative address 25 | */ 26 | path: string; 27 | } 28 | -------------------------------------------------------------------------------- /packages/api/src/microservice/Service.ts: -------------------------------------------------------------------------------- 1 | import { ServiceDefinition, ServiceReference } from '.'; 2 | 3 | /** 4 | * @interface Service 5 | * Definition and implementation of a service 6 | */ 7 | export interface Service { 8 | /** 9 | * @property 10 | * The metadata for a service, that includes the name of a service and the map of methods that are 11 | * included in it 12 | */ 13 | definition: ServiceDefinition; 14 | /** 15 | * @property 16 | * The implementation of a service, that can be an object with methods or a module with a function being exported 17 | */ 18 | reference: ServiceReference; 19 | } 20 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/src/helpers/constants.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '@scalecube/api'; 2 | import { getFullAddress } from '@scalecube/utils'; 3 | 4 | export const INVALID_ITEMS_TO_PUBLISH = 'itemsToPublish are not of type Array'; 5 | export const NODEJS_MUST_PROVIDE_CLUSTER_IMPL = 'Must provide cluster when running on nodejs'; 6 | 7 | export const getAddressCollision = (address: string, seedAddress: string) => 8 | `address ${address} must be different from the seed Address ${seedAddress}`; 9 | 10 | export const getDiscoverySuccessfullyDestroyedMessage = (address: Address) => 11 | `${getFullAddress(address)} has been removed`; 12 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/helpers/defaultConfiguration.ts: -------------------------------------------------------------------------------- 1 | export const getSerializers = () => ({ 2 | data: { 3 | deserialize: (data: any) => data, 4 | serialize: (data: any) => data, 5 | }, 6 | metadata: { 7 | deserialize: (data: any) => data, 8 | serialize: (data: any) => data, 9 | }, 10 | }); 11 | 12 | export const getSetup = (setup: { [key: string]: any }) => ({ 13 | dataMimeType: (setup && setup.dataMimeType) || 'text/plain', 14 | keepAlive: (setup && setup.keepAlive) || 1000000, 15 | lifetime: (setup && setup.lifetime) || 1000000, 16 | metadataMimeType: (setup && setup.metadataMimeType) || 'text/plain', 17 | }); 18 | -------------------------------------------------------------------------------- /packages/addressable/src/utils/Subject.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Subject for poor 3 | */ 4 | export class Subject { 5 | private values: any = {}; 6 | private subscribers: Array<(arg: any) => void> = []; 7 | 8 | public next(value: any) { 9 | this.values = { ...value }; 10 | this.notify(); 11 | } 12 | public subscribe(fn: (arg: any) => void) { 13 | this.subscribers.push(fn); 14 | fn({ ...this.values }); 15 | return () => { 16 | this.subscribers = this.subscribers.filter((s) => s !== fn); 17 | }; 18 | } 19 | protected notify() { 20 | for (const sub of this.subscribers) { 21 | sub({ ...this.values }); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/requestResponse.ts: -------------------------------------------------------------------------------- 1 | import { Single } from 'rsocket-flowable'; 2 | import { RequestHandler } from './api/Gateway'; 3 | 4 | const singleHandler: RequestHandler = (serviceCall, data, subscriber) => { 5 | subscriber.onSubscribe(); 6 | serviceCall 7 | .requestResponse(data) 8 | .then((resp: any) => { 9 | // console.log('RESP', resp); 10 | subscriber.onComplete({ data: resp }); 11 | }) 12 | .catch((err: any) => { 13 | subscriber.onError(err); 14 | }); 15 | }; 16 | 17 | export const requestResponse = ({ data }, serviceCall, handler = singleHandler) => { 18 | return new Single(handler.bind(null, serviceCall, data)); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/api/src/microservice/Router.ts: -------------------------------------------------------------------------------- 1 | import { Endpoint, LookUp, Message } from '.'; 2 | 3 | /** 4 | * @function Router 5 | * Specifies logic for picking the most appropriate Endpoint from Endpoint[] 6 | */ 7 | export type Router = (options: RouterOptions) => Promise; 8 | 9 | /** 10 | * @interface RouteOptions 11 | * The options that are used for the creation of the custom router 12 | */ 13 | export interface RouterOptions { 14 | /** 15 | * @method 16 | * The function that finds Endpoint by given criteria 17 | */ 18 | lookUp: LookUp; 19 | /** 20 | * @property 21 | * metadata, contain criteria for picking the Endpoint 22 | */ 23 | message: Message; 24 | } 25 | -------------------------------------------------------------------------------- /packages/examples/iife/iframe/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/api/src/microservice/ServiceReference.ts: -------------------------------------------------------------------------------- 1 | import { CreateProxy } from './CreateProxy'; 2 | import { CreateServiceCall } from './CreateServiceCall'; 3 | 4 | /** 5 | * @function ServiceReference 6 | * Map: key and value(to service method) 7 | */ 8 | export type ServiceReference = ServiceFactory | ServiceObject; 9 | 10 | export type ServiceFactory = ({ createProxy, createServiceCall }: ServiceFactoryOptions) => ServiceObject; 11 | 12 | export interface ServiceObject { 13 | constructor?: any; 14 | 15 | [methodName: string]: any; 16 | } 17 | 18 | export interface ServiceFactoryOptions { 19 | createProxy: CreateProxy; 20 | createServiceCall: CreateServiceCall; 21 | } 22 | -------------------------------------------------------------------------------- /packages/examples/iife/iframe/iframe.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/routers/rollup.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import pkg from './package.json'; 5 | 6 | export default { 7 | input: 'src/index.ts', 8 | output: [ 9 | { 10 | file: pkg.main, 11 | format: 'cjs', 12 | }, 13 | ], 14 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 15 | plugins: [ 16 | typescript({ 17 | typescript: require('typescript'), 18 | clean: true, 19 | }), 20 | visualizer({ 21 | filename: 'report.html', 22 | }), 23 | filesize(), 24 | ], 25 | }; 26 | -------------------------------------------------------------------------------- /packages/cluster-browser/rollup.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import pkg from './package.json'; 5 | 6 | export default { 7 | input: 'src/index.ts', 8 | output: [ 9 | { 10 | file: pkg.main, 11 | format: 'cjs', 12 | }, 13 | ], 14 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 15 | plugins: [ 16 | typescript({ 17 | typescript: require('typescript'), 18 | clean: true, 19 | }), 20 | visualizer({ 21 | filename: 'report.html', 22 | }), 23 | filesize(), 24 | ], 25 | }; 26 | -------------------------------------------------------------------------------- /packages/node/src/index.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | import { createMicroservice as msCreate, ASYNC_MODEL_TYPES } from '@scalecube/scalecube-microservice'; 3 | import { transport } from '@scalecube/transport-nodejs'; 4 | import { joinCluster } from '@scalecube/cluster-nodejs'; 5 | import { roundRobin } from '@scalecube/routers'; 6 | import { getAddress as stringToAddress } from '@scalecube/utils'; 7 | 8 | export { ASYNC_MODEL_TYPES, stringToAddress }; 9 | 10 | export const createMicroservice: MicroserviceApi.CreateMicroservice = (config: any) => { 11 | return msCreate({ 12 | transport, 13 | cluster: joinCluster, 14 | defaultRouter: roundRobin, 15 | ...config, 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /packages/examples/k8s/helm-scalecube-ex/templates/seed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | 4 | metadata: 5 | name: seed 6 | labels: 7 | name: seed 8 | spec: 9 | hostname: seed 10 | subdomain: seed 11 | containers: 12 | - name: seed 13 | image: {{$.Values.image.name}} 14 | imagePullPolicy: {{$.Values.image.pullPolicy}} 15 | command: ['node', 'seed.js'] 16 | env: 17 | - name: ADDRESS 18 | valueFrom: 19 | fieldRef: 20 | fieldPath: status.podIP 21 | ports: 22 | - containerPort: 8080 23 | --- 24 | apiVersion: v1 25 | kind: Service 26 | metadata: 27 | name: seed 28 | spec: 29 | selector: 30 | name: seed 31 | clusterIP: None 32 | -------------------------------------------------------------------------------- /packages/utils/rollup.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import pkg from './package.json'; 5 | 6 | export default { 7 | input: 'src/index.ts', 8 | output: [ 9 | { 10 | file: pkg.main, 11 | format: 'cjs', 12 | }, 13 | ], 14 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 15 | plugins: [ 16 | typescript({ 17 | typescript: require('typescript'), 18 | clean: true, 19 | }), 20 | visualizer({ 21 | filename: 'report.html', 22 | title: 'scalecube-utils', 23 | }), 24 | filesize(), 25 | ], 26 | }; 27 | -------------------------------------------------------------------------------- /packages/addressable/src/utils/eachDelta.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from './Subject'; 2 | 3 | export function eachDelta(sbj: Pick) { 4 | return { 5 | subscribe: (fn: (arg: any) => void) => { 6 | let oldState: any = {}; 7 | const notify = (s: any) => fn(s); 8 | return sbj.subscribe((state) => { 9 | for (const key in state) { 10 | if (!oldState[key] || oldState[key] !== state[key]) { 11 | notify({ key, value: state[key] }); 12 | } 13 | } 14 | for (const key in oldState) { 15 | if (!state[key]) { 16 | notify({ key, value: undefined }); 17 | } 18 | } 19 | oldState = state; 20 | }); 21 | }, 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /packages/api/src/microservice/index.ts: -------------------------------------------------------------------------------- 1 | export { AsyncModel, RequestResponseAsyncModel, RequestStreamAsyncModel } from './AsyncModel'; 2 | export { CreateProxy, ProxyOptions } from './CreateProxy'; 3 | export { CreateServiceCall, ServiceCall } from './CreateServiceCall'; 4 | export { Microservice, CreateMicroservice, MicroserviceOptions } from './Microservice'; 5 | export { Service } from './Service'; 6 | export { ServiceDefinition } from './ServiceDefinition'; 7 | export { ServiceReference, ServiceFactoryOptions, ServiceFactory, ServiceObject } from './ServiceReference'; 8 | export { Endpoint } from './Endpoint'; 9 | export { Message } from './Message'; 10 | export { LookupOptions, LookUp } from './LookUp'; 11 | export { Router, RouterOptions } from './Router'; 12 | -------------------------------------------------------------------------------- /packages/api/src/microservice/CreateProxy.ts: -------------------------------------------------------------------------------- 1 | import { Router, ServiceDefinition } from '.'; 2 | 3 | /** 4 | * @function CreateProxy 5 | * 6 | */ 7 | export type CreateProxy = (options: ProxyOptions) => T; 8 | 9 | /** 10 | * @interface ProxyOptions 11 | * The options that are used for the creation of the proxy for the specific microservice container [deprecated] 12 | */ 13 | export interface ProxyOptions { 14 | /** 15 | * @method 16 | * Custom router specifies the logic of choosing the appropriate remoteService 17 | */ 18 | router?: Router; 19 | /** 20 | * @property 21 | * The metadata for a service container, that includes the name of a service and the map of methods that are 22 | * included in it 23 | */ 24 | serviceDefinition: ServiceDefinition; 25 | } 26 | -------------------------------------------------------------------------------- /packages/examples/node/helloService.js: -------------------------------------------------------------------------------- 1 | const { createMicroservice, ASYNC_MODEL_TYPES } = require('@scalecube/node'); 2 | 3 | const definition = { 4 | serviceName: 'HelloService', 5 | methods: { 6 | hello: { 7 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE, 8 | }, 9 | }, 10 | }; 11 | 12 | process.on('message', () => { 13 | createMicroservice({ 14 | address: { 15 | protocol: 'ws', 16 | host: 'localhost', 17 | port: 6112, 18 | path: '', 19 | }, 20 | seedAddress: { 21 | protocol: 'ws', 22 | host: 'localhost', 23 | port: 6111, 24 | path: '', 25 | }, 26 | services: [ 27 | { 28 | reference: { hello: (data) => Promise.resolve(`hello ${data}`) }, 29 | definition, 30 | }, 31 | ], 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/Proxy/createProxy.ts: -------------------------------------------------------------------------------- 1 | import { CreateProxy } from '../helpers/types'; 2 | import { MICROSERVICE_NOT_EXISTS } from '../helpers/constants'; 3 | import { validateServiceDefinition } from '@scalecube/utils'; 4 | import { getProxy } from './Proxy'; 5 | import { getServiceCall } from '../ServiceCall/ServiceCall'; 6 | 7 | export const createProxy = (proxyOptions: CreateProxy) => { 8 | const { router, serviceDefinition, microserviceContext, transportClient } = proxyOptions; 9 | 10 | if (!microserviceContext) { 11 | throw new Error(MICROSERVICE_NOT_EXISTS); 12 | } 13 | validateServiceDefinition(serviceDefinition); 14 | 15 | return getProxy({ 16 | serviceCall: getServiceCall({ router, microserviceContext, transportClient }), 17 | serviceDefinition, 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/addressable/tests/fixtures/pingPong/pingPong.ts: -------------------------------------------------------------------------------- 1 | import { connect, listen } from '../../../lib'; 2 | 3 | const test = (thread) => { 4 | listen(thread, (msg, port) => { 5 | port.postMessage('pong'); 6 | }); 7 | ['iframe', 'worker', 'main'].forEach(async (addr) => { 8 | const port1 = await connect(addr); 9 | port1.postMessage('ping'); 10 | port1.onmessage = (msg) => { 11 | // tslint:disable-next-line:no-console 12 | console.log(`${thread} got ${msg.data} from ${addr}`); 13 | }; 14 | }); 15 | }; 16 | 17 | // worker 18 | // @ts-ignore 19 | if (typeof WorkerGlobalScope !== 'undefined') { 20 | test('worker'); 21 | // iframe 22 | } else if (window && window.top && window.top !== window.self) { 23 | test('iframe'); 24 | } 25 | // main 26 | else { 27 | test('main'); 28 | } 29 | -------------------------------------------------------------------------------- /packages/browser/src/index.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | import { createMicroservice as msCreate, ASYNC_MODEL_TYPES } from '@scalecube/scalecube-microservice'; 3 | import { transport } from '@scalecube/transport-browser'; 4 | import { joinCluster } from '@scalecube/cluster-browser'; 5 | import { retryRouter } from '@scalecube/routers'; 6 | import { workers, getAddress as stringToAddress } from '@scalecube/utils'; 7 | 8 | export { ASYNC_MODEL_TYPES, workers, stringToAddress }; 9 | 10 | export const createMicroservice: MicroserviceApi.CreateMicroservice = (config: any) => { 11 | return msCreate({ 12 | transport, 13 | cluster: joinCluster, 14 | defaultRouter: retryRouter({ period: 10, maxRetry: 500 }), 15 | address: stringToAddress(Date.now().toString()), 16 | ...config, 17 | }); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample2/definitions.js: -------------------------------------------------------------------------------- 1 | definitions = (function() { 2 | var remoteServiceDefinition = { 3 | serviceName: 'RemoteService1', 4 | methods: { 5 | getInterval: { 6 | asyncModel: 'requestStream', 7 | }, 8 | }, 9 | }; 10 | 11 | var remoteServiceDefinition2 = { 12 | serviceName: 'RemoteService2', 13 | methods: { 14 | getInterval: { 15 | asyncModel: 'requestStream', 16 | }, 17 | }, 18 | }; 19 | 20 | var remoteServiceDefinition3 = { 21 | serviceName: 'RemoteService3', 22 | methods: { 23 | getInterval: { 24 | asyncModel: 'requestStream', 25 | }, 26 | }, 27 | }; 28 | 29 | return { 30 | remoteServiceDefinition, 31 | remoteServiceDefinition2, 32 | remoteServiceDefinition3, 33 | }; 34 | })(); 35 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/api/Gateway.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | 3 | export type RequestHandler = (serviceCall: MicroserviceApi.ServiceCall, data: any, subscriber: any) => void; 4 | 5 | export interface GatewayOptions { 6 | port: number; 7 | requestResponse?: RequestHandler; 8 | requestStream?: RequestHandler; 9 | } 10 | 11 | export interface GatewayStartOptions { 12 | serviceCall: MicroserviceApi.ServiceCall; 13 | } 14 | 15 | export interface Gateway { 16 | // constructor(options: GatewayOptions): Gateway; 17 | /** 18 | * gateway provider implementation 19 | * start to listen on a port (ws/ rsocket/ ...) 20 | * handle incoming requests 21 | */ 22 | start: (options: GatewayStartOptions) => void; 23 | /** 24 | * stop gateway 25 | */ 26 | stop: () => void; 27 | } 28 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/requestStream.ts: -------------------------------------------------------------------------------- 1 | import { Flowable } from 'rsocket-flowable'; 2 | import { RequestHandler } from './api/Gateway'; 3 | 4 | const flowableHandler: RequestHandler = (serviceCall, data, subscriber) => { 5 | let sub; 6 | subscriber.onSubscribe({ 7 | cancel: () => { 8 | sub && sub.unsubscribe(); 9 | }, 10 | request: () => { 11 | sub = serviceCall.requestStream(data).subscribe( 12 | (response: any) => { 13 | subscriber.onNext({ data: response }); 14 | }, 15 | (error: any) => subscriber.onError(error), 16 | () => subscriber.onComplete() 17 | ); 18 | }, 19 | }); 20 | }; 21 | 22 | export const requestStream = ({ data }, serviceCall, handler = flowableHandler) => { 23 | return new Flowable(handler.bind(null, serviceCall, data)); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/rollup.es.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import pkg from './package.json'; 7 | 8 | export default { 9 | input: 'src/index.ts', 10 | output: [ 11 | { 12 | file: pkg.module, 13 | format: 'es', 14 | sourcemap: false, 15 | }, 16 | ], 17 | external: ['rxjs'], 18 | plugins: [ 19 | resolve(), 20 | visualizer({ 21 | filename: 'report.es.html', 22 | title: 'Microservice - es', 23 | }), 24 | typescript({ 25 | typescript: tscompile, 26 | clean: true, 27 | }), 28 | // global(), 29 | filesize(), 30 | ], 31 | }; 32 | -------------------------------------------------------------------------------- /packages/examples/k8s/helm-scalecube-ex/templates/greeting-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | 4 | metadata: 5 | name: 'greeting' 6 | 7 | spec: 8 | restartPolicy: Never 9 | containers: 10 | - name: greeting 11 | image: {{$.Values.image.name}} 12 | imagePullPolicy: {{$.Values.image.pullPolicy}} 13 | command: ['/bin/sh', '-c'] 14 | args: 15 | - 'until getent hosts seed.seed; do sleep 1; done; until node greeting.js; do sleep 1; done;' 16 | env: 17 | - name: NAMESPACE 18 | valueFrom: 19 | fieldRef: 20 | fieldPath: metadata.namespace 21 | - name: SEED 22 | value: seed.seed 23 | - name: ADDRESS 24 | valueFrom: 25 | fieldRef: 26 | fieldPath: status.podIP 27 | ports: 28 | - containerPort: 8080 29 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/Client/connectionManager.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { ReactiveSocket } from 'rsocket-types'; 3 | import { CreateConnectionManager } from '../helpers/types'; 4 | 5 | /** 6 | * createConnectionManager manage all open connection per process 7 | * 8 | */ 9 | export const createConnectionManager: CreateConnectionManager = () => { 10 | const openConnections: { [key: string]: Promise } = {}; 11 | 12 | return { 13 | getConnection: (connectionAddress: string) => openConnections[connectionAddress], 14 | getAllConnections: () => ({ ...openConnections }), 15 | setConnection: (connectionAddress: string, value: Promise) => 16 | (openConnections[connectionAddress] = value), 17 | removeConnection: (connectionAddress: string) => delete openConnections[connectionAddress], 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /packages/examples/k8s/greeting.js: -------------------------------------------------------------------------------- 1 | const { createMicroservice, ASYNC_MODEL_TYPES } = require('@scalecube/node'); 2 | 3 | console.log('seed', process.env.SEED); 4 | console.log('address', process.env.ADDRESS); 5 | 6 | createMicroservice({ 7 | seedAddress: { 8 | protocol: 'ws', 9 | host: process.env.SEED, 10 | port: 7001, 11 | path: '', 12 | }, 13 | address: { 14 | protocol: 'ws', 15 | host: process.env.ADDRESS, 16 | port: 7003, 17 | path: '', 18 | }, 19 | services: [ 20 | { 21 | reference: { hello: ({ name }) => Promise.resolve(`hello: ${name}`) }, 22 | definition: { 23 | serviceName: 'HelloService', 24 | methods: { 25 | hello: { 26 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE, 27 | }, 28 | }, 29 | }, 30 | }, 31 | ], 32 | debug: true, 33 | }); 34 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/rollup.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import pkg from './package.json'; 5 | import commonjs from 'rollup-plugin-commonjs'; 6 | 7 | export default { 8 | input: 'src/index.ts', 9 | output: [ 10 | { 11 | file: pkg.main, 12 | format: 'cjs', 13 | }, 14 | ], 15 | external: ['@scalecube/api', '@scalecube/utils', 'rxjs'], 16 | plugins: [ 17 | commonjs({ 18 | namedExports: { 19 | 'rsocket-types': ['CONNECTION_STATUS'], 20 | }, 21 | }), 22 | typescript({ 23 | typescript: require('typescript'), 24 | clean: true, 25 | }), 26 | visualizer({ 27 | filename: 'report.html', 28 | title: 'rsocket-adapter', 29 | }), 30 | filesize(), 31 | ], 32 | }; 33 | -------------------------------------------------------------------------------- /packages/utils/src/mocks/PostMessageWithTransferPolyfill.ts: -------------------------------------------------------------------------------- 1 | export const applyPostMessagePolyfill = () => { 2 | const addEventListenerQueue: { [key: string]: any[] } = {}; 3 | // @ts-ignore 4 | global.postMessage = (message, targetOrigin, transfer) => { 5 | const onMessageQueue = addEventListenerQueue.message || []; 6 | onMessageQueue.forEach((fn: any) => { 7 | fn({ 8 | ports: transfer, 9 | data: message, 10 | type: 'message', 11 | }); 12 | }); 13 | }; 14 | 15 | const globaladdEventListener = addEventListener; 16 | // @ts-ignore 17 | addEventListener = (type, cb) => { 18 | if (type === 'message') { 19 | const eventQueueByType = [...(addEventListenerQueue[type] || []), cb]; 20 | addEventListenerQueue[type] = eventQueueByType; 21 | } else { 22 | globaladdEventListener(type, cb); 23 | } 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/src/helpers/validation.ts: -------------------------------------------------------------------------------- 1 | import { check } from '@scalecube/utils'; 2 | import { 3 | getInvalidRequestHandler, 4 | REQUEST_STREAM_MUST_BE_FUNCTION, 5 | REQUEST_RESPONSE_MUST_BE_FUNCTION, 6 | SERVICE_CALL_MUST_BE_OBJECT, 7 | } from './constants'; 8 | 9 | export const validateCustomHandlers = (name: string, customHandler: any) => { 10 | if (!check.isDefined(customHandler)) { 11 | return; 12 | } 13 | check.assertFunction(customHandler, getInvalidRequestHandler(name, typeof customHandler)); 14 | }; 15 | 16 | export const validateServiceCall = (serviceCall: any) => { 17 | check.assertObject(serviceCall, SERVICE_CALL_MUST_BE_OBJECT); 18 | const { requestResponse, requestStream } = serviceCall; 19 | check.assertFunction(requestResponse, REQUEST_RESPONSE_MUST_BE_FUNCTION); 20 | check.assertFunction(requestStream, REQUEST_STREAM_MUST_BE_FUNCTION); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scalecube webWorker Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/mocks/microserviceFactory.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | import { createMicroservice, ASYNC_MODEL_TYPES } from '../../src'; 3 | import { transport } from '@scalecube/transport-browser'; 4 | import { joinCluster } from '@scalecube/cluster-browser'; 5 | import { retryRouter } from '@scalecube/routers'; 6 | 7 | export { ASYNC_MODEL_TYPES }; 8 | 9 | export const createMS: MicroserviceApi.CreateMicroservice = (config) => { 10 | return createMicroservice({ 11 | // @ts-ignore 12 | transport, 13 | cluster: joinCluster, 14 | defaultRouter: retryRouter({ period: 10, maxRetry: 50 }), 15 | ...config, 16 | }); 17 | }; 18 | 19 | export const createMSNoRouter: MicroserviceApi.CreateMicroservice = (config) => { 20 | return createMicroservice({ 21 | // @ts-ignore 22 | transport, 23 | cluster: joinCluster, 24 | ...config, 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scalecube webWorker Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample/bubbleSortService.js: -------------------------------------------------------------------------------- 1 | remoteBubbleSortService = { 2 | bubbleSortTime: function(size = 50000) { 3 | return new Promise((resolve, reject) => { 4 | var a = []; 5 | 6 | for (var i = size; i >= 0; i--) { 7 | a.push(i); 8 | } 9 | 10 | function bubbleSort(a) { 11 | var swapped; 12 | do { 13 | swapped = false; 14 | for (var i = 0; i < a.length - 1; i++) { 15 | if (a[i] > a[i + 1]) { 16 | var temp = a[i]; 17 | a[i] = a[i + 1]; 18 | a[i + 1] = temp; 19 | swapped = true; 20 | } 21 | } 22 | } while (swapped); 23 | } 24 | 25 | var start = new Date().getTime(); 26 | bubbleSort(a); 27 | var end = new Date().getTime(); 28 | var time = end - start; 29 | resolve({ time, start, end }); 30 | }); 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /packages/node/rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import commonjs from 'rollup-plugin-commonjs'; 6 | import pkg from './package.json'; 7 | 8 | export default { 9 | input: 'src/index.ts', 10 | output: [ 11 | { 12 | file: pkg.main, 13 | format: 'cjs', 14 | sourcemap: false, 15 | }, 16 | ], 17 | external: ['rxjs'], 18 | plugins: [ 19 | commonjs({ 20 | include: /node_modules/, 21 | namedExports: { 22 | 'rsocket-types': ['CONNECTION_STATUS'], 23 | }, 24 | }), 25 | visualizer({ 26 | filename: 'report.cjs.html', 27 | title: 'Node - cjs', 28 | }), 29 | typescript({ 30 | typescript: tscompile, 31 | clean: true, 32 | }), 33 | filesize(), 34 | ], 35 | }; 36 | -------------------------------------------------------------------------------- /packages/api/src/microservice/Endpoint.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '..'; 2 | import { AsyncModel } from '.'; 3 | 4 | /** 5 | * @interface Endpoint 6 | * Defines remote service data 7 | */ 8 | export interface Endpoint { 9 | /** 10 | * @property 11 | * The combination of serviceName and methodName: 12 | */ 13 | qualifier: string; 14 | /** 15 | * property 16 | * The name of a service, that is provided in serviceDefinition 17 | */ 18 | serviceName: string; 19 | /** 20 | * property 21 | * The name of a method, that is provided in the methods map in serviceDefinition 22 | */ 23 | methodName: string; 24 | /** 25 | * property 26 | * Type of communication between a consumer and a provider 27 | */ 28 | asyncModel: AsyncModel; 29 | /** 30 | * property 31 | * A unique address of an endpoint 32 | * ://:/ 33 | */ 34 | address: Address; 35 | } 36 | -------------------------------------------------------------------------------- /packages/transport-nodejs/src/Provider/ProviderServer.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '@scalecube/api'; 2 | import { validateAddress, constants } from '@scalecube/utils'; 3 | // @ts-ignore 4 | import RSocketWebSocketServer from 'rsocket-websocket-server'; 5 | // @ts-ignore 6 | import RSocketTCPServer from 'rsocket-tcp-server'; 7 | import { ProviderFactory } from '@scalecube/rsocket-adapter'; 8 | 9 | export const serverFactory: ProviderFactory = (options: { address: Address; factoryOptions?: any }) => { 10 | const { address, factoryOptions } = options; 11 | 12 | validateAddress(address); 13 | 14 | const { protocol, host, path, port } = address; 15 | switch (protocol.toLowerCase()) { 16 | case 'ws': 17 | case 'wss': 18 | return new RSocketWebSocketServer({ ...address }); 19 | case 'tcp': 20 | return new RSocketTCPServer({ ...address }); 21 | default: 22 | throw Error(constants.NOT_VALID_PROTOCOL); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /packages/transport-browser/rollup.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import pkg from './package.json'; 5 | import commonjs from 'rollup-plugin-commonjs'; 6 | import resolve from 'rollup-plugin-node-resolve'; 7 | 8 | export default { 9 | input: 'src/index.ts', 10 | output: [ 11 | { 12 | file: pkg.main, 13 | format: 'cjs', 14 | }, 15 | ], 16 | external: ['@scalecube/api', '@scalecube/utils'], 17 | plugins: [ 18 | commonjs({ 19 | namedExports: { 20 | 'rsocket-types': ['CONNECTION_STATUS'], 21 | }, 22 | }), 23 | resolve(), 24 | typescript({ 25 | typescript: require('typescript'), 26 | clean: true, 27 | }), 28 | visualizer({ 29 | filename: 'report.html', 30 | title: 'transport-browser', 31 | }), 32 | filesize(), 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /packages/examples/iife/remoteCallExample/remoteCall.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Scalecube remoteCall Example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /packages/api/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # API 7 | 8 | Define API for Scalecube 9 | 10 | #### common 11 | 12 | [Common](src/common/index.ts) - 13 | All interfaces that are shared between scalecube's different modules 14 | 15 | #### microservice 16 | 17 | [Microservice's interface](src/microservice/index.ts) 18 | 19 | #### discovery 20 | 21 | [Discovery's interface](src/discovery/index.ts) 22 | 23 | #### cluster 24 | 25 | [Cluster's interface](src/cluster/index.ts) 26 | 27 | #### transport 28 | 29 | [Transport's interface](src/transport/index.ts) 30 | -------------------------------------------------------------------------------- /packages/utils/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > **NOTICE** versions 0.0.x are experimental without LTS or the API and behavior might change from patch to patch 4 | 5 | # Scalecube utils 6 | 7 | reusable utils library 8 | 9 | ## address 10 | 11 | #### getFullAddress 12 | 13 | ```gherkin 14 | Given valid address: Address 15 | When calling getFullAddress(address) 16 | Then fullAddress will be added to the address object 17 | ``` 18 | 19 | #### validateAddress 20 | 21 | ```gherkin 22 | Given address: any 23 | And isOptional: boolean 24 | # isOptional = true 25 | When calling validateAddress(address, isOptional) 26 | Then valid address can be undefined or type Address 27 | # isOptional = false 28 | When calling validateAddress(address, isOptional) 29 | Then valid address must be of type Address 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/examples/iife/iframe/index.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('DOMContentLoaded', (event) => { 2 | ((createMicroservice, workers, ASYNC_MODEL_TYPES, definitions) => { 3 | const worker = new Worker('worker1.js'); 4 | 5 | workers.initialize(); 6 | workers.addWorker(worker); 7 | workers.addIframe(document.getElementById('iframe')); 8 | 9 | const proxy = createMicroservice({ 10 | // seedAddress: 'iframe', 11 | address: 'main', 12 | services: [ 13 | { 14 | definition: definitions.remoteServiceDefinition2, 15 | reference: { 16 | ack2: () => Promise.resolve('ack2'), 17 | }, 18 | }, 19 | ], 20 | debug: true, 21 | }).createProxy({ 22 | serviceDefinition: definitions.remoteServiceDefinition1, 23 | }); 24 | 25 | proxy.ack1().then((response) => { 26 | console.log('proxy1', response); 27 | }); 28 | })(window.sc.createMicroservice, window.sc.workers, window.sc.ASYNC_MODEL_TYPES, definitions); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/api", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "lib/index.js", 6 | "module": "lib/index.js", 7 | "types": "lib/index.d.ts", 8 | "files": [ 9 | "lib" 10 | ], 11 | "license": "MIT", 12 | "scripts": { 13 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib", 14 | "build": "rimraf lib && tsc", 15 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 16 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 17 | "coverage": "yarn test-dom-env --coverage --collectCoverageFrom='src/**/*.**' --collectCoverageFrom='!tests/**/*.**'", 18 | "doc": "typedoc ./src --out ./doc --mode file --name 'Scalecube API' --hideGenerator --readme ./README.md" 19 | }, 20 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 21 | "devDependencies": { 22 | "tslint": "^5.11.0", 23 | "typedoc": "^0.14.2", 24 | "typescript": "^3.2.4" 25 | }, 26 | "dependencies": { 27 | "rxjs": "^6.4.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/examples/k8s/helm-scalecube-ex/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: helm-scalecube-ex 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | version: 0.1.0 18 | 19 | # This is the version number of the application being deployed. This version number should be 20 | # incremented each time you make changes to the application. 21 | appVersion: 1.16.0 22 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/tests/integration/destroy.spec.ts: -------------------------------------------------------------------------------- 1 | import { createDiscovery } from '../mockDiscovery'; 2 | import { getAddress } from '@scalecube/utils'; 3 | import { getDiscoverySuccessfullyDestroyedMessage } from '../../src/helpers/constants'; 4 | 5 | describe(`Test discovery destroy`, () => { 6 | test(` 7 | Scenario: Call to destroy method destroys the Discovery 8 | Given discovery A 9 | And discoveredItems$ subscription is opened 10 | When calling destroy 11 | Then discovery A is destroyed 12 | And promise is resolved with message that includes the Discovery address 13 | And discoveredItems$ stream completes 14 | `, () => { 15 | expect.assertions(1); 16 | 17 | const aAddress = getAddress('A'); 18 | 19 | const discovery = createDiscovery({ 20 | address: aAddress, 21 | itemsToPublish: [], 22 | }); 23 | 24 | return expect(discovery.destroy()).resolves.toBe(getDiscoverySuccessfullyDestroyedMessage(aAddress)); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/transport-nodejs/rollup.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import pkg from './package.json'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import global from 'rollup-plugin-node-globals'; 8 | 9 | export default { 10 | input: 'src/index.ts', 11 | output: [ 12 | { 13 | file: pkg.main, 14 | format: 'cjs', 15 | }, 16 | { 17 | file: pkg.module, 18 | format: 'es', 19 | }, 20 | ], 21 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 22 | plugins: [ 23 | resolve(), 24 | commonjs({ include: 'node_modules/**' }), 25 | typescript({ 26 | typescript: require('typescript'), 27 | clean: true, 28 | }), 29 | visualizer({ 30 | filename: 'report.html', 31 | }), 32 | global(), 33 | filesize(), 34 | ], 35 | }; 36 | -------------------------------------------------------------------------------- /packages/examples/iife/iframe/definitions.js: -------------------------------------------------------------------------------- 1 | definitions = (function() { 2 | var remoteServiceDefinition1 = { 3 | serviceName: 'RemoteService1', 4 | methods: { 5 | ack1: { 6 | asyncModel: 'requestResponse', 7 | }, 8 | }, 9 | }; 10 | 11 | var remoteServiceDefinition2 = { 12 | serviceName: 'RemoteService2', 13 | methods: { 14 | ack2: { 15 | asyncModel: 'requestResponse', 16 | }, 17 | }, 18 | }; 19 | 20 | var remoteServiceDefinition3 = { 21 | serviceName: 'RemoteService3', 22 | methods: { 23 | ack3: { 24 | asyncModel: 'requestResponse', 25 | }, 26 | }, 27 | }; 28 | 29 | var remoteServiceDefinition4 = { 30 | serviceName: 'RemoteService4', 31 | methods: { 32 | ack4: { 33 | asyncModel: 'requestResponse', 34 | }, 35 | }, 36 | }; 37 | 38 | return { 39 | remoteServiceDefinition1, 40 | remoteServiceDefinition2, 41 | remoteServiceDefinition3, 42 | remoteServiceDefinition4, 43 | }; 44 | })(); 45 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import visualizer from 'rollup-plugin-visualizer'; 3 | import typescript from 'rollup-plugin-typescript2'; 4 | import tscompile from 'typescript'; 5 | import filesize from 'rollup-plugin-filesize'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | 9 | export default { 10 | input: 'src/index.ts', 11 | output: [ 12 | { 13 | name: 'gateway', 14 | file: pkg.main, 15 | format: 'cjs', 16 | }, 17 | ], 18 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 19 | plugins: [ 20 | babel({ 21 | babelrc: false, 22 | exclude: 'node_modules/**', 23 | runtimeHelpers: true, 24 | }), 25 | commonjs({ include: 'node_modules/**' }), 26 | visualizer({ 27 | filename: 'report.html', 28 | }), 29 | typescript({ 30 | typescript: tscompile, 31 | clean: true, 32 | }), 33 | 34 | filesize(), 35 | ], 36 | }; 37 | -------------------------------------------------------------------------------- /packages/routers/src/Retry/retry.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | 3 | export const retryRouter = ({ period, maxRetry }: { period: number; maxRetry?: number }) => { 4 | return (options: MicroserviceApi.RouterOptions) => { 5 | const { message, lookUp } = options; 6 | const { qualifier } = message; 7 | let retry = 0; 8 | return new Promise((resolve, reject) => { 9 | const checkRegistry = () => { 10 | const endpoints = lookUp({ qualifier }); 11 | if (!(endpoints && Array.isArray(endpoints) && endpoints.length > 0)) { 12 | if (maxRetry && maxRetry >= retry) { 13 | retry++; 14 | } 15 | 16 | if (!maxRetry || maxRetry >= retry) { 17 | setTimeout(() => { 18 | checkRegistry(); 19 | }, period); 20 | } else { 21 | reject(null); 22 | } 23 | } else { 24 | resolve(endpoints[0]); 25 | } 26 | }; 27 | 28 | checkRegistry(); 29 | }); 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/examples/iife/distributedEnvironmentExample/worker2.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/browser/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | importScripts('./reactiveStream.js'); 4 | onmessage = (ev) => { 5 | const { data } = ev; 6 | if (data.type === 'start') { 7 | switch (data.detail) { 8 | case 'ms5': 9 | sc.createMicroservice({ 10 | services: [ 11 | { 12 | reference: reactiveStreamExample, 13 | definition: definitions.remoteServiceDefinition5, 14 | }, 15 | ], 16 | address: 'ms5', 17 | seedAddress: 'ms4', 18 | }); 19 | break; 20 | case 'ms2': 21 | sc.createMicroservice({ 22 | services: [ 23 | { 24 | reference: reactiveStreamExample, 25 | definition: definitions.remoteServiceDefinition2, 26 | }, 27 | ], 28 | address: 'ms2', 29 | seedAddress: 'ms1', 30 | }); 31 | break; 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample2/worker2.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/browser/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | importScripts('./reactiveStream.js'); 4 | 5 | const ms = sc.createMicroservice({ 6 | services: [ 7 | { 8 | reference: reactiveStreamExample, 9 | definition: definitions.remoteServiceDefinition2, 10 | }, 11 | ], 12 | address: 'ms2', 13 | seedAddress: 'ms1', 14 | }); 15 | 16 | const proxyName = ms.createProxy({ serviceDefinition: definitions.remoteServiceDefinition }); 17 | const proxyName3 = ms.createProxy({ serviceDefinition: definitions.remoteServiceDefinition3 }); 18 | 19 | proxyName.getInterval(7000).subscribe( 20 | (res) => console.log(`webworker 2 - awaitProxyName resolve every 7000 ms: ${res}`), 21 | (error) => console.log(error.message) 22 | ); 23 | 24 | proxyName3.getInterval(5000).subscribe( 25 | (res) => console.log(`webworker 2 - awaitProxyName3 resolve every 5000 ms: ${res}`), 26 | (error) => console.log(error.message) 27 | ); 28 | 29 | setTimeout(() => { 30 | ms.destroy(); 31 | }, 60 * 0.5 * 1000); 32 | -------------------------------------------------------------------------------- /packages/routers/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # Index 7 | 8 | Index is responsible for picking the right Item from a Item\[]. 9 | 10 | #### Default 11 | 12 | Pick the first available item. 13 | This is very good option for monolith (When all the services are one the same microservice instance) applications built with scalecube 14 | 15 | #### RetryRouter 16 | 17 | Pick the first available item, Retry if service not found 18 | `period`- interval between retry, `maxRetry`- how much retries before giving up 19 | This is the prefer behavior for browsers 20 | 21 | #### RoundRobin 22 | 23 | Pick the next item from a list of available items. 24 | This is very common router for servers 25 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/Microservices/Destroy.ts: -------------------------------------------------------------------------------- 1 | import { Destroy } from '../helpers/types'; 2 | import { MICROSERVICE_NOT_EXISTS } from '../helpers/constants'; 3 | import { loggerUtil } from '../helpers/logger'; 4 | 5 | export const destroy = (options: Destroy) => { 6 | const { discovery, serverStop, transportClientDestroy } = options; 7 | let { microserviceContext } = options; 8 | 9 | if (!microserviceContext) { 10 | throw new Error(MICROSERVICE_NOT_EXISTS); 11 | } 12 | const logger = loggerUtil(microserviceContext.whoAmI, microserviceContext.debug); 13 | 14 | return new Promise((resolve, reject) => { 15 | if (microserviceContext) { 16 | const { localRegistry, remoteRegistry } = microserviceContext; 17 | localRegistry.destroy(); 18 | remoteRegistry.destroy(); 19 | transportClientDestroy({ address: microserviceContext.whoAmI, logger }); 20 | } 21 | 22 | serverStop && serverStop(); 23 | 24 | discovery && 25 | discovery.destroy().then(() => { 26 | resolve(''); 27 | microserviceContext = null; 28 | }); 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /packages/utils/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as check from './check'; 2 | import { getFullAddress, validateAddress, getAddress } from './address'; 3 | import * as constants from './constants'; 4 | import { addWorker, removeWorker, initialize, addIframe } from './connectWorkers'; 5 | import { saveToLogs } from './logs'; 6 | import { isNodejs } from './checkEnvironemnt'; 7 | import { validateServiceDefinition } from './serviceDefinition'; 8 | import { getQualifier } from './qualifier'; 9 | import { applyPostMessagePolyfill } from './mocks/PostMessageWithTransferPolyfill'; 10 | import { applyMessageChannelPolyfill } from './mocks/MessageChannelPolyfill'; 11 | 12 | const workers = !isNodejs() ? { addWorker, removeWorker, initialize, addIframe } : {}; 13 | 14 | const mockMessageChannel = () => { 15 | applyPostMessagePolyfill(); 16 | applyMessageChannelPolyfill(); 17 | }; 18 | 19 | export { 20 | check, 21 | getFullAddress, 22 | validateAddress, 23 | constants, 24 | getAddress, 25 | workers, 26 | saveToLogs, 27 | isNodejs, 28 | validateServiceDefinition, 29 | getQualifier, 30 | mockMessageChannel, 31 | }; 32 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | import replace from 'rollup-plugin-replace'; 9 | 10 | export default { 11 | input: 'src/index.ts', 12 | output: [ 13 | { 14 | file: pkg.main, 15 | format: 'cjs', 16 | sourcemap: false, 17 | }, 18 | ], 19 | external: ['rxjs'], 20 | plugins: [ 21 | resolve({ jsnext: true, main: true }), 22 | commonjs({ 23 | include: /node_modules/, 24 | }), 25 | replace({ 26 | 'process.env.NODE_ENV': JSON.stringify('production'), 27 | }), 28 | visualizer({ 29 | filename: 'report.cjs.html', 30 | title: 'Microservice - cjs', 31 | }), 32 | typescript({ 33 | typescript: tscompile, 34 | clean: true, 35 | }), 36 | // global(), 37 | filesize(), 38 | ], 39 | }; 40 | -------------------------------------------------------------------------------- /packages/transport-browser/src/index.ts: -------------------------------------------------------------------------------- 1 | import { TransportApi } from '@scalecube/api'; 2 | import { ClientTransportOptions, Invoker } from '@scalecube/api/lib/transport'; 3 | import { createClient, createServer } from './connection'; 4 | import { getFullAddress } from '@scalecube/utils'; 5 | 6 | function createTransport() { 7 | const client = createClient(); 8 | 9 | return { 10 | clientTransport: { 11 | start: (options: ClientTransportOptions): Promise => { 12 | return Promise.resolve({ 13 | requestResponse: (message) => client.requestResponse(getFullAddress(options.remoteAddress), message), 14 | requestStream: (message) => client.requestStream(getFullAddress(options.remoteAddress), message), 15 | }); 16 | }, 17 | destroy: (options) => { 18 | client.shutdown(options.address); 19 | }, 20 | }, 21 | serverTransport: (options) => { 22 | return createServer(getFullAddress(options.localAddress), options.serviceCall); 23 | }, 24 | } as TransportApi.Transport; 25 | } 26 | 27 | export const transport: TransportApi.Transport = createTransport(); 28 | -------------------------------------------------------------------------------- /packages/routers/tests/defaul.spec.ts: -------------------------------------------------------------------------------- 1 | import { defaultRouter } from '../src'; 2 | import { MicroserviceApi } from '@scalecube/api'; 3 | import { getAddress } from '@scalecube/utils'; 4 | 5 | const qualifier = 'serviceName/methodName'; 6 | 7 | const registry = [0, 1, 2, 3, 4, 5, 6, 7].map((v) => ({ address: getAddress(`${v}`) })); 8 | 9 | const lookUp = () => { 10 | return registry; 11 | }; 12 | 13 | test(`Given Endpoint[] 14 | And a message:Message 15 | When call defaultRouter(message) 16 | Then defaultRouter will retrieve the same Endpoint`, // @ts-ignore 17 | async () => { 18 | expect.assertions(2); 19 | 20 | // @ts-ignore 21 | const endpont1: MicroserviceApi.Endpoint = await defaultRouter({ message: { qualifier, data: [] }, lookUp }); 22 | // @ts-ignore 23 | const endpont2: MicroserviceApi.Endpoint = await defaultRouter({ message: { qualifier, data: [] }, lookUp }); 24 | // @ts-ignore 25 | const endpont3: MicroserviceApi.Endpoint = await defaultRouter({ message: { qualifier, data: [] }, lookUp }); 26 | 27 | expect(endpont1).toMatchObject(endpont2); 28 | expect(endpont1).toMatchObject(endpont3); 29 | }); 30 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import visualizer from 'rollup-plugin-visualizer'; 3 | import typescript from 'rollup-plugin-typescript2'; 4 | import tscompile from 'typescript'; 5 | import filesize from 'rollup-plugin-filesize'; 6 | import resolve from 'rollup-plugin-node-resolve'; 7 | import commonjs from 'rollup-plugin-commonjs'; 8 | import pkg from './package.json'; 9 | 10 | export default { 11 | input: 'src/index.ts', 12 | output: [ 13 | { 14 | file: pkg.main, 15 | format: 'cjs', 16 | }, 17 | ], 18 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 19 | plugins: [ 20 | babel({ 21 | babelrc: false, 22 | exclude: 'node_modules/**', 23 | runtimeHelpers: true, 24 | }), 25 | resolve(), 26 | commonjs({ include: 'node_modules/**' }), 27 | visualizer({ 28 | filename: 'report.cjs.html', 29 | title: 'Discovery - cjs', 30 | }), 31 | typescript({ 32 | typescript: tscompile, 33 | clean: true, 34 | }), 35 | 36 | filesize(), 37 | ], 38 | }; 39 | -------------------------------------------------------------------------------- /packages/examples/bundles/src/service/GreetingService.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { ASYNC_MODEL_TYPES } from '@scalecube/browser'; 3 | 4 | export default class GreetingService { 5 | public hello(name: string): Promise { 6 | return new Promise((resolve, reject) => { 7 | if (!name) { 8 | reject(new Error('please provide user to greet')); 9 | } else { 10 | resolve(`Hello ${name}`); 11 | } 12 | }); 13 | } 14 | 15 | public greet$(greetings: string[]): Observable { 16 | return new Observable((observer) => { 17 | if (!greetings || !Array.isArray(greetings) || greetings.length === 0) { 18 | observer.error(new Error('please provide Array of greetings')); 19 | } 20 | greetings.map((i) => observer.next(`greetings ${i}`)); 21 | }); 22 | } 23 | } 24 | 25 | export const greetingServiceDefinition = { 26 | serviceName: 'GreetingService', 27 | methods: { 28 | hello: { 29 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE, 30 | }, 31 | greet$: { 32 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_STREAM, 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /packages/routers/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/routers", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "cjs/index.js", 6 | "module": "es/index.js", 7 | "types": "cjs/index.d.ts", 8 | "files": [ 9 | "cjs", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf cjs && rimraf es", 15 | "build": "yarn build-rollup && tsc", 16 | "build-rollup": "rollup -c", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js" 20 | }, 21 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 22 | "devDependencies": { 23 | "jest": "^24.6.0", 24 | "rollup": "^1.14.6", 25 | "rollup-plugin-filesize": "^6.1.1", 26 | "rollup-plugin-typescript2": "^0.21.1", 27 | "rollup-plugin-visualizer": "^2.2.0", 28 | "ts-jest": "^24.2.0", 29 | "tslint": "^5.11.0", 30 | "typescript": "^3.2.4" 31 | }, 32 | "dependencies": { 33 | "@scalecube/api": "0.2.11", 34 | "@scalecube/utils": "0.2.11" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/transport-browser/tests/transport.spec.ts: -------------------------------------------------------------------------------- 1 | import { transport } from '../src'; 2 | import { getAddress } from '@scalecube/utils'; 3 | import { from } from 'rxjs'; 4 | import { transportSpec } from '../../api/src/transport/tests/transport.spec'; 5 | 6 | describe('transport', () => { 7 | transportSpec(transport); 8 | 9 | it('should request respond and request stream', async (done) => { 10 | transport.serverTransport({ 11 | localAddress: getAddress('server'), 12 | serviceCall: { 13 | requestResponse: (_) => Promise.resolve('promise'), 14 | requestStream: (_) => from(['obs']), 15 | }, 16 | logger: (_) => {}, 17 | }); 18 | const client1 = await transport.clientTransport.start({ 19 | remoteAddress: getAddress('server'), 20 | logger: (_) => {}, 21 | }); 22 | await transport.clientTransport.start({ 23 | remoteAddress: getAddress('server'), 24 | logger: (_) => {}, 25 | }); 26 | 27 | await client1.requestResponse({ data: ['hello'], qualifier: 'hello' }); 28 | client1.requestStream({ data: ['hello'], qualifier: 'hello' }).subscribe(() => { 29 | done(); 30 | }); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /packages/cluster-browser/tests/cluster.spec.ts: -------------------------------------------------------------------------------- 1 | import { clusterSpec } from '../../api/src/cluster/tests/cluster.spec'; 2 | import { joinCluster } from '../src'; 3 | import { getAddress } from '@scalecube/utils'; 4 | 5 | describe('behavior', () => { 6 | test('ClusterA join C then B join C', (done) => { 7 | joinCluster({ 8 | address: getAddress('SEED'), 9 | itemsToPublish: ['SEED'], 10 | }); 11 | 12 | joinCluster({ 13 | address: getAddress('B'), 14 | itemsToPublish: [], 15 | seedAddress: [getAddress('SEED')], 16 | }); 17 | 18 | setTimeout(() => { 19 | const clusterC = joinCluster({ 20 | itemsToPublish: [], 21 | address: getAddress('C'), 22 | seedAddress: [getAddress('SEED')], 23 | }); 24 | setTimeout(() => { 25 | clusterC.getCurrentMembersData().then((items) => { 26 | expect(items).toEqual({ 27 | 'pm://defaultHost:8080/SEED': ['SEED'], 28 | 'pm://defaultHost:8080/B': [], 29 | 'pm://defaultHost:8080/C': [], 30 | }); 31 | done(); 32 | }); 33 | }, 100); 34 | }, 100); 35 | }); 36 | clusterSpec(joinCluster); 37 | }); 38 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | types: [opened, synchronize, reopened] 5 | branches: 6 | - '**' 7 | paths: 8 | - '**' 9 | push: 10 | branches: 11 | - 'develop' 12 | paths: 13 | - '**' 14 | jobs: 15 | ci: 16 | runs-on: ubuntu-latest 17 | strategy: 18 | matrix: 19 | node: [10, 12, 14] 20 | timeout-minutes: 30 21 | name: CI 22 | steps: 23 | - uses: actions/setup-node@v2 24 | with: 25 | # The Node.js version to configure 26 | node-version: ${{ matrix.node }} 27 | - uses: actions/checkout@v2 28 | - name: NPM TOKEN 29 | run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 30 | - name: install 31 | run: yarn 32 | - name: build 33 | run: yarn build 34 | - name: lint 35 | run: yarn lint 36 | - name: test 37 | run: yarn test 38 | - name: doc 39 | if: ${{ matrix.node == 16 }} 40 | run: yarn doc 41 | - name: publish npm 42 | if: ${{ matrix.node == 16 }} 43 | run: bash scripts/publish.sh 44 | env: 45 | SHA: ${{ github.event.after }} 46 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Describe the bug 11 | 12 | A clear and concise description of the bug. 13 | 14 | ## Reproduce 15 | 16 | #### Expected behavior 17 | 18 | Test case in _**[Gherkin Syntax](https://docs.cucumber.io/gherkin/reference/)**_ or the link to this test case. 19 | ```gherkin 20 | Given A great package 21 | When I install it 22 | Then I don't find any bug 23 | ``` 24 | 25 | #### Actual behavior 26 | 27 | How the test case failed. 28 | 29 | #### Code 30 | 31 | Sandbox, snippet, repository etc.. 32 | 33 | ## Additional information 34 | 35 | #### Frequency 36 | 37 | 100% reproduce / happens occasionally / hard to reproduce 38 | 39 | #### Attachments 40 | 41 | Screenshots, videos, documents, log etc. 42 | 43 | #### Environment 44 | 45 | | Software | Version(s) | 46 | | ---------------- | ---------- | 47 | | Node | | 48 | | npm/Yarn | | 49 | | Operating System | | 50 | | Browser | | 51 | 52 | #### Additional context 53 | 54 | Add any other context about the problem here. 55 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | import visualizer from 'rollup-plugin-visualizer'; 3 | import typescript from 'rollup-plugin-typescript2'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import global from 'rollup-plugin-node-globals'; 8 | import pkg from './package.json'; 9 | 10 | export default { 11 | input: 'src/index.ts', 12 | output: [ 13 | { 14 | file: pkg.main, 15 | format: 'cjs', 16 | }, 17 | { 18 | file: pkg.module, 19 | format: 'es', 20 | }, 21 | ], 22 | external: [...Object.keys(pkg.dependencies || {}), ...Object.keys(pkg.peerDependencies || {})], 23 | plugins: [ 24 | babel({ 25 | babelrc: false, 26 | exclude: 'node_modules/**', 27 | runtimeHelpers: true, 28 | }), 29 | resolve(), 30 | commonjs({ include: 'node_modules/**' }), 31 | typescript({ 32 | typescript: require('typescript'), 33 | clean: true, 34 | }), 35 | visualizer({ 36 | filename: 'report.html', 37 | title: 'Cluster-nodeJS', 38 | }), 39 | global(), 40 | filesize(), 41 | ], 42 | }; 43 | -------------------------------------------------------------------------------- /packages/examples/k8s/helm-scalecube-ex/templates/consumer-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | 4 | metadata: 5 | name: consumer 6 | labels: 7 | name: http-consumer 8 | spec: 9 | restartPolicy: Never 10 | containers: 11 | - name: consumer 12 | image: {{$.Values.image.name}} 13 | imagePullPolicy: {{$.Values.image.pullPolicy}} 14 | command: ['/bin/sh', '-c'] 15 | args: 16 | - 'until getent hosts seed.seed; do sleep 1; done; until node consumer.js; do sleep 1; done;' 17 | env: 18 | - name: NAMESPACE 19 | valueFrom: 20 | fieldRef: 21 | fieldPath: metadata.namespace 22 | - name: SEED 23 | value: seed.seed 24 | - name: ADDRESS 25 | valueFrom: 26 | fieldRef: 27 | fieldPath: status.podIP 28 | ports: 29 | - containerPort: 8080 30 | - containerPort: 80 31 | --- 32 | apiVersion: v1 33 | kind: Service 34 | metadata: 35 | name: http-consumer 36 | labels: 37 | name: http-consumer 38 | spec: 39 | type: NodePort 40 | selector: 41 | name: http-consumer 42 | ports: 43 | - port: 80 44 | targetPort: 80 45 | protocol: TCP 46 | name: http 47 | nodePort: 30080 48 | -------------------------------------------------------------------------------- /packages/cluster-browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/cluster-browser", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "cjs/index.js", 6 | "module": "es/index.js", 7 | "types": "cjs/index.d.ts", 8 | "files": [ 9 | "cjs", 10 | "es", 11 | "src" 12 | ], 13 | "license": "MIT", 14 | "scripts": { 15 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf es", 16 | "build": "yarn build-rollup && tsc", 17 | "build-rollup": "rollup -c", 18 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 19 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 20 | "test": "jest --config jest.config.js" 21 | }, 22 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 23 | "devDependencies": { 24 | "jest": "^24.6.0", 25 | "rollup": "^1.14.6", 26 | "rollup-plugin-filesize": "^6.1.1", 27 | "rollup-plugin-typescript2": "^0.21.1", 28 | "rollup-plugin-visualizer": "^2.2.0", 29 | "ts-jest": "^24.2.0", 30 | "tslint": "^5.11.0", 31 | "typescript": "^3.2.4" 32 | }, 33 | "dependencies": { 34 | "@scalecube/addressable": "0.2.11", 35 | "@scalecube/api": "0.2.11", 36 | "@scalecube/utils": "0.2.11", 37 | "rxjs": "^6.4.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/utils/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/utils", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "cjs/index.js", 6 | "module": "es/index.js", 7 | "types": "cjs/index.d.ts", 8 | "files": [ 9 | "cjs", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib", 15 | "build": "yarn build-rollup && tsc", 16 | "build-rollup": "rollup -c", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js", 20 | "coverage": "yarn test-dom-env --coverage --collectCoverageFrom='src/**/*.**' --collectCoverageFrom='!tests/**/*.**'" 21 | }, 22 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 23 | "dependencies": { 24 | "@scalecube/api": "0.2.11" 25 | }, 26 | "devDependencies": { 27 | "jest": "^24.6.0", 28 | "rollup": "^1.14.6", 29 | "rollup-plugin-filesize": "^6.1.1", 30 | "rollup-plugin-typescript2": "^0.21.1", 31 | "rollup-plugin-visualizer": "^2.2.0", 32 | "ts-jest": "^24.2.0", 33 | "tslint": "^5.11.0", 34 | "typedoc": "^0.14.2", 35 | "typescript": "^3.2.4" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/utils/src/logs.ts: -------------------------------------------------------------------------------- 1 | const colorsMap: { [key: string]: string } = {}; 2 | 3 | const getRandomColor = () => { 4 | const letters = '0123456789ABCDEF'; 5 | let color = '#'; 6 | for (let i = 0; i < 6; i++) { 7 | color += letters[Math.floor(Math.random() * 16)]; 8 | } 9 | return color; 10 | }; 11 | 12 | export const saveToLogs = ( 13 | identifier: string, 14 | msg: string, 15 | extra: { [key: string]: any }, 16 | debug?: boolean, 17 | type: 'log' | 'warn' = 'log' 18 | ) => { 19 | if (!colorsMap[identifier]) { 20 | colorsMap[identifier] = getRandomColor(); 21 | } 22 | 23 | // tslint:disable 24 | if (debug) { 25 | const logColor = `color:${colorsMap[identifier]}`; 26 | extra && console[type](`%c******** address: ${identifier}********`, logColor); 27 | console[type](msg); 28 | extra && 29 | Object.keys(extra).forEach((key: string) => { 30 | if (Array.isArray(extra[key])) { 31 | Object.values(extra[key]).forEach((props: any) => { 32 | console[type](`${key}: ${JSON.stringify(props.qualifier || props, null, 2)}`); 33 | }); 34 | } else { 35 | console[type](`${key}: ${JSON.stringify(extra[key], null, 2)}`); 36 | } 37 | }); 38 | } 39 | // tslint:enable 40 | }; 41 | -------------------------------------------------------------------------------- /packages/addressable/tests/e2e.browser.ts: -------------------------------------------------------------------------------- 1 | describe(`Scenario Outline: multiple threads ping pong`, () => { 2 | const examples = [ 3 | { thread: 'main', address: 'main' }, 4 | { thread: 'main', address: 'iframe' }, 5 | { thread: 'main', address: 'worker' }, 6 | { thread: 'iframe', address: 'main' }, 7 | { thread: 'iframe', address: 'iframe' }, 8 | { thread: 'iframe', address: 'worker' }, 9 | { thread: 'worker', address: 'main' }, 10 | { thread: 'worker', address: 'iframe' }, 11 | { thread: 'worker', address: 'worker' }, 12 | ]; 13 | const pongs = []; 14 | beforeAll(async () => { 15 | page.on('console', (msg) => { 16 | pongs.push(msg.text()); 17 | }); 18 | page.goto('http://localhost:8000/packages/addressable/tests/fixtures/pingPong/'); 19 | }); 20 | 21 | examples.forEach((example) => { 22 | test(`Given port from connect(${example.address}) inside ${example.thread} 23 | When port.postmessage('ping') 24 | Then port should receive pong`, async (done) => { 25 | const val = setInterval(() => { 26 | if (pongs.includes(`${example.thread} got pong from ${example.address}`)) { 27 | clearInterval(val); 28 | done(); 29 | } 30 | }, 0); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /packages/examples/iife/distributedEnvironmentExample/definitions.js: -------------------------------------------------------------------------------- 1 | definitions = (function() { 2 | var remoteServiceDefinition1 = { 3 | serviceName: 'RemoteService1', 4 | methods: { 5 | getInterval: { 6 | asyncModel: 'requestStream', 7 | }, 8 | }, 9 | }; 10 | 11 | var remoteServiceDefinition2 = { 12 | serviceName: 'RemoteService2', 13 | methods: { 14 | getInterval: { 15 | asyncModel: 'requestStream', 16 | }, 17 | }, 18 | }; 19 | 20 | var remoteServiceDefinition3 = { 21 | serviceName: 'RemoteService3', 22 | methods: { 23 | getInterval: { 24 | asyncModel: 'requestStream', 25 | }, 26 | }, 27 | }; 28 | 29 | var remoteServiceDefinition4 = { 30 | serviceName: 'RemoteService4', 31 | methods: { 32 | getInterval: { 33 | asyncModel: 'requestStream', 34 | }, 35 | }, 36 | }; 37 | 38 | var remoteServiceDefinition5 = { 39 | serviceName: 'RemoteService5', 40 | methods: { 41 | getInterval: { 42 | asyncModel: 'requestStream', 43 | }, 44 | }, 45 | }; 46 | return { 47 | remoteServiceDefinition1, 48 | remoteServiceDefinition2, 49 | remoteServiceDefinition3, 50 | remoteServiceDefinition4, 51 | remoteServiceDefinition5, 52 | }; 53 | })(); 54 | -------------------------------------------------------------------------------- /packages/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/node", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "files": [ 8 | "lib" 9 | ], 10 | "license": "MIT", 11 | "scripts": { 12 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib", 13 | "build": "rimraf .cache && yarn build:cjs", 14 | "build:cjs": "rimraf lib && rollup -c rollup.cjs.config.js", 15 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 16 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 17 | "test": "echo \"no tests\"" 18 | }, 19 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 20 | "devDependencies": { 21 | "rollup": "^1.27.4", 22 | "rollup-plugin-babel": "^4.3.3", 23 | "rollup-plugin-filesize": "^6.1.1", 24 | "rollup-plugin-typescript2": "^0.21.1", 25 | "rollup-plugin-visualizer": "^2.6.0", 26 | "tslint": "^5.11.0", 27 | "typescript": "^3.2.4" 28 | }, 29 | "dependencies": { 30 | "@scalecube/api": "0.2.11", 31 | "@scalecube/cluster-nodejs": "0.2.11", 32 | "@scalecube/routers": "0.2.11", 33 | "@scalecube/scalecube-microservice": "0.2.11", 34 | "@scalecube/transport-nodejs": "0.2.11", 35 | "@scalecube/utils": "0.2.11", 36 | "rxjs": "^6.4.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # Discovery 7 | 8 | This package provides a default discovery implementation. 9 | it is intended to publish and discover any data in a distributed environment. 10 | 11 | ## Basic Usage 12 | 13 | ```javascript 14 | import { createDiscovery } from '@scalecube/scalecube-discovery'; 15 | 16 | const discoveryConfig = { 17 | seedAddress, 18 | address, 19 | itemsToPublish: [], 20 | }; 21 | 22 | const discovery = createDiscovery(discoveryConfig); 23 | 24 | // on subscribe to `discoveredItems$()`, we will start getting emits of the distributed environment's latest state. 25 | discovery.discoveredItems$().subscribe(console.log); 26 | 27 | 28 | // on calling `destroy()`, we will remove our metadata from the distributed environment. 29 | // also, it stops the discovery from sharing/publishing metadata. 30 | discovery.destroy().then(console.log); 31 | ``` 32 | -------------------------------------------------------------------------------- /packages/examples/bundles/src/index.ts: -------------------------------------------------------------------------------- 1 | import { createMicroservice } from '@scalecube/browser'; 2 | import { MicroserviceApi } from '@scalecube/api'; 3 | import GreetingService, { greetingServiceDefinition } from './service/GreetingService'; 4 | 5 | const reference: MicroserviceApi.ServiceReference = new GreetingService(); 6 | 7 | const greetingService: MicroserviceApi.Service = { 8 | definition: greetingServiceDefinition, 9 | reference, 10 | }; 11 | 12 | const ms = createMicroservice({ address: 'localMS', seedAddress: 'seed', debug: true }); 13 | 14 | const proxy = ms.createProxy({ 15 | serviceDefinition: greetingServiceDefinition, 16 | }); 17 | 18 | const resultEl = document.getElementById('result'); 19 | 20 | proxy.hello('User').then((result: string) => { 21 | const div = document.createElement('div'); 22 | div.innerHTML = result; 23 | // @ts-ignore 24 | resultEl.appendChild(div); 25 | console.info('result from greeting service - hello', result); 26 | }); 27 | 28 | proxy.greet$(['User1', 'User2', 'User3']).subscribe((result: string) => { 29 | const div = document.createElement('div'); 30 | div.innerHTML = result; 31 | // @ts-ignore 32 | resultEl.appendChild(div); 33 | console.info('result from greeting service - greet$', result); 34 | }); 35 | 36 | createMicroservice({ services: [greetingService], address: 'seed', debug: true }); 37 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/rsocket-adapter", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "cjs/index.js", 6 | "module": "es/index.js", 7 | "types": "cjs/index.d.ts", 8 | "files": [ 9 | "cjs", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf es", 15 | "build": "yarn build-rollup && tsc", 16 | "build-rollup": "rollup -c", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js" 20 | }, 21 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 22 | "devDependencies": { 23 | "jest": "^24.6.0", 24 | "rollup": "^1.14.6", 25 | "rollup-plugin-commonjs": "^10.0.1", 26 | "rollup-plugin-filesize": "^6.1.1", 27 | "rollup-plugin-typescript2": "^0.21.1", 28 | "rollup-plugin-visualizer": "^2.2.0", 29 | "ts-jest": "^24.2.0", 30 | "tslint": "^5.11.0", 31 | "typescript": "^3.2.4" 32 | }, 33 | "dependencies": { 34 | "@scalecube/api": "^0.2.11", 35 | "@scalecube/utils": "^0.2.11", 36 | "rsocket-core": "^0.0.16", 37 | "rsocket-flowable": "^0.0.14", 38 | "rsocket-types": "^0.0.16", 39 | "rxjs": "^6.4.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/Proxy/Proxy.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | import { GetProxyOptions } from '../helpers/types'; 3 | import { getQualifier } from '@scalecube/utils'; 4 | import { getServiceMethodIsMissingError, NO_PROXY_SUPPORT } from '../helpers/constants'; 5 | 6 | export const getProxy = ({ serviceCall, serviceDefinition }: GetProxyOptions) => { 7 | // workaround to support old browsers 8 | const obj: { [key: string]: any } = {}; 9 | Object.keys(serviceDefinition.methods).forEach( 10 | (key: string) => 11 | (obj[key] = () => { 12 | throw Error(NO_PROXY_SUPPORT); 13 | }) 14 | ); 15 | return new Proxy(obj, { 16 | get: preServiceCall({ serviceDefinition, serviceCall }), 17 | }); 18 | }; 19 | 20 | const preServiceCall = ({ serviceCall, serviceDefinition }: GetProxyOptions) => (target: object, prop: string) => { 21 | if (!serviceDefinition.methods[prop]) { 22 | throw new Error(getServiceMethodIsMissingError(prop)); 23 | } 24 | 25 | const { asyncModel } = serviceDefinition.methods[prop]; 26 | 27 | return (...data: any[]) => { 28 | const message: MicroserviceApi.Message = { 29 | qualifier: getQualifier({ serviceName: serviceDefinition.serviceName, methodName: prop }), 30 | data, 31 | }; 32 | return serviceCall({ message, asyncModel }); 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /packages/transport-nodejs/src/Provider/ProviderClient.ts: -------------------------------------------------------------------------------- 1 | import { validateAddress, constants } from '@scalecube/utils'; 2 | import { Address } from '@scalecube/api'; 3 | import { ProviderFactory } from '@scalecube/rsocket-adapter'; 4 | // @ts-ignore 5 | import RSocketWebSocketClient from 'rsocket-websocket-client'; 6 | // @ts-ignore 7 | import RSocketTcpClient from 'rsocket-tcp-client'; 8 | // @ts-ignore 9 | import WebSocket from 'ws'; 10 | 11 | export const clientFactory: ProviderFactory = (options: { address: Address; factoryOptions?: any }) => { 12 | const { address, factoryOptions } = options; 13 | 14 | validateAddress(address); 15 | 16 | const { protocol } = address; 17 | switch (protocol.toLowerCase()) { 18 | case 'ws': 19 | return new RSocketWebSocketClient({ 20 | url: 'ws://' + address.host + ':' + address.port, 21 | wsCreator: (url: string) => { 22 | return new WebSocket(url); 23 | }, 24 | }); 25 | case 'wss': 26 | return new RSocketWebSocketClient({ 27 | url: 'wss://' + address.host + ':' + address.port, 28 | wsCreator: (url: string) => { 29 | return new WebSocket(url); 30 | }, 31 | }); 32 | case 'tcp': 33 | return new RSocketTcpClient({ ...address }); 34 | default: 35 | throw Error(constants.NOT_VALID_PROTOCOL); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /packages/api/src/microservice/CreateServiceCall.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { Message, Router } from '.'; 3 | 4 | /** 5 | * @function CreateServiceCall 6 | */ 7 | export type CreateServiceCall = (options: CreateServiceCallOptions) => ServiceCall; 8 | 9 | /** 10 | * @interface CreateServiceCallOptions 11 | * Options for the creation of Service Call 12 | */ 13 | export default interface CreateServiceCallOptions { 14 | /** 15 | * @method 16 | * Custom router specifies the logic of choosing the appropriate remoteService 17 | */ 18 | router?: Router; 19 | } 20 | 21 | /** 22 | * @interface ServiceCall 23 | * Provides an ability to run the method from a microservice container for a specific async model 24 | */ 25 | export interface ServiceCall { 26 | /** 27 | * @method 28 | * A method using which a consumer requires a stream and receives an Observable sequence describing updates of 29 | * the method and qualifier that was used for the invocation 30 | */ 31 | requestStream: (message: Message) => Observable; 32 | /** 33 | * @method 34 | * A method using which a consumer requires data and a provider responds with the data once in the form of 35 | * promise, that includes the response from the method and qualifier that was used for the invocation 36 | */ 37 | requestResponse: (message: Message) => Promise; 38 | } 39 | -------------------------------------------------------------------------------- /packages/examples/iife/distributedEnvironmentExample/worker1.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/browser/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | importScripts('./reactiveStream.js'); 4 | 5 | onmessage = (ev) => { 6 | const { data } = ev; 7 | if (data.type === 'start') { 8 | switch (data.detail) { 9 | case 'ms1': 10 | sc.createMicroservice({ 11 | services: [ 12 | { 13 | reference: reactiveStreamExample, 14 | definition: definitions.remoteServiceDefinition1, 15 | }, 16 | ], 17 | address: 'ms1', 18 | }); 19 | break; 20 | case 'ms3': 21 | sc.createMicroservice({ 22 | services: [ 23 | { 24 | reference: reactiveStreamExample, 25 | definition: definitions.remoteServiceDefinition3, 26 | }, 27 | ], 28 | address: 'ms3', 29 | seedAddress: 'ms1', 30 | }); 31 | break; 32 | case 'ms4': 33 | sc.createMicroservice({ 34 | services: [ 35 | { 36 | reference: reactiveStreamExample, 37 | definition: definitions.remoteServiceDefinition4, 38 | }, 39 | ], 40 | address: 'ms4', 41 | seedAddress: 'ms2', 42 | }); 43 | break; 44 | } 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/Server/createServer.ts: -------------------------------------------------------------------------------- 1 | import { Address, TransportApi } from '@scalecube/api'; 2 | // @ts-ignore 3 | import RSocketServer from 'rsocket-core/build/RSocketServer'; 4 | import { getSerializers } from '../helpers/defaultConfiguration'; 5 | import { RsocketEventsPayload } from '../helpers/types'; 6 | import { Provider } from '../api/Provider'; 7 | 8 | export const createServer = ({ 9 | address, 10 | serverProvider, 11 | serviceCall, 12 | }: { 13 | address: Address; 14 | serverProvider: Provider; 15 | serviceCall: TransportApi.Invoker; 16 | }) => { 17 | const { factoryOptions, providerFactory } = serverProvider; 18 | 19 | const serializers = serverProvider.serializers || getSerializers(); 20 | 21 | const server = new RSocketServer({ 22 | getRequestHandler: (socket: any) => { 23 | return { 24 | requestResponse: ({ data = {}, metadata = {} }: RsocketEventsPayload) => serviceCall.requestResponse(data), 25 | requestStream: ({ data = {}, metadata = {} }: RsocketEventsPayload) => serviceCall.requestStream(data), 26 | }; 27 | }, 28 | serializers, 29 | transport: providerFactory({ address, factoryOptions }), 30 | }); 31 | 32 | server.start(); 33 | 34 | return () => { 35 | try { 36 | server.stop.bind(server); 37 | } catch (e) { 38 | console.error('RSocket unable to close connection ' + e); 39 | } 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/cluster-nodejs", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "lib/index.js", 6 | "module": "es/index.js", 7 | "types": "lib/index.d.ts", 8 | "files": [ 9 | "lib", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf es", 15 | "build": "yarn clean && yarn build-rollup", 16 | "build-rollup": "rollup -c", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js --forceExit" 20 | }, 21 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 22 | "devDependencies": { 23 | "jest": "^24.6.0", 24 | "rollup": "^1.14.6", 25 | "rollup-plugin-babel": "^4.3.3", 26 | "rollup-plugin-commonjs": "^10.0.1", 27 | "rollup-plugin-filesize": "^6.1.1", 28 | "rollup-plugin-node-globals": "^1.4.0", 29 | "rollup-plugin-node-resolve": "^5.2.0", 30 | "rollup-plugin-typescript2": "^0.21.1", 31 | "rollup-plugin-visualizer": "^2.2.0", 32 | "ts-jest": "^24.2.0", 33 | "tslint": "^5.11.0", 34 | "typescript": "^3.2.4" 35 | }, 36 | "dependencies": { 37 | "@scalecube/api": "0.2.11", 38 | "@scalecube/utils": "0.2.11", 39 | "rxjs": "^6.4.0", 40 | "swim": "^0.6.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/routers/src/RoundRobin/roundRobin.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | import { getFullAddress } from '@scalecube/utils'; 3 | 4 | const lastEndPointMap: { [qualifier: string]: string } = {}; 5 | 6 | export const roundRobin: MicroserviceApi.Router = (options: MicroserviceApi.RouterOptions) => { 7 | const { message, lookUp } = options; 8 | const { qualifier } = message; 9 | 10 | return new Promise((resolve, reject) => { 11 | const endpoints = lookUp({ qualifier }); 12 | if (!(endpoints && Array.isArray(endpoints) && endpoints.length > 0)) { 13 | reject(null); 14 | } else { 15 | if (!lastEndPointMap[qualifier]) { 16 | lastEndPointMap[qualifier] = getFullAddress(endpoints[0].address); 17 | resolve(endpoints[0]); 18 | } else { 19 | const lastEndPointIdentifier = lastEndPointMap[qualifier]; 20 | 21 | const lastIndex = endpoints.findIndex((endpoint: MicroserviceApi.Endpoint) => { 22 | return getFullAddress(endpoint.address) === lastEndPointIdentifier; 23 | }); 24 | 25 | if (lastIndex + 1 >= endpoints.length) { 26 | lastEndPointMap[qualifier] = getFullAddress(endpoints[0].address); 27 | resolve(endpoints[0]); 28 | } else { 29 | lastEndPointMap[qualifier] = getFullAddress(endpoints[lastIndex + 1].address); 30 | resolve(endpoints[lastIndex + 1]); 31 | } 32 | } 33 | } 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/cluster-nodejs/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # Cluster-nodejs 7 | 8 | This package provides a default cluster implementation for node-js. 9 | it uses SWIM protocol for discovering members in distributed environment. 10 | 11 | ## Basic Usage 12 | 13 | ```javascript 14 | import { joinCluster } from '@scalecube/cluster-nodejs'; 15 | 16 | const clusterOptions = { 17 | seedAddress, 18 | address, 19 | itemsToPublish: [], 20 | }; 21 | 22 | const cluster = joinCluster(clusterOptions); 23 | 24 | // calling `getCurrentMembersData()`, will resolve with the distributed environment's latest state. 25 | cluster.getCurrentMembersData().then(console.log); 26 | 27 | // on subscribe to `listen$()`, we will start getting emits of the distributed environment's latest state. 28 | cluster.listen$().subscribe(console.log); 29 | 30 | 31 | // on calling `destroy()`, we will remove our metadata from the distributed environment. 32 | // also, it stops the cluster from sharing/publishing metadata. 33 | cluster.destroy().then(console.log); 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/utils/src/serviceDefinition.ts: -------------------------------------------------------------------------------- 1 | import * as check from './check'; 2 | import { getQualifier } from './qualifier'; 3 | import { 4 | SERVICE_NAME_NOT_PROVIDED, 5 | DEFINITION_MISSING_METHODS, 6 | INVALID_METHODS, 7 | ASYNC_MODEL_TYPES, 8 | getServiceNameInvalid, 9 | getIncorrectMethodValueError, 10 | getAsynModelNotProvidedError, 11 | getInvalidAsyncModelError, 12 | } from './constants'; 13 | 14 | export const validateServiceDefinition = (definition: any) => { 15 | check.assertNonEmptyObject(definition); 16 | const { serviceName, methods } = definition; 17 | check.assertDefined(serviceName, SERVICE_NAME_NOT_PROVIDED); 18 | check.assertNonEmptyString(serviceName, getServiceNameInvalid(serviceName)); 19 | check.assertDefined(methods, DEFINITION_MISSING_METHODS); 20 | check.assertNonEmptyObject(methods, INVALID_METHODS); 21 | Object.keys(methods).forEach((methodName) => { 22 | check.assertNonEmptyString(methodName); 23 | const qualifier = getQualifier({ serviceName, methodName }); 24 | validateAsyncModel(qualifier, methods[methodName]); 25 | }); 26 | }; 27 | 28 | export const validateAsyncModel = (qualifier: string, val: any) => { 29 | check.assertNonEmptyObject(val, getIncorrectMethodValueError(qualifier)); 30 | const { asyncModel } = val; 31 | check.assertDefined(asyncModel, getAsynModelNotProvidedError(qualifier)); 32 | check.assertOneOf(ASYNC_MODEL_TYPES, asyncModel, getInvalidAsyncModelError(qualifier)); 33 | }; 34 | -------------------------------------------------------------------------------- /packages/cluster-browser/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](https://scalecube.github.io/javascript-docs) 5 | 6 | # Cluster-browser 7 | 8 | This package provides a default cluster implementation for browser. 9 | it uses native browser message event for creating the distributed environment. 10 | 11 | ## Basic Usage 12 | 13 | ```javascript 14 | import { joinCluster } from '@scalecube/cluster-browser'; 15 | 16 | const clusterOptions = { 17 | seedAddress, 18 | address, 19 | itemsToPublish: [], 20 | }; 21 | 22 | const cluster = joinCluster(clusterOptions); 23 | 24 | // calling `getCurrentMembersData()`, will resolve with the distributed environment's latest state. 25 | cluster.getCurrentMembersData().then(console.log); 26 | 27 | // on subscribe to `listen$()`, we will start getting emits of the distributed environment's latest state. 28 | cluster.listen$().subscribe(console.log); 29 | 30 | 31 | // on calling `destroy()`, we will remove our metadata from the distributed environment. 32 | // also, it stops the cluster from sharing/publishing metadata. 33 | cluster.destroy().then(console.log); 34 | ``` 35 | -------------------------------------------------------------------------------- /packages/transport-browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/transport-browser", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "cjs/index.js", 6 | "module": "es/index.js", 7 | "types": "cjs/index.d.ts", 8 | "files": [ 9 | "cjs", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf es", 15 | "build": "yarn build-rollup && tsc", 16 | "build-rollup": "rollup -c", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js" 20 | }, 21 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 22 | "devDependencies": { 23 | "jest": "^24.6.0", 24 | "rollup": "^1.14.6", 25 | "rollup-plugin-commonjs": "^10.0.1", 26 | "rollup-plugin-filesize": "^6.1.1", 27 | "rollup-plugin-typescript2": "^0.21.1", 28 | "rollup-plugin-visualizer": "^2.2.0", 29 | "ts-jest": "^24.2.0", 30 | "tslint": "^5.11.0", 31 | "typescript": "^3.2.4" 32 | }, 33 | "dependencies": { 34 | "@scalecube/addressable": "0.2.11", 35 | "@scalecube/api": "0.2.11", 36 | "@scalecube/rsocket-adapter": "0.2.11", 37 | "@scalecube/utils": "0.2.11", 38 | "rsocket-core": "^0.0.16", 39 | "rsocket-events-client": "^0.0.22", 40 | "rsocket-events-server": "^0.0.22", 41 | "rxjs": "^6.4.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/cluster-browser/src/Cluster/connection.ts: -------------------------------------------------------------------------------- 1 | import { connect, listen } from '@scalecube/addressable'; 2 | import { Observable } from 'rxjs'; 3 | import { ClusterEvent } from '@scalecube/api/lib/cluster'; 4 | 5 | export function createServer(address: string) { 6 | return new Observable((obs) => { 7 | listen(address, (msg: { data: ClusterEvent }, port) => { 8 | obs.next({ 9 | ...msg.data, 10 | send: (m: any) => port.postMessage(m), 11 | on: (cond: (ev: any) => boolean, handler: (m: any) => void) => { 12 | port.addEventListener('message', (e) => { 13 | if (cond(e.data)) { 14 | handler(e.data); 15 | } 16 | }); 17 | }, 18 | }); 19 | }); 20 | }); 21 | } 22 | 23 | export function createConnection() { 24 | const connections: { [address: string]: MessagePort } = {}; 25 | 26 | function getConnection(address: string) { 27 | connections[address] = connections[address] || connect(address); 28 | return connections[address]; 29 | } 30 | async function send(address: string, msg: any) { 31 | const con = await getConnection(address); 32 | con.postMessage(msg); 33 | } 34 | async function on(address: string, listener: (e: any) => void) { 35 | const con = await getConnection(address); 36 | con.addEventListener('message', (e) => listener(e.data)); 37 | } 38 | 39 | return { send, on }; 40 | } 41 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/helpers/serviceData.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | import { check } from '@scalecube/utils'; 3 | import { FlatteningServices } from './types'; 4 | import { getServiceFactoryOptions } from '../Microservices/MicroserviceInstance'; 5 | import { validateServiceReference } from './validation'; 6 | 7 | export const getReferencePointer = ({ 8 | reference, 9 | methodName, 10 | }: { 11 | reference: MicroserviceApi.ServiceObject; 12 | methodName: string; 13 | }): ((...args: any[]) => any) => { 14 | const methodRef = reference[methodName]; 15 | if (methodRef) { 16 | return methodRef.bind(reference); 17 | } 18 | // static method 19 | return reference.constructor && reference.constructor[methodName]; 20 | }; 21 | 22 | export const flatteningServices = ({ services, serviceFactoryOptions }: FlatteningServices) => { 23 | return services && Array.isArray(services) 24 | ? services.map((service: MicroserviceApi.Service) => { 25 | const { reference, definition } = service; 26 | if (check.isFunction(reference)) { 27 | const ref = (reference as (...data: any[]) => any)(serviceFactoryOptions); 28 | validateServiceReference(ref, definition); 29 | return { reference: ref, definition }; 30 | } else { 31 | validateServiceReference(reference, definition); 32 | return { reference, definition }; 33 | } 34 | }) 35 | : services; 36 | }; 37 | -------------------------------------------------------------------------------- /packages/examples/node/greetMePlzService.js: -------------------------------------------------------------------------------- 1 | const { createMicroservice, ASYNC_MODEL_TYPES } = require('@scalecube/node'); 2 | const { retryRouterWithLogs } = require('./helpers/retryRouterWithLogs'); 3 | 4 | process.on('message', () => { 5 | const ms = createMicroservice({ 6 | address: { 7 | protocol: 'ws', 8 | host: 'localhost', 9 | port: 6114, 10 | path: '', 11 | }, 12 | seedAddress: { 13 | protocol: 'ws', 14 | host: 'localhost', 15 | port: 6111, 16 | path: '', 17 | }, 18 | // override the default router (RoundRobin for nodejs) is not needed but possible. 19 | // in this example, we override it to add retry logic 20 | defaultRouter: retryRouterWithLogs('greetMePlz'), 21 | }); 22 | 23 | // PersonService definition 24 | const personDefinition = { 25 | serviceName: 'PersonService', 26 | methods: { 27 | requestGreeting: { 28 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE, 29 | }, 30 | }, 31 | }; 32 | 33 | const person = ms.createProxy({ 34 | serviceDefinition: personDefinition, 35 | }); 36 | 37 | try { 38 | person 39 | .requestGreeting() 40 | .then((response) => { 41 | console.log(`\nour distributed environment response with: `, response); 42 | }) 43 | .catch((e) => { 44 | console.error('service not available', e.message); 45 | }); 46 | } catch (e) { 47 | console.warn('catch error', e.message); 48 | } 49 | }); 50 | -------------------------------------------------------------------------------- /packages/examples/iife/webWorkerExample2/worker1.js: -------------------------------------------------------------------------------- 1 | importScripts('http://localhost:8000/packages/browser/dist/index.js'); 2 | importScripts('./definitions.js'); 3 | importScripts('./reactiveStream.js'); 4 | 5 | const ms1 = sc.createMicroservice({ 6 | services: [ 7 | { 8 | reference: reactiveStreamExample, 9 | definition: definitions.remoteServiceDefinition, 10 | }, 11 | ], 12 | address: 'ms1', 13 | }); 14 | 15 | const ms2 = sc.createMicroservice({ 16 | services: [ 17 | { 18 | reference: reactiveStreamExample, 19 | definition: definitions.remoteServiceDefinition3, 20 | }, 21 | ], 22 | address: 'ms3', 23 | seedAddress: 'ms1', 24 | }); 25 | 26 | const ms3 = sc.createMicroservice({ 27 | address: 'ms4', 28 | seedAddress: 'ms1', 29 | }); 30 | 31 | const proxyName = ms3.createProxy({ serviceDefinition: definitions.remoteServiceDefinition }); 32 | const proxyName3 = ms3.createProxy({ serviceDefinition: definitions.remoteServiceDefinition3 }); 33 | 34 | proxyName.getInterval(1000).subscribe( 35 | (res) => console.log(`webworker 1 - awaitProxyName is resolve every 1000ms: ${res}`), 36 | (error) => console.log(error.message) 37 | ); 38 | 39 | proxyName3.getInterval(9000).subscribe( 40 | (res) => console.log(`webworker 1 - awaitProxyName3 is resolve every 9000ms: ${res}`), 41 | (error) => console.log(error.message) 42 | ); 43 | 44 | setTimeout(() => { 45 | ms1.destroy(); 46 | ms2.destroy(); 47 | ms3.destroy(); 48 | }, 60 * 0.5 * 1000); 49 | -------------------------------------------------------------------------------- /packages/examples/rollup.iife.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | import tscompile from 'typescript'; 3 | import filesize from 'rollup-plugin-filesize'; 4 | import resolve from 'rollup-plugin-node-resolve'; 5 | import commonjs from 'rollup-plugin-commonjs'; 6 | import pkg from './package.json'; 7 | import uglify from 'rollup-plugin-uglify-es'; 8 | import babel from 'rollup-plugin-babel'; 9 | import global from 'rollup-plugin-node-globals'; 10 | 11 | export default { 12 | input: './bundles/src/index.ts', 13 | output: [ 14 | { 15 | name: 'sdk', 16 | file: pkg.rollup, 17 | format: 'iife', 18 | sourcemap: false, 19 | }, 20 | ], 21 | plugins: [ 22 | resolve({ jsnext: true, main: true }), 23 | commonjs({ 24 | browser: true, 25 | }), 26 | babel({ 27 | plugins: ['@babel/plugin-transform-arrow-functions', '@babel/plugin-transform-async-to-generator'], 28 | babelrc: false, 29 | runtimeHelpers: false, 30 | presets: [ 31 | [ 32 | '@babel/preset-env', 33 | { 34 | modules: false, 35 | spec: true, 36 | forceAllTransforms: true, 37 | targets: { 38 | chrome: '29', 39 | ie: '11', 40 | firefox: '40', 41 | }, 42 | }, 43 | ], 44 | ], 45 | }), 46 | typescript({ 47 | typescript: tscompile, 48 | clean: true, 49 | }), 50 | global(), 51 | filesize(), 52 | ], 53 | }; 54 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/unit/Microservices/endpointsUtil.spec.ts: -------------------------------------------------------------------------------- 1 | import { restore, minimized } from '../../../src/Microservices/endpointsUtil'; 2 | import { AsyncModel } from '@scalecube/api/lib/microservice'; 3 | 4 | describe('endpointsUtil', () => { 5 | test('Given endpoints when minimized & restore it should be the same', () => { 6 | const endpoints = [ 7 | { 8 | qualifier: 'GreetingService/hello', 9 | serviceName: 'GreetingService', 10 | methodName: 'hello', 11 | asyncModel: 'requestResponse' as AsyncModel, 12 | address: { 13 | protocol: 'pm', 14 | host: 'defaultHost', 15 | port: 8080, 16 | path: 'B', 17 | }, 18 | }, 19 | { 20 | qualifier: 'GreetingService/greet$', 21 | serviceName: 'GreetingService', 22 | methodName: 'greet$', 23 | asyncModel: 'requestStream' as AsyncModel, 24 | address: { 25 | protocol: 'pm', 26 | host: 'defaultHost', 27 | port: 8080, 28 | path: 'B', 29 | }, 30 | }, 31 | { 32 | qualifier: 'GreetingService/greet$', 33 | serviceName: 'GreetingService', 34 | methodName: 'greet$', 35 | asyncModel: 'requestStream' as AsyncModel, 36 | address: { 37 | protocol: 'pm', 38 | host: 'defaultHost', 39 | port: 1234, 40 | path: '', 41 | }, 42 | }, 43 | ]; 44 | 45 | expect(endpoints).toEqual(restore(minimized(endpoints))); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/addressable/rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | import babel from 'rollup-plugin-babel'; 9 | 10 | export default { 11 | input: 'src/index.ts', 12 | output: [ 13 | { 14 | file: pkg.main, 15 | format: 'cjs', 16 | sourcemap: false, 17 | }, 18 | ], 19 | plugins: [ 20 | commonjs({ 21 | include: /node_modules/, 22 | browser: true, 23 | namedExports: { 24 | 'rsocket-types': ['CONNECTION_STATUS'], 25 | }, 26 | }), 27 | resolve(), 28 | babel({ 29 | plugins: ['@babel/plugin-transform-arrow-functions'], 30 | babelrc: false, 31 | runtimeHelpers: true, 32 | presets: [ 33 | [ 34 | '@babel/preset-env', 35 | { 36 | modules: false, 37 | spec: true, 38 | forceAllTransforms: true, 39 | targets: { 40 | chrome: '29', 41 | ie: '11', 42 | }, 43 | }, 44 | ], 45 | ], 46 | }), 47 | visualizer({ 48 | filename: 'report.cjs.html', 49 | title: 'Browser - cjs', 50 | }), 51 | typescript({ 52 | typescript: tscompile, 53 | clean: true, 54 | }), 55 | // global(), 56 | filesize(), 57 | ], 58 | }; 59 | -------------------------------------------------------------------------------- /packages/utils/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { MicroserviceApi } from '@scalecube/api'; 2 | 3 | export const NOT_VALID_PROTOCOL = 'Not a valid protocol'; 4 | export const NOT_VALID_ADDRESS = 'Address must be of type object'; 5 | export const NOT_VALID_HOST = 'Not a valid host'; 6 | export const NOT_VALID_PATH = 'Not a valid path'; 7 | export const NOT_VALID_PORT = 'Not a valid port'; 8 | 9 | export const ASYNC_MODEL_TYPES: { 10 | REQUEST_STREAM: MicroserviceApi.RequestStreamAsyncModel; 11 | REQUEST_RESPONSE: MicroserviceApi.RequestResponseAsyncModel; 12 | } = { 13 | REQUEST_RESPONSE: 'requestResponse', 14 | REQUEST_STREAM: 'requestStream', 15 | }; 16 | 17 | export const SERVICE_NAME_NOT_PROVIDED = 'MS0020 - Invalid format, definition must contain valid serviceName'; 18 | export const DEFINITION_MISSING_METHODS = 'MS0021 - Invalid format, definition must contain valid methods'; 19 | export const INVALID_METHODS = 'MS0022 - Invalid format, definition must contain valid methods'; 20 | export const getServiceNameInvalid = (serviceName: any) => 21 | `MS0023 - Invalid format, serviceName must be not empty string but received type ${typeof serviceName}`; 22 | 23 | export const getIncorrectMethodValueError = (qualifier: string) => 24 | `Method value for ${qualifier} definition should be non empty object`; 25 | export const getAsynModelNotProvidedError = (qualifier: string) => 26 | `Async model is not provided in service definition for ${qualifier}`; 27 | export const getInvalidAsyncModelError = (qualifier: string) => 28 | `Invalid async model in service definition for ${qualifier}`; 29 | -------------------------------------------------------------------------------- /packages/api/src/cluster/Cluster.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '..'; 2 | import { ClusterEvent, MembersData } from './index'; 3 | import { Observable } from 'rxjs'; 4 | 5 | /** 6 | * @function JoinCluster 7 | * factory for creating a cluster instance 8 | */ 9 | export type JoinCluster = (options: ClusterOptions) => Cluster; 10 | 11 | /** 12 | * @interface ClusterOptions 13 | */ 14 | export interface ClusterOptions { 15 | /** 16 | * @property address 17 | * address of the member 18 | */ 19 | address: Address; 20 | /** 21 | * @property seedAddress 22 | * address of the member that act as the seed 23 | */ 24 | seedAddress?: Address[]; 25 | /** 26 | * @property itemsToPublish 27 | * item to share with the different members 28 | */ 29 | itemsToPublish: any; 30 | /** 31 | * @property retry 32 | * retry configuration for connecting members 33 | */ 34 | retry?: { 35 | timeout: number; 36 | }; 37 | /** 38 | * @property debug 39 | */ 40 | debug?: boolean; 41 | } 42 | 43 | /** 44 | * @interface Cluster 45 | */ 46 | export interface Cluster { 47 | /** 48 | * @property getCurrentMemberStates 49 | * resolve with the current information of the other members in the distributed environment 50 | */ 51 | getCurrentMembersData: () => Promise; 52 | /** 53 | * @property listen$ 54 | * subscribe to changes in the members state 55 | */ 56 | listen$: () => Observable; 57 | /** 58 | * @property destroy 59 | * resolve when cluster is destroyed 60 | */ 61 | destroy: () => Promise; 62 | } 63 | -------------------------------------------------------------------------------- /packages/transport-nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/transport-nodejs", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "lib/index.js", 6 | "module": "es/index.js", 7 | "types": "lib/index.d.ts", 8 | "files": [ 9 | "lib", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf es", 15 | "build": "yarn build-rollup", 16 | "build-rollup": "rollup -c", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js" 20 | }, 21 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 22 | "devDependencies": { 23 | "jest": "^24.6.0", 24 | "rollup": "^1.14.6", 25 | "rollup-plugin-commonjs": "^10.0.1", 26 | "rollup-plugin-filesize": "^6.1.1", 27 | "rollup-plugin-node-globals": "^1.4.0", 28 | "rollup-plugin-node-resolve": "^5.2.0", 29 | "rollup-plugin-typescript2": "^0.21.1", 30 | "rollup-plugin-visualizer": "^2.2.0", 31 | "ts-jest": "^24.2.0", 32 | "tslint": "^5.11.0", 33 | "typescript": "^3.2.4" 34 | }, 35 | "dependencies": { 36 | "@scalecube/api": "^0.2.11", 37 | "@scalecube/rsocket-adapter": "^0.2.11", 38 | "@scalecube/utils": "^0.2.11", 39 | "rsocket-core": "^0.0.27", 40 | "rsocket-tcp-client": "^0.0.27", 41 | "rsocket-tcp-server": "^0.0.27", 42 | "rsocket-websocket-client": "^0.0.27", 43 | "rsocket-websocket-server": "^0.0.27", 44 | "ws": ">=3.3.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/integration/retryRouter.spec.ts: -------------------------------------------------------------------------------- 1 | import { greet$, greetingServiceDefinition, hello } from '../mocks/GreetingService'; 2 | import { createMS } from '../mocks/microserviceFactory'; 3 | import { retryRouter } from '@scalecube/routers'; 4 | 5 | describe('Test retry router - distributed env.', () => { 6 | test(` 7 | Scenario: perform remoteCall from sync proxy when the remoteService is bootstrap after the localService. 8 | Given 2 services that are in the same dist. env. 9 | And localService is bootstrap before the remoteService. 10 | When doing a remoteCall 11 | And only after that the remoteService is registered. 12 | Then the remoteCall will be resolved. 13 | `, async (done) => { // @ts-ignore 14 | const service = { 15 | definition: greetingServiceDefinition, 16 | reference: { greet$, hello }, 17 | }; 18 | 19 | setTimeout(() => { 20 | createMS({ 21 | services: [service], 22 | address: 'A', 23 | }); 24 | }, 500); 25 | 26 | const msA = createMS({ 27 | address: 'B', 28 | seedAddress: 'A', 29 | }); 30 | 31 | const router = retryRouter({ period: 10 }); 32 | const proxy = msA.createProxy({ 33 | serviceDefinition: greetingServiceDefinition, 34 | // @ts-ignore 35 | router, 36 | }); 37 | 38 | const result = await proxy.hello('Me'); 39 | expect(result).toMatch('Hello Me'); 40 | 41 | proxy.greet$(['Me']).subscribe((response: any) => { 42 | expect(response).toMatch('greetings Me'); 43 | done(); 44 | }); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/examples/k8s/start: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if hash go 2>/dev/null; then 4 | export PATH=$PATH:$(go env GOPATH)/bin/ 5 | fi 6 | 7 | for cmd in docker kind helm kubectl; do 8 | if ! command -v $cmd &> /dev/null; then 9 | echo >&2 "error: \"$cmd\" not found!, please install it and make sure it in PATH" 10 | exit 1 11 | fi 12 | done 13 | 14 | # this is hack we need a public image name 15 | # it will work only on KinD 16 | # for real k8s publish docker image and use it 17 | docker build . -t scalecube-example:k8s 18 | docker images 19 | kind create cluster --name scalecube-example --config cluster.yml || echo "cluster exists, for clean run: kind delete cluster --name scalecube-example" 20 | kind load docker-image --name scalecube-example scalecube-example:k8s 21 | 22 | kubectl config use-context kind-scalecube-example 23 | kubectl create namespace scalecube-example || kubectl delete namespace scalecube-example && kubectl create namespace scalecube-example 24 | kubectl get serviceAccounts -n scalecube-example default || cat < { 8 | const serviceCall: TransportApi.Invoker = { 9 | requestStream: (message: any) => of({}), 10 | requestResponse: (message: any) => Promise.resolve(), 11 | }; 12 | 13 | const logger = () => {}; 14 | 15 | test(` 16 | Scenario: startServer is called without configuration 17 | Given startServer from setupServer without configuration 18 | When calling startServer 19 | Then expection will be thrown 20 | `, (done) => { 21 | expect.assertions(1); 22 | const startServer = setupServer({}); 23 | try { 24 | startServer({ 25 | localAddress: getAddress('A'), 26 | logger, 27 | serviceCall, 28 | }); 29 | } catch (e) { 30 | expect(e.message).toMatch(SERVER_NOT_IMPL); 31 | done(); 32 | } 33 | }); 34 | 35 | test(` 36 | Scenario: startClient is called without configuration 37 | Given startClient from setupClient without configuration 38 | When calling startClient 39 | Then expection will be thrown 40 | `, (done) => { 41 | expect.assertions(1); 42 | const client = setupClient({}); 43 | client.start({ remoteAddress: getAddress('A'), logger }).catch((e: Error) => { 44 | expect(e.message).toMatch(CLIENT_NOT_IMPL); 45 | done(); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/tests/mocks/GreetingService.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { ASYNC_MODEL_TYPES } from '../../src'; 3 | 4 | /* tslint:disable */ 5 | 6 | export const hello = (name: string): Promise => { 7 | // @ts-ignore 8 | return new Promise((resolve, reject) => { 9 | if (!name) { 10 | reject(new Error('please provide user to greet')); 11 | } else { 12 | resolve(`Hello ${name}`); 13 | } 14 | }); 15 | }; 16 | 17 | export const greet$ = (greetings: string[]): Observable => { 18 | return new Observable((observer) => { 19 | if (!greetings || !Array.isArray(greetings) || greetings.length === 0) { 20 | observer.error(new Error('please provide Array of greetings')); 21 | } 22 | greetings.map((i) => observer.next(`greetings ${i}`)); 23 | }); 24 | }; 25 | 26 | export class GreetingService { 27 | public hello(name: string): Promise { 28 | return hello(name); 29 | } 30 | 31 | public greet$(greetings: string[]): Observable { 32 | return greet$(greetings); 33 | } 34 | } 35 | 36 | export class GreetingServiceWithStatic { 37 | public static hello(name: string): Promise { 38 | return hello(name); 39 | } 40 | 41 | public static greet$(greetings: string[]): Observable { 42 | return greet$(greetings); 43 | } 44 | } 45 | 46 | export const greetingServiceDefinition = { 47 | serviceName: 'GreetingService', 48 | methods: { 49 | hello: { 50 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE, 51 | }, 52 | greet$: { 53 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_STREAM, 54 | }, 55 | }, 56 | }; 57 | -------------------------------------------------------------------------------- /packages/examples/k8s/consumer.js: -------------------------------------------------------------------------------- 1 | const { createMicroservice, ASYNC_MODEL_TYPES } = require('@scalecube/node'); 2 | const http = require('http'); 3 | const url = require('url'); 4 | 5 | console.log('seed', process.env.SEED); 6 | console.log('address', process.env.ADDRESS); 7 | 8 | const definition = { 9 | serviceName: 'HelloService', 10 | methods: { 11 | hello: { 12 | asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE, 13 | }, 14 | }, 15 | }; 16 | 17 | const proxy = createMicroservice({ 18 | seedAddress: { 19 | protocol: 'ws', 20 | host: process.env.SEED, 21 | port: 7001, 22 | path: '', 23 | }, 24 | address: { 25 | protocol: 'ws', 26 | host: process.env.ADDRESS, 27 | port: 7002, 28 | path: '', 29 | }, 30 | debug: true, 31 | }).createProxy({ 32 | serviceDefinition: definition, 33 | }); 34 | 35 | // setInterval(() => { 36 | // proxy 37 | // .hello('test') 38 | // .then(console.log) 39 | // .catch(console.error); 40 | // }, 10000); 41 | 42 | //create a server object: 43 | http 44 | .createServer(function(req, res) { 45 | console.log('got req: ', req.url); 46 | var q = url.parse(req.url, true).query; 47 | proxy 48 | .hello({ name: q.name }) 49 | .then((r) => { 50 | console.log(r); 51 | res.write(JSON.stringify(r)); //write a response to the client 52 | res.end(); //end the response 53 | }) 54 | .catch((e) => { 55 | console.log(res); 56 | res.write(JSON.stringify(e)); //write a response to the client 57 | res.end(); //end the response 58 | }); 59 | }) 60 | .listen(80); //the server object listens on port 8080 61 | -------------------------------------------------------------------------------- /packages/scalecube-discovery/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/scalecube-discovery", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "cjs/index.js", 6 | "module": "es/index.js", 7 | "types": "cjs/index.d.ts", 8 | "files": [ 9 | "cjs", 10 | "es" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf es", 15 | "build": "rimraf .cache && yarn build:cjs && tsc", 16 | "build:cjs": "rimraf lib && rollup -c rollup.cjs.config.js", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "yarn test-dom-env", 20 | "test-dom-env": "jest --config jest.config-dom.js", 21 | "coverage": "jest --coverage --collectCoverageFrom='src/**/*.**' --collectCoverageFrom='!tests/**/*.**'" 22 | }, 23 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 24 | "devDependencies": { 25 | "@babel/core": "^7.4.5", 26 | "@scalecube/cluster-browser": "0.2.11", 27 | "jest": "^24.6.0", 28 | "rollup": "^1.14.6", 29 | "rollup-plugin-babel": "^4.3.3", 30 | "rollup-plugin-commonjs": "^10.0.1", 31 | "rollup-plugin-filesize": "^6.1.1", 32 | "rollup-plugin-node-resolve": "^5.2.0", 33 | "rollup-plugin-typescript2": "^0.21.1", 34 | "rollup-plugin-visualizer": "^2.2.0", 35 | "ts-jest": "^24.2.0", 36 | "tslint": "^5.11.0", 37 | "typedoc": "^0.14.2", 38 | "typescript": "^3.2.4" 39 | }, 40 | "dependencies": { 41 | "@scalecube/api": "0.2.11", 42 | "@scalecube/utils": "0.2.11", 43 | "rxjs": "^6.4.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/rsocket-ws-gateway-client", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "unpkg": "dist/index.js", 8 | "files": [ 9 | "lib", 10 | "dist" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib", 15 | "build": "rimraf .cache && yarn build:dist && yarn build:cjs", 16 | "build:dist": "rimraf dist && rollup -c rollup.iife.config.js", 17 | "build:cjs": "rimraf lib && rollup -c rollup.cjs.config.js", 18 | "lint": "node_modules/.bin/tslint '{src,tests}/**/*.{ts,tsx}' --fix", 19 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 20 | "test": "echo \"the tests are in rsocket-ws-gateway-client\"", 21 | "coverage": "yarn test --coverage --collectCoverageFrom='src/**/*.**' --collectCoverageFrom='!tests/**/*.**'" 22 | }, 23 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 24 | "devDependencies": { 25 | "jest": "^24.6.0", 26 | "rollup": "^1.14.6", 27 | "rollup-plugin-babel": "^4.3.3", 28 | "rollup-plugin-commonjs": "^10.0.1", 29 | "rollup-plugin-filesize": "^6.1.1", 30 | "rollup-plugin-typescript2": "^0.21.1", 31 | "rollup-plugin-visualizer": "^2.2.0", 32 | "ts-jest": "^24.2.0", 33 | "tslint": "^5.11.0", 34 | "typescript": "^3.2.4" 35 | }, 36 | "dependencies": { 37 | "@scalecube/utils": "^0.2.11", 38 | "rsocket-core": "^0.0.27", 39 | "rsocket-flowable": "^0.0.27", 40 | "rsocket-websocket-client": "^0.0.27", 41 | "ws": ">=3.3.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/README.md: -------------------------------------------------------------------------------- 1 | [![Join the chat at https://gitter.im/scalecube-js/Lobby](https://badges.gitter.im/scalecube-js/Lobby.svg)](https://gitter.im/scalecube-js/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | > This is part of [scalecube-js](https://github.com/scalecube/scalecube-js) project, see more at 4 | > [Full documentation](http://scalecube.io/javascript-docs) 5 | 6 | # rsocket-websocket-gateway-client 7 | 8 | Client for rsocket websocket gateway for browser and server usage 9 | 10 | `yarn add @scalecube/rsocket-ws-gateway-client` or `npm i @scalecube/rsocket-ws-gateway-client` 11 | 12 | 13 | ```typescript 14 | import { createGatewayProxy } from '@scalecube/rsocket-ws-gateway-client'; 15 | 16 | 17 | const definition = { 18 | serviceName: 'serviceA', 19 | methods: { 20 | methodA: { asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE }, 21 | }, 22 | }; 23 | const proxy = await createGatewayProxy('ws://localhost:3000', definition); 24 | const resp = await proxy.methodA() // => 'ok' 25 | ``` 26 | 27 | Available also as IFFE at JSDELIVER 28 | ```html 29 | 30 | 41 | ``` 42 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | import babel from 'rollup-plugin-babel'; 9 | 10 | export default { 11 | input: 'src/index.ts', 12 | output: [ 13 | { 14 | file: pkg.main, 15 | format: 'cjs', 16 | sourcemap: false, 17 | }, 18 | ], 19 | external: ['rxjs'], 20 | plugins: [ 21 | commonjs({ 22 | include: /node_modules/, 23 | browser: true, 24 | namedExports: { 25 | 'rsocket-types': ['CONNECTION_STATUS'], 26 | 'rsocket-core': ['RSocketClient', 'JsonSerializers'], 27 | }, 28 | }), 29 | resolve(), 30 | babel({ 31 | plugins: ['@babel/plugin-transform-arrow-functions'], 32 | babelrc: false, 33 | runtimeHelpers: true, 34 | presets: [ 35 | [ 36 | '@babel/preset-env', 37 | { 38 | modules: false, 39 | spec: true, 40 | forceAllTransforms: true, 41 | targets: { 42 | chrome: '29', 43 | ie: '11', 44 | }, 45 | }, 46 | ], 47 | ], 48 | }), 49 | visualizer({ 50 | filename: 'report.cjs.html', 51 | title: 'Browser - cjs', 52 | }), 53 | typescript({ 54 | typescript: tscompile, 55 | clean: true, 56 | }), 57 | // global(), 58 | filesize(), 59 | ], 60 | }; 61 | -------------------------------------------------------------------------------- /packages/addressable/rollup.iife.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | import replace from 'rollup-plugin-replace'; 9 | import { terser } from 'rollup-plugin-terser'; 10 | import babel from 'rollup-plugin-babel'; 11 | 12 | export default { 13 | input: 'src/index.ts', 14 | output: [ 15 | { 16 | name: 'sc', 17 | file: pkg.unpkg, 18 | format: 'iife', 19 | sourcemap: false, 20 | }, 21 | ], 22 | plugins: [ 23 | commonjs({ 24 | include: /node_modules/, 25 | browser: true, 26 | }), 27 | resolve(), 28 | babel({ 29 | plugins: ['@babel/plugin-transform-arrow-functions'], 30 | babelrc: true, 31 | runtimeHelpers: true, 32 | presets: [ 33 | [ 34 | '@babel/preset-env', 35 | { 36 | modules: false, 37 | spec: true, 38 | forceAllTransforms: true, 39 | targets: { 40 | chrome: '29', 41 | ie: '11', 42 | }, 43 | }, 44 | ], 45 | ], 46 | }), 47 | replace({ 48 | 'process.env.NODE_ENV': JSON.stringify('production'), 49 | }), 50 | visualizer({ 51 | filename: 'report.iffe.html', 52 | title: 'Microservice - iife', 53 | }), 54 | typescript({ 55 | typescript: tscompile, 56 | clean: true, 57 | }), 58 | terser(), 59 | filesize(), 60 | ], 61 | }; 62 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/api/Provider.ts: -------------------------------------------------------------------------------- 1 | import { Address } from '@scalecube/api'; 2 | 3 | export interface Provider { 4 | /** 5 | * @method 6 | * Factory for creating RSocket client transport provider 7 | */ 8 | providerFactory: ProviderFactory; 9 | /** 10 | * @property 11 | * Extra configuration to pass to the factory 12 | */ 13 | factoryOptions?: any; 14 | 15 | /** 16 | * @property 17 | * Optional serialize functionality for the payload 18 | */ 19 | serializers?: PayloadSerializers; 20 | 21 | /** 22 | * @property 23 | * Optional setup configuration for the provider 24 | */ 25 | setup?: ProviderSetup; 26 | } 27 | 28 | /** 29 | * @interface ClientProviderSetup 30 | */ 31 | export interface ProviderSetup { 32 | dataMimeType?: string; 33 | keepAlive?: number; 34 | lifetime?: number; 35 | metadataMimeType?: string; 36 | } 37 | 38 | /** 39 | * @function 40 | * RSocket transport provider factory 41 | * DuplexConnection - https://github.com/rsocket/rsocket-js/blob/master/packages/rsocket-core/src/RSocketClient.js 42 | */ 43 | export type ProviderFactory = (options: { address: Address; factoryOptions?: any }) => DuplexConnection; 44 | 45 | /** 46 | * import { DuplexConnection } from 'rsocket-core'; 47 | */ 48 | type DuplexConnection = any; 49 | 50 | /** 51 | * PayloadSerializers - https://github.com/rsocket/rsocket-js/blob/master/packages/rsocket-core/src/RSocketSerialization.js 52 | */ 53 | export interface PayloadSerializers { 54 | data: { 55 | deserialize: (data: any) => any; 56 | serialize: (data: any) => any; 57 | }; 58 | metadata: { 59 | deserialize: (data: any) => any; 60 | serialize: (data: any) => any; 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/rsocket-ws-gateway", 3 | "version": "0.2.11", 4 | "private": false, 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "files": [ 8 | "lib", 9 | "dist" 10 | ], 11 | "license": "MIT", 12 | "scripts": { 13 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib", 14 | "build": "yarn build-rollup && yarn build:dist", 15 | "build-rollup": "rollup -c", 16 | "build:dist": "tsc -p tsconfig.json --module CommonJS", 17 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 18 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 19 | "test": "jest --config jest.config.js", 20 | "coverage": "yarn test --coverage --collectCoverageFrom='src/**/*.**' --collectCoverageFrom='!tests/**/*.**'" 21 | }, 22 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 23 | "devDependencies": { 24 | "@scalecube/browser": "0.2.11", 25 | "@scalecube/rsocket-ws-gateway-client": "0.2.11", 26 | "jest": "^24.6.0", 27 | "rollup": "^1.14.6", 28 | "rollup-plugin-babel": "^4.3.3", 29 | "rollup-plugin-commonjs": "^10.0.1", 30 | "rollup-plugin-filesize": "^6.1.1", 31 | "rollup-plugin-typescript2": "^0.21.1", 32 | "rollup-plugin-visualizer": "^2.2.0", 33 | "ts-jest": "^24.2.0", 34 | "tslint": "^5.11.0", 35 | "typescript": "^3.2.4" 36 | }, 37 | "dependencies": { 38 | "@scalecube/api": "^0.2.11", 39 | "@scalecube/utils": "^0.2.11", 40 | "rsocket-core": "^0.0.27", 41 | "rsocket-flowable": "^0.0.27", 42 | "rsocket-websocket-client": "^0.0.27", 43 | "rsocket-websocket-server": "^0.0.27", 44 | "ws": ">=3.3.1" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/tests/multi-proxy.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMicroservice, ASYNC_MODEL_TYPES } from '@scalecube/browser'; 2 | import { Gateway } from '../src/Gateway'; 3 | import { createGatewayProxy } from '@scalecube/rsocket-ws-gateway-client'; 4 | 5 | const definitionA = { 6 | serviceName: 'serviceA', 7 | methods: { 8 | methodA: { asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE }, 9 | }, 10 | }; 11 | const definitionB = { 12 | serviceName: 'serviceB', 13 | methods: { 14 | methodB: { asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE }, 15 | }, 16 | }; 17 | const serviceA = { methodA: () => Promise.resolve('ok') }; 18 | const serviceB = { methodB: () => Promise.resolve('bye') }; 19 | const services = [ 20 | { definition: definitionA, reference: serviceA }, 21 | { definition: definitionB, reference: serviceB }, 22 | ]; 23 | 24 | const ms = createMicroservice({ services }); 25 | const serviceCall = ms.createServiceCall({}); 26 | const gateway = new Gateway({ port: 8070 }); 27 | 28 | let proxyA; 29 | let proxyB; 30 | 31 | beforeAll(async () => { 32 | gateway.start({ serviceCall }); 33 | [proxyA, proxyB] = await createGatewayProxy('ws://localhost:8070', [definitionA, definitionB]); 34 | }); 35 | afterAll(() => gateway.stop()); 36 | 37 | test(`Given microservices with gateway 38 | And two service 39 | And two gateway-proxies created simultanously by createGatewayProxy method 40 | When two requests executed through those proxies 41 | Then two success responses returned by both of proxies`, async () => { 42 | const respA = await proxyA.methodA(); 43 | expect(respA).toEqual('ok'); 44 | const respB = await proxyB.methodB(); 45 | expect(respB).toEqual('bye'); 46 | }); 47 | -------------------------------------------------------------------------------- /packages/browser/rollup.iife.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | import replace from 'rollup-plugin-replace'; 9 | import { terser } from 'rollup-plugin-terser'; 10 | import babel from 'rollup-plugin-babel'; 11 | 12 | export default { 13 | input: 'src/index.ts', 14 | output: [ 15 | { 16 | name: 'sc', 17 | file: pkg.unpkg, 18 | format: 'iife', 19 | sourcemap: false, 20 | }, 21 | ], 22 | plugins: [ 23 | commonjs({ 24 | include: /node_modules/, 25 | browser: true, 26 | }), 27 | resolve(), 28 | babel({ 29 | plugins: ['@babel/plugin-transform-arrow-functions', '@babel/plugin-transform-runtime'], 30 | babelrc: true, 31 | runtimeHelpers: true, 32 | presets: [ 33 | [ 34 | '@babel/preset-env', 35 | { 36 | modules: false, 37 | spec: true, 38 | forceAllTransforms: true, 39 | targets: { 40 | chrome: '29', 41 | ie: '11', 42 | }, 43 | }, 44 | ], 45 | ], 46 | }), 47 | replace({ 48 | 'process.env.NODE_ENV': JSON.stringify('production'), 49 | }), 50 | visualizer({ 51 | filename: 'report.iffe.html', 52 | title: 'Microservice - iife', 53 | }), 54 | typescript({ 55 | typescript: tscompile, 56 | clean: true, 57 | }), 58 | terser(), 59 | filesize(), 60 | ], 61 | }; 62 | -------------------------------------------------------------------------------- /packages/scalecube-microservice/src/Microservices/endpointsUtil.ts: -------------------------------------------------------------------------------- 1 | /// This util is minimize and restore Endpoint[] 2 | /// use for optimize endpoints transport 3 | import { MicroserviceApi } from '@scalecube/api'; 4 | import { getAddress, getFullAddress } from '@scalecube/utils'; 5 | 6 | const eAsyncModel: { [key: number]: MicroserviceApi.AsyncModel } = { 7 | 0: 'requestResponse', 8 | 1: 'requestStream', 9 | }; 10 | const sAsyncModel: { [key: string]: keyof typeof eAsyncModel } = { 11 | requestResponse: 0, 12 | requestStream: 1, 13 | }; 14 | 15 | export interface Endpoints { 16 | [address: string]: { 17 | [serviceName: string]: { 18 | [methodName: string]: keyof typeof eAsyncModel; 19 | }; 20 | }; 21 | } 22 | 23 | export function minimized(endpoints: MicroserviceApi.Endpoint[]): Endpoints { 24 | const res: Endpoints = {}; 25 | endpoints.forEach((e) => { 26 | const addr = getFullAddress(e.address); 27 | res[addr] = res[addr] || {}; 28 | res[addr][e.serviceName] = res[getFullAddress(e.address)][e.serviceName] || {}; 29 | res[addr][e.serviceName][e.methodName] = sAsyncModel[e.asyncModel]; 30 | }); 31 | return res; 32 | } 33 | 34 | export function restore(endpoints: Endpoints): MicroserviceApi.Endpoint[] { 35 | const res: MicroserviceApi.Endpoint[] = []; 36 | for (const address in endpoints) { 37 | for (const service in endpoints[address]) { 38 | for (const method in endpoints[address][service]) { 39 | res.push({ 40 | asyncModel: eAsyncModel[endpoints[address][service][method]], 41 | methodName: method, 42 | serviceName: service, 43 | address: getAddress(address), 44 | qualifier: `${service}/${method}`, 45 | }); 46 | } 47 | } 48 | } 49 | return res; 50 | } 51 | -------------------------------------------------------------------------------- /packages/examples/iife/remoteCallExample/remoteCall.js: -------------------------------------------------------------------------------- 1 | /** 2 | * RemoteCall example, 3 | * adding services to one microservice but using those services from another microservice 4 | * 5 | * In this example we will use a service that was created and published in another microservice instance. 6 | * 7 | * Scalecube provide us a way to consume the service from any platform. 8 | */ 9 | 10 | window.addEventListener('DOMContentLoaded', function(event) { 11 | (function(createMicroservice, ASYNC_MODEL_TYPES, remoteServiceDefinition) { 12 | var placeHolder = document.getElementById('placeHolder'); 13 | var waitMessage = document.getElementById('waitMessage'); 14 | 15 | waitMessage.innerText = 'Wait for service ~ 2s'; 16 | 17 | var localMS = createMicroservice({ services: [], seedAddress: 'seed', address: 'local' }); 18 | 19 | var serviceNameProxy = localMS.createProxy({ serviceDefinition: remoteServiceDefinition }); 20 | 21 | function createLineHTML(data) { 22 | var response = data.response; 23 | var type = data.type; 24 | waitMessage.innerText = 'Service is available:'; 25 | 26 | var responseSpan = document.createElement('div'); 27 | responseSpan.innerText = type + ':' + response; 28 | placeHolder.appendChild(responseSpan); 29 | } 30 | 31 | serviceNameProxy 32 | .hello('ME!!!') 33 | .then(function(response) { 34 | createLineHTML({ response: response, type: ASYNC_MODEL_TYPES.REQUEST_RESPONSE }); 35 | }) 36 | .catch(console.log); 37 | 38 | serviceNameProxy.greet$(['ME!!!', 'YOU!!!']).subscribe(function(response) { 39 | createLineHTML({ response: response, type: ASYNC_MODEL_TYPES.REQUEST_STREAM }); 40 | }); 41 | })(window.sc.createMicroservice, window.sc.ASYNC_MODEL_TYPES, definitions); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/rsocket-adapter/src/Client/clientConnection.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import RSocketClient from 'rsocket-core/build/RSocketClient'; 3 | // @ts-ignore 4 | import { ReactiveSocket } from 'rsocket-types'; 5 | import { Address } from '@scalecube/api'; 6 | import { getFullAddress } from '@scalecube/utils'; 7 | import { getSerializers, getSetup } from '../helpers/defaultConfiguration'; 8 | import { ConnectionManager } from '../helpers/types'; 9 | import { Provider } from '..'; 10 | 11 | export const getClientConnection = ({ 12 | address, 13 | clientProvider, 14 | connectionManager, 15 | }: { 16 | address: Address; 17 | clientProvider: Provider; 18 | connectionManager: ConnectionManager; 19 | }) => { 20 | const fullAddress = getFullAddress(address); 21 | 22 | let connection: Promise = connectionManager.getConnection(fullAddress); 23 | 24 | if (!connection) { 25 | const client = createClient({ address, clientProvider }); 26 | connection = new Promise((resolve, reject) => { 27 | client.connect().subscribe({ 28 | onComplete: (socket: ReactiveSocket) => resolve(socket), 29 | onError: (error: Error) => reject(error), 30 | }); 31 | }); 32 | connectionManager.setConnection(fullAddress, connection); 33 | } 34 | 35 | return connection; 36 | }; 37 | 38 | const createClient = ({ address, clientProvider }: { address: Address; clientProvider: any }) => { 39 | const { factoryOptions, providerFactory } = clientProvider; 40 | 41 | const serializers = clientProvider.serializers || getSerializers(); 42 | const setup = clientProvider.setup ? getSetup(clientProvider.setup) : getSetup({}); 43 | 44 | return new RSocketClient({ 45 | serializers, 46 | setup, 47 | transport: providerFactory({ address, factoryOptions }), 48 | }); 49 | }; 50 | -------------------------------------------------------------------------------- /packages/examples/tests/greeting.spec.ts: -------------------------------------------------------------------------------- 1 | jest.setTimeout(120000); 2 | describe('k8s', () => { 3 | test('k8s', async (done) => { 4 | expect.assertions(1); 5 | const { execSync } = require('child_process'); 6 | execSync('/bin/bash -c "cd k8s && ./start"', { stdio: 'inherit' }); 7 | const http = require('http'); 8 | // how many times to try before failing 9 | // the cluster require some time to get ready for action 10 | let tries = 6; 11 | try { 12 | setInterval(() => { 13 | http 14 | .get('http://localhost:8080/?name=test', (resp: any) => { 15 | let data = ''; 16 | // A chunk of data has been recieved. 17 | resp.on('data', (chunk: any) => { 18 | data += chunk; 19 | }); 20 | // The whole response has been received. Print out the result. 21 | resp.on('end', () => { 22 | if (data === '"hello: test"') { 23 | expect(data).toBe('"hello: test"'); 24 | execSync('/bin/bash -c "cd k8s && ./stop"', { stdio: 'inherit' }); 25 | done(); 26 | } else { 27 | tries--; 28 | if (tries <= 0) { 29 | expect(data).toBe('"hello: test"'); 30 | } 31 | } 32 | }); 33 | resp.on('error', (err: Error) => { 34 | throw Error('Service responded with error: ' + err.message); 35 | }); 36 | }) 37 | .on('error', (err: Error) => { 38 | tries--; 39 | if (tries <= 0) { 40 | throw Error('http get error: ' + err.message); 41 | } 42 | }); 43 | }, 10000); 44 | } catch (e) { 45 | execSync('/bin/bash -c "cd k8s && ./stop"', { stdio: 'inherit' }); 46 | } 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway-client/rollup.iife.config.js: -------------------------------------------------------------------------------- 1 | import visualizer from 'rollup-plugin-visualizer'; 2 | import typescript from 'rollup-plugin-typescript2'; 3 | import tscompile from 'typescript'; 4 | import filesize from 'rollup-plugin-filesize'; 5 | import resolve from 'rollup-plugin-node-resolve'; 6 | import commonjs from 'rollup-plugin-commonjs'; 7 | import pkg from './package.json'; 8 | import replace from 'rollup-plugin-replace'; 9 | import { terser } from 'rollup-plugin-terser'; 10 | import babel from 'rollup-plugin-babel'; 11 | 12 | export default { 13 | input: 'src/index.ts', 14 | output: [ 15 | { 16 | name: 'sc', 17 | file: pkg.unpkg, 18 | format: 'iife', 19 | sourcemap: false, 20 | }, 21 | ], 22 | plugins: [ 23 | commonjs({ 24 | include: /node_modules/, 25 | browser: true, 26 | namedExports: { 27 | 'rsocket-types': ['CONNECTION_STATUS'], 28 | 'rsocket-core': ['RSocketClient', 'JsonSerializers'], 29 | }, 30 | }), 31 | resolve(), 32 | babel({ 33 | plugins: ['@babel/plugin-transform-arrow-functions'], 34 | babelrc: true, 35 | runtimeHelpers: true, 36 | presets: [ 37 | [ 38 | '@babel/preset-env', 39 | { 40 | modules: false, 41 | spec: true, 42 | forceAllTransforms: true, 43 | targets: { 44 | chrome: '29', 45 | ie: '11', 46 | }, 47 | }, 48 | ], 49 | ], 50 | }), 51 | replace({ 52 | 'process.env.NODE_ENV': JSON.stringify('production'), 53 | }), 54 | visualizer({ 55 | filename: 'report.iffe.html', 56 | title: 'Microservice - iife', 57 | }), 58 | typescript({ 59 | typescript: tscompile, 60 | clean: true, 61 | }), 62 | terser(), 63 | filesize(), 64 | ], 65 | }; 66 | -------------------------------------------------------------------------------- /packages/examples/iife/remoteCallExample/remoteService.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Remote service. 3 | * The service can be written and re-written in every available technology. 4 | * it can be run in workers, browser or server. 5 | * Scalecube provide us a way to publish the service from any platform. 6 | * In this example we will create the service and use it by other microservice instance. 7 | */ 8 | 9 | window.addEventListener('DOMContentLoaded', function(event) { 10 | (function(createMicroservice, ASYNC_MODEL_TYPES, rxjs, remoteServiceDefinition) { 11 | var remoteService = { 12 | hello: function(name) { 13 | return new Promise(function(resolve, reject) { 14 | if (!name) { 15 | reject(new Error('please provide user to greet')); 16 | } else { 17 | resolve('Hello ' + name); 18 | } 19 | }); 20 | }, 21 | 22 | greet$: function(greetings) { 23 | return new rxjs.Observable(function(observer) { 24 | if (!greetings || !Array.isArray(greetings) || greetings.length === 0) { 25 | observer.error(new Error('please provide Array of greetings')); 26 | } 27 | for (var i = 0; i < greetings.length; i++) { 28 | observer.next('greetings ' + greetings[i]); 29 | } 30 | }); 31 | }, 32 | }; 33 | 34 | /** 35 | * the remote service will be available only after 2s 36 | */ 37 | setTimeout(function() { 38 | console.log('bootstrap remote microservice after 2s'); 39 | createMicroservice({ 40 | services: [ 41 | { 42 | definition: remoteServiceDefinition, 43 | reference: remoteService, 44 | }, 45 | ], 46 | address: 'seed', 47 | }); 48 | }, 2000); 49 | })(window.sc.createMicroservice, window.sc.ASYNC_MODEL_TYPES, rxjs, definitions); 50 | }); 51 | -------------------------------------------------------------------------------- /packages/addressable/src/boostrap.ts: -------------------------------------------------------------------------------- 1 | import { createConnectionServer } from './ConnectionServer'; 2 | import { createConnectionClient } from './ConnectionClient'; 3 | 4 | export function bootstrap(window: any, worker: any) { 5 | const server = createConnectionServer(); 6 | const client = createConnectionClient(); 7 | 8 | // @ts-ignore 9 | if (typeof Worker !== 'undefined') { 10 | const W = Worker; 11 | // @ts-ignore 12 | // tslint:disable-next-line:only-arrow-functions 13 | Worker = function(url: string, options: WorkerOptions = {}) { 14 | const w = new W(url, options); 15 | w.addEventListener('message', server.channelHandler); 16 | return w; 17 | }; 18 | } 19 | 20 | // worker 21 | if (typeof worker !== 'undefined') { 22 | const localChannel = new MessageChannel(); 23 | localChannel.port1.start(); 24 | localChannel.port2.start(); 25 | worker.addEventListener('message', server.channelHandler); 26 | localChannel.port2.addEventListener('message', server.channelHandler); 27 | client.createChannel(localChannel.port1.postMessage.bind(localChannel.port1)).catch(() => {}); 28 | client.createChannel(worker.postMessage.bind(worker)).catch(() => {}); 29 | // iframe 30 | } else if (window && window.top && window.top !== window.self) { 31 | client 32 | .createChannel((msg: any, port: MessagePort) => window.postMessage.bind(window)(msg, '*', port)) 33 | .catch(() => {}); 34 | client 35 | .createChannel((msg: any, port: MessagePort) => window.top.postMessage.bind(window.top)(msg, '*', port)) 36 | .catch(() => {}); 37 | window.addEventListener('message', server.channelHandler); 38 | } 39 | // main 40 | else { 41 | client.createChannel((msg: any, port: MessagePort) => window.postMessage(msg, '*', port)).catch(() => {}); 42 | window.addEventListener('message', server.channelHandler); 43 | } 44 | 45 | return client; 46 | } 47 | -------------------------------------------------------------------------------- /packages/browser/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@scalecube/browser", 3 | "version": "0.2.11", 4 | "private": false, 5 | "unpkg": "dist/index.js", 6 | "main": "lib/index.js", 7 | "types": "lib/index.d.ts", 8 | "files": [ 9 | "lib", 10 | "dist" 11 | ], 12 | "license": "MIT", 13 | "scripts": { 14 | "clean": "rimraf node_modules && rimraf .cache && rimraf lib && rimraf dist", 15 | "build": "rimraf .cache && yarn build:dist && yarn build:cjs", 16 | "build:dist": "rimraf dist && rollup -c rollup.iife.config.js", 17 | "build:cjs": "rimraf lib && rollup -c rollup.cjs.config.js", 18 | "lint": "tslint '{src,tests}/**/*.{ts,tsx}' --fix", 19 | "prettier": "prettier --write '{src,tests}/**/*.{ts,tsx}'", 20 | "test": "echo \"no tests\"" 21 | }, 22 | "author": "Scalecube (https://github.com/scalecube/scalecube-js)", 23 | "devDependencies": { 24 | "@babel/core": "^7.7.4", 25 | "@babel/plugin-transform-arrow-functions": "^7.7.4", 26 | "@babel/preset-env": "^7.7.4", 27 | "regenerator-runtime": "^0.13.3", 28 | "rollup": "^1.27.4", 29 | "rollup-plugin-babel": "^4.3.3", 30 | "rollup-plugin-commonjs": "^10.1.0", 31 | "rollup-plugin-filesize": "^6.1.1", 32 | "rollup-plugin-node-globals": "^1.4.0", 33 | "rollup-plugin-node-resolve": "^5.2.0", 34 | "rollup-plugin-replace": "^2.2.0", 35 | "rollup-plugin-terser": "^5.3.0", 36 | "rollup-plugin-typescript2": "^0.21.1", 37 | "rollup-plugin-uglify-es": "^0.0.1", 38 | "rollup-plugin-visualizer": "^2.6.0", 39 | "tslint": "^5.11.0", 40 | "typescript": "^3.2.4" 41 | }, 42 | "dependencies": { 43 | "@scalecube/api": "0.2.11", 44 | "@scalecube/cluster-browser": "0.2.11", 45 | "@scalecube/routers": "0.2.11", 46 | "@scalecube/scalecube-microservice": "0.2.11", 47 | "@scalecube/transport-browser": "0.2.11", 48 | "@scalecube/utils": "0.2.11", 49 | "rxjs": "^6.4.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/addressable/src/Node.ts: -------------------------------------------------------------------------------- 1 | import { Subject } from './utils/Subject'; 2 | import { eachDelta } from './utils/eachDelta'; 3 | import { map } from './utils/map'; 4 | import { Peer } from './types'; 5 | 6 | /** 7 | * @class Node 8 | * Node represents current Node and holds all "peers" (channel to other Nodes) 9 | */ 10 | export class Node { 11 | /** 12 | * @property id 13 | * Node id 14 | */ 15 | public readonly id = `${Math.random().toString()}-${Math.random().toString()}-${Math.random().toString()}-${Math.random().toString()}`; 16 | private peers: { [id: string]: MessagePort } = {}; 17 | private peers$ = new Subject(); 18 | 19 | /** 20 | * @method Subscribe 21 | * Notify each time new peer register in node 22 | * It's also send all peers joined before subscription started 23 | * @param fn notification handler 24 | */ 25 | public subscribe(fn: (peer: Peer) => void): () => void { 26 | // Peers act like unique reply subject 27 | return map((o: Peer) => ({ id: o.key, port: o.value }), eachDelta(this.peers$)).subscribe(fn); 28 | } 29 | /** 30 | * @Method get 31 | * Get all peers 32 | */ 33 | public get() { 34 | return { ...this.peers }; 35 | } 36 | 37 | /** 38 | * @method add 39 | * Add new new peer to node 40 | * 41 | * @param id 42 | * @param port 43 | */ 44 | public add(id: string, port: MessagePort) { 45 | this.peers[id] = port; 46 | this.peers$.next(this.peers); 47 | } 48 | /** 49 | * Peer removal right now is not needed 50 | * Right now we create Node for every process 51 | * There isn't any use case we are doing that the process will be remove 52 | * At the moment it won't clear up the memory 53 | * 54 | * @method remove 55 | * Remove peer from node 56 | * 57 | * @param id 58 | */ 59 | // public remove(id: string) { 60 | // delete this.peers[id]; 61 | // this.peers$.next(this.peers); 62 | // } 63 | } 64 | -------------------------------------------------------------------------------- /packages/routers/tests/retry.spec.ts: -------------------------------------------------------------------------------- 1 | import { retryRouter } from '../src'; 2 | import { getAddress } from '@scalecube/utils'; 3 | 4 | describe(`Test retry router`, () => { 5 | const qualifier = 'serviceName/methodName'; 6 | 7 | let registry: any[] = []; 8 | 9 | test(` 10 | Scenario: registry update only after lookup. 11 | Given a registry without any endPoints 12 | And retry router 13 | When calling lookUp registry return empty array as a result 14 | And after 10ms it fills the registry with endPoint 15 | Then on the next iteration of the lookUp the registry returns an endPoint. 16 | `, // @ts-ignore 17 | async () => { 18 | const addToRegistry = () => { 19 | registry = ['A'].map((v) => ({ address: getAddress(`${v}`) })); 20 | }; 21 | 22 | const lookUp = () => { 23 | setTimeout(addToRegistry, 10); 24 | return registry; 25 | }; 26 | 27 | expect.assertions(1); 28 | const router = retryRouter({ period: 10, maxRetry: 3 }); 29 | 30 | const endPoint = await router({ message: { qualifier, data: [] }, lookUp }); 31 | expect(endPoint).toMatchObject({ address: getAddress('A') }); 32 | }); 33 | 34 | test(` 35 | Scenario: registry never update 36 | Given a registry without any endPoints 37 | And retry router with 3 retry every 10 ms 38 | When calling lookUp registry return empty array as a result 39 | Then after the retry reach 3 times, the router will reject with null 40 | `, (done) => { 41 | const lookUp = () => { 42 | return []; 43 | }; 44 | 45 | expect.assertions(1); 46 | const router = retryRouter({ period: 10, maxRetry: 3 }); 47 | 48 | router({ message: { qualifier, data: [] }, lookUp }).catch((result) => { 49 | expect(result).toBe(null); 50 | done(); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /packages/rsocket-ws-gateway/tests/stop.spec.ts: -------------------------------------------------------------------------------- 1 | import { createMicroservice, ASYNC_MODEL_TYPES } from '@scalecube/browser'; 2 | import { Gateway } from '../src/Gateway'; 3 | import { createGatewayProxy } from '@scalecube/rsocket-ws-gateway-client'; 4 | 5 | const definition = { 6 | serviceName: 'serviceA', 7 | methods: { 8 | methodA: { asyncModel: ASYNC_MODEL_TYPES.REQUEST_RESPONSE }, 9 | }, 10 | }; 11 | const reference = { methodA: () => Promise.resolve('ok') }; 12 | const services = [{ definition, reference }]; 13 | 14 | test(`Given microservices with gateway 15 | And start method was called and the microservice start listening 16 | When stop method is called 17 | And the client sends a request to the gateway 18 | Then gateway doesn't receive the request`, async () => { 19 | const ms = createMicroservice({ services }); 20 | const serviceCall = ms.createServiceCall({}); 21 | const gateway = new Gateway({ port: 1081 }); 22 | gateway.start({ serviceCall }); 23 | const proxy: any = await createGatewayProxy('ws://localhost:1081', definition); 24 | const resp = await proxy.methodA(); 25 | expect(resp).toEqual('ok'); 26 | gateway.stop(); 27 | return proxy.methodA().catch((e) => { 28 | expect(e.message).toBe('RSocketWebSocketClient: Socket closed unexpectedly.'); 29 | }); 30 | }); 31 | 32 | test(`Given microservices with gateway 33 | And start method was called and the microservice start listening 34 | And stop method is called and gateway stopped receiving requests 35 | When stop method is called again 36 | Then a message informing that gateway is not active is returned`, async () => { 37 | const gateway = new Gateway({ port: 1081 }); 38 | gateway.warn = jest.fn(); 39 | const ms = createMicroservice({}); 40 | const serviceCall = ms.createServiceCall({}); 41 | gateway.start({ serviceCall }); 42 | gateway.stop(); 43 | gateway.stop(); 44 | expect(gateway.warn).toHaveBeenCalledWith('Gateway is already stopped'); 45 | }); 46 | --------------------------------------------------------------------------------