* rework ntp faiure handling and display to user

* uptime in seconds

* change how we handle ntp

---------

Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
Matt Hill
2023-10-26 17:33:57 -06:00
committed by GitHub
parent 9aa08dfb9b
commit af2b2f33c2
21 changed files with 284 additions and 113 deletions

View File

@@ -37,7 +37,7 @@
<p>
Download your server's Root CA and
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-lan"
href="https://docs.start9.com/0.3.5.x/user-manual/getting-started/connecting-lan"
target="_blank"
rel="noreferrer"
style="color: #6866cc; font-weight: bold; text-decoration: none"
@@ -104,7 +104,7 @@
<span style="font-weight: bold">Note:</span>
This address will only work from a Tor-enabled browser.
<a
href="https://docs.start9.com/latest/user-manual/connecting/connecting-tor"
href="https://docs.start9.com/0.3.5.x/user-manual/getting-started/connecting-tor"
target="_blank"
rel="noreferrer"
style="color: #6866cc; font-weight: bold; text-decoration: none"

View File

@@ -53,9 +53,9 @@ export function getErrorMessage(
} else if (e.code === 0) {
message =
'Request Error. Your browser blocked the request. This is usually caused by a corrupt browser cache or an overly aggressive ad blocker. Please clear your browser cache and/or adjust your ad blocker and try again'
link = 'https://docs.start9.com/0.3.5.x/support/common-issues#request-error'
} else if (!e.message) {
message = 'Unknown Error'
link = 'https://docs.start9.com/latest/support/faq'
} else {
message = e.message
}

View File

