web-bluetooth Get service long wait - web-bluetooth

I am a novice
I get the UUID of the service through NRF connect, but I have been waiting for it
this.device=null;
this.server=null;
function connect() {
return navigator.bluetooth.requestDevice({filters:[{services:[ '0000ffb0-0000-1000-8000-00805f9b34fb' ]}]})
.then(device => {
this.device = device;
return device.gatt.connect();
})
.then(server => {
this.server = server;
return Promise.all([
//Keep waiting
server.getPrimaryService('0000ffb0-0000-1000-8000-00805f9b34fb').then(service => {
this.service = service;
console.log(service);
return Promise.all([
//this._cacheCharacteristic(service,''),
])
})
]);
})
}

I tested for an hour
'''
server.getPrimaryService (0x1800);
'''
Only once
The rest of the time is waiting

Related

How to reuse Promise<void> after using it once in my Angular service?

I have a problem with my Angular Promise<void> in one of my services.
The service establishes SignalR connection with the server's hub. And I am waiting with broadcasting to the hub for connection to be established:
export class SignalRService {
private hubConnection: signalR.HubConnection;
private url = environment.apiUrl + 'messageHub';
private thenable: Promise<void>;
public startConnection = (): void => {
if (!this.hubConnection) {
const token = this.auth.getAuth().token;
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl(this.url, { accessTokenFactory: () => token })
.build();
this.startHubConnection();
this.hubConnection.onclose(() => this.connectionHubClosed());
}
};
private startHubConnection() {
this.thenable = this.hubConnection.start();
this.thenable
.then(() => console.log('Connection started!'))
.catch((err) => console.log('Error while establishing connection :('));
}
public broadcastGameState = (): void => {
this.thenable.then(() => {
const name = this.auth.getAuth().displayName;
let message = this.game.getGame();
this.hubConnection
.invoke('SendMessage', message)
.catch((err) => console.error(err));
});
};
But after I will close my connection with:
public stopConnection = (): void => {
if (this.hubConnection) {
this.hubConnection.stop();
}
};
and use again my service, I can not use my thenable anymore, and broadcastGameState does not wait anymore for it, throwing an error:
Error: Cannot send data if the connection is not in the 'Connected'
State.
I do not understand why?
xxh you got your point and made me thinking, so I found the problem :) After calling:
public stopConnection = (): void => {
if (this.hubConnection) {
this.hubConnection.stop();
}
};
on connection close is called:
private connectionHubClosed(): void {
//trigerred when lost connection with server
alert('todo: SignalR connection closed');
}
BUT this.hubConnection is still with assigned value, so because of if (!this.hubConnection) new this.thenable was skipped.

RXJS flatMap to repetitive observable

I'm trying to implement service, which provides observable if app has connection to my server or not, so when browser online, we ping server with timer. Here is code:
public get $connected(): Observable<boolean> {
return this.hasInternetConnection
.asObservable()
.pipe(
distinctUntilChanged(),
flatMap((connected: boolean) => {
if (!connected) {
return of(connected);
} else {
return timer(5000)
.pipe(
map(() => {
var success = Math.random() > 0.5;
console.log('PING: ' + success);
return success;
})
);
}
})
);
}
hasInternetConnection is just a BehaviorSubject bound to window online and offline events, timer emulates ping to my API server.
The issue is that my subscription $connected catches only first value from timer observable and then doesn't work. After hasInternetConnection subject changes to false and back to true, my subscription again gets first value and then nothing. Here is what I see in console:
PING: true
subscription tap
PING: true
PING: false
PING: true
...
How can I fix that? Thank you!
Full solution:
private hasInternetConnection: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(navigator.onLine);
private connectedSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
private recheckConnectionSubject: Subject<void> = new Subject<void>();
constructor(
private readonly http: HttpClient,
) {
fromEvent(window, 'online')
.pipe(takeUntil(this.destroyed))
.subscribe(() => {
this.hasInternetConnection.next(true);
});
fromEvent(window, 'offline')
.pipe(takeUntil(this.destroyed))
.subscribe(() => {
this.hasInternetConnection.next(false);
});
merge(
this.hasInternetConnection,
this.recheckConnectionSubject,
)
.pipe(
mapTo(this.hasInternetConnection.value),
switchMap((connected: boolean) => {
if (!connected) {
return of(connected);
} else {
return timer(0, 30000)
.pipe(
mergeMapTo(this.http.get(`${environment.apiRoot}/ping`, { responseType: 'text' })
.pipe(
map((res) => {
return true;
}),
catchError(() => {
return of(false);
})
)
),
);
}
})
)
.subscribe(this.connectedSubject);
}
public get $connected(): Observable<boolean> {
return this.connectedSubject.asObservable()
.pipe(
distinctUntilChanged(),
);
}
public resetTimer(): void {
this.recheckConnectionSubject.next();
}

