first commit

This commit is contained in:
lihansani
2026-07-13 15:37:05 +08:00
commit 8b11aa2efc
299 changed files with 206339 additions and 0 deletions

529
code/utils/server/linux.py Normal file
View File

@@ -0,0 +1,529 @@
#!/bin/python
# coding: utf-8
# +-------------------------------------------------------------------
# | django-vue3-lyadmin
# +-------------------------------------------------------------------
# | Author: lybbn
# +-------------------------------------------------------------------
# | QQ: 1042594286
# +-------------------------------------------------------------------
# ------------------------------
# linux系统命令工具类封装
# ------------------------------
import os, sys, re, time, json
import psutil
from django.core.cache import cache
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent
PUBLIC_DICT = os.path.join(BASE_DIR, 'public.json')
def Md5(strings):
"""
@name 生成MD5
@author hwliang<hwl@bt.cn>
@param strings 要被处理的字符串
@return string(32)
"""
if type(strings) != bytes:
strings = strings.encode()
import hashlib
m = hashlib.md5()
m.update(strings)
return m.hexdigest()
def md5(strings):
return Md5(strings)
def get_preexec_fn(run_user):
'''
@name 获取指定执行用户预处理函数
@author hwliang<2021-08-19>
@param run_user<string> 运行用户
@return 预处理函数
'''
import pwd
pid = pwd.getpwnam(run_user)
uid = pid.pw_uid
gid = pid.pw_gid
def _exec_rn():
os.setgid(gid)
os.setuid(uid)
return _exec_rn
def get_error_info():
import traceback
errorMsg = traceback.format_exc()
return errorMsg
def ExecShell(cmdstring, timeout=None, shell=True, cwd=None, env=None, user=None):
'''
@name 执行命令
@author hwliang<2021-08-19>
@param cmdstring 命令 [必传]
@param timeout 超时时间
@param shell 是否通过shell运行
@param cwd 进入的目录
@param env 环境变量
@param user 执行用户名
@return 命令执行结果
'''
a = ''
e = ''
import subprocess, tempfile
preexec_fn = None
tmp_dir = '/dev/shm'
if user:
preexec_fn = get_preexec_fn(user)
tmp_dir = '/tmp'
try:
rx = md5(cmdstring)
succ_f = tempfile.SpooledTemporaryFile(max_size=4096, mode='wb+', suffix='_succ', prefix='btex_' + rx,
dir=tmp_dir)
err_f = tempfile.SpooledTemporaryFile(max_size=4096, mode='wb+', suffix='_err', prefix='btex_' + rx,
dir=tmp_dir)
sub = subprocess.Popen(cmdstring, close_fds=True, shell=shell, bufsize=128, stdout=succ_f, stderr=err_f,
cwd=cwd, env=env, preexec_fn=preexec_fn)
if timeout:
s = 0
d = 0.01
while sub.poll() == None:
time.sleep(d)
s += d
if s >= timeout:
if not err_f.closed: err_f.close()
if not succ_f.closed: succ_f.close()
return 'Timed out'
else:
sub.wait()
err_f.seek(0)
succ_f.seek(0)
a = succ_f.read()
e = err_f.read()
if not err_f.closed: err_f.close()
if not succ_f.closed: succ_f.close()
except:
return '', get_error_info()
try:
# 编码修正
if type(a) == bytes: a = a.decode('utf-8')
if type(e) == bytes: e = e.decode('utf-8')
except:
a = str(a)
e = str(e)
return a, e
def ReadFile(filename, mode='r'):
"""
读取文件内容
@filename 文件名
return string(bin) 若文件不存在则返回None
"""
import os
if not os.path.exists(filename): return False
fp = None
try:
fp = open(filename, mode)
f_body = fp.read()
except Exception as ex:
if sys.version_info[0] != 2:
try:
fp = open(filename, mode, encoding="utf-8")
f_body = fp.read()
except:
fp = open(filename, mode, encoding="GBK")
f_body = fp.read()
else:
return False
finally:
if fp and not fp.closed:
fp.close()
return f_body
def readFile(filename, mode='r'):
'''
@name 读取指定文件数据
@author hwliang<2021-06-09>
@param filename<string> 文件名
@param mode<string> 文件打开模式默认r
@return string or bytes or False 如果返回False则说明读取失败
'''
return ReadFile(filename, mode)
# xss 防御
def xsssec(text):
return text.replace('&', '&amp;').replace('"', '&quot;').replace('<', '&lt;').replace('>', '&gt;')
def get_os_version():
'''
@name 取操作系统版本
@author hwliang<2021-08-07>
@return string
'''
p_file = '/etc/.productinfo'
if os.path.exists(p_file):
s_tmp = readFile(p_file).split("\n")
if s_tmp[0].find('Kylin') != -1 and len(s_tmp) > 1:
version = s_tmp[0] + ' ' + s_tmp[1].split('/')[0].strip()
else:
version = readFile('/etc/redhat-release')
if not version:
version = readFile('/etc/issue').strip().split("\n")[0].replace('\\n', '').replace('\l', '').strip()
else:
version = version.replace('release ', '').replace('Linux', '').replace('(Core)', '').strip()
v_info = sys.version_info
try:
version = "{} {}(Py{}.{}.{})".format(version, os.uname().machine, v_info.major, v_info.minor, v_info.micro)
except:
version = "{} (Py{}.{}.{})".format(version, v_info.major, v_info.minor, v_info.micro)
return xsssec(version)
def GetSystemVersion():
# 取操作系统版本
key = 'lybbn_sys_version'
version = cache.get(key)
if version: return version
version = get_os_version()
cache.set(key, version, 10000)
return version
def GetLoadAverage():
try:
c = os.getloadavg()
except:
c = [0, 0, 0]
data = {}
data['one'] = float(c[0])
data['five'] = float(c[1])
data['fifteen'] = float(c[2])
data['max'] = psutil.cpu_count() * 2
data['limit'] = data['max']
data['safe'] = data['max'] * 0.75
temppercent = round(data['one'] / data['max'] * 100)
data['percent'] = 100 if temppercent > 100 else temppercent
return data
# 取内存信息
def GetMemInfo():
mem = psutil.virtual_memory()
memInfo = {}
# memInfo['percent'] = mem.percent
memInfo2 = {'memTotal': int(mem.total / 1024 / 1024), 'memFree': int(mem.free / 1024 / 1024),
'memBuffers': int(mem.buffers / 1024 / 1024), 'memCached': int(mem.cached / 1024 / 1024)}
memInfo['total'] = round(float(mem.total) / 1024 / 1024 / 1024, 2)
memInfo['free'] = round((memInfo2['memFree'] + memInfo2['memBuffers'] + memInfo2['memCached']) / 1024, 2)
memInfo['used'] = round(float(mem.used) / 1024 / 1024 / 1024, 2)
memInfo['percent'] = round((int(mem.used) / 1024 / 1024) / memInfo2['memTotal'] * 100, 1)
# memInfo['realUsed'] = round((memInfo2['memTotal'] - memInfo2['memFree'] - memInfo2['memBuffers'] - memInfo2['memCached']) / 1024,2) # memRealUsed
return memInfo
# 获取磁盘IO开销数据
def get_disk_iostat():
iokey = 'iostat'
diskio = cache.get(iokey)
mtime = int(time.time())
if not diskio:
diskio = {}
diskio['info'] = None
diskio['time'] = mtime
diskio_1 = diskio['info']
stime = mtime - diskio['time']
if not stime: stime = 1
diskInfo = {}
diskInfo['ALL'] = {}
diskInfo['ALL']['read_count'] = 0
diskInfo['ALL']['write_count'] = 0
diskInfo['ALL']['read_bytes'] = 0
diskInfo['ALL']['write_bytes'] = 0
diskInfo['ALL']['read_time'] = 0
diskInfo['ALL']['write_time'] = 0
diskInfo['ALL']['read_merged_count'] = 0
diskInfo['ALL']['write_merged_count'] = 0
try:
if os.path.exists('/proc/diskstats'):
diskio_2 = psutil.disk_io_counters(perdisk=True)
if not diskio_1:
diskio_1 = diskio_2
for disk_name in diskio_2.keys():
diskInfo[disk_name] = {}
diskInfo[disk_name]['read_count'] = int(
(diskio_2[disk_name].read_count - diskio_1[disk_name].read_count) / stime)
diskInfo[disk_name]['write_count'] = int(
(diskio_2[disk_name].write_count - diskio_1[disk_name].write_count) / stime)
diskInfo[disk_name]['read_bytes'] = int(
(diskio_2[disk_name].read_bytes - diskio_1[disk_name].read_bytes) / stime)
diskInfo[disk_name]['write_bytes'] = int(
(diskio_2[disk_name].write_bytes - diskio_1[disk_name].write_bytes) / stime)
diskInfo[disk_name]['read_time'] = int(
(diskio_2[disk_name].read_time - diskio_1[disk_name].read_time) / stime)
diskInfo[disk_name]['write_time'] = int(
(diskio_2[disk_name].write_time - diskio_1[disk_name].write_time) / stime)
diskInfo[disk_name]['read_merged_count'] = int(
(diskio_2[disk_name].read_merged_count - diskio_1[disk_name].read_merged_count) / stime)
diskInfo[disk_name]['write_merged_count'] = int(
(diskio_2[disk_name].write_merged_count - diskio_1[disk_name].write_merged_count) / stime)
diskInfo['ALL']['read_count'] += diskInfo[disk_name]['read_count']
diskInfo['ALL']['write_count'] += diskInfo[disk_name]['write_count']
diskInfo['ALL']['read_bytes'] += diskInfo[disk_name]['read_bytes']
diskInfo['ALL']['write_bytes'] += diskInfo[disk_name]['write_bytes']
if diskInfo['ALL']['read_time'] < diskInfo[disk_name]['read_time']:
diskInfo['ALL']['read_time'] = diskInfo[disk_name]['read_time']
if diskInfo['ALL']['write_time'] < diskInfo[disk_name]['write_time']:
diskInfo['ALL']['write_time'] = diskInfo[disk_name]['write_time']
diskInfo['ALL']['read_merged_count'] += diskInfo[disk_name]['read_merged_count']
diskInfo['ALL']['write_merged_count'] += diskInfo[disk_name]['write_merged_count']
cache.set(iokey, {'info': diskio_2, 'time': mtime})
except:
return diskInfo
return diskInfo
# 获取网卡数据
def GetNetWork():
cache_timeout = 86400
otime = cache.get("lybbn_otime")
ntime = time.time()
networkInfo = {}
networkInfo['network'] = {}
networkInfo['upTotal'] = 0
networkInfo['downTotal'] = 0
networkInfo['up'] = 0
networkInfo['down'] = 0
networkInfo['downPackets'] = 0
networkInfo['upPackets'] = 0
networkIo_list = psutil.net_io_counters(pernic=True)
for net_key in networkIo_list.keys():
networkIo = networkIo_list[net_key][:4]
up_key = "{}_up".format(net_key)
down_key = "{}_down".format(net_key)
otime_key = "lybbn_otime"
if not otime:
otime = time.time()
cache.set(up_key, networkIo[0], cache_timeout)
cache.set(down_key, networkIo[1], cache_timeout)
cache.set(otime_key, otime, cache_timeout)
networkInfo['network'][net_key] = {}
up = cache.get(up_key)
down = cache.get(down_key)
if not up:
up = networkIo[0]
if not down:
down = networkIo[1]
networkInfo['network'][net_key]['upTotal'] = networkIo[0]
networkInfo['network'][net_key]['downTotal'] = networkIo[1]
networkInfo['network'][net_key]['up'] = round(float(networkIo[0] - up) / 1024 / (ntime - otime), 2)
networkInfo['network'][net_key]['down'] = round(float(networkIo[1] - down) / 1024 / (ntime - otime), 2)
networkInfo['network'][net_key]['downPackets'] = networkIo[3]
networkInfo['network'][net_key]['upPackets'] = networkIo[2]
networkInfo['upTotal'] += networkInfo['network'][net_key]['upTotal']
networkInfo['downTotal'] += networkInfo['network'][net_key]['downTotal']
networkInfo['up'] += networkInfo['network'][net_key]['up']
networkInfo['down'] += networkInfo['network'][net_key]['down']
networkInfo['downPackets'] += networkInfo['network'][net_key]['downPackets']
networkInfo['upPackets'] += networkInfo['network'][net_key]['upPackets']
cache.set(up_key, networkIo[0], cache_timeout)
cache.set(down_key, networkIo[1], cache_timeout)
cache.set(otime_key, time.time(), cache_timeout)
networkInfo['up'] = round(float(networkInfo['up']), 2)
networkInfo['down'] = round(float(networkInfo['down']), 2)
networkInfo['iostat'] = get_disk_iostat()
return networkInfo
# 取系统启动时间
def GetBootTime():
key = 'lybbn_sys_time'
sys_time = cache.get(key)
if sys_time: return sys_time
import math
conf = readFile('/proc/uptime').split()
tStr = float(conf[0])
min = tStr / 60
hours = min / 60
days = math.floor(hours / 24)
hours = math.floor(hours - (days * 24))
min = math.floor(min - (days * 60 * 24) - (hours * 60))
sys_time = "{}".format(int(days))
cache.set(key, sys_time, 1800)
return sys_time
# 取CPU类型
def getCpuType():
cpuinfo = open('/proc/cpuinfo', 'r').read()
rep = "model\s+name\s+:\s+(.+)"
tmp = re.search(rep, cpuinfo, re.I)
cpuType = ''
if tmp:
cpuType = tmp.groups()[0]
else:
cpuinfo = ExecShell('LANG="en_US.UTF-8" && lscpu')[0]
rep = "Model\s+name:\s+(.+)"
tmp = re.search(rep, cpuinfo, re.I)
if tmp: cpuType = tmp.groups()[0]
return cpuType
# 取CPU信息
def GetCpuInfo(interval=1):
# 取CPU信息
cpuCount = psutil.cpu_count()
cpuNum = psutil.cpu_count(logical=False)
c_tmp = readFile('/proc/cpuinfo')
d_tmp = re.findall("physical id.+", c_tmp)
cpuW = len(set(d_tmp))
import threading
p = threading.Thread(target=get_cpu_percent_thead, args=(interval,))
# p.setDaemon(True)
p.start()
used = cache.get('lybbn_cpu_used_all')
if not used: used = get_cpu_percent_thead(interval)
used_all = psutil.cpu_percent(percpu=True)
cpu_name = getCpuType() + " * {}".format(cpuW)
return used, cpuCount, used_all, cpu_name, cpuNum, cpuW
def get_cpu_percent_thead(interval):
used = psutil.cpu_percent(interval)
cache.set('lybbn_cpu_used_all', used, 10)
return used
def get_cpu_time():
cpu_time = 0.00
cpu_times = psutil.cpu_times()
for s in cpu_times: cpu_time += s
return cpu_time
def GetDiskInfo(human=True):
# 取磁盘分区信息
key = 'lybbn_sys_disk'
diskInfo = cache.get(key)
if diskInfo: return diskInfo
if human:
temp = ExecShell("df -hT -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")[0]
else:
temp = ExecShell("df -T -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")[0]
tempInodes = ExecShell("df -i -P|grep '/'|grep -v tmpfs|grep -v 'snap/core'|grep -v udev")[0]
temp1 = temp.split('\n')
tempInodes1 = tempInodes.split('\n')
diskInfo = []
n = 0
cuts = ['/mnt/cdrom', '/boot', '/boot/efi', '/dev', '/dev/shm', '/run/lock', '/run', '/run/shm', '/run/user']
for tmp in temp1:
n += 1
try:
inodes = tempInodes1[n - 1].split()
disk = re.findall(
r"^(.+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\w\.]+)\s+([\d%]{2,4})\s+(/.{0,100})$", tmp.strip())
if disk: disk = disk[0]
if len(disk) < 6: continue
if disk[2].find('M') != -1: continue
if disk[2].find('K') != -1: continue
if len(disk[6].split('/')) > 10: continue
if disk[6] in cuts: continue
if disk[6].find('docker') != -1: continue
if disk[1].strip() in ['tmpfs']: continue
arr = {}
arr['filesystem'] = disk[0].strip()
arr['type'] = disk[1].strip()
arr['path'] = disk[6].replace('/usr/local/lighthouse/softwares/btpanel', '/www')
tmp1 = [disk[2], disk[3], disk[4], disk[5].split('%')[0]]
arr['size'] = tmp1
arr['inodes'] = [inodes[1], inodes[2], inodes[3], inodes[4]]
diskInfo.append(arr)
except Exception as ex:
continue
cache.set(key, diskInfo, 10)
return diskInfo
def GetMsg(key, args=()):
"""
根据key获取内置消息返回
@key 指定消息的key
@args 消息内容中的参数
"""
try:
log_message = json.loads(ReadFile(PUBLIC_DICT));
keys = log_message.keys();
msg = None;
if key in keys:
msg = log_message[key];
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i]);
return msg;
except:
return key
def getMsg(key, args=()):
return GetMsg(key, args)
def ReturnMsg(status, msg, args=()):
"""
@name 取通用dict返回
@author hwliang<hwl@bt.cn>
@param status 返回状态
@param msg 返回消息
@return dict {"status":bool,"msg":string}
"""
log_message = json.loads(ReadFile(PUBLIC_DICT))
keys = log_message.keys()
if type(msg) == str:
if msg in keys:
msg = log_message[msg]
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i])
return {'status': status, 'msg': msg}
def returnMsg(status, msg, args=()):
"""
@name 取通用dict返回
@author hwliang<hwl@bt.cn>
@param status 返回状态
@param msg 返回消息
@return dict {"status":bool,"msg":string}
"""
return ReturnMsg(status, msg, args)
def RestartServer():
ExecShell("sync && init 6 &")
return returnMsg(True, 'SYS_REBOOT')

