Why does didenterregion triggers multiple times even I am already in that beacon region? - ionic2

I have added one beacon region for monitoring.I am using the method didenterregion to identify when ever he enters into beacon region but the thing is even I am already in beacon region then also I am getting multiple times didenterregion signal.Can anyone help me why is this happening?
`
#Injectable()
export class BeaconProvider {
delegate: any;
region: any;
constructor(public platform: Platform, public events: Events,public IBeacon:IBeacon,public appService:AppService) {
}
initialise(): any {
let promise = new Promise((resolve, reject) => {
if (this.platform.is('cordova')) {
// Request permission to use location on iOS
this.IBeacon.requestAlwaysAuthorization();
this.IBeacon.getMonitoredRegions().then(data=>{
console.log(data);
});
this.IBeacon.getRangedRegions().then(data=>{
console.log(data);
});
this.delegate = this.IBeacon.Delegate();
// Subscribe to some of the delegate's event handlers
this.delegate.didEnterRegion()
.subscribe(
data => {
this.events.publish('this.delegate.didEnterRegion', data);
},
error => console.error()
);
this.delegate.didExitRegion()
.subscribe(
data => {
this.events.publish('this.delegate.didExitRegion', data);
},
error => console.error()
);
this.appService.getBeacons()
.subscribe(beacons => {
console.log(beacons);
var i=0;
for(i=0;i<beacons.length;i++){
// setup a beacon region – CHANGE THIS TO YOUR OWN UUID
this.region = this.IBeacon.BeaconRegion(beacons[i].beaconDetailes.beaconId,beacons[i].beaconDetailes.uuid,beacons[i].beaconDetailes.major,beacons[i].beaconDetailes.minor);
this.region.NotifyEntryStateOnDisplay = true;
this.region.NotifyOnEntry = true;
this.region.NotifyOnExit = true;
// start ranging
this.IBeacon.startMonitoringForRegion(this.region)
.then(
() => {
resolve(true);
console.log("monitor for region");
},
error => {
resolve(false);
}
);
}
}
);
} else {
resolve(false);
}
});
return promise;
}
}
`
This is the provider for beacon monitor.In some other pages I am triggering the method initialize to register beacon and start monitoring the beacons.Using events publish I am getting the beacon details when ever I entered into region in other pages.

Related

expo-task-manager with expo-location error

Please provide the following:
SDK Version: "expo": "^45.0.0",
IOS Emulator (atm) but all normally.
expo-task-manager & expo-location
Hello, We are setting up background location tracking in our App...
I am defining my background location task before is loaded
BackgroundLocation.ts
export const LOCATION_TASK_NAME = 'background-location-task'
function init() {
TaskManager.defineTask(LOCATION_TASK_NAME, _execute)
setTimeout(() => {
TaskManager.getRegisteredTasksAsync().then((tasks) =>
console.log('registered tasks', tasks) // logs empty array
)
}, 5000)
}
export default { init }
App.tsx
import BackgroundLocation from '../../......'
BackgroundLocation.init()
export default App() { ... }
Now in the App component hiararchy i have a Component called <LocationTracker />
import { LOCATION_TASK_NAME } from '../../BackgroundLocation'
...
React.useEffect(() => {
async function handleLocation() {
try {
if (backgroundLocationServicesEnabled) {
await Location.startLocationUpdatesAsync(
LOCATION_TASK_NAME,
{
accuracy: Location.Accuracy.Balanced,
distanceInterval: 20,
}
)
} else {
await Location.stopLocationUpdatesAsync(
LOCATION_TASK_NAME
).catch((e) => {
console.error(
'error calling stopLocationUpdatesAsync',
e
)
})
}
} catch (e) {
console.error('error in handleLocation', e)
}
}
handleLocation().then(() => {})
}, [backgroundServicesEnabled])
Background location is not enabled in my case so the error being fired is
error calling stopLocationUpdatesAsync, [Error: Task 'background-location-task' not found for app ID 'mainApplication'.]
at components/LocationTracker.tsx:70:37 in Location.stopLocationUpdatesAsync._catch$argument_0
its this part
[Error: Task 'background-location-task' not found for app ID 'mainApplication'.]
that is causing me confusion because i'm registering that task ID right at the begining of the app.
OP over here https://forums.expo.dev/t/expo-task-manager-with-expo-location-error/68515