@@ -39,7 +39,7 @@ export class CAWizardComponent {
instructions() {
this.windowRef.open(
'https://docs.start9.com/0.3.5.x/getting-started/trust-ca/#trust-root-ca',
'https://docs.start9.com/0.3.5.x/user-manual/getting-started/trust-ca/#trust-root-ca',
'_blank',
'noreferrer',
)

View File

@@ -15,7 +15,7 @@
<h2>
For a secure local connection and faster Tor experience,
<a
href="https://docs.start9.com/0.3.5.x/getting-started/connecting-lan"
href="https://docs.start9.com/0.3.5.x/user-manual/getting-started/connecting-lan"
target="_blank"
rel="noreferrer"
>

View File

@@ -4,9 +4,9 @@
<ion-back-button defaultHref="system"></ion-back-button>
</ion-buttons>
<ion-title>Monitor</ion-title>
<ion-title slot="end"
><ion-spinner name="dots" class="fader"></ion-spinner
></ion-title>
<ion-title slot="end">
<ion-spinner name="dots" class="fader"></ion-spinner>
</ion-title>
</ion-toolbar>
</ion-header>
@@ -16,28 +16,51 @@
<div id="metricSection">
<ng-container *ngIf="!loading">
<ion-item-group>
<ion-item-divider>Time</ion-item-divider>
<ion-item>
<ion-label>System Time</ion-label>
<ion-note slot="end" class="metric-note">
<ion-text style="color: white"
>{{ systemTime$ | async | date:'MMMM d, y, h:mm a z':'UTC'
}}</ion-text
>
</ion-note>
<!-- <ion-item-divider>Time</ion-item-divider> -->
<ion-item *ngIf="now$ | async as now; else timeLoading">
<ion-label>
<h1>System Time</h1>
<h2>
<ion-text style="color: white">
<b>{{ now.value | date:'MMMM d, y, h:mm a z':'UTC' }}</b>
</ion-text>
</h2>
<p *ngIf="!now.synced">
<ion-text color="warning">
NTP not synced, time could be wrong
</ion-text>
</p>
</ion-label>
<ion-note slot="end" class="metric-note"></ion-note>
</ion-item>
<ng-template #timeLoading>
<ion-item>
<ion-label>
<h1>System Time</h1>
<p>Loading...</p>
</ion-label>
<ion-note slot="end" class="metric-note"></ion-note>
</ion-item>
</ng-template>
<ion-item>
<ion-label>System Uptime</ion-label>
<ion-note
*ngIf="systemUptime$ | async as uptime"
slot="end"
class="metric-note"
>
<ion-text style="color: white">
<b>{{ uptime.days }}</b> Days, <b>{{ uptime.hours }}</b> Hours,
<b>{{ uptime.minutes }}</b> Minutes
</ion-text>
</ion-note>
<ion-label>
<h1>System Uptime</h1>
<h2>
<ion-text style="color: white">
<ng-container *ngIf="uptime$ | async as uptime">
<b>{{ uptime.days }}</b>
Days,
<b>{{ uptime.hours }}</b>
Hours,
<b>{{ uptime.minutes }}</b>
Minutes,
<b>{{ uptime.seconds }}</b>
Seconds
</ng-container>
</ion-text>
</h2>
</ion-label>
</ion-item>
</ion-item-group>
@@ -50,9 +73,9 @@
>
<ion-label>{{ metric.key }}</ion-label>
<ion-note *ngIf="metric.value" slot="end" class="metric-note">
<ion-text style="color: white"
>{{ metric.value.value }} {{ metric.value.unit }}</ion-text
>
<ion-text style="color: white">
{{ metric.value.value }} {{ metric.value.unit }}
</ion-text>
</ion-note>
</ion-item>
</ion-item-group>

View File

@@ -14,8 +14,8 @@ export class ServerMetricsPage {
going = false
metrics: Metrics = {}
readonly systemTime$ = this.timeService.systemTime$
readonly systemUptime$ = this.timeService.systemUptime$
readonly now$ = this.timeService.now$
readonly uptime$ = this.timeService.uptime$
constructor(
private readonly errToast: ErrorToastService,

View File

@@ -15,7 +15,32 @@
<!-- loaded -->
<ion-item-group *ngIf="server$ | async as server; else loading">
<ion-item *ngIf="isTorHttp" color="warning">
<ion-item
*ngIf="!server['ntp-synced']"
color="warning"
class="ion-margin-bottom"
>
<ion-icon slot="start" name="warning-outline"></ion-icon>
<ion-label>
<h2 style="font-weight: bold">Clock sync failure</h2>
<p style="font-weight: 600">
This will cause connectivity issues. Refer to the StartOS docs to
resolve the issue.
</p>
</ion-label>
<ion-button
slot="end"
color="light"
href="https://docs.start9.com/0.3.5.x/support/common-issues#clock-sync-failure"
target="_blank"
rel="noreferrer"
>
Open Docs
<ion-icon slot="end" name="open-outline"></ion-icon>
</ion-button>
</ion-item>
<ion-item *ngIf="isTorHttp" color="warning" class="ion-margin-bottom">
<ion-icon slot="start" name="warning-outline"></ion-icon>
<ion-label>
<h2 style="font-weight: bold">Http detected</h2>

View File

@@ -42,7 +42,10 @@ export module RR {
export type EchoRes = string
export type GetSystemTimeReq = {} // server.time
export type GetSystemTimeRes = string
export type GetSystemTimeRes = {
now: string
uptime: number // seconds
}
export type GetServerLogsReq = ServerLogsReq // server.logs & server.kernel-logs
export type GetServerLogsRes = LogsRes

View File

@@ -179,7 +179,10 @@ export class MockApiService extends ApiService {
params: RR.GetSystemTimeReq,
): Promise<RR.GetSystemTimeRes> {
await pauseFor(2000)
return new Date().toUTCString()
return {
now: new Date().toUTCString(),
uptime: 1234567,
}
}
async getServerLogs(

View File

@@ -70,7 +70,7 @@ export const mockPatchData: DataModel = {
hostname: 'random-words',
pubkey: 'npub1sg6plzptd64u62a878hep2kev88swjh3tw00gjsfl8f237lmu63q0uf63m',
'ca-fingerprint': 'SHA-256: 63 2B 11 99 44 40 17 DF 37 FC C3 DF 0F 3D 15',
'system-start-time': new Date(new Date().valueOf() - 360042).toUTCString(),
'ntp-synced': false,
zram: false,
platform: 'x86_64-nonfree',
},

View File

@@ -76,7 +76,7 @@ export interface ServerInfo {
hostname: string
pubkey: string
'ca-fingerprint': string
'system-start-time': string
'ntp-synced': boolean
zram: boolean
platform: string
}

View File

@@ -1,54 +1,53 @@
import { Injectable } from '@angular/core'
import {
map,
shareReplay,
startWith,
switchMap,
take,
tap,
} from 'rxjs/operators'
import { map, shareReplay, startWith, switchMap } from 'rxjs/operators'
import { PatchDB } from 'patch-db-client'
import { DataModel } from './patch-db/data-model'
import { ApiService } from './api/embassy-api.service'
import { combineLatest, from, timer } from 'rxjs'
import { combineLatest, from, interval } from 'rxjs'
@Injectable({
providedIn: 'root',
})
export class TimeService {
private readonly startTimeMs$ = this.patch
.watch$('server-info', 'system-start-time')
.pipe(map(startTime => new Date(startTime).valueOf()))
readonly systemTime$ = from(this.apiService.getSystemTime({})).pipe(
switchMap(utcStr => {
const dateObj = new Date(utcStr)
const msRemaining = (60 - dateObj.getSeconds()) * 1000
dateObj.setSeconds(0)
const current = dateObj.valueOf()
return timer(msRemaining, 60000).pipe(
private readonly time$ = from(this.apiService.getSystemTime({})).pipe(
switchMap(({ now, uptime }) => {
const current = new Date(now).valueOf()
return interval(1000).pipe(
map(index => {
const incremented = index + 1
const msToAdd = 60000 * incremented
return current + msToAdd
return {
now: current + 1000 * incremented,
uptime: uptime + incremented,
}
}),
startWith({
now: current,
uptime,
}),
startWith(current),
)
}),
shareReplay({ bufferSize: 1, refCount: true }),
)
readonly systemUptime$ = combineLatest([
this.startTimeMs$,
this.systemTime$,
readonly now$ = combineLatest([
this.time$,
this.patch.watch$('server-info', 'ntp-synced'),
]).pipe(
map(([startTime, currentTime]) => {
const ms = currentTime - startTime
const days = Math.floor(ms / (24 * 60 * 60 * 1000))
const daysms = ms % (24 * 60 * 60 * 1000)
const hours = Math.floor(daysms / (60 * 60 * 1000))
const hoursms = ms % (60 * 60 * 1000)
const minutes = Math.floor(hoursms / (60 * 1000))
return { days, hours, minutes }
map(([time, synced]) => ({
value: time.now,
synced,
})),
)
readonly uptime$ = this.time$.pipe(
map(({ uptime }) => {
const days = Math.floor(uptime / (24 * 60 * 60))
const daysSec = uptime % (24 * 60 * 60)
const hours = Math.floor(daysSec / (60 * 60))
const hoursSec = uptime % (60 * 60)
const minutes = Math.floor(hoursSec / 60)
const seconds = uptime % 60
return { days, hours, minutes, seconds }
}),
)