View File

@@ -0,0 +1,12 @@
{
"ERROR": "操作失败",
"SUCCESS": "操作成功",
"START": "启动",
"STOP": "停止",
"OFF": "停用",
"ON": "启用",
"OPEN": "打开",
"CLOSE": "关闭",
"SYS_EXEC_SUCCESS": "执行成功!",
"SYS_REBOOT": "命令发送成功!"
}

View File

@@ -0,0 +1,78 @@
#!/bin/python
#coding: utf-8
# +-------------------------------------------------------------------
# | django-vue3-lyadmin
# +-------------------------------------------------------------------
# | Author: lybbn
# +-------------------------------------------------------------------
# | QQ: 1042594286
# +-------------------------------------------------------------------
# ------------------------------
# 系统命令封装
# ------------------------------
import platform
plat = platform.system().lower()
if plat == 'windows':
import windows as myos
else:
import linux as myos
class system:
isWindows = False
def __init__(self):
self.isWindows = self.isWindows()
def isWindows(self):
plat = platform.system().lower()
if plat == 'windows':
return True
return False
def GetSystemAllInfo(self,isCache=False):
"""
获取系统所有信息
"""
data = {}
data['mem'] = self.GetMemInfo()
data['load_average'] = self.GetLoadAverage()
data['network'] = self.GetNetWork()
data['cpu'] = self.GetCpuInfo(1)
data['disk'] = self.GetDiskInfo()
data['time'] = self.GetBootTime()
data['system'] = self.GetSystemVersion()
data['is_windows'] = self.isWindows
return data
def GetMemInfo(self):
memInfo = myos.GetMemInfo()
return memInfo
def GetLoadAverage(self):
data = myos.GetLoadAverage()
return data
def GetNetWork(self):
data = myos.GetNetWork()
return data
def GetCpuInfo(self,interval=1):
data = myos.GetCpuInfo(interval)
return data
def GetBootTime(self):
data = myos.GetBootTime()
return data
def GetDiskInfo(self):
data = myos.GetDiskInfo()
return data
def GetSystemVersion(self):
data = myos.GetSystemVersion()
return data

