Improved stability

This commit is contained in:
DomySh
2022-06-13 10:59:05 +02:00
parent cff484a976
commit b53768b5d2
16 changed files with 270 additions and 159 deletions

View File

@@ -2,7 +2,7 @@ import { Button, Group, Space, TextInput, Notification, Switch, NativeSelect } f
import { useForm } from '@mantine/hooks';
import React, { useState } from 'react';
import { RegexAddForm } from '../js/models';
import { addregex, b64encode, validateRegex } from '../js/utils';
import { addregex, b64encode, getHumanReadableRegex, okNotify, validateRegex } from '../js/utils';
import { ImCross } from "react-icons/im"
import FilterTypeSelector from './FilterTypeSelector';
@@ -58,6 +58,7 @@ function AddNewRegex({ closePopup, service }:{ closePopup:()=>void, service:stri
if (!res){
setSubmitLoading(false)
closePopup();
okNotify(`Regex ${getHumanReadableRegex(request.regex)} has been added`, `Successfully added ${request.is_blacklist?"blacklist":"whitelist"} regex to ${request.service_id} service`)
}else{
setSubmitLoading(false)
setError("Invalid request! [ "+res+" ]")

View File

@@ -2,7 +2,7 @@ import { Button, Group, NumberInput, Space, TextInput, Notification } from '@man
import { useForm } from '@mantine/hooks';
import React, { useState } from 'react';
import { ServiceAddForm } from '../js/models';
import { addservice } from '../js/utils';
import { addservice, okNotify } from '../js/utils';
import { ImCross } from "react-icons/im"
function AddNewService({ closePopup }:{ closePopup:()=>void }) {
@@ -27,6 +27,7 @@ function AddNewService({ closePopup }:{ closePopup:()=>void }) {
if (!res){
setSubmitLoading(false)
closePopup();
okNotify(`Service ${values.name} has been added`, `Successfully added ${values.name} with port ${values.port}`)
}else{
setSubmitLoading(false)
setError("Invalid request! [ "+res+" ]")

View File

@@ -1,7 +1,7 @@
import { Grid, Text, Title, Badge, Space, ActionIcon } from '@mantine/core';
import React, { useState } from 'react';
import { RegexFilter } from '../../js/models';
import { getHumanReadableRegex } from '../../js/utils';
import { deleteregex, errorNotify, getHumanReadableRegex, okNotify } from '../../js/utils';
import style from "./RegexView.module.scss";
import { BsTrashFill } from "react-icons/bs"
import YesNoModal from '../YesNoModal';
@@ -24,6 +24,16 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
const [deleteModal, setDeleteModal] = useState(false);
const deleteRegex = () => {
deleteregex(regexInfo.id).then(res => {
if(!res){
okNotify(`Regex ${regex_expr} deleted successfully!`,`Regex '${regex_expr}' ID:${regexInfo.id} has been deleted!`)
}else{
errorNotify(`Regex ${regex_expr} deleation failed!`,`Error: ${res}`)
}
}).catch( err => errorNotify(`Regex ${regex_expr} deleation failed!`,`Error: ${err}`))
}
return <div className={style.box}>
<Grid>
<Grid.Col span={2}>
@@ -66,7 +76,7 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) {
title='Are you sure to delete this regex?'
description={`You are going to delete the regex '${regex_expr}', causing the restart of the firewall if it is active.`}
onClose={()=>setDeleteModal(false)}
action={()=>console.log("Delete regex please!")}
action={deleteRegex}
opened={deleteModal}
/>

View File

@@ -5,6 +5,7 @@ import { Service } from '../../js/models';
import { MdOutlineArrowForwardIos } from "react-icons/md"
import style from "./ServiceRow.module.scss";
import YesNoModal from '../YesNoModal';
import { errorNotify, okNotify, pauseservice, startservice, stopservice } from '../../js/utils';
//"status":"stop"/"wait"/"active"/"pause",
function ServiceRow({ service, onClick, additional_buttons }:{ service:Service, onClick?:()=>void, additional_buttons?:any }) {
@@ -20,26 +21,48 @@ function ServiceRow({ service, onClick, additional_buttons }:{ service:Service,
const [stopModal, setStopModal] = useState(false);
const [buttonLoading, setButtonLoading] = useState(false)
const stopService = () => {
const stopService = async () => {
setButtonLoading(true)
console.log("Stop this service please!")
await stopservice(service.id).then(res => {
if(!res){
okNotify(`Service ${service.id} stopped successfully!`,`The service ${service.name} has been stopped!`)
}else{
errorNotify(`An error as occurred during the stopping of the service ${service.id}`,`Error: ${res}`)
}
}).catch(err => {
errorNotify(`An error as occurred during the stopping of the service ${service.id}`,`Error: ${err}`)
})
setButtonLoading(false)
}
const startService = () => {
const startService = async () => {
setButtonLoading(true)
console.log("Start this service please!")
await startservice(service.id).then(res => {
if(!res){
okNotify(`Service ${service.id} started successfully!`,`The service ${service.name} has been started!`)
}else{
errorNotify(`An error as occurred during the starting of the service ${service.id}`,`Error: ${res}`)
}
}).catch(err => {
errorNotify(`An error as occurred during the starting of the service ${service.id}`,`Error: ${err}`)
})
setButtonLoading(false)
}
const pauseService = () => {
if (service.status === "pause") return setStopModal(true)
const pauseService = async () => {
setButtonLoading(true)
console.log("Pause this service please!")
await pauseservice(service.id).then(res => {
if(!res){
okNotify(`Service ${service.id} paused successfully!`,`The service ${service.name} has been paused (Transparent mode)!`)
}else{
errorNotify(`An error as occurred during the pausing of the service ${service.id}`,`Error: ${res}`)
}
}).catch(err => {
errorNotify(`An error as occurred during the pausing of the service ${service.id}`,`Error: ${err}`)
})
setButtonLoading(false)
}
return <>
<Grid className={style.row} style={{width:"100%"}}>
@@ -59,11 +82,19 @@ function ServiceRow({ service, onClick, additional_buttons }:{ service:Service,
<Space w="xl" /><Space w="xl" />
<div className="center-flex">
{additional_buttons}
<ActionIcon color={service.status === "pause"?"yellow":"red"} loading={buttonLoading}
{["pause","wait"].includes(service.status)?
<ActionIcon color="yellow" loading={buttonLoading}
onClick={stopService} size="xl" radius="md" variant="filled"
disabled={service.status === "stop"}>
<FaStop size="20px" />
</ActionIcon>:
<ActionIcon color="red" loading={buttonLoading}
onClick={pauseService} size="xl" radius="md" variant="filled"
disabled={!["wait","active","pause"].includes(service.status)?true:false}>
{service.status === "pause"?<FaStop size="20px" />:<FaPause size="20px" />}
</ActionIcon>
disabled={service.status === "stop"}>
<FaPause size="20px" />
</ActionIcon>
}
<Space w="md"/>
<ActionIcon color="teal" size="xl" radius="md" onClick={startService} loading={buttonLoading}
variant="filled" disabled={!["stop","pause"].includes(service.status)?true:false}>

View File

@@ -1,7 +1,7 @@
export const update_freq = 3000;
export const notification_time = 2000;
export const update_freq = 2000;
export const notification_time = 1500;
export type GeneralStats = {
services:number,
@@ -38,8 +38,8 @@ export type RegexFilter = {
}
export type RegexAddForm = {
"service_id":string,
"regex":string,
"is_blacklist":boolean,
"mode":string // C->S S->C BOTH
service_id:string,
regex:string,
is_blacklist:boolean,
mode:string // C->S S->C BOTH
}

View File

@@ -5,12 +5,14 @@ import { GeneralStats, Service, ServiceAddForm, ServerResponse, RegexFilter, not
var Buffer = require('buffer').Buffer
const custom_url = ""//"http://127.0.0.1:8080"
export async function getapi(path:string):Promise<any>{
return await fetch(`/api/${path}`).then( res => res.json() )
return await fetch(`${custom_url}/api/${path}`).then( res => res.json() )
}
export async function postapi(path:string,data:any):Promise<any>{
return await fetch(`/api/${path}`, {
return await fetch(`${custom_url}/api/${path}`, {
method: 'POST',
cache: 'no-cache',
headers: {
@@ -33,11 +35,40 @@ export async function serviceinfo(service_id:string){
return await getapi(`service/${service_id}`) as Service;
}
export async function deleteregex(regex_id:number){
const { status } = await getapi(`regex/${regex_id}/delete`) as ServerResponse;
return status === "ok"?undefined:status
}
export async function startservice(service_id:string){
const { status } = await getapi(`service/${service_id}/start`) as ServerResponse;
return status === "ok"?undefined:status
}
export async function stopservice(service_id:string){
const { status } = await getapi(`service/${service_id}/stop`) as ServerResponse;
return status === "ok"?undefined:status
}
export async function pauseservice(service_id:string){
const { status } = await getapi(`service/${service_id}/pause`) as ServerResponse;
return status === "ok"?undefined:status
}
export async function regenport(service_id:string){
const { status } = await getapi(`service/${service_id}/regen-port`) as ServerResponse;
return status === "ok"?undefined:status
}
export async function addservice(data:ServiceAddForm) {
const { status } = await postapi("services/add",data) as ServerResponse;
return status === "ok"?undefined:status
}
export async function deleteservice(service_id:string) {
const { status } = await getapi(`service/${service_id}/delete`) as ServerResponse;
return status === "ok"?undefined:status
}
export async function addregex(data:RegexAddForm) {
const { status } = await postapi("regexes/add",data) as ServerResponse;
return status === "ok"?undefined:status

View File

@@ -1,4 +1,4 @@
import { Space, Title } from '@mantine/core';
import { LoadingOverlay, Space, Title } from '@mantine/core';
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import ServiceRow from '../components/ServiceRow';
@@ -9,14 +9,16 @@ import { errorNotify, servicelist } from '../js/utils';
function HomePage() {
const [services, setServices] = useState<Service[]>([]);
const [loader, setLoader] = useState(true);
const navigator = useNavigate()
const updateInfo = () => {
servicelist().then(res => {
setServices(res)
}).catch(
err => errorNotify("Home Page Auto-Update failed!", err.toString())
)
const updateInfo = async () => {
await servicelist().then(res => {
setServices(res)
}).catch(err => {
errorNotify("Home Page Auto-Update failed!", err.toString())
})
setLoader(false)
}
useEffect(()=>{
@@ -24,8 +26,11 @@ function HomePage() {
const updater = setInterval(updateInfo, update_freq)
return () => { clearInterval(updater) }
}, []);
return <div id="service-list" className="center-flex-row">
<LoadingOverlay visible={loader} />
{services.length > 0?services.map( srv => <ServiceRow service={srv} key={srv.id} onClick={()=>{
navigator("/"+srv.id)
}} />):<><Space h="xl"/> <Title className='center-flex' order={3}>No services found! Add one clicking the button above</Title></>}

View File

@@ -1,4 +1,4 @@
import { ActionIcon, Grid, Space, Title } from '@mantine/core';
import { ActionIcon, Grid, LoadingOverlay, Space, Title } from '@mantine/core';
import React, { useEffect, useState } from 'react';
import { BsTrashFill } from 'react-icons/bs';
import { useNavigate, useParams } from 'react-router-dom';
@@ -6,7 +6,8 @@ import RegexView from '../components/RegexView';
import ServiceRow from '../components/ServiceRow';
import YesNoModal from '../components/YesNoModal';
import { RegexFilter, Service, update_freq } from '../js/models';
import { errorNotify, serviceinfo, serviceregexlist } from '../js/utils';
import { deleteservice, errorNotify, okNotify, regenport, serviceinfo, serviceregexlist } from '../js/utils';
import { BsArrowRepeat } from "react-icons/bs"
function ServiceDetails() {
const {srv_id} = useParams()
@@ -22,6 +23,7 @@ function ServiceDetails() {
})
const [regexesList, setRegexesList] = useState<RegexFilter[]>([])
const [loader, setLoader] = useState(true);
const navigator = useNavigate()
@@ -41,20 +43,47 @@ function ServiceDetails() {
}).catch(
err => errorNotify(`Updater for ${srv_id} service failed [Regex list]!`, err.toString())
)
setLoader(false)
}
useEffect(()=>{
updateInfo()
const updater = setInterval(updateInfo, update_freq)
return () => { clearInterval(updater) }
});
},[]);
const [deleteModal, setDeleteModal] = useState(false)
const [changePortModal, setChangePortModal] = useState(false)
return <>
const deleteService = () => {
deleteservice(serviceInfo.id).then(res => {
if (!res)
okNotify("Service delete complete!",`The service ${serviceInfo.id} has been deleted!`)
else
errorNotify("An error occurred while deleting a service",`Error: ${res}`)
}).catch(err => {
errorNotify("An error occurred while deleting a service",`Error: ${err}`)
})
}
const changePort = () => {
regenport(serviceInfo.id).then(res => {
if (!res)
okNotify("Service port regeneration completed!",`The service ${serviceInfo.id} has changed the internal port!`)
else
errorNotify("An error occurred while changing the internal service port",`Error: ${res}`)
}).catch(err => {
errorNotify("An error occurred while changing the internal service port",`Error: ${err}`)
})
}
return <div>
<LoadingOverlay visible={loader} />
<ServiceRow service={serviceInfo} additional_buttons={<>
<ActionIcon color="red" onClick={()=>setDeleteModal(true)} size="xl" radius="md" variant="filled"><BsTrashFill size={22} /></ActionIcon>
<Space w="md"/>
<ActionIcon color="blue" onClick={()=>setChangePortModal(true)} size="xl" radius="md" variant="filled"><BsArrowRepeat size={28} /></ActionIcon>
<Space w="md"/>
</>}></ServiceRow>
{regexesList.length === 0?
<><Space h="xl" /> <Title className='center-flex' order={3}>No regex found for this service! Add one clicking the add button above</Title></>:
@@ -66,10 +95,17 @@ function ServiceDetails() {
title='Are you sure to delete this service?'
description={`You are going to delete the service '${serviceInfo.id}', causing the stopping of the firewall and deleting all the regex associated. This will cause the shutdown of your service ⚠️!`}
onClose={()=>setDeleteModal(false)}
action={()=>console.log("Delete the service please!")}
action={deleteService}
opened={deleteModal}
/>
</>
<YesNoModal
title='Are you sure to change the proxy internal port?'
description={`You are going to change the proxy port '${serviceInfo.internal_port}'. This will cause the shutdown of your service temporarily ⚠️!`}
onClose={()=>setChangePortModal(false)}
action={changePort}
opened={changePortModal}
/>
</div>
}
export default ServiceDetails;