27 changed files with 350 additions and 28 deletions
@ -0,0 +1,23 @@ |
|||||
|
export class PlayerProfile { |
||||
|
ban: any|null = null; |
||||
|
gametime: {[srv_name: string]: {[map_name: string]: number}} = {}; |
||||
|
lastplay: {[srv_name: string]: {[map_name: string]: number}} = {}; |
||||
|
permition: any|null = null; |
||||
|
response_time: {[request: string]: number} = {}; |
||||
|
steam_data: any|null = null; |
||||
|
steamids: any|null = null; |
||||
|
play_on: any|null = null; |
||||
|
attached_discords: any[]|null = null; |
||||
|
donates: any[]|null = null; |
||||
|
ban_list: any[]|null = null; |
||||
|
killfeed: any|null = null; |
||||
|
killfeed_current: any = null; |
||||
|
messages: any = null; |
||||
|
reports: any = null; |
||||
|
|
||||
|
static fromData(data:any): PlayerProfile { |
||||
|
const p = new PlayerProfile(); |
||||
|
Object.assign(p, data); |
||||
|
return p; |
||||
|
} |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
export class ProfileRequestData { |
||||
|
static PLAY_ON: ProfileRequestData = new ProfileRequestData("play_on", "Проверка играет ли сейчас"); |
||||
|
static STEAM_DATA: ProfileRequestData = new ProfileRequestData("steam_data", "Данные стима"); |
||||
|
static LAST_PLAY: ProfileRequestData = new ProfileRequestData("lastplay", "Последняя игра"); |
||||
|
static USER_TIME: ProfileRequestData = new ProfileRequestData("usertime", "Количество наигранного времени"); |
||||
|
static PERMITION: ProfileRequestData = new ProfileRequestData("permition", "Получить данные о правах"); |
||||
|
static BAN: ProfileRequestData = new ProfileRequestData("ban", "Получение текущего бана"); |
||||
|
static ATTACHED_DISCORD: ProfileRequestData = new ProfileRequestData("attached_discord", "Привязка к дискорду"); |
||||
|
static DONATES: ProfileRequestData = new ProfileRequestData("donates", "Получения данных о донатах"); |
||||
|
static BAN_LIST: ProfileRequestData = new ProfileRequestData("ban_list", "Получить список банов от пельменя"); |
||||
|
static KILLFEED: ProfileRequestData = new ProfileRequestData("killfeed", "Информация о убийствах, смертях, помощи"); |
||||
|
static REPORTS: ProfileRequestData = new ProfileRequestData("reports", "Информация о количестве репортах"); |
||||
|
static MESSAGES: ProfileRequestData = new ProfileRequestData("messages", "Информация о количестве сообщений"); |
||||
|
|
||||
|
param: string; |
||||
|
description: string; |
||||
|
default: boolean; |
||||
|
|
||||
|
|
||||
|
constructor(request_parameter: string, description_text: string) { |
||||
|
this.param = request_parameter; |
||||
|
this.description = description_text; |
||||
|
this.default = false; |
||||
|
} |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
export interface DockerStats { |
||||
|
cpu: {percent: number}; |
||||
|
io: {input: number, output: number}; |
||||
|
mem: {percent: number, usage: number, limit: number}; |
||||
|
net: {input:number, output: number}; |
||||
|
utime: number; |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
export interface Player { |
||||
|
clz: number|null; |
||||
|
deads: number; |
||||
|
duration_seconds: number; |
||||
|
id: number; |
||||
|
loss: number; |
||||
|
name: string; |
||||
|
ping: number; |
||||
|
pos: number[]; |
||||
|
score: number; |
||||
|
state: string; |
||||
|
steam: any; |
||||
|
steam2: string; |
||||
|
team: number; |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
import {DockerStats} from "./DockerStats"; |
||||
|
import {Uniq} from "./Uniq"; |
||||
|
import {Player} from "./Player"; |
||||
|
|
||||
|
export interface Server { |
||||
|
address: string; |
||||
|
city_pos: number[]; |
||||
|
color: string; |
||||
|
description: string; |
||||
|
dockerStats: DockerStats; |
||||
|
last_update: number; |
||||
|
map: string; |
||||
|
max_players: number; |
||||
|
name: string; |
||||
|
naming: string[]; |
||||
|
player_count: number; |
||||
|
players: Player[]; |
||||
|
preview: string; |
||||
|
status: boolean; |
||||
|
uniq: Uniq; |
||||
|
workshop: string|null; |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
export interface Uniq { |
||||
|
day: number; |
||||
|
month: number; |
||||
|
year: number; |
||||
|
total: number; |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
<div class="content-in-center-header" style="flex-direction: column;"> |
||||
|
<h1>Вася убийца 2007</h1> |
||||
|
<h3>бибики</h3> |
||||
|
</div> |
||||
|
|
||||
|
<div class="content-in-center"> |
||||
|
</div> |
@ -0,0 +1,31 @@ |
|||||
|
import { Component, OnInit } from '@angular/core'; |
||||
|
import {ActivatedRoute} from "@angular/router"; |
||||
|
import {PlayerServiceService} from "../../services/player-service.service"; |
||||
|
import {PlayerProfile} from "../../entities/profile/PlayerProfile"; |
||||
|
import {MatSnackBar} from "@angular/material/snack-bar"; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-profile-page', |
||||
|
templateUrl: './profile-page.component.html', |
||||
|
styleUrls: ['./profile-page.component.scss'] |
||||
|
}) |
||||
|
export class ProfilePageComponent implements OnInit { |
||||
|
|
||||
|
profile: PlayerProfile|null = null; |
||||
|
|
||||
|
constructor(private route: ActivatedRoute, |
||||
|
private playerService: PlayerServiceService, |
||||
|
private snack: MatSnackBar) { } |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
const steam64: string|null = this.route.snapshot.queryParamMap.get("steam64"); |
||||
|
this.loadPlayer(steam64); |
||||
|
} |
||||
|
|
||||
|
loadPlayer(steam64: string|null) { |
||||
|
this.playerService.getProfile(steam64, []).subscribe( |
||||
|
(res) => this.profile = res, |
||||
|
(err) => this.snack.open("Невозможно загрузить профиль") |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
<div class="content-in-center-header" style="flex-direction: column;"> |
||||
|
<h1>Серверы</h1> |
||||
|
<h3>Информация о игроках и живых серверах</h3> |
||||
|
</div> |
||||
|
|
||||
|
<div class="content-in-center"> |
||||
|
<mat-accordion> |
||||
|
<mat-expansion-panel hideToggle *ngFor="let server of servers | keyvalue"> |
||||
|
<mat-expansion-panel-header> |
||||
|
<mat-panel-title> |
||||
|
{{server.value.name}} |
||||
|
</mat-panel-title> |
||||
|
<mat-panel-description> |
||||
|
{{server.value.player_count}}/{{server.value.max_players}} |
||||
|
</mat-panel-description> |
||||
|
</mat-expansion-panel-header> |
||||
|
<div> |
||||
|
<p>{{server.value.description}}</p> |
||||
|
<mat-expansion-panel hideToggle *ngFor="let player of server.value.players"> |
||||
|
<mat-expansion-panel-header> |
||||
|
<mat-panel-title> |
||||
|
{{player.name}} |
||||
|
</mat-panel-title> |
||||
|
<mat-panel-description> |
||||
|
{{player.score}} / {{player.deads}} / {{player.duration_seconds}} |
||||
|
</mat-panel-description> |
||||
|
</mat-expansion-panel-header> |
||||
|
<p>Ид игрока: {{player.id}}</p> |
||||
|
<p>Пинг: {{player.ping}}</p> |
||||
|
<p>Потери пакетов: {{player.loss}}</p> |
||||
|
</mat-expansion-panel> |
||||
|
</div> |
||||
|
</mat-expansion-panel> |
||||
|
</mat-accordion> |
||||
|
</div> |
@ -0,0 +1,27 @@ |
|||||
|
import { Component, OnInit } from '@angular/core'; |
||||
|
import {WebsocketServersListenerService} from "../../services/websocket-servers-listener.service"; |
||||
|
import {Server} from "../../entities/servers/Server"; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'app-servers-page', |
||||
|
templateUrl: './servers-page.component.html', |
||||
|
styleUrls: ['./servers-page.component.scss'] |
||||
|
}) |
||||
|
export class ServersPageComponent implements OnInit { |
||||
|
|
||||
|
servers:{[srv_name: string]:Server} = {}; |
||||
|
|
||||
|
constructor(private servers_ws:WebsocketServersListenerService) { } |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.servers_ws.getServers().subscribe((r) => { |
||||
|
if (r.state == 0) this.servers = r.servers; |
||||
|
else { |
||||
|
for (let srv_name of Object.keys(r.servers)) { |
||||
|
Object.assign(this.servers[srv_name], r.servers[srv_name]); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
import {Server} from "../entities/servers/Server"; |
||||
|
|
||||
|
export interface WebSockerServerMessage { |
||||
|
servers: {[srv_name: string]:Server}; |
||||
|
state: 0|1; |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
import {HttpClient} from "@angular/common/http"; |
||||
|
import {ProfileRequestData} from "../entities/profile/ProfileRequestData"; |
||||
|
import * as http from "http"; |
||||
|
import {map, Observable} from "rxjs"; |
||||
|
import {PlayerProfile} from "../entities/profile/PlayerProfile"; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root' |
||||
|
}) |
||||
|
export class PlayerServiceService { |
||||
|
|
||||
|
constructor(private http: HttpClient) {} |
||||
|
|
||||
|
getProfile(steam64: string|null, request: ProfileRequestData[]): Observable<PlayerProfile> { |
||||
|
const params = { |
||||
|
requests: request.map((p) => p.param) |
||||
|
} |
||||
|
return this.http.get("api/profile/" + steam64 == null ? 'current' : 'web', {params: params}) |
||||
|
.pipe(map((r) => PlayerProfile.fromData(r))); |
||||
|
} |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
import { Injectable } from '@angular/core'; |
||||
|
import {WebSocketSubject} from "rxjs/internal/observable/dom/WebSocketSubject"; |
||||
|
import {webSocket} from "rxjs/webSocket"; |
||||
|
import {map, Observable} from "rxjs"; |
||||
|
import {WebSockerServerMessage} from "./WebSockerServerMessage"; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root' |
||||
|
}) |
||||
|
export class WebsocketServersListenerService { |
||||
|
private socket: WebSocketSubject<any>; |
||||
|
|
||||
|
constructor() { |
||||
|
this.socket = webSocket('wss://tf2.pblr-nyk.pro/ws/servers'); |
||||
|
} |
||||
|
|
||||
|
getServers(): Observable<WebSockerServerMessage> { |
||||
|
return this.socket.asObservable() |
||||
|
} |
||||
|
} |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue