Browse Source

docker img

main
gsd 4 months ago
parent
commit
f340d9417f
  1. 16
      docker-compose.example.yaml
  2. 10
      ui/Dockerfile
  3. 1
      ui/src/app/auth/AuthInterceptor.ts
  4. 46
      ui/src/app/components/messages/MessageHistory.component.ts
  5. 19
      ui/srv.conf

16
docker-compose.example.yaml

@ -39,4 +39,18 @@ services:
resources:
limits:
cpus: "1"
memory: 1024M
memory: 1024M
meshcenterfrontend:
build:
context: ./ui
dockerfile: Dockerfile
ports:
- 8686:80
depends_on:
- meshcenterbackend
deploy:
resources:
limits:
cpus: "1"
memory: 1024M

10
ui/Dockerfile

@ -0,0 +1,10 @@
FROM node:18-alpine as builder
WORKDIR /build
COPY . .
RUN npm install --reg https://nexus.pblr-nyk.pro/repository/npm/ && \
npm run ng build
FROM nginx:stable-alpine
COPY --from=builder /build/dist/ui /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY srv.conf /etc/nginx/conf.d
CMD ["nginx", "-g", "daemon off;"]

1
ui/src/app/auth/AuthInterceptor.ts

@ -123,6 +123,7 @@ export class AuthInterceptor implements HttpInterceptor {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status === 401 && !this.dialogOpened) {
this.dialogOpened = true;
const ref = this.dialog.open(AuthDialog, {disableClose: true, width:"30%"})
ref.afterClosed().subscribe((res:any) => this.dialogOpened = false)
}

46
ui/src/app/components/messages/MessageHistory.component.ts

@ -1,4 +1,4 @@
import {Component, OnInit} from "@angular/core";
import {Component, OnDestroy, OnInit} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {MessageDTO} from "../../entities/MessageDTO";
import {NodeDTO} from "../../entities/NodeDTO";
@ -11,7 +11,7 @@ import {Subscription} from "rxjs";
<div>
<div style="height: 100%; overflow-y: scroll">
<button [disabled]="!canLoadMoreMessage || loading" mat-button mat-stroked-button style="width: 100%;" (click)="getMessages()">Загрузить еще...</button>
<mat-card *ngFor="let msg of messages" style="margin-top: 4px">
<mat-card [ngStyle]="{'background-color':numToColor(msg.from)}" *ngFor="let msg of messages" style="margin-top: 4px">
<mat-card-subtitle>{{knownNodes[msg.from.toString()] == null ? msg.from : knownNodes[msg.from.toString()].long_name}} | {{msg.ts * 1000 | date: 'HH:mm:ss dd.MM.yyyy'}} | {{msg.hop_start - msg.hop_limit == 0 ? 'напрямую' : (msg.hop_start - msg.hop_limit) + ' хопов'}} | rssi: {{msg.rx_rssi}} snr: {{msg.rx_snr}}</mat-card-subtitle>
<mat-card-content>{{msg.decoded_payload}}</mat-card-content>
</mat-card>
@ -19,7 +19,7 @@ import {Subscription} from "rxjs";
</div>
`
})
export class MessageHistoryComponent implements OnInit {
export class MessageHistoryComponent implements OnInit, OnDestroy {
constructor(private http: HttpClient) {}
loading: boolean = false;
@ -28,20 +28,26 @@ export class MessageHistoryComponent implements OnInit {
offset = 0;
limit = 10;
lastMsgTs = 0;
olderMsgTs = new Date().getTime()/1000;
interval:any = null;
knownNodes:KeyValueMap<NodeDTO> = {}
ngOnInit() {
this.getMessages();
setInterval(() => {
//this.newMessagePooler()
}, 1000)
this.interval = setInterval(() => {
this.newMessagePooler()
}, 5000)
}
ngOnDestroy(): void {
if (this.interval)
clearInterval(this.interval)
}
tryKnownNodes(nums: number[]) {
let notKnownNodes = nums.filter(num => Object.keys(this.knownNodes).indexOf(`${num}`) == -1)
if (notKnownNodes.length == 0) return Subscription.EMPTY;
let params = notKnownNodes.length > 1 ? notKnownNodes.join("&nums=") : `$nums=${notKnownNodes.pop()}`;
let params = notKnownNodes.length > 1 ? "&nums=" + notKnownNodes.join("&nums=") : `?nums=${notKnownNodes.pop()}`;
return this.http.get(`api/nodes?s=1${params}`).subscribe(
(res) => {
(res as NodeDTO[]).forEach(
@ -53,7 +59,7 @@ export class MessageHistoryComponent implements OnInit {
getMessages() {
this.loading = true;
this.http.get(`api/messages?offset=${this.offset}&limit=${this.limit}&after=${this.lastMsgTs}`)
this.http.get(`api/messages?limit=${this.limit}&before=${this.olderMsgTs}`)
.subscribe((res) => {
let new_msgs = res as MessageDTO[]
this.tryKnownNodes(new_msgs.map(msg => msg.from)).add(
@ -62,6 +68,9 @@ export class MessageHistoryComponent implements OnInit {
.sort((m1, m2) => m1.ts - m2.ts);
if (this.messages.length>0) {
if (this.messages[0].ts < this.olderMsgTs)
this.olderMsgTs = this.messages[0].ts;
if (this.messages[this.messages.length-1].ts > this.lastMsgTs)
this.lastMsgTs = this.messages[this.messages.length-1].ts;
}
@ -77,7 +86,7 @@ export class MessageHistoryComponent implements OnInit {
//ЭХ ВОТ БЫ ВЕБСОКЕТ НО МНЕ ЛЕНЬ
newMessagePooler() {
this.http.get(`api/messages?offset=0&limit=10&after=${this.lastMsgTs}`)
this.http.get(`api/messages?limit=10&after=${this.lastMsgTs}&before=2147483647`)//todo 37 year moment
.subscribe((res) => {
let new_msgs = res as MessageDTO[]
this.tryKnownNodes(new_msgs.map(msg => msg.from)).add(
@ -92,4 +101,21 @@ export class MessageHistoryComponent implements OnInit {
)
})
}
numToColor(num:number) {
// Приводим к беззнаковому 32-битному и перемешиваем биты
let n = num >>> 0;
// Мультипликативная хеш-функция с простыми числами
n = (n * 2654435761) >>> 0; // константа из Knuth
n ^= (n >> 16);
n = (n * 0x85EBCA6B) >>> 0;
n ^= (n >> 13);
n = (n * 0xC2B2AE35) >>> 0;
n ^= (n >> 16);
const r = (n >> 16) & 0xFF;
const g = (n >> 8) & 0xFF;
const b = n & 0xFF;
return `rgba(${r}, ${g}, ${b}, 0.2)`
}
}

19
ui/srv.conf

@ -0,0 +1,19 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri /index.html;
}
location /api/ {
proxy_pass http://meshcenterbackend:8680;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Loading…
Cancel
Save