diff --git a/py/api/api_dev.py b/py/api/api_dev.py index 55a61df..c23f985 100644 --- a/py/api/api_dev.py +++ b/py/api/api_dev.py @@ -8,12 +8,11 @@ from flask import request,redirect ,session import datetime import html - import config import re from libs.red import RedisDB from libs.webutil import app,buildResponse,login_required,get_myself,get_ip,get_agent -from libs import util +from libs import util,ping from libs.db import db_device,db_groups,db_user_group_perm,db_user_tasks,db_sysconfig,db_syslog import logging import json @@ -299,12 +298,16 @@ def dev_info(): res=db_device.get_device(devid) options=util.build_api_options(db_device.get_devices_by_id([res['id'],])[0]) network_info=[] + res['online']=True try: if util.check_port(options['host'],options['port']): router=util.RouterOSCheckResource(options) network_info=util.get_network_data(router) del network_info['total'] + else: + res['online']=False except: + res['online']=False pass interfaces=[] for iface in network_info: @@ -325,6 +328,45 @@ def dev_info(): log.error(e) return buildResponse({'status': 'failed'}, 200, error="Wrong Data") pass + try: + res['active_users']=[] + if res['online']: + res['active_users']=tuple(router.api("/user/active/print")) + except: + res['active_users']=[] + try: + res['ping']=ping.get_ping_results(res['ip'], 5, 1) + except Exception as e: + res['ping']=[] + return buildResponse(res,200) + +@app.route('/api/dev/kill_session', methods = ['POST']) +@login_required(role='admin',perm={'device':'full'}) +def dev_kill_session(): + """return dev info""" + input = request.json + devid=input.get('devid',False) + item=input.get('item',False) + if not devid or not isinstance(devid, int): + return buildResponse({'status': 'failed'},200,error="Wrong Data") + try: + dev=db_device.get_devices_by_id([devid,])[0] + except: + return buildResponse({'status': 'failed'},200,error="Wrong Data") + if not dev: + return buildResponse({'status': 'failed'},200,error="Wrong Data") + options=util.build_api_options(dev) + router=util.RouterOSCheckResource(options) + # active_users=tuple(router.api("/user/active/print")) + # if item in active_users: + try: + acturl=router.api.path("user","active") + res=tuple(acturl('request-logout', **{'.id': item['.id']})) + log.error(res) + except Exception as e: + log.error(e) + pass + res=tuple(router.api("/user/active/print")) return buildResponse(res,200) @app.route('/api/dev/sensors', methods = ['POST']) diff --git a/py/api/api_logs.py b/py/api/api_logs.py index afa8892..3d23fb3 100644 --- a/py/api/api_logs.py +++ b/py/api/api_logs.py @@ -402,6 +402,8 @@ def dashboard_stats(): # res['update_available']=True if username: res['username']=username + else: + res['username']=False res['blog']=[] noconnectiondata={ "content": "Unable to connect to mikrowizard.com! please check server connection", diff --git a/py/libs/ping.py b/py/libs/ping.py new file mode 100644 index 0000000..1274f34 --- /dev/null +++ b/py/libs/ping.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# ping.py: ping tool for MikroWizard +# MikroWizard.com , Mikrotik router management solution +# Author: sepehr.ha@gmail.com + +import asyncio +import platform + +def ping_quality(time_ms): + if time_ms is None: + return "unreachable", "fa-solid fa-times-circle", "#dc3545" # Red, times circle + if time_ms <= 50: + return "excellent", "fa-solid fa-check-circle", "#28a745" # Green, check circle + elif time_ms <= 100: + return "good", "fa-solid fa-thumbs-up", "#80c29e" # Light green, thumbs up + elif time_ms <= 200: + return "average", "fa-solid fa-exclamation-circle", "#ffc107" # Yellow, exclamation circle + else: + return "poor", "fa-solid fa-times-circle", "#dc3545" # Red, times circle + +async def ping_host(host, timeout=1): + system = platform.system() + cmd = ["ping", "-c", "1", "-W", str(timeout), host] + + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + + stdout, stderr = await process.communicate() + result = stdout.decode().strip() + error = stderr.decode().strip() + + # Extract time from output + time_ms = None + if "time=" in result: + try: + time_part = result.split("time=")[-1].split()[0] + time_ms = float(time_part) + except ValueError: + pass + + quality, icon, color = ping_quality(time_ms) + raw_response = result.split("\n")[0] if result else error.split("\n")[0] + + return { + "host": host, + "status": "success" if time_ms is not None else "failed", + "time": time_ms if time_ms is not None else None, + "ping_quality": quality, + "icon": icon, + "color": color, + "raw_response": raw_response + } + +async def multi_ping_one_host(host, count=4, timeout=1): + tasks = [ping_host(host, timeout) for _ in range(count)] + results = await asyncio.gather(*tasks) + + successful_pings = [r["time"] for r in results if r["status"] == "success"] + failed_pings = count - len(successful_pings) + + average_ping_time = round(sum(successful_pings) / len(successful_pings), 2) if successful_pings else None + + response = { + "host": host, + "count": count, + "successful_pings": len(successful_pings), + "failed_pings": failed_pings, + "average_ping_time": average_ping_time, + "results": results + } + + return response + +def get_ping_results(host, count=4, timeout=1): + return asyncio.run(multi_ping_one_host(host, count, timeout))