Начал рефакторинг запросов к апи.
Выношу в клиент
This commit is contained in:
parent
23ca544247
commit
f1de8a69f9
@ -1,4 +0,0 @@
|
||||
|
||||
export class Client {
|
||||
|
||||
}
|
63
api/schema-client.ts
Normal file
63
api/schema-client.ts
Normal file
@ -0,0 +1,63 @@
|
||||
export enum Method {
|
||||
GET = 'GET',
|
||||
POST = 'POST',
|
||||
PUT = 'PUT',
|
||||
PATCH = 'PATCH',
|
||||
}
|
||||
|
||||
export let hasQuery = (method: Method) => {
|
||||
return Method.GET === method
|
||||
}
|
||||
|
||||
export interface ClientOptions {
|
||||
baseUrl: string
|
||||
}
|
||||
|
||||
export interface SchemaInterface {
|
||||
url: string,
|
||||
method: Method
|
||||
contentType: string | null
|
||||
}
|
||||
|
||||
export class SchemaClient {
|
||||
baseUrl: string
|
||||
|
||||
constructor({baseUrl}: ClientOptions) {
|
||||
this.baseUrl = baseUrl
|
||||
}
|
||||
|
||||
async send(schema: SchemaInterface, data: any) {
|
||||
let url = `${this.baseUrl}${schema.url}`
|
||||
let {url: preparedUrl, data: preparedData} = this.processAttributes(url, data)
|
||||
|
||||
if (hasQuery(schema.method)) {
|
||||
preparedUrl += '?' + new URLSearchParams(preparedData)
|
||||
}
|
||||
|
||||
let response = await fetch(preparedUrl, {
|
||||
method: schema.method.toString(),
|
||||
headers: {
|
||||
...(schema.contentType ? {'Content-Type': schema.contentType} : {}),
|
||||
'X-Plugin-Token': 'passw0rd'
|
||||
},
|
||||
body: hasQuery(schema.method) ? null : JSON.stringify(preparedData)
|
||||
});
|
||||
|
||||
let responseData = response.headers.get('Content-Type')?.toString().includes('application/json')
|
||||
? await response.json()
|
||||
: await response.text()
|
||||
return {responseData: responseData, headers: response.headers}
|
||||
}
|
||||
|
||||
private processAttributes(url: string, data: any)
|
||||
{
|
||||
const preparedData = data
|
||||
for (const key in data) {
|
||||
if (url.indexOf('{' + key + '}') > -1) {
|
||||
url = url.replace('{' + key + '}', preparedData[key])
|
||||
delete preparedData[key]
|
||||
}
|
||||
}
|
||||
return {url, data: preparedData }
|
||||
}
|
||||
}
|
9
api/sm/requests/get-processes.ts
Normal file
9
api/sm/requests/get-processes.ts
Normal file
@ -0,0 +1,9 @@
|
||||
export enum ProcessesType
|
||||
{
|
||||
RUNNING = 'running',
|
||||
HISTORY = 'history',
|
||||
}
|
||||
|
||||
export class GetProcessesRequest {
|
||||
type?: ProcessesType
|
||||
}
|
4
api/sm/requests/pagination.ts
Normal file
4
api/sm/requests/pagination.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export class PaginationRequest {
|
||||
page?: number
|
||||
limit?: number
|
||||
}
|
28
api/sm/responses/comamnds.ts
Normal file
28
api/sm/responses/comamnds.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export interface OptionInterface {
|
||||
name: string,
|
||||
description: string | null,
|
||||
default: any,
|
||||
value: any,
|
||||
shortcut: string | null,
|
||||
isArray: boolean,
|
||||
isNegatable: boolean,
|
||||
isValueOptional: boolean,
|
||||
isValueRequired: boolean
|
||||
acceptValue: boolean
|
||||
}
|
||||
|
||||
export interface ArgumentInterface {
|
||||
name: string,
|
||||
description: string|null,
|
||||
default: any,
|
||||
isArray: boolean,
|
||||
isRequired: boolean,
|
||||
}
|
||||
|
||||
export interface CommandResponseInterface {
|
||||
class: string,
|
||||
name: string,
|
||||
description: string,
|
||||
options: OptionInterface[],
|
||||
arguments: ArgumentInterface[],
|
||||
}
|
32
api/sm/responses/processes.ts
Normal file
32
api/sm/responses/processes.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export interface ProcessExceptionInterface {
|
||||
message: string,
|
||||
file: string,
|
||||
line: number,
|
||||
code: number,
|
||||
trace: any[],
|
||||
}
|
||||
|
||||
export interface ProcessProgressInterface {
|
||||
total: number,
|
||||
progress: number,
|
||||
memory: any[],
|
||||
}
|
||||
|
||||
export interface ProcessesResponseInterface {
|
||||
id: string
|
||||
lock: string | null
|
||||
containerUuid: string | null
|
||||
pid: bigint | null
|
||||
name: string
|
||||
options: Record<string, any>
|
||||
arguments: Record<string, any>
|
||||
exception: ProcessExceptionInterface | null
|
||||
progress: ProcessProgressInterface | null
|
||||
outputId: string | null
|
||||
createdAt: string
|
||||
updatedAt: string | null
|
||||
startedAt: string | null
|
||||
pausedAt: string | null
|
||||
cancelledAt: string | null
|
||||
completedAt: string | null
|
||||
}
|
4
api/sm/responses/response.ts
Normal file
4
api/sm/responses/response.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface ResponseInterface {
|
||||
data: any
|
||||
headers: Headers
|
||||
}
|
10
api/sm/schemas/commands.ts
Normal file
10
api/sm/schemas/commands.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import {Method, SchemaInterface} from "../../schema-client";
|
||||
|
||||
class CommandsSchema implements SchemaInterface {
|
||||
method = Method.GET
|
||||
url = '/system-monitoring/commands'
|
||||
contentType = null;
|
||||
}
|
||||
|
||||
export let commandsSchema = new CommandsSchema()
|
||||
export default commandsSchema
|
10
api/sm/schemas/processes.ts
Normal file
10
api/sm/schemas/processes.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import {Method, SchemaInterface} from "../../schema-client";
|
||||
|
||||
class ProcessesSchema implements SchemaInterface {
|
||||
method = Method.GET
|
||||
url = '/system-monitoring/processes'
|
||||
contentType = null;
|
||||
}
|
||||
|
||||
export let processesSchema = new ProcessesSchema()
|
||||
export default processesSchema
|
10
api/sm/schemas/run-commands.ts
Normal file
10
api/sm/schemas/run-commands.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import {Method, SchemaInterface} from "../../schema-client";
|
||||
|
||||
class RunCommandsSchema implements SchemaInterface {
|
||||
method = Method.POST
|
||||
url = '/system-monitoring/commands/{commandName}/run'
|
||||
contentType = 'application/json;charset=utf-8';
|
||||
}
|
||||
|
||||
export let runCommandsSchema = new RunCommandsSchema()
|
||||
export default runCommandsSchema
|
46
api/sm/sm-client.ts
Normal file
46
api/sm/sm-client.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import {processesSchema} from "./schemas/processes";
|
||||
import {ProcessesResponseInterface} from "./responses/processes";
|
||||
import {SchemaClient} from "../schema-client";
|
||||
import {GetProcessesRequest} from "./requests/get-processes";
|
||||
import {PaginationRequest} from "./requests/pagination";
|
||||
import {ResponseInterface} from "./responses/response";
|
||||
import {CommandResponseInterface} from "./responses/comamnds";
|
||||
import commandsSchema from "./schemas/commands";
|
||||
import runCommandsSchema from "./schemas/run-commands";
|
||||
|
||||
export class SMClient {
|
||||
schemaClient: SchemaClient
|
||||
|
||||
constructor() {
|
||||
this.schemaClient = new SchemaClient({
|
||||
baseUrl: 'http://fmw.sipachev.sv'
|
||||
})
|
||||
}
|
||||
|
||||
async getCommands(): Promise<ResponseInterface> {
|
||||
let { responseData, headers } = await this.schemaClient.send(commandsSchema, {})
|
||||
return {
|
||||
data: responseData as CommandResponseInterface[],
|
||||
headers: headers
|
||||
}
|
||||
}
|
||||
|
||||
async runCommand(data: any): Promise<ResponseInterface> {
|
||||
let { headers } = await this.schemaClient.send(runCommandsSchema, data)
|
||||
return {
|
||||
data: null,
|
||||
headers: headers
|
||||
}
|
||||
}
|
||||
|
||||
async getProcesses(data: GetProcessesRequest | PaginationRequest): Promise<ResponseInterface> {
|
||||
let { responseData, headers } = await this.schemaClient.send(processesSchema, data)
|
||||
return {
|
||||
data: responseData as ProcessesResponseInterface[],
|
||||
headers: headers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export let smClient = new SMClient
|
||||
export default smClient
|
@ -6,6 +6,7 @@ import PlayCircleOutline from '@mui/icons-material/PlayCircleOutline';
|
||||
import ConfirmDialog from "../confirm-dialog";
|
||||
import TabContext from "../../../context/tab";
|
||||
import {TabEnum} from "../../../pages";
|
||||
import smClient from "../../../api/sm/sm-client";
|
||||
|
||||
export default function Commands() {
|
||||
const {setTab} = useContext(TabContext)
|
||||
@ -16,14 +17,7 @@ export default function Commands() {
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
|
||||
let refreshCommands = async () => {
|
||||
let response = await fetch('http://fmw.sipachev.sv/system-monitoring/commands', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'X-Plugin-Token': 'passw0rd'
|
||||
},
|
||||
});
|
||||
const commands: CommandInterface[] = await response.json()
|
||||
const { data: commands } = await smClient.getCommands()
|
||||
setCommands(commands)
|
||||
}
|
||||
|
||||
@ -57,17 +51,12 @@ export default function Commands() {
|
||||
return
|
||||
}
|
||||
lock = true
|
||||
let url = `http://fmw.sipachev.sv/system-monitoring/commands/${selectedCommand.name}/run`
|
||||
let data = command2data[selectedCommand.name] || {}
|
||||
data['requestId'] = dialogId;
|
||||
let response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json;charset=utf-8',
|
||||
'X-Plugin-Token': 'passw0rd'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
await smClient.runCommand({
|
||||
commandName: selectedCommand.name,
|
||||
...data
|
||||
})
|
||||
lock = false
|
||||
setTab(TabEnum.Processes)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import RunCircleOutlined from "@mui/icons-material/RunCircleOutlined"
|
||||
import FactCheckOutlined from "@mui/icons-material/FactCheckOutlined"
|
||||
import {IconButton, LinearProgress, TableContainer, Table, TableBody, TableCell, TableHead, TableRow, TablePagination} from "@mui/material"
|
||||
import ConfirmDialog from "../confirm-dialog";
|
||||
import smClient from "../../../api/sm/sm-client";
|
||||
|
||||
export interface ProcessExceptionInterface {
|
||||
message: string,
|
||||
@ -67,20 +68,12 @@ export default function Processes() {
|
||||
return
|
||||
}
|
||||
refreshLock = true
|
||||
let response = await fetch('http://fmw.sipachev.sv/system-monitoring/processes?' + new URLSearchParams({
|
||||
page: (page + 1) + '',
|
||||
limit: 20 + '',
|
||||
}),
|
||||
{
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-Plugin-Token': 'passw0rd',
|
||||
'X-Pagination-Count': '0',
|
||||
},
|
||||
});
|
||||
const processes: ProcessInterface[] = await response.json()
|
||||
const { data: processes, headers } = await smClient.getProcesses({
|
||||
page: page + 1,
|
||||
limit: 20,
|
||||
})
|
||||
setProcesses(processes)
|
||||
setCount(Number(response.headers.get('X-Pagination-Count')))
|
||||
setCount(Number(headers.get('X-Pagination-Count')))
|
||||
refreshLock = false
|
||||
}
|
||||
let output = async (process: ProcessInterface) => {
|
||||
@ -164,6 +157,55 @@ export default function Processes() {
|
||||
setOpen(false)
|
||||
}
|
||||
|
||||
let formatSize = (length: any) => {
|
||||
var i = 0, type = ['b','Kb','Mb','Gb','Tb','Pb'];
|
||||
while((length / 1000 | 0) && i < type.length - 1) {
|
||||
length /= 1024;
|
||||
i++;
|
||||
}
|
||||
return length.toFixed(2) + ' ' + type[i];
|
||||
}
|
||||
|
||||
let remaining = (process: ProcessInterface) =>
|
||||
{
|
||||
if (!process?.progress?.progress || !process.startedAt) {
|
||||
return null
|
||||
}
|
||||
return Math.round((new Date().getTime() - new Date(process.startedAt).getTime()) / process?.progress.progress * (process?.progress.total - process?.progress.progress));
|
||||
}
|
||||
|
||||
let formatTime = ($secs: number | null) => {
|
||||
if ($secs === null) {
|
||||
return ''
|
||||
}
|
||||
let $timeFormats = [
|
||||
[0, '< 1 sec'],
|
||||
[1, '1 sec'],
|
||||
[2, 'secs', 1],
|
||||
[60, '1 min'],
|
||||
[120, 'mins', 60],
|
||||
[3600, '1 hr'],
|
||||
[7200, 'hrs', 3600],
|
||||
[86400, '1 day'],
|
||||
[172800, 'days', 86400],
|
||||
];
|
||||
|
||||
for (let $index in $timeFormats) {
|
||||
let $format = $timeFormats[$index]
|
||||
if ($secs >= $format[0]) {
|
||||
if ((typeof $timeFormats[$index + 1] !== 'undefined' && $secs < $timeFormats[$index + 1][0])
|
||||
|| $index == $timeFormats.length - 1
|
||||
) {
|
||||
if (2 == $format.length) {
|
||||
return $format[1];
|
||||
}
|
||||
|
||||
return Math.floor($secs / $format[2]) + ' ' + $format[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableContainer>
|
||||
@ -184,9 +226,9 @@ export default function Processes() {
|
||||
<TableCell>
|
||||
{!process.progress && !isFinished(process) && <LinearProgress/>}
|
||||
{!process.progress && isFinished(process) && <LinearProgress variant="determinate" value={100}/>}
|
||||
{process.progress && <LinearProgress value={progress(process.progress)}/>}
|
||||
{process.progress && <LinearProgress variant="determinate" value={progress(process.progress)}/>}
|
||||
{process.progress && <span>
|
||||
{`${process.progress.progress}`} / {`${process.progress.total}`} - 50% [53Mb] / 20 sec
|
||||
{`${process.progress.progress}`} / {`${process.progress.total}`} - {progress(process.progress)}% [{formatSize(process.progress.memory)}] / {formatTime(remaining(process))}
|
||||
</span>}
|
||||
{canPlay(process) && <IconButton title={`Play`} aria-label="Play">
|
||||
<PlayCircleOutline/>
|
||||
|
Loading…
Reference in New Issue
Block a user