Coder Social home page Coder Social logo

shadowboxdev / ngrx-signalr Goto Github PK

View Code? Open in Web Editor NEW

This project forked from odonno/ngrx-signalr

0.0 1.0 0.0 92 KB

A library to handle realtime SignalR (.NET Framework) events using @angular, rxjs and the @ngrx library

Home Page: https://www.npmjs.com/package/ngrx-signalr

License: MIT License

TypeScript 100.00%

ngrx-signalr's Introduction

ngrx-signalr

A library to handle realtime SignalR (.NET Framework) events using angular, rxjs and the @ngrx library.

This library is made for the SignalR client using .NET Framework. If you need target .NET Core, please check this repository : https://github.com/Odonno/ngrx-signalr-core

Get started

Install dependencies

Once you created your angular project, you need to install all the libraries required to create the communication between angular and a SignalR hub.

npm install rxjs --save
npm install @ngrx/store @ngrx/effects --save
npm install ngrx-signalr --save

Don't forget to add the dependency in the angular.json file so angular will automatically inject the $ and $.hubConnection function used to initialize signalr.

npm install jquery signalr --save
npm install @types/signalr @types/jquery --save-dev
{
    "projects": {
        "architect": {
            "build": {
                "scripts": [
                    "./node_modules/jquery/dist/jquery.js",
                    "./node_modules/signalr/jquery.signalR.js"
                ]
            }
        }
    }
}

Once everything is installed, you can use the reducer and the effects inside the AppModule.

@NgModule({
    ...,
    imports: [
        StoreModule.forRoot({ signalr: signalrReducer }),
        EffectsModule.forRoot([SignalREffects, AppEffects])
    ],
    ...
})
export class AppModule { }

Start with a single Hub

First, you will start the application by dispatching the creation of one Hub.

const hub = {
    name: 'hub name',
    url: 'https://localhost/path'
};

this.store.dispatch(
    createSignalRHub(hub)
);

Then you will create an effect to start listening to events before starting the Hub.

initRealtime$ = createEffect(() => 
    this.actions$.pipe(
        ofType(SIGNALR_HUB_UNSTARTED),
        mergeMap(action => {
            const hub = findHub(action);

            if (!hub) {
                return of(realtimeError(new Error('No SignalR Hub found...')));
            }

            // add event listeners
            const whenEvent$ = hub.on('eventName').pipe(
                map(x => createAction(x))
            );

            return merge(
                whenEvent$,
                of(startSignalRHub(hub))
            );
        })
    )
);

You can also send events at anytime.

sendEvent$ = createEffect(() => 
    this.actions$.pipe(
        ofType(SEND_EVENT),
        mergeMap(action => {
            const hub = findHub(action);

            if (!hub) {
                return of(realtimeError(new Error('No SignalR Hub found...')));
            }

            return hub.send('eventName', params).pipe(
                map(_ => sendEventFulfilled()),
                catchError(error => of(sendEventFailed(error)))
            );
        })
    )
);

Using multiple Hubs

Now, start with multiple hubs at a time.

const dispatchHubCreation = (hub) => this.store.dispatch(createSignalRHub(hub));

const hub1 = {}; // define name and url
const hub2 = {}; // define name and url
const hub3 = {}; // define name and url

dispatchHubCreation(hub1);
dispatchHubCreation(hub2);
dispatchHubCreation(hub3);

You will then initialize your hubs in the same way but you need to know which one is initialized.

const hub1 = {}; // define name and url
const hub2 = {}; // define name and url

initHubOne$ = createEffect(() => 
    this.actions$.pipe(
        ofType(SIGNALR_HUB_UNSTARTED),
        ofHub(hub1),
        mergeMap(action => {
            // TODO : init hub 1
        })
    )
);

initHubTwo$ = createEffect(() => 
    this.actions$.pipe(
        ofType(SIGNALR_HUB_UNSTARTED),
        ofHub(hub2),
        mergeMap(action => {
            // TODO : init hub 2
        })
    )
);

And then you can start your app when all hubs are connected the first time.

appStarted$ = createEffect(() => 
    this.store.select(selectAreAllHubsConnected).pipe(
        filter(areAllHubsConnected => !!areAllHubsConnected),
        first(),
        map(_ => of(appStarted()))
    )
);

Features

SignalR Hub

The SignalR Hub is an abstraction of the hub connection. It contains function you can use to:

  • start the connection
  • listen to events emitted
  • send a new event
interface ISignalRHub {
    hubName: string;
    url: string | undefined;
    
    start$: Observable<void>;
    state$: Observable<string>;
    error$: Observable<SignalR.ConnectionError>;

    constructor(hubName: string, url: string | undefined);

    start(options?: SignalR.ConnectionOptions | undefined): Observable<void>;
    on<T>(event: string): Observable<T>;
    send(method: string, ...args: any[]): Observable<any>;
    hasSubscriptions(): boolean;
}

You can find an existing hub by its name and url.

function findHub(hubName: string, url?: string | undefined): ISignalRHub | undefined;
function findHub({ hubName, url }: {
    hubName: string;
    url?: string | undefined;
}): ISignalRHub | undefined;

And create a new hub.

function createHub(hubName: string, url?: string | undefined): ISignalRHub;

State

The state contains all existing hubs that was created with their according status (unstarted, connecting, connected, disconnected, reconnecting).

const unstarted = "unstarted";
const connecting = "connecting";
const connected = "connected";
const disconnected = "disconnected";
const reconnecting = "reconnecting";

type SignalRHubState = 
    | typeof unstarted 
    | typeof connecting 
    | typeof connected 
    | typeof disconnected 
    | typeof reconnecting;

type SignalRHubStatus = {
    hubName: string;
    url: string | undefined;
    state: SignalRHubState | undefined;
};
class BaseSignalRStoreState {
    hubStatuses: SignalRHubStatus[];
}

Actions

Actions to dispatch

createSignalRHub will initialize a new hub connection but it won't start the connection so you can create event listeners.

const createSignalRHub = createAction(
    '@ngrx/signalr/createHub',
    props<{ hubName: string, url?: string | undefined }>()
);

startSignalRHub will start the hub connection so you can send and receive events.

const startSignalRHub = createAction(
    '@ngrx/signalr/startHub',
    props<{ hubName: string, url?: string | undefined, options?: SignalR.ConnectionOptions | undefined }>()
);

Effects

// create hub automatically
createHub$: Observable<{
    type: string;
    hubName: string;
    url: string | undefined;
}>;
// listen to start result (success/fail)
// listen to change connection state (connecting, connected, disconnected, reconnecting)
// listen to hub error
beforeStartHub$: Observable<{
    type: string;
    hubName: string;
    url: string | undefined;
    error: any;
} | {
    type: string;
    hubName: string;
    url: string | undefined;
} | {
    type: string;
    hubName: string;
    url: string | undefined;
    error: SignalR.ConnectionError;
}>;
// start hub automatically
startHub$: Observable<SignalRStartHubAction>;

Selectors

// used to select all hub statuses in state
const hubStatuses$ = store.select(selectHubsStatuses);

// used to select a single hub status based on its name and url
const hubStatus$ = store.select(selectHubStatus, { hubName, url });

// used to know if all hubs are connected
const areAllHubsConnected$ = store.select(selectAreAllHubsConnected);

Publish a new version

First compile using tsc and then publish to npm registry.

tsc
npm publish --access public

ngrx-signalr's People

Contributors

odonno avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.