diff --git a/.dockerignore b/.dockerignore index 91a50cc..61bedfc 100755 --- a/.dockerignore +++ b/.dockerignore @@ -15,6 +15,9 @@ docker-compose.yml # production /frontend/build +/backend/db/firegex.db +/backend/db/firegex.db-journal + # misc **/.DS_Store **/.env.local diff --git a/.gitignore b/.gitignore index e5a403b..6e34a1f 100755 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ # testing /frontend/coverage +/backend/db/firegex.db +/backend/db/firegex.db-journal # production /frontend/build diff --git a/README.md b/README.md index 61aaef2..857f3e9 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,9 @@ ## TODO 1. custom windows docker-compose -2. fix glich change page with loading screen -3. Instant refresh after an add or delete -4. backend checks and errors -5. frontend requests on buttons -6. frontend messages on success and some failure -7. back and frontend password -8. volume on the database -9. compile c++ -O3 +2. backend checks and errors +3. back and frontend password +4. compile c++ -O3 # # Documentation @@ -24,6 +19,7 @@ - [Service info](#get-apiserviceserv) - [Stop service](#get-apiserviceservstop) - [Start service](#get-apiserviceservstart) +- [Pause service](#get-apiserviceservpause) - [Delete service](#get-apiserviceservdelete) - [Terminate service](#get-apiserviceservterminate) - [Regenerate public port](#get-apiserviceservregen-port) @@ -106,7 +102,7 @@ ``` # -## **GET** **```/api/service//terminate```** +## **GET** **```/api/service//pause```** ### Server response: ```json { diff --git a/backend/app.py b/backend/app.py index ade163f..126d8fc 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1,4 +1,4 @@ -import sqlite3, random, string, subprocess +import sqlite3, random, string, subprocess, sys, threading, os from flask import Flask, jsonify, request, abort @@ -7,41 +7,61 @@ class SQLite(): self.conn = None self.cur = None self.db_name = db_name + self.lock = threading.Lock() def connect(self) -> None: + if not os.path.exists("db"): os.mkdir("db") try: - self.conn = sqlite3.connect(self.db_name + '.db', check_same_thread = False) - except: + self.conn = sqlite3.connect("db/" + self.db_name + '.db', check_same_thread = False) + except Exception: with open(self.db_name + '.db', 'x') as f: pass - - self.conn = sqlite3.connect(self.db_name + '.db', check_same_thread = False) - - self.cur = self.conn.cursor() + self.conn = sqlite3.connect("db/" + self.db_name + '.db', check_same_thread = False) def disconnect(self) -> None: self.conn.close() def check_integrity(self, tables = {}) -> None: + cur = self.conn.cursor() for t in tables: - self.cur.execute(''' + cur.execute(''' SELECT name FROM sqlite_master WHERE type='table' AND name='{}'; '''.format(t)) - if len(self.cur.fetchall()) == 0: - self.cur.execute('''CREATE TABLE main.{}({});'''.format(t, ''.join([(c + ' ' + tables[t][c] + ', ') for c in tables[t]])[:-2])) - + if len(cur.fetchall()) == 0: + cur.execute('''CREATE TABLE main.{}({});'''.format(t, ''.join([(c + ' ' + tables[t][c] + ', ') for c in tables[t]])[:-2])) + cur.close() + def query(self, query, values = ()): - self.cur.execute(query, values) - return self.cur.fetchall() + cur = self.conn.cursor() + try: + with self.lock: + cur.execute(query, values) + return cur.fetchall() + finally: + cur.close() + self.conn.commit() + +def from_name_get_id(name): + serv_id = name.strip().replace(" ","-") + serv_id = "".join([c for c in serv_id if c in (string.ascii_uppercase + string.ascii_lowercase + string.digits + "-")]) + return serv_id.lower() + +def gen_internal_port(): + while True: + res = random.randint(30000, 45000) + if len(db.query('SELECT 1 FROM services WHERE internal_port = ?;', (res,))) == 0: + break + return res # DB init db = SQLite('firegex') db.connect() - app = Flask(__name__) +DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG" + @app.route('/api/general-stats') def get_general_stats(): n_services = db.query(''' @@ -54,15 +74,12 @@ def get_general_stats(): SELECT SUM(blocked_packets) FROM regexes; ''')[0][0] - res = { + return { 'services': n_services, 'regexes': n_regexes, 'closed': n_packets if n_packets else 0 } - return res - - @app.route('/api/services') def get_services(): res = [] @@ -86,14 +103,10 @@ def get_services(): @app.route('/api/service/') def get_service(serv): q = db.query('SELECT * FROM services WHERE service_id = ?;', (serv,)) - - res = {} if len(q) != 0: n_regex = db.query('SELECT COUNT (*) FROM regexes WHERE service_id = ?;', (serv,))[0][0] n_packets = db.query('SELECT SUM(blocked_packets) FROM regexes WHERE service_id = ?;', (serv,))[0][0] - - print(q[0]) - res = { + return { 'id': q[0][1], 'status': q[0][0], 'public_port': q[0][3], @@ -105,167 +118,146 @@ def get_service(serv): else: return abort(404) - return res - - @app.route('/api/service//stop') def get_service_stop(serv): db.query(''' UPDATE services SET status = 'stop' WHERE service_id = ?; ''', (serv,)) - res = { + return { 'status': 'ok' } - return res +@app.route('/api/service//pause') +def get_service_pause(serv): + db.query(''' + UPDATE services SET status = 'pause' WHERE service_id = ?; + ''', (serv,)) + return { + 'status': 'ok' + } @app.route('/api/service//start') def get_service_start(serv): db.query(''' - UPDATE services SET status = 'active' WHERE service_id = ?; + UPDATE services SET status = 'wait' WHERE service_id = ?; ''', (serv,)) - res = { + return { 'status': 'ok' } - return res - - @app.route('/api/service//delete') def get_service_delete(serv): - db.query(''' - DELETE FROM services WHERE service_id = ?; - ''', (serv,)) + db.query('DELETE FROM services WHERE service_id = ?;', (serv,)) + db.query('DELETE FROM regexes WHERE service_id = ?;', (serv,)) - res = { + return { 'status': 'ok' } - return res - - -@app.route('/api/service//terminate') -def get_service_termite(serv): - db.query(''' - UPDATE services SET status = 'stop' WHERE service_id = ?; - ''', (serv,)) - - res = { - 'status': 'ok' - } - - return res - @app.route('/api/service//regen-port') def get_regen_port(serv): - db.query('UPDATE services SET public_port = ? WHERE service_id = ?;', (random.randint(30000, 45000), serv)) - - res = { + db.query('UPDATE services SET internal_port = ? WHERE service_id = ?;', (gen_internal_port(), serv)) + return { 'status': 'ok' } - return res - @app.route('/api/service//regexes') def get_service_regexes(serv): - res = [] - for i in db.query('SELECT * FROM regexes WHERE service_id = ?;', (serv,)): - res.append({ - 'id': i[5], - 'service_id': i[2], - 'regex': i[0], - 'is_blacklist': i[3], - 'mode': i[1] - }) - - return jsonify(res) + return jsonify([ + { + 'id': row[5], + 'service_id': row[2], + 'regex': row[0], + 'is_blacklist': True if row[3] == "1" else False, + 'mode': row[1], + 'n_packets': row[4], + } for row in db.query('SELECT * FROM regexes WHERE service_id = ?;', (serv,)) + ]) @app.route('/api/regex/') def get_regex_id(regex_id): q = db.query('SELECT * FROM regexes WHERE regex_id = ?;', (regex_id,)) - - res = {} if len(q) != 0: - res = { + return { 'id': regex_id, 'service_id': q[0][2], 'regex': q[0][0], - 'is_blacklist': q[0][3], - 'mode': q[0][1] + 'is_blacklist': True if q[0][3] == "1" else False, + 'mode': q[0][1], + 'n_packets': q[0][4], } - - return res + else: + return abort(404) @app.route('/api/regex//delete') def get_regex_delete(regex_id): db.query('DELETE FROM regexes WHERE regex_id = ?;', (regex_id,)) - res = { + return { 'status': 'ok' } - return res - @app.route('/api/regexes/add', methods = ['POST']) def post_regexes_add(): req = request.get_json(force = True) db.query(''' - INSERT INTO regexes (regex_id, service_id, regex, is_blacklist, mode) VALUES (?, ?, ?, ?, ?); - ''', (random.randint(1, 1 << 32), req['service_id'], req['regex'], req['is_blacklist'], req['mode'])) + INSERT INTO regexes (service_id, regex, is_blacklist, mode) VALUES (?, ?, ?, ?); + ''', (req['service_id'], req['regex'], req['is_blacklist'], req['mode'])) - res = { + return { 'status': 'ok' } - return res - @app.route('/api/services/add', methods = ['POST']) def post_services_add(): req = request.get_json(force = True) + serv_id = from_name_get_id(req['name']) - serv_id = req['name'].strip().replace(" ","-") - serv_id = "".join([c for c in serv_id if c in (string.ascii_uppercase + string.ascii_lowercase + string.digits + "-")]) - serv_id = serv_id.lower() + try: + db.query(''' + INSERT INTO services (name, service_id, internal_port, public_port, status) VALUES (?, ?, ?, ?, ?) + ''', (req['name'], serv_id, gen_internal_port(), req['port'], 'stop')) + except sqlite3.IntegrityError: + return {'status': 'Name or/and port of the service has been already assigned to another service'} + + return {'status': 'ok'} - db.query(''' - INSERT INTO services (name, service_id, internal_port, public_port, status) VALUES (?, ?, ?, ?, ?) - ''', (req['name'], serv_id, req['port'], random.randint(30000, 45000), 'stop')) - - res = { - 'status': 'ok' - } - - return res +if DEBUG: + from flask_cors import CORS + cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) if __name__ == '__main__': db.check_integrity({ + 'services': { + 'status': 'VARCHAR(100)', + 'service_id': 'VARCHAR(100) PRIMARY KEY', + 'internal_port': 'INT NOT NULL UNIQUE', + 'public_port': 'INT NOT NULL UNIQUE', + 'name': 'VARCHAR(100) NOT NULL' + }, 'regexes': { 'regex': 'TEXT NOT NULL', - 'mode': 'CHAR(1)', - 'service_id': 'TEXT NOT NULL', - 'is_blacklist': 'CHAR(50) NOT NULL', - 'blocked_packets': 'INTEGER DEFAULT 0', - 'regex_id': 'INTEGER NOT NULL' + 'mode': 'VARCHAR(1)', + 'service_id': 'VARCHAR(100) NOT NULL', + 'is_blacklist': 'VARCHAR(1) NOT NULL', + 'blocked_packets': 'INTEGER NOT NULL DEFAULT 0', + 'regex_id': 'INTEGER PRIMARY KEY', + 'FOREIGN KEY (service_id)':'REFERENCES services (service_id)' }, - 'services': { - 'status': 'CHAR(50)', - 'service_id': 'TEXT NOT NULL', - 'internal_port': 'INT NOT NULL', - 'public_port': 'INT NOT NULL', - 'name': 'TEXT NOT NULL' - } }) - #uwsgi - subprocess.run(["uwsgi","--socket","/tmp/uwsgi.sock","--master","--module","app:app"]) + if DEBUG: + app.run(host="0.0.0.0", port=8080 ,debug=True) + else: + subprocess.run(["uwsgi","--socket","./uwsgi.sock","--master","--module","app:app"]) diff --git a/backend/requirements.txt b/backend/requirements.txt index 7f5756b..bf9438b 100755 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -5,4 +5,5 @@ itsdangerous==2.1.2 Jinja2==3.1.2 MarkupSafe==2.1.1 Werkzeug==2.1.2 -uwsgi \ No newline at end of file +uwsgi +flask-cors \ No newline at end of file diff --git a/config/nginx.conf b/config/nginx.conf index 67dfaaa..3ab5bb4 100755 --- a/config/nginx.conf +++ b/config/nginx.conf @@ -14,12 +14,12 @@ http{ location / { include proxy_params; - proxy_pass http://unix:/tmp/react.sock; + proxy_pass http://unix:/execute/react.sock; } location /api/ { include uwsgi_params; - uwsgi_pass unix:/tmp/uwsgi.sock; + uwsgi_pass unix:/execute/uwsgi.sock; } } diff --git a/config/supervisord.conf b/config/supervisord.conf index 42cdb18..1c1a1d8 100755 --- a/config/supervisord.conf +++ b/config/supervisord.conf @@ -17,7 +17,7 @@ killasgroup=true [program:frontend] directory=/execute user = nobody -command=serve -s frontend -l unix:/tmp/react.sock +command=serve -s frontend -l unix:/execute/react.sock startsecs=10 stopsignal=QUIT stopasgroup=true diff --git a/docker-compose.yml b/docker-compose.yml index 21ef4f4..d2a0810 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,4 +9,6 @@ services: - 80:80 environment: - NGINX_PORT=80 + volumes: + - /execute/db \ No newline at end of file diff --git a/frontend/src/components/AddNewRegex.tsx b/frontend/src/components/AddNewRegex.tsx index 2640206..54d4e02 100755 --- a/frontend/src/components/AddNewRegex.tsx +++ b/frontend/src/components/AddNewRegex.tsx @@ -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+" ]") diff --git a/frontend/src/components/AddNewService.tsx b/frontend/src/components/AddNewService.tsx index b0ea47d..7ec36cf 100755 --- a/frontend/src/components/AddNewService.tsx +++ b/frontend/src/components/AddNewService.tsx @@ -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+" ]") diff --git a/frontend/src/components/RegexView/index.tsx b/frontend/src/components/RegexView/index.tsx index 53c7671..71e2e0d 100755 --- a/frontend/src/components/RegexView/index.tsx +++ b/frontend/src/components/RegexView/index.tsx @@ -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
@@ -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} /> diff --git a/frontend/src/components/ServiceRow/index.tsx b/frontend/src/components/ServiceRow/index.tsx index 6b31559..701da1e 100755 --- a/frontend/src/components/ServiceRow/index.tsx +++ b/frontend/src/components/ServiceRow/index.tsx @@ -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 <> @@ -59,11 +82,19 @@ function ServiceRow({ service, onClick, additional_buttons }:{ service:Service,
{additional_buttons} - + + : + - {service.status === "pause"?:} - + disabled={service.status === "stop"}> + + + } + diff --git a/frontend/src/js/models.ts b/frontend/src/js/models.ts index 234d710..219f848 100755 --- a/frontend/src/js/models.ts +++ b/frontend/src/js/models.ts @@ -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 } \ No newline at end of file diff --git a/frontend/src/js/utils.tsx b/frontend/src/js/utils.tsx index 9698a9c..0fbf77d 100755 --- a/frontend/src/js/utils.tsx +++ b/frontend/src/js/utils.tsx @@ -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{ - 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{ - 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 diff --git a/frontend/src/pages/HomePage.tsx b/frontend/src/pages/HomePage.tsx index cfe7695..0b0f348 100755 --- a/frontend/src/pages/HomePage.tsx +++ b/frontend/src/pages/HomePage.tsx @@ -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([]); + 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
+ {services.length > 0?services.map( srv => { navigator("/"+srv.id) }} />):<> No services found! Add one clicking the button above} diff --git a/frontend/src/pages/ServiceDetails.tsx b/frontend/src/pages/ServiceDetails.tsx index 2cf15f3..9c4d198 100755 --- a/frontend/src/pages/ServiceDetails.tsx +++ b/frontend/src/pages/ServiceDetails.tsx @@ -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([]) + 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
+ setDeleteModal(true)} size="xl" radius="md" variant="filled"> + setChangePortModal(true)} size="xl" radius="md" variant="filled"> + }> {regexesList.length === 0? <> No regex found for this service! Add one clicking the add button above: @@ -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} /> - + setChangePortModal(false)} + action={changePort} + opened={changePortModal} + /> +
} export default ServiceDetails;