UNPKG

reactive-actor

Version:
140 lines 5.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.eventStateMachine = exports.eventReducer = exports.createStateMachineReducer = exports.Actor = exports.stop = void 0; const tslib_1 = require("tslib"); const rxjs_1 = require("rxjs"); const of_type_operator_1 = require("../operators/of-type.operator"); const util_1 = require("../util"); exports.stop = (0, util_1.createEvent)('REACTIVE_ACTOR_STOP'); /** * Reference: * https://www.youtube.com/watch?v=7erJ1DV_Tlo&ab_channel=jasonofthel33t * * Actor: * Fundamental unit of computation * Actor needs to embody * - Processing * - Storage * - Communication * * "One ant is no ant" - "One human is no human" - "One actor is no actor" * Actors live within systems * * Fundamental Properties: * - Receive messages, in response of this it can" * - Create actors * - Send messages (to other actors and itself) * - Designates what to do with the next message it receives */ class Actor { constructor(address) { this.address = address; this.message$ = new rxjs_1.Subject(); /** * Stream of stop events (might be useful to know when the actor stops) */ this.stop$ = this.message$.pipe((0, of_type_operator_1.ofType)(exports.stop)); } /** * Method to send messages to the actor * @param message we want to send to the actor */ send(message) { this.message$.next(message); } /** * Subscribes to an observable of events when there is an emission will send the event to a * recipient (actor reference) when specified and to itself when not. * completes when stop message is send to the actor. * @param messages an observable of messages * @example * * import { Actor, createEvent } from 'reactive-actor'; * * export const getUsers = createEvent('[Users] Get Users'); * * export const getUsersSuccess = createEvent<GitHubUser[]>( * '[Users] Get Users Success' * ); * * export const getUsersFail = createEvent<string>('[Users] Get Users Fail'); * * * export type UsersActorEvents = ReturnType<typeof getUsers>; * * export class UsersActor extends Actor<UsersActorEvents> { * // Reference to logger actor * private readonly logger = new Actor('logger'); * * // Recipient is not define thus will send the resulting event to itself * private readonly getUsers$ = this.messages$.pipe( * ofType(getUsers), * exhaustMap(() => * ajax<GitHubUser[]>(`https://api.github.com/users?per_page=5`).pipe( * map(({ response }) => getUsersSuccess(response)), * catchError((err) => of(getUsersFail(err))) * ) * ) * ); * * // Recipient is define thus will send event (getUsersFail) to specified recipient (logger) * private readonly getUsersFail$ = this.messages$.pipe( * ofType(getUsersFail), * addRecipient(this.logger) * ); * * constructor() { * super('users'); * this.answer(this.getUsers$, this.getUsersFail$); * } * } */ answer(...messages) { const answers$ = (0, rxjs_1.merge)(...messages).pipe((0, rxjs_1.tap)((_a) => { var { recipient } = _a, message = tslib_1.__rest(_a, ["recipient"]); return recipient ? recipient.send(message) : this.send(message); }), (0, rxjs_1.takeUntil)(this.stop$)); answers$.subscribe(); } /** * Actor message stream, allows to define actor behavior * see [example](https://www.npmjs.com/package/reactive-actor) */ get messages$() { return this.message$.asObservable(); } } exports.Actor = Actor; /** * Creates an event reducer from a state machine defined as a dictionary see: ``EventStateMachineStructure`` * @param stateMachine a state machine defined as a dictionary * @returns reducer function that process the next state based on current state and an event */ function createStateMachineReducer(stateMachine) { return (state, message) => { var _a, _b; return (_b = (_a = stateMachine[state]) === null || _a === void 0 ? void 0 : _a[message.type]) !== null && _b !== void 0 ? _b : state; }; } exports.createStateMachineReducer = createStateMachineReducer; /** * Creates a function that once applied to a stream of events will reduce state and events over time * similar to rxjs ``scan`` operator but will multicast values to subscribers * @param reducer - a function with the form of ``(state: TState, event: TEvent) => TState`` * ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce * @param initialState state that will be reduced will the first event or state at time 0 * @returns operator function to reduce state and events over time */ function eventReducer(reducer, initialState) { return (source$) => source$.pipe((0, rxjs_1.scan)(reducer, initialState), (0, rxjs_1.share)({ connector: () => new rxjs_1.BehaviorSubject(initialState) })); } exports.eventReducer = eventReducer; /** * Creates a function that once applied to a stream of events will reduce state and events over time * similar to rxjs ``scan`` operator but will multicast values to subscribers * @param stateMachine a state machine defined as a dictionary see: ``EventStateMachineStructure`` * @param initialState state that will be reduced will the first event or state at time 0 * @returns operator function to reduce state and events over time */ function eventStateMachine(stateMachine, initialState) { return eventReducer(createStateMachineReducer(stateMachine), initialState); } exports.eventStateMachine = eventStateMachine; //# sourceMappingURL=actor.model.js.map