Want to indefinitely Observe an Array that changes over time - sockets

I am trying to use Rxjs Observables To watch for changes in my array with no luck.
Imports:
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
In my main service in Angular 2
I am getting an array from a socket.io server that changes when users connect or disconnect.
I set the data after every change.
I know userList is Updating when the socket emits, but for some reason I can't figure out how to continuously observe this change in my component.
Main Service:
socket.on('get users',(data)=>{
this.userList= data;
});
Function in Main Service - getUsers():
getUsers(){
return Observable.of(this.userList);
}
I am trying to both subscribe to the userList var, and use an async pipe, but neither are updating, They only work the first time then stop.
How do I make it actually indefinitely observe for changes?

MainService
userList: Subject = new Subject<any>();
userList$ = this.userList.asObservable();
socket.on('get users', (data: any) => {
this.userList.next(data);
});
In Component
this.mainService.userList$
.subscribe(
(data:any) => console.log(data)
);

Related

listen to events on the client side only when a change has occurred Dart?

Is there some way to use a listener that listens for changes on the server and sends the changes to UI as soon as those changes happen? I'm using a websocket (singalr package to be exact) and I need to set up an event listener so that the client side captures all changes. I read that I need to use streams instead of futures and I can also subscribe to the event there, but is this suitable for the application to poll the server every time only when it actually changes, and not constantly? For example, I read that in a java script, you can use an event listener that independently "understand" that changes have occurred on the server side and pass them on to the frontend side (I am not a JS developer, but I have heard that JS has such functionality, so if there is something like this in Dart?). Right now I'm using the following code, but I'm not sure if it does exactly what I described
static Stream<String?> getData() =>
Stream.periodic(Duration(seconds: 1)).asyncMap((event) => fetchData());
static Future<String?> fetchData() async {
final hubConnection =
HubConnectionBuilder().withUrl('https://secure/secure').build();
await hubConnection.start();
String? values;
if (hubConnection.state == HubConnectionState.Connected) {
await hubConnection
.invoke('GetData')
.then((value) => values= value as String);
}
print('values');
hubConnection.onclose(({error}) {
throw Exception(error);
});
print(values);
return values;
}

Is it necessary to close a Mongodb Change Stream?

I coded the next Node/Express/Mongo script:
const { MongoClient } = require("mongodb");
const stream = require("stream");
async function main() {
// CONECTING TO LOCALHOST (REPLICA SET)
const client = new MongoClient("mongodb://localhost:27018");
try{
// CONECTION
await client.connect();
// EXECUTING MY WATCHER
console.log("Watching ...");
await myWatcher(client, 15000);
} catch (e) {
// ERROR MANAGEMENT
console.log(`Error > ${e}`);
} finally {
// CLOSING CLIENT CONECTION ???
await client.close(); << ????
}
}main().catch(console.error);
// MY WATCHER. LISTENING CHANGES FROM MY DATABASE
async function myWatcher(client, timeInMs, pipeline = []) {
// TARGET TO WATCH
const watching = client.db("myDatabase").collection("myCollection").watch(pipeline);
// WATCHING CHANGES ON TARGET
watching.on("change", (next) => {
console.log(JSON.stringify(next));
console.log(`Doing my things...`);
});
// CLOSING THE WATCHER ???
closeChangeStream(timeInMs, watching); << ????
}
// CHANGE STREAM CLOSER
function closeChangeStream(timeInMs = 60000, watching) {
return new Promise((resolve) => {
setTimeout(() => {
console.log("Closing the change stream");
watching.close();
resolve();
}, timeInMs);
});
}
So, the goal is to keep always myWatcher function in an active state, to watch any database changes and for example, send an user notification when is detected some updating. The closeChangeStream function close myWatcher function in X seconds after any database changes. So, to keep the myWatcher always active, do you recomment not to use the closeChangeStream function ??
Another thing. With this goal in mind, to keep always myWatcher function in an active state, if I keep the await client.close();, my code emits an error: Topology is closed, so when I ignore this await client.close(), my code works perfectly. Do you recomment not to use the await client.close() function to keep always myWatcher function in an active state ??
Im a newbee in this topics !
thanks for the advice !
Thanks for help !
MongoDB change streams are implemented in a pub/sub paradigm.
Send your application to a friend in the Sudan. Have both you and your friend run the application (that has the change stream implemented). If you open up mongosh and run db.getCollection('myCollection').updateOne({_id: ObjectId("6220ee09197c13d24a7997b7")}, {FirstName: Bob}); both you and your friend will get the console.log for the change stream.
This is assuming you're not running localhost, but you can simulate this with two copies of the applications locally.
The issue comes from going into production and suddenly you have 200 load bearers, 5 developers, etc. running and your watch fires a ton of writes around the globe.
I believe, the practice is to functionize it. Wrap your watch in a function and fire the function when you're about to do a write (and close after you do your associated writes).

Listening for Electron's ipcRenderer message inside a Vue component

