diff --git a/src/app/app-initNetwork.service.ts b/src/app/app-initNetwork.service.ts index c2bf0891..cb78cab8 100644 --- a/src/app/app-initNetwork.service.ts +++ b/src/app/app-initNetwork.service.ts @@ -14,7 +14,6 @@ import { IConnectionConfig } from "./app-settings.interfaces"; import { SignalKConnectionService } from "./signalk-connection.service"; import { AuthenticationService } from './authentication.service'; import { DefaultConnectionConfig } from './config.blank.const'; -import { UUID } from './uuid'; const configFileVersion = 9; // used to change the Signal K configuration storage file name (ie. 9.0.0.json) that contains the configuration definitions. Applies only to remote storage. @@ -40,7 +39,7 @@ export class AppNetworkInitService { try { if (this.config?.signalKUrl !== undefined && this.config.signalKUrl !== null) { - await this.connection.resetSignalK({url: this.config.signalKUrl, new: false}); + await this.connection.resetSignalK({url: this.config.signalKUrl, new: false}, this.config.proxyEnabled); } if (!this.isLoggedIn && this.config?.signalKUrl && this.config?.useSharedConfig && this.config?.loginName && this.config?.loginPassword) { @@ -85,7 +84,6 @@ export class AppNetworkInitService { if (!this.config) { this.config = DefaultConnectionConfig; - this.config.kipUUID = UUID.create(); this.config.signalKUrl = window.location.origin; console.log(`[AppInit Network Service] Connection Configuration not found. Creating configuration using Auto-Discovery URL: ${this.config.signalKUrl}`); localStorage.setItem('connectionConfig', JSON.stringify(this.config)); diff --git a/src/app/app-settings.interfaces.ts b/src/app/app-settings.interfaces.ts index 01bcd9c8..f9d25796 100644 --- a/src/app/app-settings.interfaces.ts +++ b/src/app/app-settings.interfaces.ts @@ -7,6 +7,7 @@ export interface IConnectionConfig { configVersion: number; kipUUID: string; signalKUrl: string; + proxyEnabled: boolean; useDeviceToken: boolean; loginName: string; loginPassword: string; diff --git a/src/app/app-settings.service.ts b/src/app/app-settings.service.ts index 2607c5db..8fb7496b 100644 --- a/src/app/app-settings.service.ts +++ b/src/app/app-settings.service.ts @@ -6,6 +6,7 @@ import { IDataSet } from './data-set.service'; import { ISplitSet } from './layout-splits.service'; import { IWidget } from './widgets-interface'; import { IUnitDefaults } from './units.service'; +import { UUID } from './uuid'; import { IConfig, IAppConfig, IConnectionConfig, IThemeConfig, IWidgetConfig, ILayoutConfig, IZonesConfig, INotificationConfig, IZone, ISignalKUrl } from "./app-settings.interfaces"; import { DefaultAppConfig, DefaultConnectionConfig as DefaultConnectionConfig, DefaultWidgetConfig, DefaultLayoutConfig, DefaultThemeConfig, DefaultZonesConfig } from './config.blank.const'; @@ -30,6 +31,7 @@ export class AppSettingsService { private kipKNotificationConfig: BehaviorSubject = new BehaviorSubject(DefaultNotificationConfig); private autoNightMode: BehaviorSubject = new BehaviorSubject(false); + public proxyEnabled: boolean = false; private useDeviceToken: boolean = false; private loginName: string; private loginPassword: string; @@ -39,12 +41,11 @@ export class AppSettingsService { private kipUUID: string; public signalkUrl: ISignalKUrl; - widgets: Array; - splitSets: ISplitSet[] = []; - rootSplits: string[] = []; - dataSets: IDataSet[] = []; - zones: BehaviorSubject> = new BehaviorSubject>([]); - root + private widgets: Array; + private splitSets: ISplitSet[] = []; + private rootSplits: string[] = []; + private dataSets: IDataSet[] = []; + private zones: BehaviorSubject> = new BehaviorSubject>([]); constructor( private storage: StorageService @@ -96,6 +97,7 @@ export class AppSettingsService { this.resetConnection(); } else { this.signalkUrl = {url: config.signalKUrl, new: false}; + this.proxyEnabled = config.proxyEnabled; this.useDeviceToken = config.useDeviceToken; this.loginName = config.loginName; this.loginPassword = config.loginPassword; @@ -176,6 +178,7 @@ export class AppSettingsService { this.replaceConfig('appConfig', upgradedConfig, true); } } + /** * Get configuration from local browser storage rather then in * memory running config. @@ -277,6 +280,7 @@ public loadConfigFromLocalStorage(type: string) { this.loginName = value.loginName; this.loginPassword = value.loginPassword; this.useSharedConfig = value.useSharedConfig; + this.proxyEnabled = value.proxyEnabled; this.signalkUrl.url = value.signalKUrl; if (!value.useSharedConfig) { this.useDeviceToken = true; @@ -536,6 +540,7 @@ public loadConfigFromLocalStorage(type: string) { configVersion: configVersion, kipUUID: this.kipUUID, signalKUrl: this.signalkUrl.url, + proxyEnabled: this.proxyEnabled, useDeviceToken: this.useDeviceToken, loginName: this.loginName, loginPassword: this.loginPassword, @@ -617,7 +622,7 @@ public loadConfigFromLocalStorage(type: string) { private getDefaultConnectionConfig(): IConnectionConfig { let config: IConnectionConfig = DefaultConnectionConfig; - config.kipUUID = this.newUuid(); + config.kipUUID = UUID.create(); config.signalKUrl = window.location.origin; localStorage.setItem('connectionConfig', JSON.stringify(config)); return config; @@ -646,12 +651,4 @@ public loadConfigFromLocalStorage(type: string) { localStorage.setItem("zonesConfig", JSON.stringify(config)); return config; } - - private newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); - } - } diff --git a/src/app/config.blank.const.ts b/src/app/config.blank.const.ts index 0c507091..c68f732e 100644 --- a/src/app/config.blank.const.ts +++ b/src/app/config.blank.const.ts @@ -1,6 +1,7 @@ import { IConfig ,IAppConfig, IConnectionConfig, ILayoutConfig, IThemeConfig, IWidgetConfig, IZonesConfig } from "./app-settings.interfaces" import { DefaultNotificationConfig } from './config.blank.notification.const'; import { DefaultUnitsConfig } from "./config.blank.units.const"; +import { UUID } from "./uuid"; export const DefaultAppConfig: IAppConfig = { "configVersion": 9, @@ -57,18 +58,12 @@ export const defaultConfig: IConfig = { export const DefaultConnectionConfig: IConnectionConfig = { "configVersion": 9, - "kipUUID": newUuid(), + "kipUUID": UUID.create(), "signalKUrl": null, // get's overwritten with host at getDefaultConnectionConfig() + "proxyEnabled": false, "useDeviceToken": false, "loginName": null, "loginPassword": null, "useSharedConfig": false, "sharedConfigName": "default" } - -function newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} diff --git a/src/app/config.demo.const.ts b/src/app/config.demo.const.ts index e88f2efb..5563bf4e 100644 --- a/src/app/config.demo.const.ts +++ b/src/app/config.demo.const.ts @@ -1,4 +1,5 @@ import { IConfig, IAppConfig, IConnectionConfig, IThemeConfig, ILayoutConfig, IWidgetConfig, IZonesConfig } from "./app-settings.interfaces" +import { UUID } from "./uuid" // Demo Mode config settings file export const DemoAppConfig: IAppConfig = { @@ -420,18 +421,12 @@ export const DemoConfig: IConfig = { export const DemoConnectionConfig: IConnectionConfig = { "configVersion": 9, - "kipUUID": newUuid(), + "kipUUID": UUID.create(), "signalKUrl": "https://demo.signalk.org", + "proxyEnabled": false, "useDeviceToken": false, "loginName": null, "loginPassword": null, "useSharedConfig": false, "sharedConfigName": "default" } - -function newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); -} diff --git a/src/app/data-set.service.ts b/src/app/data-set.service.ts index 179ebe62..2cad9291 100644 --- a/src/app/data-set.service.ts +++ b/src/app/data-set.service.ts @@ -2,6 +2,7 @@ import { Injectable, NgZone } from '@angular/core'; import { Subscription, BehaviorSubject, sampleTime, pipe, UnaryFunction, filter, OperatorFunction, Observable, interval } from 'rxjs'; import { AppSettingsService } from './app-settings.service'; import { SignalKService } from './signalk.service'; +import { UUID } from'./uuid' export interface dataPoint { @@ -70,13 +71,6 @@ export class DataSetService { } } - private newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); - } - public subscribeDataSet(uuid, dataSetUuid) { //see if already subscribed, if yes return that... let registerIndex = this.dataSetRegister.findIndex(registration => (registration.uuid == uuid) && (registration.dataSetUuid == dataSetUuid)); @@ -173,7 +167,7 @@ export class DataSetService { } public addDataSet(path: string, source: string, updateTimer: number, dataPoints: number ) { - let uuid = this.newUuid(); + let uuid = UUID.create(); let newSub: IDataSet = { uuid: uuid, diff --git a/src/app/layout-splits.service.ts b/src/app/layout-splits.service.ts index 8e59a196..42faa42c 100644 --- a/src/app/layout-splits.service.ts +++ b/src/app/layout-splits.service.ts @@ -4,6 +4,7 @@ import { Router } from '@angular/router'; import { AppSettingsService } from './app-settings.service'; import { WidgetManagerService } from './widget-manager.service'; +import { UUID } from './uuid' interface ISplitArea { @@ -45,13 +46,6 @@ export class LayoutSplitsService { this.rootUUIDs = this.AppSettingsService.getRootSplits(); } - private newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); - } - getActiveRootSub() { return this.activeRoot.asObservable(); } @@ -101,7 +95,7 @@ export class LayoutSplitsService { //should only ever be called when changing directions. widgetUUID of area we're splitting // becomes first area of new split newSplit(parentUUID: string, direction: string, widget1UUID: string, widget2UUID) { - let uuid = this.newUuid(); + let uuid = UUID.create(); let newSplit: ISplitSet = { uuid: uuid, parentUUID: parentUUID, @@ -126,7 +120,7 @@ export class LayoutSplitsService { newRootSplit() { //create new root split - let uuid = this.newUuid(); + let uuid = UUID.create(); let newWidget = this.WidgetManagerService.newWidget(); let newRootSplit: ISplitSet = { uuid: uuid, diff --git a/src/app/settings/signalk/signalk.component.html b/src/app/settings/signalk/signalk.component.html index 5ab2984d..07ba94db 100644 --- a/src/app/settings/signalk/signalk.component.html +++ b/src/app/settings/signalk/signalk.component.html @@ -10,6 +10,10 @@