Lambda failed silently without any logs, when updating a record from dynamodb table

I am using a lambda function for dynamo streaming after a record is inserted.
However, after the dynamoDB.update call, it seems the lambda is dead, and there are no other logs printed. Can anyone help?
Here is my javascript code:
/* Amplify Params - DO NOT EDIT
API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_ARN
API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_NAME
ENV
REGION
Amplify Params - DO NOT EDIT */
const AWS = require('aws-sdk');
const awsConfig = {
region: process.env.REGION,
endpoint:
process.env.DYNAMODB_ENDPOINT ||
`https://dynamodb.${process.env.REGION}.amazonaws.com`
};
const dynamoDB = new AWS.DynamoDB.DocumentClient(awsConfig);
async function handleNewEmployeeInfo(dynamoId, employeeId) {
console.log(
`[handleNewEmployeeInfo] begin. dynamoId(${dynamoId}) employeeId(${employeeId})`
);
try {
const employeeName = "TestString";
// this log is working
console.log(
'try to update table:',
process.env.API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_NAME,
dynamoId,
employeeName
);
// something wrong with the update
await dynamoDB
.update({
TableName: process.env.API_SCHOLARGRAPH_EMPLOYEEINFOTABLE_NAME,
Key: {
id: dynamoId
},
UpdateExpression: `set employeeName = :employeeName`,
ExpressionAttributeValues: {
':employeeName': employeeName
}
})
.promise()
.then((data) => console.log(data.Attributes))
.catch(console.error);
} catch (error) {
// NOT working
console.log('[ERROR]:', error);
}
// NOT working
console.log('[FINISH] call end');
}
async function handleEventRecord(record) {
console.log(record.eventID);
console.log(record.eventName);
try {
// after EmployeeInfo is created by the admin
if (record.eventName === 'INSERT') {
const arn = record.eventSourceARN;
console.log(`[INSERT][${arn}]: ${JSON.stringify(record)}`);
if (arn.includes(':table/EmployeeInfo')) {
const dynamoId = record.dynamodb.NewImage.id['S'];
const employeeId = record.dynamodb.NewImage.employeeId['S'];
await handleNewEmployeeInfo(dynamoId, employeeId);
}
}
} catch (error) {
console.log('[ERROR]:', error);
}
}
/**
* #type {import('#types/aws-lambda').APIGatewayProxyHandler}
*/
exports.handler = async (event) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
event.Records.forEach(async (record) => {
await handleEventRecord(record);
});
return Promise.resolve('Successfully processed DynamoDB record');
};
After I remove the update logic, the following log works fine. So I am pretty sure it is the update line has the problem.

AWS Lamda/API Gateway Every Second Call Results in Internal Server Error