Currently, I'm using Vue inside an Electron application. Inside a Vue's master component there are possibly multiple children. Each child listens to a signal that might be broadcasted by Electron's main process, like so:
export default {
...
created() {
ipcRenderer.on('set-service-status', (e, data) => {
// something with the data
})
}
...
}
However when there are more than 11 child components, node throws the error MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 set-service-status listeners added. Use emitter.setMaxListeners() to increase limit. This makes sense since multiple event listeners are being setup, one for every component.
How could this be solved? Should I just listen for the set-service-status signal inside the master component and then use Vue's eventing system to broadcast the message further down to the children? Or is there a better way to deal with this?
as I understand the problem with your current setup is, your starting listening each time component created and this cause problem of having a lot of listeners for one IPC call.
instead of listening via created() put this logic inside of your vuex
and call it only once. or you can still use created() in your entry file, the main root component. and give the data to your child components as props. That also works.
for example;
function setupIpc(dispatch) {
ipcRenderer.on('set-service-status', (e, data) => {
// something with the data
})
ipcRenderer.on('fullscreenChanged', (e, args) => {
dispatch('fullscreenHandler', args)
})
ipcRenderer.send('ipcReady')
}
and only call once when you start the application,
updateState({ commit, dispatch }) {
setupIpc(dispatch)
setInterval(() => { dispatch('stateSaveImmediate') }, 5000)
dispatch('init')
ipcRenderer.once('configGet', (e, data) => {
if (data === !null || !undefined) {
commit(ActionTypes.UPDATE_STATE, data)
} else {
commit(ActionTypes.UPDATE_STATE_ERROR_NO_CONFIG_FILE)
}
dispatch('doSomething')
})
ipcRenderer.send('configGet')
},

#ngrx Effect does not run the second time

I've just started learning about #ngrx/store and #ngrx.effects and have created my first effect in my Angular/Ionic app. It runs ok the first time but if I dispatch the event to the store again (i.e when clicking the button again), nothing happens (no network call is made, nothing in console logs). Is there something obvious I'm doing wrong? Here's the effect:
#Effect() event_response$ = this.action$
.ofType(SEND_EVENT_RESPONSE_ACTION)
.map(toPayload)
.switchMap((payload) => this.myService.eventResponse(payload.eventId,payload.response))
.map(data => new SentEventResponseAction(data))
.catch((error) => Observable.of(new ErrorOccurredAction(error)));
Thanks
It sounds like an error is occurring. In that situation, the action in the observable returned by catch will be emitted into the effect's stream and the effect will then complete - which will prevent the effect from running after the error action is emitted.
Move the map and the catch into the switchMap:
#Effect() event_response$ = this.action$
.ofType(SEND_EVENT_RESPONSE_ACTION)
.map(toPayload)
.switchMap((payload) => this.myService
.eventResponse(payload.eventId, payload.response)
.map(data => new SentEventResponseAction(data))
.catch((error) => Observable.of(new ErrorOccurredAction(error)))
);
Composing the catch within the switchMap will prevent the effect from completing if an error occurs.
You must move map() and catchError() into swithchMap() as following
#Effect()
public event_response$ = this.action$.pipe(
ofType(SEND_EVENT_RESPONSE_ACTION),
switchMap((payload) => {
return this.myService.eventResponse(payload.eventId,payload.response).pipe(
map((data: DataType) => new SentEventResponseAction(data)),
catchError((error) => Observable.of(new ErrorOccurredAction(error)))
})
);
);
Please note that, evetResponse() method inside myService should return an observable in order to use pipe afterward.
In case your method inside service returns Promise, you can convert it into an observable by the use of from in the rxjs package as below:
import { from } from 'rxjs';
...
const promise = this.myService.eventResponse(payload.eventId,payload.response);
const observable = from(promise);
return observable.pipe(...
For more and detail description take a look at this link

Angular2 e2e test case with protractor throwing error

I have created my app with angular2-webpack-starter and i have used socket.io with it. I have created one common service to create socket connection and listen its method. this service is used and initialized after user is logged in. When app is running and i execute test case for login, i am checking url with below code :
browser.getCurrentUrl().then((url) => {
expect(url).toEqual('/dashboard');
});
The issue is when socket is connected its throwing error 'Timed out waiting for Protractor to synchronize with the page after 15 seconds' and if socket is not connected same test case is running without any error.
I'm not sure if connecting to the socket is actually make things take longer or not but if the 15 seconds isn't enough time, you can change the
allScriptsTimeout:timeout_in_millis in your protractor configuration file
protractor timeouts
So the solution I have found is:
(This is copied from here for your convenience. All credit goes to https://github.com/cpa-level-it
https://github.com/angular/angular/issues/11853#issuecomment-277185526)
What I did to fix the problem was using ngZone everywhere I have an observable that relies on socket.io.
So let's say you have this method in your service that gives you an observable on a socket.io.
private socket: SocketIOClient.Socket;
public getSocketIOEvents(): Observable<SocketIOEvent> {
if (this.socket == null) {
this.socket = io.connect(this._socketPath);
}
return Observable.create((observer: any) => {
this.socket.on('eventA', (item: any) => observer.next(new SocketIOEvent(item)));
this.socket.on('eventB', (item: any) => observer.next(new SocketIOEvent(item)));
return () => this.socket.close();
});
}
Then you need to use the ngZone service to tell Angular to create the socket outside the Angular 2 zone and then execute the callback of the Observable inside the Angular 2 zone.
import { NgZone } from '#angular/core';
constructor(
private socketService: SocketIOService, ,
private ngZone: NgZone) { }
ngOnInit() {
// Subscribe to the Observable outside Angular zone...
this.ngZone.runOutsideAngular(() => {
this.socketService
.getSocketIOEvents()
.subscribe(event => {
// Come back into Angular zone when there is a callback from the Observable
this.ngZone.run(() => {
this.handleEvent(event);
});
});
});
}
This way protractor doesn't hang waiting on the socket.