Connection


+ Signal K server is behind a Proxy +
+
+
Signal K Authentication @@ -18,6 +22,7 @@

Connection

+
diff --git a/src/app/settings/signalk/signalk.component.ts b/src/app/settings/signalk/signalk.component.ts index 7bcf4752..50314139 100644 --- a/src/app/settings/signalk/signalk.component.ts +++ b/src/app/settings/signalk/signalk.component.ts @@ -14,6 +14,7 @@ import { NotificationsService } from '../../notifications.service'; import { ModalUserCredentialComponent } from '../../modal-user-credential/modal-user-credential.component'; import { HttpErrorResponse } from '@angular/common/http'; import { compare } from 'compare-versions'; +import { MatCheckboxChange } from '@angular/material/checkbox'; @Component({ @@ -32,6 +33,7 @@ export class SettingsSignalkComponent implements OnInit { authToken: IAuthorizationToken; isLoggedInSub: Subscription; isLoggedIn: boolean; + public proxyEnabled: boolean = false; endpointServiceStatus: IEndpointStatus; skEndpointServiceStatusSub: Subscription; @@ -136,7 +138,7 @@ export class SettingsSignalkComponent implements OnInit { return; } - if (this.connectionConfig.signalKUrl != this.appSettingsService.signalkUrl.url) { + if ((this.connectionConfig.signalKUrl !== this.appSettingsService.signalkUrl.url) || (this.connectionConfig.proxyEnabled !== this.appSettingsService.proxyEnabled )) { this.appSettingsService.setConnectionConfig(this.connectionConfig); if (this.connectionConfig.useSharedConfig) { diff --git a/src/app/settings/zones/zones.component.ts b/src/app/settings/zones/zones.component.ts index 223bcbdc..792c8047 100644 --- a/src/app/settings/zones/zones.component.ts +++ b/src/app/settings/zones/zones.component.ts @@ -9,6 +9,7 @@ import { MatSort } from '@angular/material/sort'; import { AppSettingsService } from '../../app-settings.service'; import { IPathMetaData } from "../../app-interfaces"; import { IZone } from "../../app-settings.interfaces"; +import { UUID } from './../../uuid'; @Component({ selector: 'settings-zones', @@ -83,7 +84,7 @@ export class SettingsZonesComponent implements OnInit, AfterViewInit { if (zone.uuid) { this.editZone(zone); } else { - zone.uuid = this.newUuid(); + zone.uuid = UUID.create(); this.addZone(zone); } } @@ -117,17 +118,10 @@ export class SettingsZonesComponent implements OnInit, AfterViewInit { this.appSettingsService.saveZones(zones); } } - - private newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); - } } -// Add zone compoment +// Add zone component @Component({ selector: 'dialog-new-zone', templateUrl: 'new-zone.modal.html', @@ -179,7 +173,7 @@ export class DialogNewZone { } -// Edit zone compoment +// Edit zone component @Component({ selector: 'dialog-edit-zone', templateUrl: 'edit-zone.modal.html', diff --git a/src/app/signalk-connection.service.ts b/src/app/signalk-connection.service.ts index b0321bf4..ad35b129 100644 --- a/src/app/signalk-connection.service.ts +++ b/src/app/signalk-connection.service.ts @@ -75,7 +75,7 @@ export class SignalKConnectionService { * @return {*} {Promise} * @memberof SignalKConnectionService */ - public async resetSignalK(skUrl: ISignalKUrl): Promise { + public async resetSignalK(skUrl: ISignalKUrl, proxyEnabled?: boolean): Promise { if (skUrl.url === null) { console.log("[Connection Service] Connection reset called with null or empty URL value"); return; @@ -98,11 +98,26 @@ export class SignalKConnectionService { console.log("[Connection Service] Connecting to: " + this.signalKURL.url); const endpointResponse = await lastValueFrom(this.http.get(fullURL, {observe: 'response'})); - console.debug("[Connection Service] SignalK HTTP Endpoints retrieved"); + console.debug("[Connection Service] Signal K HTTP Endpoints retrieved"); this.serverVersion$.next(endpointResponse.body.server.version); - this.serverServiceEndpoints.httpServiceUrl = endpointResponse.body.endpoints.v1["signalk-http"]; - this.serverServiceEndpoints.WsServiceUrl = endpointResponse.body.endpoints.v1["signalk-ws"]; + if (proxyEnabled) { + console.debug("[Connection Service] Proxy Mode Enabled"); + const skHttpUrl = new URL(endpointResponse.body.endpoints.v1["signalk-http"]); + const skWsUrl = new URL(endpointResponse.body.endpoints.v1["signalk-ws"]); + + this.serverServiceEndpoints.httpServiceUrl = window.location.origin + skHttpUrl.pathname; + console.debug("[Connection Service] Proxy HTTP URI: " +this.serverServiceEndpoints.httpServiceUrl); + + this.serverServiceEndpoints.WsServiceUrl = window.location.protocol == 'https:' ? 'wss:' : 'ws:' + window.location.host + skWsUrl.pathname; + console.debug("[Connection Service] Proxy WebSocket URI: " + this.serverServiceEndpoints.WsServiceUrl); + } else { + this.serverServiceEndpoints.httpServiceUrl = endpointResponse.body.endpoints.v1["signalk-http"]; + console.debug("[Connection Service] HTTP URI: " +this.serverServiceEndpoints.httpServiceUrl); + this.serverServiceEndpoints.WsServiceUrl = endpointResponse.body.endpoints.v1["signalk-ws"]; + console.debug("[Connection Service] WebSocket URI: " + this.serverServiceEndpoints.WsServiceUrl); + } + this.serverServiceEndpoints.operation = 2; this.serverServiceEndpoints.message = endpointResponse.status.toString(); this.serverServiceEndpoints.serverDescription = endpointResponse.body.server.id + " " + endpointResponse.body.server.version; diff --git a/src/app/signalk-requests.service.ts b/src/app/signalk-requests.service.ts index 84c5f323..5a53b442 100644 --- a/src/app/signalk-requests.service.ts +++ b/src/app/signalk-requests.service.ts @@ -6,6 +6,7 @@ import { ISignalKDeltaMessage } from './signalk-interfaces'; import { SignalKDeltaService } from './signalk-delta.service'; import { NotificationsService } from './notifications.service'; import { AuthenticationService } from './authentication.service'; +import { UUID } from './uuid' const deltaStatusCodes = { 200: "The request was successfully.", @@ -57,7 +58,7 @@ export class SignalkRequestsService { * The Device authorization is a manual process done on the server. */ public requestDeviceAccessToken() { - let requestId = this.newUuid(); + let requestId = UUID.create(); let deviceTokenRequest = { requestId: requestId, accessRequest: { @@ -96,7 +97,7 @@ export class SignalkRequestsService { * @memberof SignalkRequestsService */ public requestUserLogin(userId: string, userPassword: string): string { - let requestId = this.newUuid(); + let requestId = UUID.create(); let loginRequest = { requestId: requestId, login: { @@ -126,7 +127,7 @@ export class SignalkRequestsService { * @return requestId Identifier for this specific request. Enables Request specific filtering. */ public putRequest(path: string, value: any, widgetUUID: string): string { - let requestId = this.newUuid(); + let requestId = UUID.create(); let noSelfPath = path.replace(/^(self\.)/,""); //no self in path... let selfContext: string = "vessels.self"; // hard coded context. Could be dynamic at some point let message = { @@ -222,11 +223,4 @@ export class SignalkRequestsService { public subscribeRequest(): Observable { return this.requestStatus$.asObservable(); } - - private newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); - return v.toString(16); - }); - } } diff --git a/src/app/utils.spec.ts b/src/app/utils.spec.ts deleted file mode 100644 index fa4f3755..00000000 --- a/src/app/utils.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Uuid } from './uuid'; - -describe('Utils', () => { - it('should create an instance', () => { - expect(new Uuid()).toBeTruthy(); - }); -}); diff --git a/src/app/uuid.ts b/src/app/uuid.ts index 84cdd9bb..508b824b 100644 --- a/src/app/uuid.ts +++ b/src/app/uuid.ts @@ -1,6 +1,6 @@ export class UUID { /** - * Generates a new UUID + * Generates a new UUID using UUID.create() * * @static * @return {*} {string} UUID diff --git a/src/app/widget-manager.service.ts b/src/app/widget-manager.service.ts index 60f43646..92a16ed0 100644 --- a/src/app/widget-manager.service.ts +++ b/src/app/widget-manager.service.ts @@ -5,6 +5,7 @@ import { Injectable } from '@angular/core'; import { AppSettingsService } from './app-settings.service'; import { IWidget } from './widgets-interface'; +import { UUID } from './uuid' @Injectable() export class WidgetManagerService { @@ -17,19 +18,12 @@ export class WidgetManagerService { this.widgets = this.AppSettingsService.getWidgets(); } - private newUuid() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - const r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - } - getWidget(uuid: string) { return this.widgets.find(w => w.uuid == uuid); } newWidget() { - const uuid = this.newUuid(); + const uuid = UUID.create(); this.widgets.push({ uuid: uuid, type: 'WidgetBlank', config: null }); this.saveWidgets(); return uuid;