From 63690b40370b30f5056c3bba37dd46c8764c0926 Mon Sep 17 00:00:00 2001
From: Oleksandr Husak <oleksandr.husak@mailbox.tu-dresden.de>
Date: Mon, 11 Apr 2022 11:20:38 +0200
Subject: [PATCH] validate messages. Type guards for Object, Position

---
 .../chart-timeline.component.ts               | 13 ++++--
 src/app/components/map/map.component.ts       | 24 +++++++----
 src/app/components/table/table.component.ts   | 14 ++++---
 src/app/model/base-model.ts                   | 41 +++++++++++++++++++
 4 files changed, 75 insertions(+), 17 deletions(-)

diff --git a/src/app/components/chart-timeline/chart-timeline.component.ts b/src/app/components/chart-timeline/chart-timeline.component.ts
index 8398863..57cab72 100644
--- a/src/app/components/chart-timeline/chart-timeline.component.ts
+++ b/src/app/components/chart-timeline/chart-timeline.component.ts
@@ -17,7 +17,7 @@ import {
 } from 'ng-apexcharts';
 
 import { MarkerColorMap } from 'src/environments/environment';
-import {NotificationType, Object, PositionUpdate} from 'src/app/model/base-model';
+import {NotificationType, Object, PositionUpdate, validateTypeObject} from 'src/app/model/base-model';
 
 export type ChartOptions = {
   series: ApexAxisChartSeries;
@@ -73,8 +73,15 @@ export class ChartTimelineComponent implements OnInit {
 
 
     this.subsPosition = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => {
-      let upd: PositionUpdate = JSON.parse(message.payload.toString())
-      upd.objects.forEach(obj => this.addNewSeries(obj))
+      try {
+        let upd: PositionUpdate = JSON.parse(message.payload.toString())
+        upd.objects.forEach(obj => {
+          validateTypeObject(obj)
+          this.addNewSeries(obj)
+        });
+      } catch(e) {
+          console.log(e)
+      }
     });
 
   }
diff --git a/src/app/components/map/map.component.ts b/src/app/components/map/map.component.ts
index 185aea6..01c3e68 100644
--- a/src/app/components/map/map.component.ts
+++ b/src/app/components/map/map.component.ts
@@ -6,7 +6,7 @@ import 'leaflet-arrowheads';
 import { IMqttMessage, MqttService } from 'ngx-mqtt';
 
 import { environment, MarkerColorMap } from 'src/environments/environment';
-import {Position, PositionUpdate, RelativePos, WGS84} from 'src/app/model/base-model';
+import {Position, PositionUpdate, RelativePos, WGS84, validateTypePosition, validateTypeObject} from 'src/app/model/base-model';
 
 
 @Component({
@@ -31,9 +31,11 @@ export class MapComponent implements OnInit {
 
     this.subsRoot = this._mqttService.observe('ipos/client/root').subscribe((message: IMqttMessage) => {
       try {
-        this.root = JSON.parse(message.payload.toString())
-        console.log("New root: ", this.root)
-        this.registerPoint("ROOT", {"position": this.root})
+        let root = <Position>JSON.parse(message.payload.toString())
+        validateTypePosition(root)
+        console.log("New root: ", root)
+        this.registerPoint("ROOT", {"position": root})
+        this.root = root
       } catch(e) {
           console.log(e)
       }
@@ -41,8 +43,12 @@ export class MapComponent implements OnInit {
 
     this.subsPosition = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => {
       try {
-        let upd: PositionUpdate = JSON.parse(message.payload.toString())
-        upd.objects.forEach(obj => this.registerPoint(obj.id, obj));
+        let upd: PositionUpdate = <PositionUpdate>JSON.parse(message.payload.toString())
+        
+        upd.objects.forEach(obj => {
+          validateTypeObject(obj)
+          this.registerPoint(obj.id, obj)
+        });
       } catch(e) {
           console.log(e)
       }
@@ -143,10 +149,10 @@ export class MapComponent implements OnInit {
     }
 
     // --- Orientation
-    if (theta && 'x' in point) {
+    if ('x' in point) {
       let orient: RelativePos = {
-        "x": point.x + Math.sin(theta) * 3 ?? 3, 
-        "y": point.y + Math.cos(theta) * 3 ?? 3,
+        "x": point.x + (theta ? Math.sin(theta)*3 : 0), 
+        "y": point.y + (theta ? Math.cos(theta)*3 : 3.5),
         "z": point.z
       }
       let globPointOrient = this.ref2root(orient)
diff --git a/src/app/components/table/table.component.ts b/src/app/components/table/table.component.ts
index 9d71cab..b0b4844 100644
--- a/src/app/components/table/table.component.ts
+++ b/src/app/components/table/table.component.ts
@@ -1,5 +1,5 @@
 import { Component, OnInit, ViewChild } from '@angular/core';
-import {PositionUpdate, ZoneDesc} from 'src/app/model/base-model';
+import {PositionUpdate, validateTypeObject} from 'src/app/model/base-model';
 
 import { IMqttMessage, MqttService } from 'ngx-mqtt';
 import { Subscription } from 'rxjs';
@@ -35,10 +35,14 @@ export class TableComponent implements OnInit {
     // this.testMessages.forEach(upd => this.dataSource.push(...upd.objects))
 
     this.subsPosition = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => {
-      let upd: PositionUpdate = JSON.parse(message.payload.toString())
-      console.log(upd.objects)
-      this.dataSource.push(...upd.objects);
-      this.table?.renderRows();
+      try {
+        let upd: PositionUpdate = JSON.parse(message.payload.toString())
+        upd.objects.forEach(obj => validateTypeObject(obj));
+        this.dataSource.push(...upd.objects);
+        this.table?.renderRows();
+      } catch(e) {
+          console.log(e)
+      }
     });
   }
 
diff --git a/src/app/model/base-model.ts b/src/app/model/base-model.ts
index 17bd669..681dbd7 100644
--- a/src/app/model/base-model.ts
+++ b/src/app/model/base-model.ts
@@ -71,3 +71,44 @@ interface ExtAttribute {
 } 
 
 
+export function validateTypePosition(obj: any) {
+    if (!isPosition(obj)) {
+        throw new TypeError("Object is not Position")  
+    }
+}
+  
+export function validateTypeObject(obj: any) {
+    if (!isObject(obj)) {
+        console.log(obj)
+        throw new TypeError("Unvalid Object: " + Object.keys(obj))  
+    }
+}
+
+
+// --- Type Guards
+
+function isWGS84(obj: any): obj is WGS84 {
+    return Object.prototype.hasOwnProperty.call(obj, "latitude")
+        && Object.prototype.hasOwnProperty.call(obj, "longitude")
+} 
+
+function isRelativePos(obj: any): obj is RelativePos {
+    return Object.prototype.hasOwnProperty.call(obj, "x")
+        && Object.prototype.hasOwnProperty.call(obj, "y")
+} 
+
+export function isPosition(obj: any): obj is Position {
+    return isWGS84(obj.point) || isRelativePos(obj.point)
+    && Object.prototype.hasOwnProperty.call(obj, "refSystemId")
+} 
+
+export function isObject(obj: any): obj is Object {
+    return "id" in obj
+        && "type" in obj
+        && "sensorId" in obj
+        && "sensorType" in obj
+        && "position" in obj
+        && isPosition(obj.position)
+        && "lastPosUpdate" in obj
+        && "zoneDescriptors" in obj
+} 
\ No newline at end of file
-- 
GitLab