@ -14,7 +14,7 @@
/// limitations under the License.
///
import { Component , forwardRef , OnDestroy } from '@angular/core' ;
import { Component , forwardRef , Input , OnDestroy } from '@angular/core' ;
import {
ControlValueAccessor ,
UntypedFormBuilder ,
@ -32,9 +32,12 @@ import {
Lwm2mSecurityType ,
Lwm2mSecurityTypeTranslationMap
} from '@shared/models/lwm2m-security-config.models' ;
import { Subject } from 'rxjs' ;
import { takeUntil } from 'rxjs/operators' ;
import { Subject , throwError , timeout , catchError , of } from 'rxjs' ;
import { map , takeUntil } from 'rxjs/operators' ;
import { isDefinedAndNotNull } from '@core/utils' ;
import { HttpClient } from '@angular/common/http' ;
import { DeviceId } from "@shared/models/id/device-id" ;
import { Observable } from "rxjs/internal/Observable" ;
@Component ( {
selector : 'tb-device-credentials-lwm2m' ,
@ -65,7 +68,11 @@ export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Va
private destroy $ = new Subject < void > ( ) ;
private propagateChange = ( v : any ) = > { } ;
constructor ( private fb : UntypedFormBuilder ) {
@Input ( )
deviceId : DeviceId ;
constructor ( private fb : UntypedFormBuilder ,
private http : HttpClient ) {
this . lwm2mConfigFormGroup = this . initLwm2mConfigForm ( ) ;
}
@ -101,6 +108,119 @@ export class DeviceCredentialsLwm2mComponent implements ControlValueAccessor, Va
this . destroy $ . complete ( ) ;
}
/ * *
* AbstractRpcController - > rpcController
* - API
* "/api/plugins/rpc/twoway/${this.deviceId.id}"
* - DiscoveryAll
* requestBody = "{\"method\":\"DiscoverAll\"}" ;
* - "Registration Update Trigger" ,
* requestBody = "{\"method\": \"Execute\", \"params\": {\"id\": \"/1_1.2/0/8\" } }
* - "Bootstrap-Request Trigger"
* requestBody = "{\"method\": \"Execute\", \"params\": {\"id\": \"/1_1.2/0/9\" } }
* /
public rebootDevice ( isBootstrapServer : boolean ) : void {
const urlApi = ` /api/plugins/rpc/twoway/ ${ this . deviceId . id } ` ;
// DiscoveryAll}
this . http . post ( urlApi , { method : "DiscoverAll" } )
. pipe (
timeout ( 10000 ) , // 10 sec
catchError ( err = > {
console . error ( 'DiscoverAll timeout or error' , err ) ;
return throwError ( ( ) = > err ) ;
} )
)
. subscribe ( {
next : ( response : any ) = > {
console . log ( 'success: Discovery' ) ;
console . log ( response ) ;
// result = 'CONTENT'
if ( response . result && response . result . toUpperCase ( ) === 'CONTENT' ) {
const verId = this . getVerId ( response . value ) ;
console . log ( "ObjectId=1 ver:" , verId ) ;
const resourceId = isBootstrapServer ? 9 : 8 ;
const resourcePath = ` /1_ ${ verId } /0/ ${ resourceId } ` ;
// first rebootTrigger
this . rebootTrigger ( resourcePath , urlApi ) . subscribe ( first = > {
if ( first . result === 'CHANGED' ) {
console . log ( 'Reboot success first' ) ;
}
else if ( first . result === 'BAD_REQUEST' && first . newVersionId && first . newVersionId !== verId ) {
// Retry with new version
const correctedPath = ` /1_ ${ first . newVersionId } /0/ ${ resourceId } ` ;
console . log ( ` Retrying with version ${ first . newVersionId } ` ) ;
this . rebootTrigger ( correctedPath , urlApi ) . subscribe ( second = > {
if ( second . result === 'CHANGED' ) {
console . log ( 'Success reboot after retry' ) ;
} else {
console . error ( ` error1: Reboot second failed: ${ second . toString ( ) } ` ) ;
}
} ) ;
} else {
console . error ( ` error2: Reboot first failed: ${ first . toString ( ) } ` ) ;
}
} ) ;
}
else {
console . error ( ` error3: Bad registration device with id = ${ this . deviceId . id } ❗ RPC result is not CONTENT ` ) ;
}
} ,
error : ( e ) = > {
console . error ( ` error4: Bad registration device with id = ${ this . deviceId . id } ${ e . toString ( ) } ` ) ;
return throwError ( ( ) = > e ) ;
} ,
complete : ( ) = > {
console . log ( 'Discovery stream complete' ) ; }
} ) ;
}
private getVerId ( value : string ) : string {
const verDef = '1.1' ;
try {
const arr = JSON . parse ( value ) ;
if ( ! Array . isArray ( arr ) ) return verDef ;
const obj1 = arr . find ( ( s : string ) = > s . startsWith ( '</1' ) ) ;
const match = obj1 ? . match ( /ver="?([\d.]+)"?/ ) ;
return match ? match [ 1 ] : verDef ;
} catch {
return verDef ;
}
}
private rebootTrigger ( resourcePath : string , urlApi : string ) : Observable < { result : string ; newVersionId? : string | null } > {
console . log ( ` Sending reboot command to ${ resourcePath } ` ) ;
return this . http . post < any > ( urlApi , {
method : 'Execute' ,
params : { id : resourcePath }
} ) . pipe (
timeout ( 10000 ) ,
map ( res = > {
console . log ( ` Reboot for ${ resourcePath } ` ) ;
console . log ( res ) ;
if ( res ? . result ? . toUpperCase ( ) === 'CHANGED' ) {
return { result : 'CHANGED' } ;
}
if ( res ? . result ? . toUpperCase ( ) === 'BAD_REQUEST' && res ? . error ) {
const match = ( res . error as string ) . match ( /version[:=]\s*([\d.]+)/i ) ;
const newVersionId = match ? match [ 1 ] : null ;
console . warn ( ` BAD_REQUEST: suggested version ${ newVersionId ? ? 'unknown' } ` ) ;
return { result : 'BAD_REQUEST' , newVersionId } ;
}
return { result : 'ERROR' } ;
} ) ,
catchError ( err = > {
console . error ( ` Execute error5 for ${ resourcePath } : ` , err ) ;
return of ( { result : 'ERROR' } ) ;
} )
) ;
}
private initClientSecurityConfig ( config : Lwm2mSecurityConfigModels ) : void {
this . lwm2mConfigFormGroup . patchValue ( config , { emitEvent : false } ) ;
this . securityConfigClientUpdateValidators ( config . client . securityConfigClientMode ) ;