ultrasonicsoft / ng-connection-service

Detects active internet connection in Angular application via DI ready Observable service.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

stop working after restarting angular server

mohammadtetouan opened this issue · comments

stop working after restarting angular server
and it never work again

weird. I will check it out.

You could write this in a more rxjs-ish way. Instead of new Observable you can use merge and fromEvent

import {fromEvent, merge} from 'rxjs';
import {mapTo} from 'rxjs/operators';

 this.connectionMonitor = merge(
      fromEvent(window, 'offline').pipe(mapTo(false)),
      fromEvent(window, 'online').pipe(mapTo(true))
    );

One problem with the current version is that it never emits any value as long as the state is online or offline. What I wanted in my application is that the subscriber always gets the latest state.

Here a solution that always emits at least one value and each subscriber receives the latest state

import {fromEvent, merge} from 'rxjs';
import {mapTo, shareReplay, startWith} from 'rxjs/operators';

     this.connectionMonitor =
      merge(
        fromEvent(window, 'offline').pipe(mapTo(false)),
        fromEvent(window, 'online').pipe(mapTo(true))
      )
        .pipe(
          startWith(window.navigator.onLine),
          shareReplay(1)
        );

This does not solve the problem of the online state. online does not mean that you are connected to the Internet it only says that your device has a connection to the next router. One way to detect if the device is really online, is to send a request to your back end and check the response.
https://developer.mozilla.org/en-US/docs/Web/API/NavigatorOnLine/onLine

Here an example that sends a http request whenever the connectivity state changes to online
In this example the endpoint /ping sends back a 1 in the response body

    const onlineCheck$ = this.httpClient.get('ping', {responseType: 'text'})
      .pipe(
        map(response => response === '1'),
        catchError(_ => of(false))
      );

    this.connection$ =
      merge(
        fromEvent(window, 'offline').pipe(mapTo(false)),
        fromEvent(window, 'online').pipe(mapTo(true))
      )
        .pipe(
          startWith(window.navigator.onLine),
          switchMap(flag => flag ? onlineCheck$ : of(false)),
          shareReplay(1)
        );

This solution unfortunately also does not really solve all the problems. For example, when the router, your device is connected to, loses the Internet connection. The browser still reports online and does not emit any state change.

@ralscha latest merge (dc0c045) includes enhancements about reporting network & internet connection state, please check..

Hi
That's great. Thanks for your work.

There are only two things I would change.

According to the specification if navigator.onLine returns false the browser is definitely offline

Returns false if the user agent is definitely offline (disconnected from the network). Returns true if the user agent might be online.

According to this I would remove the network check in case of the offline event

    this.offlineSubscription = fromEvent(window, 'offline').subscribe(() => {
      this.currentState.hasNetworkConnection = false;
      // this.checkInternetState();    <----   These requests will always fail
      this.currentState.hasInternetAccess = false;   <---- User agent  is definitely offline
      this.emitEvent();
    });

https://github.com/ultrasonicsoft/ng-connection-service/blob/master/projects/connection-service/src/lib/connection-service.service.ts#L132-L136

The second thing I would change is removing the dependency on lodash. Not because it's a bad library, but because the two functions _.clone and _.defaults can easily be replaced with the spread operator.

return _.clone(this.serviceOptions);
becomes
return {...this.serviceOptions};
and
this.serviceOptions = _.defaults({}, options, this.serviceOptions);
becomes
this.serviceOptions = { ...this.serviceOptions, ...options };

and _.isNil is just a comparison with null
if (!_.isNil(this.httpSubscription)) { ------> if (this.httpSubscription != null) {

Hi,

Thanks for the comments, for the first one, if our network access is broken then definitely our Internet access will also be broken but, there is one particular case where heartbeat check may work even though machine has no network access. This could happen when the application is served from localhost (actually during development) and heartbeat url was configured as the local resource (like the one in the sample checking for "/assets/ping.json" file). In this case library will report for no network access but heartbeat still returns true because we could access our local machine. As a result of this case, I decided to leave the network and heartbeat checks independent from each other.

For the second one, you are right about the lodash dependency which I added to project. Actually I had problems with spread operator before and not using it much and I think "isNil" function is much safer than only "null" comparisons (which is actually sufficient for this case). Thus as a habit I prefer to use lodash functions. Of course it can be removed from the library.

@yildiraymeric @ralscha @mohammadtetouan
I have removed the "lodash" dependency from the library.
Package has been updated and released on NPM. Please refer to the latest version supporting Angular v9-v15.