Call multiple ajax and wait for result Angular2

I have problem with my Angular. I have this functions:
private callUserInfo(): any {
this.isLoading = true;
return this._ajaxService.getService('/system/ping')
.map(
result => {
this.userId =
result.participant.substring(result.participant.indexOf('#'));
this.isLoading = false;
}
)
.catch(error => {
return Observable.throw(error);
});
}
public loadUserData(userName: string): any {
this.isLoading = true;
return this._ajaxService.getService('/User/' + userName)
.map(
result => {
const data = result[0];
this.user = new User(
data.id,
data.contacts[0].email,
data.name,
data.surname,
data.address.street,
data.address.city,
data.address.state,
data.address.country,
data.address.postCode,
data.address.timeZone);
this.isLoading = false;
})
.catch(error => {
return Observable.throw(error);
});
}
public getUser(): any {
if (this.user == null) {
this.callUserInfo().subscribe(() => {
this.loadUserData(this.userId).subscribe(() => {
return this.user;
});
});
} else {
return this.user;
}
}
In my component I call this service functions like this (auth service is service with functions defined up):
constructor(private _auth: AuthService) {
this.user = _auth.getUser();
}
But it stills return null (because Ajax calls are not finished?) Can someone explain me, how to call this two calls (first is system/ping service and based on return (userId) I need to call second ajax call (/user/id). After this two calls I have defined user in my service and I can return it to other components. Can someone expllain me, what am i doing wrong, or how I can do it better? I´m using newest version of angular.
P.S. Get service is from my wrapper service:
getService(url: string): Observable<any> {
return this.http
.get(this.base + url, this.options)
.map(this.extractData)
.catch(this.handleError);
}
You are not returning anything in case this.user==null
Change your function as following:
userObservabel=new BehaviourSubject(null);
public getUser(): any {
if (this.user == null) {
this.callUserInfo().subscribe(() => {
this.loadUserData(this.userId).subscribe(() => {
this.userObservabel.next(this.user);
});
});
return this.userObservabel.asObservable();
} else {
return this.userObservabel.asObservable();
}
}
and then you need to subscribe it
constructor(private _auth: AuthService) {
_auth.getUser().subscribe(user => this.user = user);
}
You need to call the second service in the subscribe or in the map method i.e. the Observable has returned a promise and that is resolved. Once that is resolved u should call your chained service.
A sample snipped from my POC might help you
this._accountListService.getAccountsFromBE().subscribe(
response => {
this.response = response;
this._accountListService.getAccountSorting().subscribe(
response => {
this.acctSort = response;
if (response.prodCode) {
this._accountListService.getAccountOrder().subscribe(
response => {
this.acctOrder = response;
this.response = this.setAccountOrder(this.response);
this.response.sort(this.myComparator);
this.acctFlag = true;
if (this.prodDesc) {
this.loader = false;
this.accountDetl = this.response[0];
this.accountDetl.entCdeDesc = this.prodDesc[this.accountDetl.entProdCatCde];
}
},
err => console.log(err)
);
}
},
err => console.log(err)
);
},
err => console.log(err)
);

Getting Messages In Skipped Queue

Can someone help me understand why I'm getting response messages (CreditAuthorizationResponse) in my skipped queue (mtSubscriber_creditAuthRequest_queue_skipped)? The sender is receiving the responses as expected, but they are also going to the skipped queue.
I've created the following consumer, which is working as expected except for the messages going into the skipped queue:
class CreditAuthorizationConsumer : IConsumer<CreditAuthorizationRequest>
{
private Func<string, Task> _outputDelegate2;
public CreditAuthorizationConsumer(Func<string, Task> outputDelegate)
{
_outputDelegate2 = outputDelegate;
}
public async Task Consume(ConsumeContext<CreditAuthorizationRequest> context)
{
await _outputDelegate2($"Received: {context.Message}: {context.Message.CardNumber}");
await context.RespondAsync<CreditAuthorizationResponse>(new CreditAuthorizationResponse(true));
await _outputDelegate2($"Sent CreditAuthorizationResponse for card request {context.Message.CardNumber}");
}
}
Here is where I'm sending the request:
private async Task SendCreditAuthRequestAsync(int numberToSend)
{
for (int i = 0; i < numberToSend; i++)
{
var cardNumber = generateCardNumber();
await SendRequestAsync(new CreditAuthorizationRequest(cardNumber), "mtSubscriber_creditAuthRequest_queue");
await WriteOutputAsync($"Sent credit auth request for card {cardNumber}.");
}
}
Here is where I'm initializing my client-side bus:
private void InitializeBus()
{
_messageBus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
var host = sbc.Host(new Uri(hostUriTextBox.Text), h =>
{
h.Username("guest");
h.Password("guest");
});
sbc.ReceiveEndpoint(host, "mtSubscriber_creditAuthResponse_queue", endpoint =>
{
endpoint.Handler<CreditAuthorizationResponse>(async context =>
{
await WriteOutputAsync($"Received: {context.Message}: {context.Message.IsAuthorized}");
});
});
});
}
Here is where I'm initializing my service-side bus:
private void InitializeBus()
{
_messageBus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
var host = sbc.Host(new Uri(hostUriTextBox.Text), h =>
{
h.Username("guest");
h.Password("guest");
});
sbc.ReceiveEndpoint(host, "mtSubscriber_creditAuthRequest_queue", endpoint =>
{
endpoint.Consumer(() => new CreditAuthorizationConsumer(WriteOutputAsync));
});
}
}
Alexey Zimarev was right -- my responses were bound to my request queue (in addition to the response queue). Simply deleting that binding resolved the problem and it hasn't come back. thanks!

