From 5668140d13a061d3b421a56ab4e29e59622ecc8a Mon Sep 17 00:00:00 2001 From: none Date: Sat, 9 Mar 2024 15:05:31 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=BE=D0=B4=D0=B5=D1=80=D0=BD=D0=B8?= =?UTF-8?q?=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=20ping.py,=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=20=D1=81=D0=B0=D0=B9?= =?UTF-8?q?=D1=82=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D1=81=D0=BC?= =?UTF-8?q?=D0=BE=D1=82=D1=80=D0=B0=20=D0=B0=D0=BD=D0=B0=D0=BB=D0=B8=D1=82?= =?UTF-8?q?=D0=B8=D0=BA=D0=B8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- func.py | 20 ++++++ ping.py | 128 +++++++++++++++++++++++-------------- site_stat.py | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+), 45 deletions(-) create mode 100644 func.py create mode 100644 site_stat.py diff --git a/func.py b/func.py new file mode 100644 index 0000000..bccbbe0 --- /dev/null +++ b/func.py @@ -0,0 +1,20 @@ +from db import * +import json +import os + +def stat_exist(date): + if not os.path.exists(f'data/{date}.json'): + db = {} + js = json.dumps(db, indent=2) + with open(f'data/{date}.json', "w") as outfile: + outfile.write(js) + + # Заполняем БД, если она пустая + # Пинг + # "ping": {"time": ["14:30:36", "14:30:41"], "ms": [42, 39]} + db["ping"] = {"time": [], "ms": []} + # Онлайн + # "online": {"time": ["14:30:36", "14:30:41"], "count": [1, 0]} + db["online"] = {"time": [], "count":[]} + + write(db, f'data/{date}.json') diff --git a/ping.py b/ping.py index 1eccd26..dd1461d 100644 --- a/ping.py +++ b/ping.py @@ -1,49 +1,87 @@ from mctools import PINGClient -ping = PINGClient('135.181.170.94',25630) -#stats = ping.get_stats() - -#Get home dir -from subprocess import getoutput -global home -home = getoutput("echo $HOME") - -#Work with JSON -import json -def read(): - global db, home - with open(f'{home}/db.json', 'r') as openfile: - db = json.load(openfile) -def write(): - global db - js = json.dumps(db, indent=4) - with open(f'{home}/db.json', 'w') as outfile: - outfile.write(js) - -#My libraries -from time import sleep - -#Read -read() - -ttime = 0 -while True: - sleep(1) +from time import sleep, time + +from datetime import datetime +now = datetime.now + +host = 'CoolFunZone.aternos.me' +port = 36413 +# 764 - 1.20.2 +prot = 764 +global c +c = PINGClient(host, port, proto_num = prot) + +from db import * +from func import * +date = now().strftime("%Y-%m-%d") +# Проверяем существует ли +stat_exist(date) +db = read(f'data/{date}.json') + +# КАК ЧАСТО ОБНОВЛЯЕМ (секунды) +update = 60 + +while True: try: - #if True: - stats = ping.get_stats() - if stats['players']['online'] != 0: - for i in stats['players']['sample']: - #Add in db if not in db - if i[0] not in db: - db[i[0]] = 1 + ttime - write() - else: - db[i[0]] = db[i[0]] + 1 + ttime - write() - ttime = 0 - - except Exception as e: - ping = PINGClient('135.181.170.94',25630) - print(e) + raw = c.get_stats() + ms = round( c.ping() ) # Пинг + except: + c.stop() + c = PINGClient(host, port, proto_num = prot) + continue + + if "sample" in raw["players"]: + # Список игроков + players_raw = raw["players"]["sample"] + # Оставляем только ники (без айди) + players = [] + for i in players_raw: + players.append(i[0][:i[0].find('[')]) + # Онлайн + online = raw["players"]["online"] + else: + players = [] + online = 0 + + # Фикс атерноса + max = raw["players"]["max"] + if max == 0: + ms = 0 + + # Открываем БД. + # Дата + date = now().strftime("%Y-%m-%d") + # Проверяем существует ли + stat_exist(date) + db = read(f'data/{date}.json') + + # Заполняем БД + # Пинг + db["ping"]["time"].append( now().strftime('%H:%M') ) + db["ping"]["ms"].append( ms ) + # Онлайн + db["online"]["time"].append( now().strftime('%H:%M') ) + db["online"]["count"].append( online ) + + + # Топ игроков по времени и последнее время захода + stat = read('data/stat.json') + # Перебираем игроков + for i in players: + # Если игрок уже в базе + if i in stat["players"]["time"]: + stat["players"]["time"][i] += update + else: + stat["players"]["time"][i] = update + # Время захода + stat["players"]["last"][i] = time() + + + # Записываем изменения + write(db, f'data/{date}.json') + + write(stat, 'data/stat.json') + # Задержка + sleep(update) diff --git a/site_stat.py b/site_stat.py new file mode 100644 index 0000000..e54f76c --- /dev/null +++ b/site_stat.py @@ -0,0 +1,173 @@ +from dash import Dash, html, dcc, Input, Output, callback +import plotly.graph_objs as go + +from time import strftime, localtime + +from db import * + +from func import stat_exist +from datetime import datetime +now = datetime.now + +app = Dash(__name__) + +app.layout = html.Div([ + + html.Div([ + dcc.Dropdown(["Сервер", "Игроки"], "Сервер", id = "select", clearable=False, searchable=False, style = {"flex": 70}), + dcc.Dropdown(id = "date", clearable=True, searchable=False, style = {"flex": 30}, placeholder="Дата"), + ], style = {"display": "flex", "flexDirection": "row"}), + + html.Div([], id = "out") + +]) + + +def server(date = None): + if not date: + date = now().strftime("%Y-%m-%d") + stat_exist(date) + db = read(f'data/{date}.json') + + # Настройка для графика без рамок + layout = go.Layout( margin=go.layout.Margin(l=0, r=0, b=0, t=0,), height = 300 ) + + ping = db["ping"] + ping_fig = go.Figure(data=[go.Scatter(x = ping["time"], y = ping["ms"] )], layout = layout ) + #ping_fig.update_xaxes(visible=False) + ping_fig.update_traces(hoverinfo='y') + #ping_fig.update_layout(yaxis=dict(dtick=1)) + + online = db["online"] + online_fig = go.Figure(data=[go.Scatter(x = online["time"], y = online["count"] )], layout = layout) + #online_fig.update_xaxes(visible=False) + online_fig.update_traces(hoverinfo='y') + online_fig.update_layout(yaxis=dict(dtick=1)) + + gr_conf = {"displayModeBar": False, "showAxisDragHandles": False, "showAxisRangeEntryBoxes": False, "fillFrame": False} + return html.Div([ + html.H2("Пинг"), + dcc.Graph( + id = 'ping', + figure = ping_fig, + config = gr_conf + ), + html.H2("Онлайн"), + dcc.Graph( + id = 'online', + figure = online_fig, + config = gr_conf + ) + ]) + + +def players(): + db = read('data/stat.json') + + layout = go.Layout( margin=go.layout.Margin(l=0, r=0, b=0, t=0,), height = 300 ) + + time = db["players"]["time"] + # Конвертируем в вид ["hythe", "freedom"] и [1764, 6532] + time_nick = list(time.keys()) + time_time = list(time.values()) + # Сортируем по времени (3, 2, 1) + sorted = False + while not sorted: + sorted = True + for i in range(len(time_time) - 1): + # Если [5, 7] => [7, 5] + if time_time[i + 1] > time_time[i]: + sorted = False + # Меняем местами + time_time[i], time_time[i + 1] = time_time[i + 1], time_time[i] + time_nick[i], time_nick[i + 1] = time_nick[i + 1], time_nick[i] + + # Конвертируем 12960 => 3:36 + conv_time = [] + for i in range(len(time_time)): + seconds = time_time[i] + hours = seconds // 3600 + minutes = (seconds-hours*3600) // 60 + + conv_time.append(f"Время: {hours} час. {minutes} мин.") + + time_fig = go.Figure(data=[go.Bar(x = time_nick, y = time_time, hovertemplate=conv_time, name="", + text=conv_time, textposition='inside', insidetextfont=dict(size=16, color='white') + )], layout = layout ) + time_fig.update_yaxes(visible=False) + #time_fig.update_xaxes(visible=False) + time_fig.update_xaxes({"tickfont": {"size": 18} }) + time_fig.update_traces(hoverinfo='y') + + last = db["players"]["last"] + # Конвертируем в вид ["hythe"] и [1434657.567523] + last_nick = list(last.keys()) + last_time = list(last.values()) + # Сортируем по времени (3, 2, 1) + # Сортируем по времени + sorted = False + while not sorted: + sorted = True + for i in range(len(last_time) - 1): + # Если [5, 7] => [7, 5] + if float(last_time[i + 1]) > float(last_time[i]): + sorted = False + # Меняем местами + last_time[i], last_time[i + 1] = last_time[i + 1], last_time[i] + last_nick[i], last_nick[i + 1] = last_nick[i + 1], last_nick[i] + + # Конвертируем 1709475944.625857 => '2012-09-13 02:22:50' + for i in range(len(last_time)): + last_time[i] = strftime('%Y-%m-%d %H:%M:%S', localtime( float(last_time[i]) )) + + last_fig = go.Figure(data= [go.Table(header={"values": ["Игрок","Время захода"], "font": {"size": 18}, "height": 40}, + cells={"values": [last_nick, last_time], "font_size": 18, "height": 30}, + ) ], layout = layout ) + + gr_conf = {"displayModeBar": False, "showAxisDragHandles": False, "showAxisRangeEntryBoxes": False, "fillFrame": False} + return html.Div([ + html.H2("Топ по времени"), + dcc.Graph( + id = 'ping', + figure = time_fig, + config = gr_conf + ), + html.H2("Последний заход"), + dcc.Graph( + id = 'ping', + figure = last_fig, + config = gr_conf + ) + ]) + + + +def av_stats(): + raw = sorted( next(os.walk('data/'), (None, None, []))[2] ) + # Убираем .json + dates = [] + for i in raw: + if i != "stat.json": + dates.append(i[:i.find(".json")]) + + return dates + +@callback( + Output('out', 'children'), + Output('date', 'options'), + Input('date', 'value'), + Input('select', 'value'), +) +def main(date, select): + if select == "Сервер": + return server(date), av_stats() + elif select == "Игроки": + return players(), av_stats() + +while True: + try: + app.run(debug=False) + except KeyboardInterrupt: + exit() + except: + pass