View File

@@ -0,0 +1,818 @@
#!/bin/python
# coding: utf-8
# +-------------------------------------------------------------------
# | django-vue3-lyadmin
# +-------------------------------------------------------------------
# | Author: lybbn
# +-------------------------------------------------------------------
# | QQ: 1042594286
# +-------------------------------------------------------------------
# ------------------------------
# windows系统命令工具类封装
# ------------------------------
import platform
import os, time, re, json, socket
import psutil
import winreg
from random import Random
from django.core.cache import cache
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent
PUBLIC_DICT = os.path.join(BASE_DIR, 'public.json')
def ReadFile(filename, mode='r'):
"""
读取文件内容
@filename 文件名
return string(bin) 若文件不存在则返回None
"""
import os, chardet
if not os.path.exists(filename): return False
if not os.path.isfile(filename): return False
f_body = '';
try:
fp = open(filename, mode)
f_body = fp.read()
except:
try:
fp.close()
except:
pass
try:
encoding = 'utf8'
fp = open(filename, mode, encoding=encoding)
f_body = fp.read()
except:
try:
fp.close()
except:
pass
try:
encoding = 'gbk'
fp = open(filename, mode, encoding=encoding)
f_body = fp.read()
except:
try:
fp.close()
except:
pass
encoding = 'ansi'
fp = open(filename, mode, encoding=encoding)
f_body = fp.read()
try:
if f_body[0] == '\ufeff':
# 处理带bom格式
new_code = chardet.detect(f_body.encode(encoding))["encoding"]
f_body = f_body.encode(encoding).decode(new_code);
except:
pass
fp.close()
return f_body
def readFile(filename, mode='r'):
return ReadFile(filename, mode)
def ReadReg(path, key):
"""
读取注册表
@path 注册表路径
@key 注册表键值
"""
import winreg
try:
newKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
value, type = winreg.QueryValueEx(newKey, key)
return value
except:
return False
def DelReg(path, key):
"""
删除注册表
@path 注册表路径
@key 注册表键值
"""
import winreg
try:
newKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
winreg.DeleteKey(newKey, key)
return True
except:
return False
def WriteReg(path, key, value, type=winreg.REG_SZ):
"""
写入/创建注册表
@path 注册表路径
@key 注册表键值
@value 注册表值
@type 注册表值类型
"""
import winreg
try:
newKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path, 0, winreg.KEY_ALL_ACCESS)
except:
newKey = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, path)
try:
# SetValue 只支持字符串其他类型使用SetValueEx
if isinstance(value, int):
winreg.SetValueEx(newKey, key, 0, winreg.REG_DWORD, value)
else:
winreg.SetValueEx(newKey, key, 0, type, value)
return True
except Exception as ex:
return False
def get_mac_address():
"""
获取mac
"""
import uuid
mac = uuid.UUID(int=uuid.getnode()).hex[-12:]
return ":".join([mac[e:e + 2] for e in range(0, 11, 2)])
def process_exists(pname, exe=None):
"""
检查进程是否存在
@pname 进程名称
@exe 进程路径
"""
try:
pids = psutil.pids()
for pid in pids:
try:
p = psutil.Process(pid)
if p.name() == pname:
if not exe:
return True;
else:
if p.exe() == exe: return True
except:
pass
return False
except:
return True
def GetRandomString(length):
"""
@name 取随机字符串
@author hwliang<hwl@bt.cn>
@param length 要获取的长度
@return string(length)
"""
strings = ''
chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
chrlen = len(chars) - 1
random = Random()
for i in range(length):
strings += chars[random.randint(0, chrlen)]
return strings
def Md5(strings):
"""
@name 生成MD5
@author hwliang<hwl@bt.cn>
@param strings 要被处理的字符串
@return string(32)
"""
if type(strings) != bytes:
strings = strings.encode()
import hashlib
m = hashlib.md5()
m.update(strings)
return m.hexdigest()
def md5(strings):
return Md5(strings)
def ExecShell(cmdstring, cwd=None, timeout=None, shell=True):
"""
通过管道执行SHELL
@cmdstring 需要执行的cmd命令
@cwd 设置工作目录
@timeout 超时时间
@shell 是否通过shell输出
@output 是否通过文件重定向输出结果(当结果数据量过大必须使用此参数,否则造成管道阻塞)
"""
import shlex
import datetime
import subprocess
import time, tempfile
a = ''
e = ''
try:
rx = md5(cmdstring)
succ_f = tempfile.SpooledTemporaryFile(max_size=4096000, mode='wb+', suffix='_succ', prefix='btex_' + rx)
err_f = tempfile.SpooledTemporaryFile(max_size=4096000, mode='wb+', suffix='_err', prefix='btex_' + rx)
sub = subprocess.Popen(cmdstring, shell=shell, bufsize=128, stdout=succ_f, stderr=err_f)
sub.wait()
err_f.seek(0)
succ_f.seek(0)
a = succ_f.read()
e = err_f.read()
if not err_f.closed: err_f.close()
if not succ_f.closed: succ_f.close()
except:
pass
if type(a) == bytes:
try:
a = a.decode('utf-8')
except:
try:
a = a.decode('gb2312')
except:
try:
a = a.decode('utf-16')
except:
a = a.decode('gb2312', 'ignore')
if type(e) == bytes:
try:
e = e.decode('utf-8')
except:
try:
a = a.decode('utf-16')
except:
e = e.decode('gb2312', 'ignore')
return a, e
class ExcepError(Exception):
'''
通用异常对像
'''
def __init__(self, value):
self.value = value
def __str__(self):
return ("运行时发生错误: {}".format(repr(self.value)))
def exists_args(args, get):
'''
@name 检查参数是否存在
@author hwliang<2021-06-08>
@param args<list or str> 参数列表 允许是列表或字符串
@param get<dict_obj> 参数对像
@return bool 都存在返回True否则抛出KeyError异常
'''
if type(args) == str:
args = args.split(',')
for arg in args:
if not arg in get:
raise KeyError('缺少必要参数: {}'.format(arg))
return True
# xss 防御
def xssencode(text):
from html import escape, unescape
list = ['`', '~', '&', '#', '*', '$', '@', '<', '>', '\"', '\'', ';', '%', ',', '\\u']
ret = []
for i in text:
if i in list:
i = ''
ret.append(i)
str_convert = ''.join(ret)
text2 = escape(str_convert, quote=True)
return text2
def path_safe_check(path, force=True):
"""
校验路径安全
@path 校验路径
@force
"""
if len(path) > 256: return False
checks = ['..', './', '\\', '%', '$', '^', '&', '*', '~', '#', '"', "'", ';', '|', '{', '}', '`']
for c in checks:
if path.find(c) != -1: return False
if force:
rep = r"^[\w\s\.\/-]+$"
if not re.match(rep, path): return False
return True
def is_ipv4(ip):
"""
判断是否IPV4地址
@ip ip地址
return bool
"""
try:
socket.inet_pton(socket.AF_INET, ip)
except AttributeError:
try:
socket.inet_aton(ip)
except socket.error:
return False
return ip.count('.') == 3
except socket.error:
return False
return True
def is_ipv6(ip):
"""
判断是否IPV6地址
@ip ip地址
return bool
"""
try:
socket.inet_pton(socket.AF_INET6, ip)
except socket.error:
return False
return True
def to_size(size):
"""
字节单位转换
@size 字节大小
return 返回带单位的格式(如1 GB)
"""
if not size: return '0.00 b'
size = float(size)
d = ('b', 'KB', 'MB', 'GB', 'TB');
s = d[0];
for b in d:
if size < 1024: return ("%.2f" % size) + ' ' + b;
size = size / 1024;
s = b;
return ("%.2f" % size) + ' ' + b;
# 取通用对象
re_key_match = re.compile(r'^[\w\s\[\]\-]+$')
re_key_match2 = re.compile(r'^\.?__[\w\s[\]\-]+__\.?$')
key_filter_list = ['get', 'set', 'get_items', 'exists', '__contains__', '__setitem__', '__getitem__', '__delitem__',
'__delattr__', '__setattr__', '__getattr__', '__class__']
class dict_obj:
def __contains__(self, key):
return getattr(self, key, None)
def __setitem__(self, key, value):
if key in key_filter_list:
raise ExcepError("错误的字段名")
if not re_key_match.match(key) or re_key_match2.match(key):
raise ExcepError("错误的字段名")
setattr(self, key, value)
def __getitem__(self, key):
return getattr(self, key, None)
def __delitem__(self, key):
delattr(self, key)
def __delattr__(self, key):
delattr(self, key)
def get_items(self):
return self
def exists(self, keys):
return exists_args(keys, self)
def set(self, key, value):
if not isinstance(value, str) or not isinstance(key, str): return False
if key in key_filter_list:
raise ExcepError("错误的字段名")
if not re_key_match.match(key) or re_key_match2.match(key):
raise ExcepError("错误的字段名")
return setattr(self, key, value)
def get(self, key, default='', format='', limit=[]):
'''
@name 获取指定参数
@param key<string> 参数名称,允许在/后面限制参数格式,请参考参数值格式(format)
@param default<string> 默认值,默认空字符串
@param format<string> 参数值格式(int|str|port|float|json|xss|path|url|ip|ipv4|ipv6|letter|mail|phone|正则表达式|>1|<1|=1),默认为空
@param limit<list> 限制参数值内容
@param return mixed
'''
if key.find('/') != -1:
key, format = key.split('/')
result = getattr(self, key, default)
if isinstance(result, str): result = result.strip()
if format:
if format in ['str', 'string', 's']:
result = str(result)
elif format in ['int', 'd']:
try:
result = int(result)
except:
raise ValueError("参数:{}要求int类型数据".format(key))
elif format in ['float', 'f']:
try:
result = float(result)
except:
raise ValueError("参数:{}要求float类型数据".format(key))
elif format in ['json', 'j']:
try:
result = json.loads(result)
except:
raise ValueError("参数:{}, 要求JSON字符串".format(key))
elif format in ['xss', 'x']:
result = xssencode(result)
elif format in ['path', 'p']:
if not path_safe_check(result):
raise ValueError("参数:{},要求正确的路径格式".format(key))
result = result.replace('//', '/')
elif format in ['url', 'u']:
regex = re.compile(
r'^(?:http|ftp)s?://'
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
r'localhost|'
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
r'(?::\d+)?'
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
if not re.match(regex, result):
raise ValueError('参数:{}要求正确的URL格式'.format(key))
elif format in ['ip', 'ipaddr', 'i', 'ipv4', 'ipv6']:
if format == 'ipv4':
if not is_ipv4(result):
raise ValueError('参数:{}要求正确的ipv4地址'.format(key))
elif format == 'ipv6':
if not is_ipv6(result):
raise ValueError('参数:{}要求正确的ipv6地址'.format(key))
else:
if not is_ipv4(result) and not is_ipv6(result):
raise ValueError('参数:{}要求正确的ipv4/ipv6地址'.format(key))
elif format in ['w', 'letter']:
if not re.match(r'^\w+$', result):
raise ValueError('参数:{},要求只能是英文字母或数据组成'.format(key))
elif format in ['email', 'mail', 'm']:
if not re.match(r"^.+\\@(\\[?)[a-zA-Z0-9\\-\\.]+\\.([a-zA-Z]{2,3}|[0-9]{1,3})(\\]?)$)", result):
raise ValueError("参数:{},要求正确的邮箱地址格式".format(key))
elif format in ['phone', 'mobile', 'p']:
if not re.match("^[0-9]{11,11}$", result):
raise ValueError("参数:{},要求手机号码格式".format(key))
elif format in ['port']:
result_port = int(result)
if result_port > 65535 or result_port < 0:
raise ValueError("参数:{}要求端口号为0-65535".format(key))
result = result_port
elif re.match(r"^[<>=]\d+$", result):
operator = format[0]
length = int(format[1:].strip())
result_len = len(result)
error_obj = ValueError("参数:{},要求长度为{}".format(key, format))
if operator == '=':
if result_len != length:
raise error_obj
elif operator == '>':
if result_len < length:
raise error_obj
else:
if result_len > length:
raise error_obj
elif format[0] in ['^', '(', '[', '\\', '.'] or format[-1] in ['$', ')', ']', '+', '}']:
if not re.match(format, result):
raise ValueError("指定参数格式不正确, {}:{}".format(key, format))
if limit:
if not result in limit:
raise ValueError("指定参数值范围不正确, {}:{}".format(key, limit))
return result
def is_64bitos():
"""
判断是否x64系统(windows)
"""
bites = {'AMD64': 64, 'x86_64': 64, 'i386': 32, 'x86': 32}
info = platform.uname()
if bites.get(info.machine) == 64:
return True
return False
def get_registry_value(key, subkey, value):
"""
读取注册表信息
@key 注册表类型
@subkey 注册表路径
@value 注册表具体key值
"""
key = getattr(winreg, key)
handle = winreg.OpenKey(key, subkey)
(value, type) = winreg.QueryValueEx(handle, value)
return value
def GetSystemVersion():
"""
取操作系统版本
"""
try:
key = 'lybbn_sys_version'
version = cache.get(key)
if version: return version
bit = 'x86';
if is_64bitos(): bit = 'x64'
def get(key):
return get_registry_value("HKEY_LOCAL_MACHINE", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", key)
os = get("ProductName")
build = get("CurrentBuildNumber")
version = "%s (build %s) %s (Py%s)" % (os, build, bit, platform.python_version())
cache.set(key, version, 10000)
return version
except Exception as ex:
version = "未知系统版本."
cache.set(key, version, 10000)
return version
# 取负载信息
def GetLoadAverage():
data = {}
data['one'] = 0
data['five'] = 0
data['fifteen'] = 0
data['max'] = psutil.cpu_count() * 2
data['limit'] = data['max']
data['safe'] = data['max'] * 0.75
data['percent'] = 0
return data
# 取内存信息
def GetMemInfo():
mem = psutil.virtual_memory()
memInfo = {}
memInfo['percent'] = mem.percent
memInfo['total'] = round(float(mem.total) / 1024 / 1024 / 1024, 2)
memInfo['free'] = round(float(mem.free) / 1024 / 1024 / 1024, 2)
memInfo['used'] = round(float(mem.used) / 1024 / 1024 / 1024, 2)
return memInfo
# 获取网卡信息
def GetNetWork():
cache_timeout = 86400
otime = cache.get("otime")
ntime = time.time()
networkInfo = {}
networkInfo['network'] = {}
networkInfo['upTotal'] = 0
networkInfo['downTotal'] = 0
networkInfo['up'] = 0
networkInfo['down'] = 0
networkInfo['downPackets'] = 0
networkInfo['upPackets'] = 0
networkIo_list = psutil.net_io_counters(pernic=True)
for net_key in networkIo_list.keys():
if net_key.find('Loopback') >= 0 or net_key.find('Teredo') >= 0 or net_key.find('isatap') >= 0: continue
networkIo = networkIo_list[net_key][:4]
up_key = "{}_up".format(net_key)
down_key = "{}_down".format(net_key)
otime_key = "otime"
if not otime:
otime = time.time()
cache.set(up_key, networkIo[0], cache_timeout)
cache.set(down_key, networkIo[1], cache_timeout)
cache.set(otime_key, otime, cache_timeout)
networkInfo['network'][net_key] = {}
up = cache.get(up_key)
down = cache.get(down_key)
if not up:
up = networkIo[0]
if not down:
down = networkIo[1]
networkInfo['network'][net_key]['upTotal'] = networkIo[0]
networkInfo['network'][net_key]['downTotal'] = networkIo[1]
try:
networkInfo['network'][net_key]['up'] = round(float(networkIo[0] - up) / 1024 / (ntime - otime), 2)
networkInfo['network'][net_key]['down'] = round(float(networkIo[1] - down) / 1024 / (ntime - otime), 2)
except:
networkInfo['up'] = 0
networkInfo['down'] = 0
networkInfo['network'][net_key]['up'] = 0
networkInfo['network'][net_key]['down'] = 0
networkInfo['network'][net_key]['downPackets'] = networkIo[3]
networkInfo['network'][net_key]['upPackets'] = networkIo[2]
networkInfo['upTotal'] += networkInfo['network'][net_key]['upTotal']
networkInfo['downTotal'] += networkInfo['network'][net_key]['downTotal']
networkInfo['up'] += networkInfo['network'][net_key]['up']
networkInfo['down'] += networkInfo['network'][net_key]['down']
networkInfo['downPackets'] += networkInfo['network'][net_key]['downPackets']
networkInfo['upPackets'] += networkInfo['network'][net_key]['upPackets']
cache.set(up_key, networkIo[0], cache_timeout)
cache.set(down_key, networkIo[1], cache_timeout)
cache.set(otime_key, time.time(), cache_timeout)
networkInfo['up'] = round(float(networkInfo['up']), 2)
networkInfo['down'] = round(float(networkInfo['down']), 2)
networkInfo['iostat'] = {}
return networkInfo
# 取系统启动时间
def GetBootTime():
key = 'lybbn_sys_time'
sys_time = cache.get(key)
if sys_time: return sys_time
import math
tStr = time.time() - psutil.boot_time()
min = tStr / 60;
hours = min / 60;
days = math.floor(hours / 24);
hours = math.floor(hours - (days * 24));
min = math.floor(min - (days * 60 * 24) - (hours * 60));
sys_time = "{}".format(int(days))
cache.set(key, sys_time, 1800)
return sys_time
def getCpuType():
"""
取CPU类型
"""
try:
cpuType = ReadReg(r'HARDWARE\DESCRIPTION\System\CentralProcessor\0', 'ProcessorNameString')
except:
cpuType = ''
return cpuType;
# 取CPU详细信息
def GetCpuInfo(interval=1):
cpuCount = psutil.cpu_count()
cpuNum = psutil.cpu_count(logical=False)
import threading
p = threading.Thread(target=get_cpu_percent_thead, args=(interval,))
# p.setDaemon(True)
p.start()
used = cache.get('lybbn_cpu_used_all')
if not used: used = get_cpu_percent_thead(interval)
used_all = psutil.cpu_percent(percpu=True)
used_total = 0
for x in used_all: used_total += x
ret = ExecShell('wmic cpu get NumberOfCores')[0]
cpuW = 0
arrs = ret.strip().split('\r\n')
for x in arrs:
val = x.strip()
if not val: continue;
try:
val = int(val)
cpuW += 1;
except:
pass
try:
cpu_name = '{} * {}'.format(
ReadReg(r'HARDWARE\DESCRIPTION\System\CentralProcessor\0', 'ProcessorNameString').strip(), cpuW);
except:
cpu_name = ''
tmp = 0
if cpuW: tmp = cpuNum / cpuW
used = 0
if used_total: used = round(used_total / cpuCount, 2)
return used, cpuCount, used_all, cpu_name, tmp, cpuW
def get_cpu_percent_thead(interval):
used = psutil.cpu_percent(interval)
cache.set('lybbn_cpu_used_all', used, 10)
return used
# 取磁盘分区信息
def GetDiskInfo():
key = 'lybbn_sys_disk'
diskInfo = cache.get(key)
if diskInfo: return diskInfo
try:
diskIo = psutil.disk_partitions();
except:
import string
diskIo = []
for c in string.ascii_uppercase:
disk = c + ':'
if os.path.isdir(disk):
data = dict_obj()
data['mountpoint'] = disk + '/'
diskIo.append(data)
diskInfo = []
for disk in diskIo:
try:
tmp = {}
tmp['path'] = disk.mountpoint.replace("\\", "/")
usage = psutil.disk_usage(disk.mountpoint)
tmp['size'] = [to_size(usage.total), to_size(usage.used), to_size(usage.free), usage.percent]
tmp['inodes'] = False
diskInfo.append(tmp)
except:
pass
cache.set(key, diskInfo, 10)
return diskInfo
def GetMsg(key, args=()):
"""
根据key获取内置消息返回
@key 指定消息的key
@args 消息内容中的参数
"""
try:
log_message = json.loads(ReadFile(PUBLIC_DICT));
keys = log_message.keys();
msg = None;
if key in keys:
msg = log_message[key];
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i]);
return msg;
except:
return key
def getMsg(key, args=()):
return GetMsg(key, args)
def ReturnMsg(status, msg, args=()):
"""
@name 取通用dict返回
@param status 返回状态
@param msg 返回消息
@return dict {"status":bool,"msg":string}
"""
log_message = json.loads(ReadFile(PUBLIC_DICT));
keys = log_message.keys();
if type(msg) == str:
if msg in keys:
msg = log_message[msg];
for i in range(len(args)):
rep = '{' + str(i + 1) + '}'
msg = msg.replace(rep, args[i]);
return {'status': status, 'msg': msg}
def returnMsg(status, msg, args=()):
return ReturnMsg(status, msg, args)
# 重启系统
def RestartServer():
try:
os.system("shutdown /r /f /t 0");
except:
pass
return returnMsg(True, 'SYS_REBOOT');