How to get an observable to return data immediately and every 5 seconds thereafter

I want to create an observable that returns data from a webapi. I'd like it to return the data immediately, and poll the API every 10 seconds. The code below shows I'm using the 'interval' method. But this delays the first set of data by 10 seconds. How do I get that first flush of data to come down with no initial delay?
export class EventService {
public events$: Observable<Event[]>;
private _eventsObserver: Observer<Event[]>;
private pollInterval: number = 5000;
private _dataStore: {
events: Event[];
};
constructor(private http: Http) {
this._dataStore = { events: [] };
this.events$ = new Observable(observer => this._eventsObserver = observer)
.startWith(this._dataStore.events)
.share();
}
pollEvents() {
return Observable.interval(10000)
.switchMap(() => {
return this.http.get('app/resources/data/scheduleevents.json')
.map((responseData) => {
return responseData.json();
});
})
.map((events: Array<any>) => {
let result: Array<Event> = [];
if (events["data"]) {
events["data"].forEach((event) => {
result.push(event);
});
}
return result;
});
}
}
Got it:
.interval(5000)
.startWith(0);
Use timer. I think the timer is what you need (see RxJS tab):
http://reactivex.io/documentation/operators/timer.html#collapseRxJS
Could be used like:
Observable.timer(0, 5000).flatMap(() => apiCall())
Where 0 - delay before emitting the first value, 5000 - emit value after each 5s
let timer = TimerObservable.create(0, 5000);
this.sub = timer.subscribe(t => {
this.yourMethod()
});
To unsubscribe run this.sub.unsubscribe()
I personnally use interval with startWith (need RxJs 6+), here is a complete example:
history: any;
historySubscription: Subscription;
constructor(private jobService: JobService) { }
ngOnInit() {
this.historySubscription = interval(10000).pipe(
startWith(0),
flatMap(() => this.jobService.getHistory())
).subscribe(data => {
this.history = data;
});
}
ngOnDestroy() {
this.historySubscription.unsubscribe();
}
This retrieves history on init and then every 10 seconds.
Another alternative is using timer as explained by #Alendorff.
For angualr2 below is the code i have written in my application and it is working as expected -
In service --
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
getList(): Observable<IVM> {
return Observable.interval(5000).startWith(0)
.switchMap(() =>
this._http.get(this._vmURL )
.map((response: Response) => <IVM>response.json().data)
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError)
);
}
In component --
private getInstanceDetails(): void {
this._vmDataService.getList()
.subscribe(vmList => {
//Do whatever you want with the vmList here :)
},
error => this.errorMessage = <any>error);
}
Thanks,
Kindly let me know your thoughts.
Observable.interval(5L, TimeUnit.SECONDS)
.startWith(0)
.observeOn(AndroidSchedulers.mainThread())
.map { foobar() }
works fine for me.
Thanks

Resources