I'm need to 'Nodejs' and 'Serveless'. I've created a 'Serverless' API and deployed to AWS. Everything works as expected. The issue i have and i can't seem to find anything about this is, on every second call i get an internal server error. the first call is, returns data as expected.
I've deployed to AWS only in a dev stage. I'm wondering if there is some configuration i'm missing or something?
If you need the 'Serverless' config or code examples i can provide.
Thanks.
ANSWER
I think there was an issue with the DB call not returning data in time for the callback, therefore i was finding inconsistent results.
So basically what i did was create a Database class returning Promises like so...
'use strict';
const mysql = require('mysql');
/**
* Database
*/
class Database {
constructor(config) {
if (!this.dbConnection) {
console.log('connect to DB');
this.dbConnection = mysql.createPool(config);
this.dbConnection.on('connection', (connection) => {
console.info('Connection Made!');
});
}
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.dbConnection.query(sql, args, (err, rows) => {
if (err) {
reject(err);
}
resolve(rows);
})
});
}
close() {
return new Promise((resolve, reject) => {
this.dbConnection.end((error) => {
if (error) {
reject(error);
}
resolve();
});
});
}
}
module.exports = Database;
So when i made my query there was a result ready for the callback.
'use strict';
const Database = require('./lib/Database');
const {successResponse, errorResponse} = require('./lib/response');
const CategoryResource = require('./resource/Category');
module.exports.list = (event, context, callback) => {
let sql = 'SELECT * FROM categories AS c WHERE c.company_id = ? AND c.parent_id IS NULL AND c.status = 1 LIMIT ?, ?;';
const company = parseInt(event.queryStringParameters.company);
let page = 1;
let limit = 20;
if (null != event.queryStringParameters) {
if ('page' in event.queryStringParameters) {
page = parseInt(event.queryStringParameters.page);
}
if ('limit' in event.queryStringParameters) {
limit = parseInt(event.queryStringParameters.limit);
}
}
let start = (page - 1) * limit;
if (isNaN(company)) {
callback(null, errorResponse(400, 'Company ID Required', 'Parameter company_id is required.', []));
return;
}
let Category = new Database();
let categoryResource = [];
Category
.query(sql, [company, start, limit])
.then(response => {
Category.close();
response.forEach((category) => {
categoryResource.push(CategoryResource(category));
});
callback(null, successResponse(200, {
"total": response.length,
"perPage": limit,
"currentPage": page,
"data": categoryResource
}));
})
.catch((error) => {
callback(null, errorResponse(error.code, error.sqlMessage, error.sql, {
code: error.errno,
field: error.sqlMessage,
message: error.sqlMessage
}));
Category.close();
});
};
I hope that helps anyone that may have run into the same issue.
If every other time you get an internal server error, that means your code is syntactically sound but has some sort of logic error. It's impossible to help without example code, but some of the more common errors I've seen that only sometimes occur can be:
race conditions (if you're doing parallel access of the same array, for example)
array access errors (length+1 instead of length-1, less-than-zero, or your iterators are jumping someplace in memory they shouldn't)
simply mentioning the wrong variable (putting an i instead of a j, for example)
Unfortunately, without specific examples, the best we can offer is wild speculation and personal experience. Have you tried looking at AWS's CloudWatch and what it says about your execution? There should be some errors logged in there too.
I think there was an issue with the DB call not returning data in time for the callback, therefore i was finding inconsistent results.
So basically what i did was create a Database class returning Promises like so...
'use strict';
const mysql = require('mysql');
/**
* Database
*/
class Database {
constructor(config) {
if (!this.dbConnection) {
console.log('connect to DB');
this.dbConnection = mysql.createPool(config);
this.dbConnection.on('connection', (connection) => {
console.info('Connection Made!');
});
}
}
query(sql, args) {
return new Promise((resolve, reject) => {
this.dbConnection.query(sql, args, (err, rows) => {
if (err) {
reject(err);
}
resolve(rows);
})
});
}
close() {
return new Promise((resolve, reject) => {
this.dbConnection.end((error) => {
if (error) {
reject(error);
}
resolve();
});
});
}
}
module.exports = Database;
So when i made my query there was a result ready for the callback.
'use strict';
const Database = require('./lib/Database');
const {successResponse, errorResponse} = require('./lib/response');
const CategoryResource = require('./resource/Category');
module.exports.list = (event, context, callback) => {
let sql = 'SELECT * FROM categories AS c WHERE c.company_id = ? AND c.parent_id IS NULL AND c.status = 1 LIMIT ?, ?;';
const company = parseInt(event.queryStringParameters.company);
let page = 1;
let limit = 20;
if (null != event.queryStringParameters) {
if ('page' in event.queryStringParameters) {
page = parseInt(event.queryStringParameters.page);
}
if ('limit' in event.queryStringParameters) {
limit = parseInt(event.queryStringParameters.limit);
}
}
let start = (page - 1) * limit;
if (isNaN(company)) {
callback(null, errorResponse(400, 'Company ID Required', 'Parameter company_id is required.', []));
return;
}
let Category = new Database();
let categoryResource = [];
Category
.query(sql, [company, start, limit])
.then(response => {
Category.close();
response.forEach((category) => {
categoryResource.push(CategoryResource(category));
});
callback(null, successResponse(200, {
"total": response.length,
"perPage": limit,
"currentPage": page,
"data": categoryResource
}));
})
.catch((error) => {
callback(null, errorResponse(error.code, error.sqlMessage, error.sql, {
code: error.errno,
field: error.sqlMessage,
message: error.sqlMessage
}));
Category.close();
});
};
I hope that helps anyone that may have run into the same issue.

Delay in retrieving data from Ionic 2 storage

Before I launches the app I will check with local storage if any user data available, If yes I will navigation to Home page else Login page.
Here I'm unable to retrieve stored data, Any inputs please...
Currently using Ionic 2 SQlite plugin.
Note: In browser it's working fine but on Android device it's not working.
app.component.ts : checking user data
loadUser() {
this.userSettings.getUser().then(user => {
this.userObj = JSON.stringify(user);
if (user) {
console.log('App : ', this.userObj);
this.nav.setRoot(HomePage,this.userObj);
} else {
console.log('App : No user data');
this.rootPage = LoginPage;
}
});
}
login.ts : Saving user data
this.userSettings.addUser(
userData.employeeCode,
userData.password,
userData.role
);
user-settings.ts : Storage file in providers
getUser() {
if (this.sql) {
return this.sql.get('user').then(value => value);
} else {
return new Promise(resolve => resolve(this.storage.get('user').then(value => value)));
}
}
addUser(employeeCode, password, role) {
let item = { employeeCode: employeeCode, password: password, role: role };
if (this.sql) {
this.sql.set('user', JSON.stringify(item)).then(data => {
this.events.publish('userObj:changed');
});
} else {
return new Promise(resolve => {
this.storage.set('user', JSON.stringify(item)).then(() => {
this.events.publish('userObj:changed');
resolve();
});
});
}
}
app.module.ts:
providers: [
{ provide: ErrorHandler, useClass: IonicErrorHandler },
AuthService,
SqlStorage,
UserSettings,
Storage
]
Thanks in advance.
Problem solved
After calling the sqlite operation in ngAfterViewInit it's working fine.
ngAfterViewInit() {
this.storage.get('user').then((user: any) => {
if (user) {
this.userCredentials = JSON.parse(user);
this.nav.setRoot(HomePage, this.userCredentials);
}
else {
this.rootPage = LoginPage;
}
});
}
[Source] (https://github.com/driftyco/ionic-conference-app/blob/master/src/pages/account/account.ts)
Cheers :)
As you point out that your code is working in Chrome, but not on your device, you might be calling sqlite before cordova's device.ready() has fired.
In app.component.ts ensure you call this.loadUser() in the following manner: (platform.ready() should already be in the constructor)
platform.ready().then(() => {
this.loadUser();
});

Testing component logic with Angular2 TestComponentBuilder

There are a lot of different approaches to unit test your angular application you can find at the moment. A lot are already outdated and basically there's no real documentation at this point. So im really not sure which approach to use.
It seems a good approach at the moment is to use TestComponentBuilder, but i have some trouble to test parts of my code especially if a function on my component uses an injected service which returns an observable.
For example a basic Login Component with a Authentication Service (which uses a BackendService for the requests).
I leave out the templates here, because i don't want to test them with UnitTests (as far as i understood, TestComponentBuilder is pretty useful for this, but i just want to use a common approach for all my unit tests, and the it seems that TestComponentBuilder is supposed to handle every testable aspect, please correct me if i'm wrong here)
So i got my LoginComponent:
export class LoginComponent {
user:User;
isLoggingIn:boolean;
errorMessage:string;
username:string;
password:string;
constructor(private _authService:AuthService, private _router:Router) {
this._authService.isLoggedIn().subscribe(isLoggedIn => {
if(isLoggedIn) {
this._router.navigateByUrl('/anotherView');
}
});
}
login():any {
this.errorMessage = null;
this.isLoggingIn = true;
this._authService.login(this.username, this.password)
.subscribe(
user => {
this.user = user;
setTimeout(() => {
this._router.navigateByUrl('/anotherView');
}, 2000);
},
errorMessage => {
this.password = '';
this.errorMessage = errorMessage;
this.isLoggingIn = false;
}
);
}
}
My AuthService:
#Injectable()
export class AuthService {
private _user:User;
private _urls:any = {
...
};
constructor( private _backendService:BackendService,
#Inject(APP_CONFIG) private _config:Config,
private _localStorage:LocalstorageService,
private _router:Router) {
this._user = _localStorage.get(LOCALSTORAGE_KEYS.CURRENT_USER);
}
get user():User {
return this._user || this._localStorage.get(LOCALSTORAGE_KEYS.CURRENT_USER);
}
set user(user:User) {
this._user = user;
if (user) {
this._localStorage.set(LOCALSTORAGE_KEYS.CURRENT_USER, user);
} else {
this._localStorage.remove(LOCALSTORAGE_KEYS.CURRENT_USER);
}
}
isLoggedIn (): Observable<boolean> {
return this._backendService.get(this._config.apiUrl + this._urls.isLoggedIn)
.map(response => {
return !(!response || !response.IsUserAuthenticated);
});
}
login (username:string, password:string): Observable<User> {
let body = JSON.stringify({username, password});
return this._backendService.post(this._config.apiUrl + this._urls.login, body)
.map(() => {
this.user = new User(username);
return this.user;
});
}
logout ():Observable<any> {
return this._backendService.get(this._config.apiUrl + this._urls.logout)
.map(() => {
this.user = null;
this._router.navigateByUrl('/login');
return true;
});
}
}
and finally my BackendService:
#Injectable()
export class BackendService {
_lastErrorCode:number;
private _errorCodes = {
...
};
constructor( private _http:Http, private _router:Router) {
}
post(url:string, body:any):Observable<any> {
let options = new RequestOptions();
this._lastErrorCode = 0;
return this._http.post(url, body, options)
.map((response:any) => {
...
return body.Data;
})
.catch(this._handleError);
}
...
private _handleError(error:any) {
...
let errMsg = error.message || 'Server error';
return Observable.throw(errMsg);
}
}
Now i want to test the basic logic of logging in, one time it should fail and i expect an error message (which is thrown by my BackendService in its handleError function) and in another test it should login and set my User-object
This is my current approach for my Login.component.spec:
Updated: added fakeAsync like suggested in Günters answer.
export function main() {
describe('Login', () => {
beforeEachProviders(() => [
ROUTER_FAKE_PROVIDERS
]);
it('should try and fail logging in',
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
tcb.createAsync(TestComponent)
.then((fixture: any) => {
tick();
fixture.detectChanges();
let loginInstance = fixture.debugElement.children[0].componentInstance;
expect(loginInstance.errorMessage).toBeUndefined();
loginInstance.login();
tick();
fixture.detectChanges();
expect(loginInstance.isLoggingIn).toBe(true);
fixture.detectChanges();
expect(loginInstance.isLoggingIn).toBe(false);
expect(loginInstance.errorMessage.length).toBeGreaterThan(0);
});
})));
it('should log in',
inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => {
tcb.createAsync(TestComponent)
.then((fixture: any) => {
tick();
fixture.detectChanges();
let loginInstance = fixture.debugElement.children[0].componentInstance;
loginInstance.username = 'abc';
loginInstance.password = '123';
loginInstance.login();
tick();
fixture.detectChanges();
expect(loginInstance.isLoggingIn).toBe(true);
expect(loginInstance.user).toEqual(jasmine.any(User));
});
})));
});
}
#Component({
selector: 'test-cmp',
template: `<my-login></my-login>`,
directives: [LoginComponent],
providers: [
HTTP_PROVIDERS,
provide(APP_CONFIG, {useValue: CONFIG}),
LocalstorageService,
BackendService,
AuthService,
BaseRequestOptions,
MockBackend,
provide(Http, {
useFactory: function(backend:ConnectionBackend, defaultOptions:BaseRequestOptions) {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
})
]
})
class TestComponent {
}
There are several issues with this test.
ERROR: 'Unhandled Promise rejection:', 'Cannot read property 'length' of null' I get this for the test of `loginInstance.errorMessage.length
Expected true to be false. in the first test after i called login
Expected undefined to equal <jasmine.any(User)>. in the second test after it should have logged in.
Any hints how to solve this? Am i using a wrong approach here?
Any help would be really appreciated (and im sorry for the wall of text / code ;) )
As you can't know when this._authService.login(this.username, this.password).subscribe( ... ) is actually called you can't just continue the test synchronically and assume the subscribe callback has happened. In fact it can't yet have happened because sync code (your test) is executed to the end first.
You can add artificial delays (ugly and flaky)
You can provide observables or promises in your component that emit/resolve when something you want to test is actually done (ugly because test code added to production code)
I guess the best option is using fakeAsync which provides more control about async execution during tests (I haven't used it myself)
As far as I know there will come support in Angular tests using zone, to wait for the async queue to become empty before the test continues (I don't know details about this neither).