update
This commit is contained in:
44
data/db/menu.yaml
Normal file
44
data/db/menu.yaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# 카테고리
|
||||||
|
# uri 가 plugin인 경우 name 값은 대체
|
||||||
|
|
||||||
|
#- name: "토렌트"
|
||||||
|
# list:
|
||||||
|
# - uri: "rss"
|
||||||
|
|
||||||
|
|
||||||
|
#- name: "기본 기능"
|
||||||
|
# list:
|
||||||
|
# - uri: "terminal"
|
||||||
|
# - uri: "command"
|
||||||
|
# - uri: "flaskfilemanager"
|
||||||
|
# - uri: "flaskcode"
|
||||||
|
# - uri: "number_baseball"
|
||||||
|
|
||||||
|
|
||||||
|
#- name: "링크"
|
||||||
|
# list:
|
||||||
|
# - uri: "https://app.plex.tv"
|
||||||
|
# name: "Plex"
|
||||||
|
# target: "_self"
|
||||||
|
# - uri: "https://www.netflix.com"
|
||||||
|
# name: "Netflix"
|
||||||
|
|
||||||
|
|
||||||
|
- name: "시스템"
|
||||||
|
list:
|
||||||
|
- uri: "system"
|
||||||
|
name: "설정"
|
||||||
|
- uri: "setting"
|
||||||
|
name: "확장 설정"
|
||||||
|
- uri: "system/plugin"
|
||||||
|
name: "플러그인 관리"
|
||||||
|
- uri: "-"
|
||||||
|
- uri: "system/logout"
|
||||||
|
name: "로그아웃"
|
||||||
|
- uri: "system/restart"
|
||||||
|
name: "재시작(업데이트)"
|
||||||
|
- uri: "system/shutdown"
|
||||||
|
#uri: "javascript:shutdown_confirm();"
|
||||||
|
name: "종료"
|
||||||
|
|
||||||
|
|
||||||
BIN
data/db/system.db
Normal file
BIN
data/db/system.db
Normal file
Binary file not shown.
@@ -43,7 +43,7 @@ class PluginManager:
|
|||||||
for t in tmps:
|
for t in tmps:
|
||||||
if not t.startswith('_') and os.path.isdir(os.path.join(plugin_path, t)):
|
if not t.startswith('_') and os.path.isdir(os.path.join(plugin_path, t)):
|
||||||
add_plugin_list.append(t)
|
add_plugin_list.append(t)
|
||||||
cls.all_package_list[t] = {'pos':'normal', 'path':os.path.join(plugin_path, t)}
|
cls.all_package_list[t] = {'pos':'normal', 'path':os.path.join(plugin_path, t), 'loading':(F.config.get('plugin_loading_only_devpath', None) != True)}
|
||||||
|
|
||||||
plugins = plugins + add_plugin_list
|
plugins = plugins + add_plugin_list
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
@@ -64,7 +64,7 @@ class PluginManager:
|
|||||||
for t in tmps:
|
for t in tmps:
|
||||||
if not t.startswith('_') and os.path.isdir(os.path.join(plugin_path, t)):
|
if not t.startswith('_') and os.path.isdir(os.path.join(plugin_path, t)):
|
||||||
add_plugin_list.append(t)
|
add_plugin_list.append(t)
|
||||||
cls.all_package_list[t] = {'pos':'dev', 'path':os.path.join(plugin_path, t)}
|
cls.all_package_list[t] = {'pos':'dev', 'path':os.path.join(plugin_path, t), 'loading':True}
|
||||||
plugins = plugins + add_plugin_list
|
plugins = plugins + add_plugin_list
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
F.logger.error('Exception:%s', exception)
|
F.logger.error('Exception:%s', exception)
|
||||||
|
|||||||
@@ -34,10 +34,15 @@ def global_ajax(sub):
|
|||||||
elif sub == 'is_available_edit':
|
elif sub == 'is_available_edit':
|
||||||
# globalEditBtn
|
# globalEditBtn
|
||||||
try:
|
try:
|
||||||
import flaskcode
|
if F.PluginManager.all_package_list['flaskcode']['loading']:
|
||||||
from flaskcode.setup import P as PP
|
PP = F.PluginManager.all_package_list['flaskcode']['P']
|
||||||
|
#import flaskcode
|
||||||
|
#from flaskcode.setup import P as PP
|
||||||
ret = {'ret':True, 'target':PP.ModelSetting.get('setting_open_target')}
|
ret = {'ret':True, 'target':PP.ModelSetting.get('setting_open_target')}
|
||||||
return jsonify(ret)
|
return jsonify(ret)
|
||||||
|
else:
|
||||||
|
return jsonify({'ret':False})
|
||||||
|
|
||||||
except:
|
except:
|
||||||
return jsonify({'ret':False})
|
return jsonify({'ret':False})
|
||||||
elif sub == 'command_modal_hide':
|
elif sub == 'command_modal_hide':
|
||||||
|
|||||||
@@ -9,13 +9,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
<meta name="google" value="notranslate">
|
<meta name="google" value="notranslate">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<!--<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">-->
|
|
||||||
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
|
||||||
-->
|
|
||||||
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.ico') }}">
|
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.ico') }}">
|
||||||
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ logger = get_logger()
|
|||||||
from .base.aes import SupportAES
|
from .base.aes import SupportAES
|
||||||
from .base.discord import SupportDiscord
|
from .base.discord import SupportDiscord
|
||||||
from .base.file import SupportFile
|
from .base.file import SupportFile
|
||||||
from .base.process import SupportProcess
|
|
||||||
from .base.string import SupportString
|
from .base.string import SupportString
|
||||||
from .base.subprocess import SupportSubprocess
|
from .base.subprocess import SupportSubprocess
|
||||||
from .base.telegram import SupportTelegram
|
from .base.telegram import SupportTelegram
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
import os, sys, traceback, subprocess, json, platform
|
|
||||||
from . import logger
|
|
||||||
|
|
||||||
|
|
||||||
class SupportProcess(object):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def execute(cls, command, format=None, shell=False, env=None, timeout=1000):
|
|
||||||
logger.debug(command)
|
|
||||||
try:
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
command = ' '.join(command)
|
|
||||||
|
|
||||||
iter_arg = ''
|
|
||||||
process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, shell=shell, env=env, encoding='utf8')
|
|
||||||
try:
|
|
||||||
process_ret = process.wait(timeout=timeout) # wait for the subprocess to exit
|
|
||||||
except:
|
|
||||||
import psutil
|
|
||||||
process = psutil.Process(process.pid)
|
|
||||||
for proc in process.children(recursive=True):
|
|
||||||
proc.kill()
|
|
||||||
process.kill()
|
|
||||||
return "timeout"
|
|
||||||
ret = []
|
|
||||||
with process.stdout:
|
|
||||||
for line in iter(process.stdout.readline, iter_arg):
|
|
||||||
ret.append(line.strip())
|
|
||||||
|
|
||||||
if format is None:
|
|
||||||
ret2 = '\n'.join(ret)
|
|
||||||
elif format == 'json':
|
|
||||||
try:
|
|
||||||
index = 0
|
|
||||||
for idx, tmp in enumerate(ret):
|
|
||||||
#logger.debug(tmp)
|
|
||||||
if tmp.startswith('{') or tmp.startswith('['):
|
|
||||||
index = idx
|
|
||||||
break
|
|
||||||
ret2 = json.loads(''.join(ret[index:]))
|
|
||||||
except:
|
|
||||||
ret2 = None
|
|
||||||
return ret2
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f'Exception:{str(e)}', )
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
logger.error('command : %s', command)
|
|
||||||
|
|
||||||
@@ -132,13 +132,16 @@ class SupportSubprocess(object):
|
|||||||
self.start_send_callback()
|
self.start_send_callback()
|
||||||
if self.process is not None:
|
if self.process is not None:
|
||||||
self.process.wait()
|
self.process.wait()
|
||||||
#logger.info(f"{self.command} 정상 종료")
|
logger.info(f"{self.command} 정상 종료")
|
||||||
if self.stdout_queue != None:
|
|
||||||
self.stdout_queue.put('<END>')
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f'Exception:{str(e)}')
|
logger.error(f'Exception:{str(e)}')
|
||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
|
if self.stdout_callback != None:
|
||||||
|
self.stdout_callback('error', str(e))
|
||||||
|
self.stdout_callback('error', str(traceback.format_exc()))
|
||||||
|
finally:
|
||||||
|
if self.stdout_callback != None:
|
||||||
|
self.stdout_callback('thread_end', None)
|
||||||
|
|
||||||
|
|
||||||
def start_communicate(self):
|
def start_communicate(self):
|
||||||
@@ -150,8 +153,6 @@ class SupportSubprocess(object):
|
|||||||
|
|
||||||
def rdr():
|
def rdr():
|
||||||
while True:
|
while True:
|
||||||
if self.process == None:
|
|
||||||
break
|
|
||||||
buf = self.process.stdout.read(1)
|
buf = self.process.stdout.read(1)
|
||||||
if buf:
|
if buf:
|
||||||
_queue.put( buf )
|
_queue.put( buf )
|
||||||
@@ -178,9 +179,8 @@ class SupportSubprocess(object):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if r is not None:
|
if r is not None:
|
||||||
if self.stdout_queue != None:
|
#print(f"{r=}")
|
||||||
self.stdout_queue.put(r)
|
self.stdout_queue.put(r)
|
||||||
if self.stdout_queue != None: # 사용자 중지
|
|
||||||
self.stdout_queue.put('<END>')
|
self.stdout_queue.put('<END>')
|
||||||
for tgt in [rdr, clct]:
|
for tgt in [rdr, clct]:
|
||||||
th = threading.Thread(target=tgt)
|
th = threading.Thread(target=tgt)
|
||||||
@@ -200,10 +200,6 @@ class SupportSubprocess(object):
|
|||||||
else:
|
else:
|
||||||
if self.stdout_callback != None:
|
if self.stdout_callback != None:
|
||||||
self.stdout_callback('log', line)
|
self.stdout_callback('log', line)
|
||||||
self.send_to_ui_thread = None
|
|
||||||
self.stdout_queue = None
|
|
||||||
self.process = None
|
|
||||||
|
|
||||||
th = threading.Thread(target=func, args=())
|
th = threading.Thread(target=func, args=())
|
||||||
th.setDaemon(True)
|
th.setDaemon(True)
|
||||||
th.start()
|
th.start()
|
||||||
@@ -222,7 +218,7 @@ class SupportSubprocess(object):
|
|||||||
logger.error(traceback.format_exc())
|
logger.error(traceback.format_exc())
|
||||||
finally:
|
finally:
|
||||||
try:
|
try:
|
||||||
self.stdout_queue = None
|
#self.stdout_queue = None
|
||||||
self.process.kill()
|
self.process.kill()
|
||||||
except: pass
|
except: pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,275 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
from datetime import datetime
|
|
||||||
import string
|
|
||||||
import random
|
|
||||||
import json
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
import requests
|
|
||||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
|
||||||
from flask_login import login_user, logout_user, current_user, login_required
|
|
||||||
|
|
||||||
|
|
||||||
from framework import F, frame, app, db, scheduler, VERSION, path_app_root, logger, Job, User
|
|
||||||
from framework.util import Util
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
from .model import ModelSetting
|
|
||||||
import system
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
class SystemLogic(object):
|
|
||||||
point = 0
|
|
||||||
db_default = {
|
|
||||||
'db_version' : '1',
|
|
||||||
'port' : '9999',
|
|
||||||
'ddns' : 'http://localhost:9999',
|
|
||||||
#'url_filebrowser' : 'http://localhost:9998',
|
|
||||||
#'url_celery_monitoring' : 'http://localhost:9997',
|
|
||||||
'id' : 'admin',
|
|
||||||
'pw' : '//nCv0/YkVI3U2AAgYwOuJ2hPlQ7cDYIbuaCt4YJupY=',
|
|
||||||
'system_start_time' : '',
|
|
||||||
'repeat' : '',
|
|
||||||
'auto_restart_hour' : '12',
|
|
||||||
#'unique' : '',
|
|
||||||
'theme' : 'Cerulean',
|
|
||||||
'log_level' : '10',
|
|
||||||
'use_login' : 'False',
|
|
||||||
'link_json' : '[{"type":"link","title":"위키","url":"https://sjva.me/wiki/public/start"}]',
|
|
||||||
'plugin_dev_path': '',
|
|
||||||
'plugin_tving_level2' : 'False',
|
|
||||||
'web_title' : 'Home',
|
|
||||||
'my_ip' : '',
|
|
||||||
'wavve_guid' : '',
|
|
||||||
|
|
||||||
#인증
|
|
||||||
'auth_use_apikey' : 'False',
|
|
||||||
'auth_apikey' : '',
|
|
||||||
#'hide_menu' : 'True',
|
|
||||||
|
|
||||||
#Selenium
|
|
||||||
'selenium_remote_url' : '',
|
|
||||||
'selenium_remote_default_option' : '--no-sandbox\n--disable-gpu',
|
|
||||||
'selenium_binary_default_option' : '',
|
|
||||||
|
|
||||||
# notify
|
|
||||||
'notify_telegram_use' : 'False',
|
|
||||||
'notify_telegram_token' : '',
|
|
||||||
'notify_telegram_chat_id' : '',
|
|
||||||
'notify_telegram_disable_notification' : 'False',
|
|
||||||
'notify_discord_use' : 'False',
|
|
||||||
'notify_discord_webhook' : '',
|
|
||||||
|
|
||||||
'notify_advaned_use' : 'False',
|
|
||||||
'notify_advaned_policy' : u"# 각 플러그인 설정 설명에 명시되어 있는 ID = 형식\n# DEFAULT 부터 주석(#) 제거 후 작성\n\n# DEFAULT = ",
|
|
||||||
|
|
||||||
# telegram
|
|
||||||
'telegram_bot_token' : '',
|
|
||||||
'telegram_bot_auto_start' : 'False',
|
|
||||||
'telegram_resend' : 'False',
|
|
||||||
'telegram_resend_chat_id' : '',
|
|
||||||
|
|
||||||
# 홈페이지 연동 2020-06-07
|
|
||||||
'sjva_me_user_id' : '',
|
|
||||||
'auth_status' : '',
|
|
||||||
'sjva_id' : '',
|
|
||||||
|
|
||||||
# memo
|
|
||||||
'memo' : '',
|
|
||||||
|
|
||||||
# tool - decrypt
|
|
||||||
'tool_crypt_use_user_key' : 'False',
|
|
||||||
'tool_crypt_user_key' : '',
|
|
||||||
'tool_crypt_encrypt_word' : '',
|
|
||||||
'tool_crypt_decrypt_word' : '',
|
|
||||||
|
|
||||||
'use_beta' : 'False',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_info():
|
|
||||||
info = {}
|
|
||||||
import platform
|
|
||||||
info['platform'] = platform.platform()
|
|
||||||
info['processor'] = platform.processor()
|
|
||||||
|
|
||||||
import sys
|
|
||||||
info['python_version'] = sys.version
|
|
||||||
info['version'] = VERSION
|
|
||||||
info['recent_version'] = SystemLogic.recent_version
|
|
||||||
info['path_app_root'] = path_app_root
|
|
||||||
info['running_type'] = u'%s. 비동기 작업 : %s' % (frame.config['running_type'], u"사용" if frame.config['use_celery'] else "미사용")
|
|
||||||
import system
|
|
||||||
|
|
||||||
info['auth'] = frame.config['member']['auth_desc']
|
|
||||||
info['cpu_percent'] = 'not supported'
|
|
||||||
info['memory'] = 'not supported'
|
|
||||||
info['disk'] = 'not supported'
|
|
||||||
if frame.config['running_type'] != 'termux':
|
|
||||||
try:
|
|
||||||
import psutil
|
|
||||||
from framework.util import Util
|
|
||||||
info['cpu_percent'] = '%s %%' % psutil.cpu_percent()
|
|
||||||
tmp = psutil.virtual_memory()
|
|
||||||
#info['memory'] = [Util.sizeof_fmt(tmp[0], suffix='B'), Util.sizeof_fmt(tmp[3]), Util.sizeof_fmt(tmp[1]), tmp[2]]
|
|
||||||
info['memory'] = u'전체 : %s 사용량 : %s 남은량 : %s (%s%%)' % (Util.sizeof_fmt(tmp[0], suffix='B'), Util.sizeof_fmt(tmp[3], suffix='B'), Util.sizeof_fmt(tmp[1], suffix='B'), tmp[2])
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
import platform
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
s = os.path.splitdrive(path_app_root)
|
|
||||||
root = s[0]
|
|
||||||
else:
|
|
||||||
root = '/'
|
|
||||||
tmp = psutil.disk_usage(root)
|
|
||||||
info['disk'] = u'전체 : %s 사용량 : %s 남은량 : %s (%s%%) - 드라이브 (%s)' % (Util.sizeof_fmt(tmp[0], suffix='B'), Util.sizeof_fmt(tmp[1], suffix='B'), Util.sizeof_fmt(tmp[2], suffix='B'), tmp[3], root)
|
|
||||||
except Exception as exception:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
tmp = SystemLogic.get_setting_value('system_start_time')
|
|
||||||
#logger.debug('SYSTEM_START_TIME:%s', tmp)
|
|
||||||
tmp_datetime = datetime.strptime(tmp, '%Y-%m-%d %H:%M:%S')
|
|
||||||
timedelta = datetime.now() - tmp_datetime
|
|
||||||
info['time'] = u'시작 : %s 경과 : %s 재시작 : %s' % (tmp, str(timedelta).split('.')[0], frame.config['arg_repeat'])
|
|
||||||
except Exception as exception:
|
|
||||||
info['time'] = str(exception)
|
|
||||||
return info
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def setting_save_system(req):
|
|
||||||
try:
|
|
||||||
for key, value in req.form.items():
|
|
||||||
logger.debug('Key:%s Value:%s', key, value)
|
|
||||||
entity = db.session.query(ModelSetting).filter_by(key=key).with_for_update().first()
|
|
||||||
entity.value = value
|
|
||||||
#if key == 'theme':
|
|
||||||
# SystemLogic.change_theme(value)
|
|
||||||
db.session.commit()
|
|
||||||
lists = ModelSetting.query.all()
|
|
||||||
SystemLogic.setting_list = Util.db_list_to_dict(lists)
|
|
||||||
frame.users[db.session.query(ModelSetting).filter_by(key='id').first().value] = User(db.session.query(ModelSetting).filter_by(key='id').first().value, passwd_hash=db.session.query(ModelSetting).filter_by(key='pw').first().value)
|
|
||||||
SystemLogic.set_restart_scheduler()
|
|
||||||
frame.set_level(int(db.session.query(ModelSetting).filter_by(key='log_level').first().value))
|
|
||||||
|
|
||||||
return True
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def setting_save_after():
|
|
||||||
try:
|
|
||||||
frame.users[ModelSetting.get('id')] = User(ModelSetting.get('id'), passwd_hash=ModelSetting.get('pw'))
|
|
||||||
SystemLogic.set_restart_scheduler()
|
|
||||||
frame.set_level(int(db.session.query(ModelSetting).filter_by(key='log_level').first().value))
|
|
||||||
from .logic_site import SystemLogicSite
|
|
||||||
SystemLogicSite.get_daum_cookies(force=True)
|
|
||||||
SystemLogicSite.create_tving_instance()
|
|
||||||
return True
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def change_theme(theme):
|
|
||||||
try:
|
|
||||||
source = os.path.join(path_app_root, 'static', 'css', 'theme', '%s_bootstrap.min.css' % theme)
|
|
||||||
target = os.path.join(path_app_root, 'static', 'css', 'bootstrap.min.css')
|
|
||||||
os.remove(target)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_setting_value(key):
|
|
||||||
try:
|
|
||||||
#logger.debug('get_setting_value:%s', key)
|
|
||||||
entity = db.session.query(ModelSetting).filter_by(key=key).first()
|
|
||||||
if entity is None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return entity.value
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
logger.error('error key : %s', key)
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def command_run(command_text):
|
|
||||||
try:
|
|
||||||
ret = {}
|
|
||||||
tmp = command_text.strip().split(' ')
|
|
||||||
if not tmp:
|
|
||||||
ret['ret'] = 'success'
|
|
||||||
ret['log'] = 'Empty..'
|
|
||||||
return ret
|
|
||||||
if tmp[0] == 'set':
|
|
||||||
if len(tmp) == 3:
|
|
||||||
if tmp[1] == 'token':
|
|
||||||
tmp[1] = 'unique'
|
|
||||||
entity = db.session.query(ModelSetting).filter_by(key=tmp[1]).with_for_update().first()
|
|
||||||
if entity is None:
|
|
||||||
ret['ret'] = 'fail'
|
|
||||||
ret['log'] = '%s not exist' % tmp[1]
|
|
||||||
return ret
|
|
||||||
entity.value = tmp[2] if tmp[2] != 'EMPTY' else ""
|
|
||||||
db.session.commit()
|
|
||||||
ret['ret'] = 'success'
|
|
||||||
ret['log'] = '%s - %s' % (tmp[1], tmp[2])
|
|
||||||
return ret
|
|
||||||
|
|
||||||
if tmp[0] == 'set2':
|
|
||||||
if tmp[1] == 'klive':
|
|
||||||
from klive import ModelSetting as KLiveModelSetting
|
|
||||||
if KLiveModelSetting.get(tmp[2]) is not None:
|
|
||||||
KLiveModelSetting.set(tmp[2], tmp[3])
|
|
||||||
ret['ret'] = 'success'
|
|
||||||
ret['log'] = f'KLive 설정 값 변경 : {tmp[2]} - {tmp[3]}'
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
ret['ret'] = 'fail'
|
|
||||||
ret['log'] = 'wrong command'
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
ret['ret'] = 'fail'
|
|
||||||
ret['log'] = str(exception)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def link_save(link_data_str):
|
|
||||||
try:
|
|
||||||
data = json.loads(link_data_str)
|
|
||||||
entity = db.session.query(ModelSetting).filter_by(key='link_json').with_for_update().first()
|
|
||||||
entity.value = link_data_str
|
|
||||||
db.session.commit()
|
|
||||||
SystemLogic.apply_menu_link()
|
|
||||||
return True
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return False
|
|
||||||
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
"""
|
|
||||||
from .plugin import blueprint, menu, plugin_load, plugin_unload, restart, shutdown
|
|
||||||
from .logic import SystemLogic
|
|
||||||
from .model import ModelSetting
|
|
||||||
from .model import ModelSetting as SystemModelSetting
|
|
||||||
|
|
||||||
|
|
||||||
from .logic_plugin import LogicPlugin
|
|
||||||
from .logic_selenium import SystemLogicSelenium
|
|
||||||
from .logic_command import SystemLogicCommand
|
|
||||||
|
|
||||||
from .logic_site import SystemLogicSite
|
|
||||||
|
|
||||||
"""
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import codecs
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import random
|
|
||||||
import string
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
import requests
|
|
||||||
from flask import (Blueprint, Response, jsonify, redirect, render_template,
|
|
||||||
request, send_file)
|
|
||||||
from framework import app, frame, path_app_root
|
|
||||||
from framework.util import Util
|
|
||||||
|
|
||||||
from .model import ModelSetting
|
|
||||||
# 패키지
|
|
||||||
from .plugin import logger, package_name
|
|
||||||
|
|
||||||
# sjva 공용
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicAuth(object):
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
logger.debug(sub)
|
|
||||||
try:
|
|
||||||
if sub == 'apikey_generate':
|
|
||||||
ret = SystemLogicAuth.apikey_generate()
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'do_auth':
|
|
||||||
ret = SystemLogicAuth.do_auth()
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_auth_status(retry=True):
|
|
||||||
try:
|
|
||||||
value = ModelSetting.get('auth_status')
|
|
||||||
ret = {'ret' : False, 'desc' : '', 'level' : 0, 'point': 0}
|
|
||||||
if value == '':
|
|
||||||
ret['desc'] = '미인증'
|
|
||||||
elif value == 'wrong_id':
|
|
||||||
ret['desc'] = '미인증 - 홈페이지 아이디가 없습니다.'
|
|
||||||
elif value == 'too_many_sjva':
|
|
||||||
ret['desc'] = '미인증 - 너무 많은 SJVA를 사용중입니다.'
|
|
||||||
elif value == 'wrong_apikey':
|
|
||||||
ret['desc'] = '미인증 - 홈페이지에 등록된 APIKEY와 다릅니다.'
|
|
||||||
elif value == 'auth_status':
|
|
||||||
ret['desc'] = '인증 실패'
|
|
||||||
else:
|
|
||||||
status = SystemLogicAuth.check_auth_status(value)
|
|
||||||
if status is not None and status['ret']:
|
|
||||||
ret['ret'] = status['ret']
|
|
||||||
ret['desc'] = '인증되었습니다. (회원등급:%s, 포인트:%s)' % (status['level'], status['point'])
|
|
||||||
ret['level'] = status['level']
|
|
||||||
ret['point'] = status['point']
|
|
||||||
else:
|
|
||||||
if retry:
|
|
||||||
SystemLogicAuth.do_auth()
|
|
||||||
#ModelSetting.set('auth_status', SystemLogicAuth.make_auth_status())
|
|
||||||
return SystemLogicAuth.get_auth_status(retry=False)
|
|
||||||
else:
|
|
||||||
ret['desc'] = '잘못된 값입니다. 다시 인증하세요.'
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def check_auth_status(value=None):
|
|
||||||
try:
|
|
||||||
from support import SupportAES
|
|
||||||
mykey=(codecs.encode(SystemLogicAuth.get_ip().encode(), 'hex').decode() + codecs.encode(ModelSetting.get('auth_apikey').encode(), 'hex').decode()).zfill(32)[:32].encode()
|
|
||||||
logger.debug(mykey)
|
|
||||||
tmp = SupportAES.decrypt(value, mykey=mykey)
|
|
||||||
tmp = tmp.split('_')
|
|
||||||
ret = {}
|
|
||||||
ret['ret'] = (ModelSetting.get('sjva_id') == tmp[0])
|
|
||||||
ret['level'] = int(tmp[1])
|
|
||||||
ret['point'] = int(tmp[2])
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def make_auth_status(level, point):
|
|
||||||
try:
|
|
||||||
from support.base import SupportAES
|
|
||||||
mykey=(codecs.encode(SystemLogicAuth.get_ip().encode(), 'hex').decode() + codecs.encode(ModelSetting.get('auth_apikey').encode(), 'hex').decode()).zfill(32)[:32].encode()
|
|
||||||
ret = SupportAES.encrypt(str('%s_%s_%s' % (ModelSetting.get('sjva_id'), level, point)), mykey=mykey)
|
|
||||||
logger.debug(ret)
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_ip():
|
|
||||||
import socket
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
try:
|
|
||||||
# doesn't even have to be reachable
|
|
||||||
s.connect(('10.255.255.255', 1))
|
|
||||||
IP = s.getsockname()[0]
|
|
||||||
except Exception:
|
|
||||||
IP = '127.0.0.1'
|
|
||||||
finally:
|
|
||||||
s.close()
|
|
||||||
logger.debug('IP:%s', IP)
|
|
||||||
return IP
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def do_auth():
|
|
||||||
try:
|
|
||||||
ret = {'ret':False, 'msg':'', 'level':0, 'point':0}
|
|
||||||
apikey = ModelSetting.get('auth_apikey')
|
|
||||||
user_id = ModelSetting.get('sjva_me_user_id')
|
|
||||||
if len(apikey) != 10:
|
|
||||||
ret['msg'] = 'APIKEY 문자 길이는 10자리여야합니다.'
|
|
||||||
return ret
|
|
||||||
if user_id == '':
|
|
||||||
ret['msg'] = '홈페이지 ID가 없습니다.'
|
|
||||||
return ret
|
|
||||||
|
|
||||||
data = requests.post(f"{frame.config['DEFINE']['WEB_DIRECT_URL']}/sjva/auth.php", data={'apikey':apikey,'user_id':user_id, 'sjva_id':ModelSetting.get('sjva_id')}).json()
|
|
||||||
if data['result'] == 'success':
|
|
||||||
ret['ret'] = True
|
|
||||||
ret['msg'] = u'총 %s개 등록<br>회원등급:%s, 포인트:%s' % (data['count'], data['level'], data['point'])
|
|
||||||
ret['level'] = int(data['level'])
|
|
||||||
ret['point'] = int(data['point'])
|
|
||||||
ModelSetting.set('auth_status', SystemLogicAuth.make_auth_status(ret['level'], ret['point']))
|
|
||||||
else:
|
|
||||||
ModelSetting.set('auth_status', data['result'])
|
|
||||||
tmp = SystemLogicAuth.get_auth_status(retry=False)
|
|
||||||
ret['ret'] = tmp['ret']
|
|
||||||
ret['msg'] = tmp['desc']
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
ret['msg'] = '인증 실패'
|
|
||||||
ret['level'] = -1
|
|
||||||
ret['point'] = -1
|
|
||||||
ModelSetting.set('auth_status', 'auth_fail')
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
import platform
|
|
||||||
import subprocess
|
|
||||||
import threading
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import queue
|
|
||||||
# third-party
|
|
||||||
|
|
||||||
# sjva 공용
|
|
||||||
|
|
||||||
from framework import path_app_root, socketio, app, logger
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicCommand(object):
|
|
||||||
|
|
||||||
commands = None
|
|
||||||
process = None
|
|
||||||
stdout_queue = None
|
|
||||||
thread = None
|
|
||||||
send_to_ui_thread = None
|
|
||||||
return_log = None
|
|
||||||
@staticmethod
|
|
||||||
def start(title, commands, clear=True, wait=False, show_modal=True):
|
|
||||||
try:
|
|
||||||
if show_modal:
|
|
||||||
if clear:
|
|
||||||
socketio.emit("command_modal_clear", None, namespace='/framework', broadcast=True)
|
|
||||||
SystemLogicCommand.return_log = []
|
|
||||||
SystemLogicCommand.title = title
|
|
||||||
SystemLogicCommand.commands = commands
|
|
||||||
SystemLogicCommand.thread = threading.Thread(target=SystemLogicCommand.execute_thread_function, args=(show_modal,))
|
|
||||||
SystemLogicCommand.thread.setDaemon(True)
|
|
||||||
SystemLogicCommand.thread.start()
|
|
||||||
if wait:
|
|
||||||
time.sleep(1)
|
|
||||||
SystemLogicCommand.thread.join()
|
|
||||||
return SystemLogicCommand.return_log
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def execute_thread_function(show_modal):
|
|
||||||
try:
|
|
||||||
#if wait:
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("loading_hide", None, namespace='/framework', broadcast=True)
|
|
||||||
for command in SystemLogicCommand.commands:
|
|
||||||
#logger.debug('Command :%s', command)
|
|
||||||
if command[0] == 'msg':
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", '%s\n\n' % command[1], namespace='/framework', broadcast=True)
|
|
||||||
elif command[0] == 'system':
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", '$ %s\n\n' % command[1], namespace='/framework', broadcast=True)
|
|
||||||
os.system(command[1])
|
|
||||||
else:
|
|
||||||
show_command = True
|
|
||||||
if command[0] == 'hide':
|
|
||||||
show_command = False
|
|
||||||
command = command[1:]
|
|
||||||
#SystemLogicCommand.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, bufsize=1)
|
|
||||||
SystemLogicCommand.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8')
|
|
||||||
SystemLogicCommand.start_communicate(command, show_command=show_command)
|
|
||||||
SystemLogicCommand.send_queue_start(show_modal)
|
|
||||||
if SystemLogicCommand.process is not None:
|
|
||||||
SystemLogicCommand.process.wait()
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
#logger.error('Exception:%s', exception)
|
|
||||||
#logger.error(traceback.format_exc())
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("command_modal_show", SystemLogicCommand.title, namespace='/framework', broadcast=True)
|
|
||||||
socketio.emit("command_modal_add_text", str(exception), namespace='/framework', broadcast=True)
|
|
||||||
socketio.emit("command_modal_add_text", str(traceback.format_exc()), namespace='/framework', broadcast=True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def start_communicate(current_command, show_command=True):
|
|
||||||
SystemLogicCommand.stdout_queue = queue.Queue()
|
|
||||||
if show_command:
|
|
||||||
SystemLogicCommand.stdout_queue.put('$ %s\n' % ' '.join(current_command))
|
|
||||||
sout = io.open(SystemLogicCommand.process.stdout.fileno(), 'rb', closefd=False)
|
|
||||||
#serr = io.open(process.stderr.fileno(), 'rb', closefd=False)
|
|
||||||
|
|
||||||
def Pump(stream):
|
|
||||||
queue = queue.Queue()
|
|
||||||
|
|
||||||
def rdr():
|
|
||||||
logger.debug('START RDR')
|
|
||||||
while True:
|
|
||||||
buf = SystemLogicCommand.process.stdout.read(1)
|
|
||||||
if buf:
|
|
||||||
queue.put( buf )
|
|
||||||
else:
|
|
||||||
queue.put( None )
|
|
||||||
break
|
|
||||||
logger.debug('END RDR')
|
|
||||||
queue.put( None )
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
#Logic.command_close()
|
|
||||||
def clct():
|
|
||||||
active = True
|
|
||||||
logger.debug('START clct')
|
|
||||||
while active:
|
|
||||||
r = queue.get()
|
|
||||||
if r is None:
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
r1 = queue.get(timeout=0.005)
|
|
||||||
if r1 is None:
|
|
||||||
active = False
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
r += r1
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if r is not None:
|
|
||||||
try:
|
|
||||||
r = r.decode('utf-8')
|
|
||||||
except Exception as exception:
|
|
||||||
#logger.error('Exception:%s', e)
|
|
||||||
#logger.error(traceback.format_exc())
|
|
||||||
try:
|
|
||||||
r = r.decode('cp949')
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
try:
|
|
||||||
r = r.decode('euc-kr')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
SystemLogicCommand.stdout_queue.put(r)
|
|
||||||
#SystemLogicCommand.return_log.append(r)
|
|
||||||
SystemLogicCommand.return_log += r.split('\n')
|
|
||||||
logger.debug('IN:%s', r)
|
|
||||||
SystemLogicCommand.stdout_queue.put('<END>')
|
|
||||||
logger.debug('END clct')
|
|
||||||
#Logic.command_close()
|
|
||||||
for tgt in [rdr, clct]:
|
|
||||||
th = threading.Thread(target=tgt)
|
|
||||||
th.setDaemon(True)
|
|
||||||
th.start()
|
|
||||||
Pump(sout)
|
|
||||||
#Pump(serr, 'stderr')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def send_queue_start(show_modal):
|
|
||||||
def send_to_ui_thread_function():
|
|
||||||
logger.debug('send_queue_thread_function START')
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("command_modal_show", SystemLogicCommand.title, namespace='/framework', broadcast=True)
|
|
||||||
while SystemLogicCommand.stdout_queue:
|
|
||||||
line = SystemLogicCommand.stdout_queue.get()
|
|
||||||
logger.debug('Send to UI :%s', line)
|
|
||||||
if line == '<END>':
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", "\n", namespace='/framework', broadcast=True)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", line, namespace='/framework', broadcast=True)
|
|
||||||
SystemLogicCommand.send_to_ui_thread = None
|
|
||||||
SystemLogicCommand.stdout_queue = None
|
|
||||||
SystemLogicCommand.process = None
|
|
||||||
logger.debug('send_to_ui_thread_function END')
|
|
||||||
|
|
||||||
if SystemLogicCommand.send_to_ui_thread is None:
|
|
||||||
SystemLogicCommand.send_to_ui_thread = threading.Thread(target=send_to_ui_thread_function, args=())
|
|
||||||
SystemLogicCommand.send_to_ui_thread.start()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def plugin_unload():
|
|
||||||
try:
|
|
||||||
if SystemLogicCommand.process is not None and SystemLogicCommand.process.poll() is None:
|
|
||||||
import psutil
|
|
||||||
process = psutil.Process(SystemLogicCommand.process.pid)
|
|
||||||
for proc in SystemLogicCommand.process.children(recursive=True):
|
|
||||||
proc.kill()
|
|
||||||
SystemLogicCommand.process.kill()
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
##################################
|
|
||||||
# 외부 호출
|
|
||||||
@staticmethod
|
|
||||||
def execute_command_return(command, format=None, force_log=False):
|
|
||||||
from tool_base import ToolSubprocess
|
|
||||||
return ToolSubprocess.execute_command_return(command, format=format, force_log=force_log)
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
logger.debug('execute_command_return : %s', ' '.join(command))
|
|
||||||
|
|
||||||
if app.config['config']['running_type'] == 'windows':
|
|
||||||
command = ' '.join(command)
|
|
||||||
|
|
||||||
process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8')
|
|
||||||
ret = []
|
|
||||||
with process.stdout:
|
|
||||||
for line in iter(process.stdout.readline, ''):
|
|
||||||
ret.append(line.strip())
|
|
||||||
if force_log:
|
|
||||||
logger.debug(ret[-1])
|
|
||||||
process.wait() # wait for the subprocess to exit
|
|
||||||
|
|
||||||
|
|
||||||
if format is None:
|
|
||||||
ret2 = '\n'.join(ret)
|
|
||||||
elif format == 'json':
|
|
||||||
try:
|
|
||||||
index = 0
|
|
||||||
for idx, tmp in enumerate(ret):
|
|
||||||
#logger.debug(tmp)
|
|
||||||
if tmp.startswith('{') or tmp.startswith('['):
|
|
||||||
index = idx
|
|
||||||
break
|
|
||||||
ret2 = json.loads(''.join(ret[index:]))
|
|
||||||
except:
|
|
||||||
ret2 = None
|
|
||||||
|
|
||||||
return ret2
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
logger.error('command : %s', command)
|
|
||||||
"""
|
|
||||||
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
import platform
|
|
||||||
import subprocess
|
|
||||||
import threading
|
|
||||||
import sys
|
|
||||||
import io
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import queue
|
|
||||||
# third-party
|
|
||||||
|
|
||||||
# sjva 공용
|
|
||||||
|
|
||||||
from framework import path_app_root, socketio, logger, app
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
|
|
||||||
# 로그
|
|
||||||
package_name = __name__.split('.')[0]
|
|
||||||
#logger = get_logger(package_name)
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
class SystemLogicCommand2(object):
|
|
||||||
instance_list = []
|
|
||||||
|
|
||||||
def __init__(self, title, commands, clear=True, wait=False, show_modal=True):
|
|
||||||
self.title = title
|
|
||||||
self.commands = commands
|
|
||||||
self.clear = clear
|
|
||||||
self.wait = wait
|
|
||||||
self.show_modal = show_modal
|
|
||||||
|
|
||||||
self.process = None
|
|
||||||
self.stdout_queue = None
|
|
||||||
self.thread = None
|
|
||||||
self.send_to_ui_thread = None
|
|
||||||
self.return_log = []
|
|
||||||
SystemLogicCommand2.instance_list.append(self)
|
|
||||||
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
try:
|
|
||||||
if self.show_modal:
|
|
||||||
if self.clear:
|
|
||||||
socketio.emit("command_modal_clear", None, namespace='/framework', broadcast=True)
|
|
||||||
|
|
||||||
self.thread = threading.Thread(target=self.execute_thread_function, args=())
|
|
||||||
self.thread.setDaemon(True)
|
|
||||||
self.thread.start()
|
|
||||||
if self.wait:
|
|
||||||
time.sleep(1)
|
|
||||||
self.thread.join()
|
|
||||||
return self.return_log
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
def execute_thread_function(self):
|
|
||||||
try:
|
|
||||||
#if wait:
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_show", self.title, namespace='/framework', broadcast=True)
|
|
||||||
socketio.emit("loading_hide", None, namespace='/framework', broadcast=True)
|
|
||||||
|
|
||||||
for command in self.commands:
|
|
||||||
if command[0] == 'msg':
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", '%s\n\n' % command[1], namespace='/framework', broadcast=True)
|
|
||||||
elif command[0] == 'system':
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", '$ %s\n\n' % command[1], namespace='/framework', broadcast=True)
|
|
||||||
os.system(command[1])
|
|
||||||
else:
|
|
||||||
show_command = True
|
|
||||||
if command[0] == 'hide':
|
|
||||||
show_command = False
|
|
||||||
command = command[1:]
|
|
||||||
#self.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, bufsize=1)
|
|
||||||
self.process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8')
|
|
||||||
self.start_communicate(command, show_command=show_command)
|
|
||||||
self.send_queue_start()
|
|
||||||
if self.process is not None:
|
|
||||||
self.process.wait()
|
|
||||||
time.sleep(1)
|
|
||||||
except Exception as exception:
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_show", self.title, namespace='/framework', broadcast=True)
|
|
||||||
socketio.emit("command_modal_add_text", str(exception), namespace='/framework', broadcast=True)
|
|
||||||
socketio.emit("command_modal_add_text", str(traceback.format_exc()), namespace='/framework', broadcast=True)
|
|
||||||
|
|
||||||
|
|
||||||
def start_communicate(self, current_command, show_command=True):
|
|
||||||
self.stdout_queue = queue.Queue()
|
|
||||||
if show_command:
|
|
||||||
self.stdout_queue.put('$ %s\n' % ' '.join(current_command))
|
|
||||||
sout = io.open(self.process.stdout.fileno(), 'rb', closefd=False)
|
|
||||||
#serr = io.open(process.stderr.fileno(), 'rb', closefd=False)
|
|
||||||
|
|
||||||
def Pump(stream):
|
|
||||||
queue = queue.Queue()
|
|
||||||
|
|
||||||
def rdr():
|
|
||||||
#logger.debug('START RDR')
|
|
||||||
while True:
|
|
||||||
buf = self.process.stdout.read(1)
|
|
||||||
if buf:
|
|
||||||
queue.put( buf )
|
|
||||||
else:
|
|
||||||
queue.put( None )
|
|
||||||
break
|
|
||||||
#logger.debug('END RDR')
|
|
||||||
queue.put( None )
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
#Logic.command_close()
|
|
||||||
def clct():
|
|
||||||
active = True
|
|
||||||
#logger.debug('START clct')
|
|
||||||
while active:
|
|
||||||
r = queue.get()
|
|
||||||
if r is None:
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
r1 = queue.get(timeout=0.005)
|
|
||||||
if r1 is None:
|
|
||||||
active = False
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
r += r1
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if r is not None:
|
|
||||||
if app.config['config']['is_py2']:
|
|
||||||
try:
|
|
||||||
r = r.decode('utf-8')
|
|
||||||
except Exception as exception:
|
|
||||||
#logger.error('Exception:%s', e)
|
|
||||||
#logger.error(traceback.format_exc())
|
|
||||||
try:
|
|
||||||
r = r.decode('cp949')
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
try:
|
|
||||||
r = r.decode('euc-kr')
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
self.stdout_queue.put(r)
|
|
||||||
self.return_log += r.split('\n')
|
|
||||||
#logger.debug('IN:%s', r)
|
|
||||||
self.stdout_queue.put('<END>')
|
|
||||||
#logger.debug('END clct')
|
|
||||||
#Logic.command_close()
|
|
||||||
for tgt in [rdr, clct]:
|
|
||||||
th = threading.Thread(target=tgt)
|
|
||||||
th.setDaemon(True)
|
|
||||||
th.start()
|
|
||||||
Pump(sout)
|
|
||||||
#Pump(serr, 'stderr')
|
|
||||||
|
|
||||||
def send_queue_start(self):
|
|
||||||
def send_to_ui_thread_function():
|
|
||||||
#logger.debug('send_queue_thread_function START')
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_show", self.title, namespace='/framework', broadcast=True)
|
|
||||||
while self.stdout_queue:
|
|
||||||
line = self.stdout_queue.get()
|
|
||||||
#logger.debug('Send to UI :%s', line)
|
|
||||||
if line == '<END>':
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", "\n", namespace='/framework', broadcast=True)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if self.show_modal:
|
|
||||||
socketio.emit("command_modal_add_text", line, namespace='/framework', broadcast=True)
|
|
||||||
self.send_to_ui_thread = None
|
|
||||||
self.stdout_queue = None
|
|
||||||
self.process = None
|
|
||||||
#logger.debug('send_to_ui_thread_function END')
|
|
||||||
|
|
||||||
if self.send_to_ui_thread is None:
|
|
||||||
self.send_to_ui_thread = threading.Thread(target=send_to_ui_thread_function, args=())
|
|
||||||
self.send_to_ui_thread.start()
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def plugin_unload(cls):
|
|
||||||
for instance in cls.instance_list:
|
|
||||||
try:
|
|
||||||
if instance.process is not None and instance.process.poll() is None:
|
|
||||||
import psutil
|
|
||||||
process = psutil.Process(instance.process.pid)
|
|
||||||
for proc in instance.process.children(recursive=True):
|
|
||||||
proc.kill()
|
|
||||||
instance.process.kill()
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
finally:
|
|
||||||
try: instance.process.kill()
|
|
||||||
except: pass
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
from flask import (Blueprint, Response, jsonify, redirect, render_template,
|
|
||||||
request, send_file)
|
|
||||||
from framework import F, app, celery, path_app_root, path_data
|
|
||||||
|
|
||||||
from .model import ModelSetting
|
|
||||||
# 패키지
|
|
||||||
from .plugin import logger, package_name
|
|
||||||
|
|
||||||
# sjva 공용
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicEnv(object):
|
|
||||||
@staticmethod
|
|
||||||
def load_export():
|
|
||||||
try:
|
|
||||||
from support import SupportFile
|
|
||||||
f = os.path.join(path_app_root, 'export.sh')
|
|
||||||
if os.path.exists(f):
|
|
||||||
return SupportFile.read_file(f)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
ret = False
|
|
||||||
try:
|
|
||||||
if sub == 'setting_save':
|
|
||||||
data = req.form['export']
|
|
||||||
#logger.debug(data)
|
|
||||||
data = data.replace("\r\n", "\n" ).replace( "\r", "\n" )
|
|
||||||
ret = False
|
|
||||||
if platform.system() != 'Windows':
|
|
||||||
f = os.path.join(path_app_root, 'export.sh')
|
|
||||||
with open(f, 'w') as f:
|
|
||||||
f.write(data)
|
|
||||||
#os.system("dos2unix export.sh")
|
|
||||||
ret = True
|
|
||||||
elif sub == 'ps':
|
|
||||||
def func():
|
|
||||||
import system
|
|
||||||
commands = [
|
|
||||||
['msg', u'잠시만 기다려주세요.'],
|
|
||||||
['ps', '-ef'],
|
|
||||||
['top', '-n1']
|
|
||||||
]
|
|
||||||
#commands.append(['msg', u'설치가 완료되었습니다.'])
|
|
||||||
system.SystemLogicCommand.start('ps', commands)
|
|
||||||
t = threading.Thread(target=func, args=())
|
|
||||||
t.setDaemon(True)
|
|
||||||
t.start()
|
|
||||||
elif sub == 'celery_test':
|
|
||||||
ret = SystemLogicEnv.celery_test()
|
|
||||||
elif sub == 'worker_start':
|
|
||||||
os.system('sh worker_start.sh &')
|
|
||||||
"""
|
|
||||||
def func():
|
|
||||||
import system
|
|
||||||
commands = [
|
|
||||||
['msg', u'잠시만 기다려주세요.'],
|
|
||||||
['sh', 'worker_start.sh'],
|
|
||||||
]
|
|
||||||
#commands.append(['msg', u'설치가 완료되었습니다.'])
|
|
||||||
system.SystemLogicCommand.start('ps', commands)
|
|
||||||
t = threading.Thread(target=func, args=())
|
|
||||||
t.setDaemon(True)
|
|
||||||
t.start()
|
|
||||||
"""
|
|
||||||
ret = True
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return jsonify(ret)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def celery_test():
|
|
||||||
if F.config['use_celery']:
|
|
||||||
from celery import Celery
|
|
||||||
from celery.exceptions import NotRegistered, TimeoutError
|
|
||||||
|
|
||||||
data = {}
|
|
||||||
try:
|
|
||||||
result = SystemLogicEnv.celery_test2.apply_async()
|
|
||||||
logger.debug(result)
|
|
||||||
try:
|
|
||||||
tmp = result.get(timeout=5, propagate=True)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
#result = SystemLogicEnv.celery_test2.delay()
|
|
||||||
data['ret'] = 'success'
|
|
||||||
data['data'] = tmp
|
|
||||||
except TimeoutError:
|
|
||||||
data['ret'] = 'timeout'
|
|
||||||
data['data'] = u'celery가 동작중이 아니거나 모든 프로세스가 작업중입니다.'
|
|
||||||
except NotRegistered:
|
|
||||||
data['ret'] = 'not_registered'
|
|
||||||
data['data'] = u'Not Registered'
|
|
||||||
#logger.debug(data)
|
|
||||||
else:
|
|
||||||
data['ret'] = 'no_celery'
|
|
||||||
data['data'] = u'celery 실행환경이 아닙니다.'
|
|
||||||
return data
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@celery.task
|
|
||||||
def celery_test2():
|
|
||||||
try:
|
|
||||||
logger.debug('!!!! celery_test2222')
|
|
||||||
import time
|
|
||||||
time.sleep(1)
|
|
||||||
data = u'정상입니다. 이 메시지는 celery 에서 반환됩니다. '
|
|
||||||
return data
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
import platform
|
|
||||||
import time
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
|
||||||
|
|
||||||
|
|
||||||
# sjva 공용
|
|
||||||
|
|
||||||
from framework import path_app_root, path_data
|
|
||||||
from tool_base import ToolBaseNotify
|
|
||||||
# 패키지
|
|
||||||
from .plugin import logger, package_name
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicNotify(object):
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
try:
|
|
||||||
if sub == 'telegram_test':
|
|
||||||
ret = ToolBaseNotify.send_telegram_message(req.form['text'], bot_token=req.form['bot_token'], chat_id=req.form['chat_id'])
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'discord_test':
|
|
||||||
ret = ToolBaseNotify.send_discord_message(req.form['text'], webhook_url=req.form['url'])
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'advanced_test':
|
|
||||||
ret = ToolBaseNotify.send_advanced_message(req.form['text'], policy=req.form['policy'], message_id=req.form['message_id'])
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return jsonify('exception')
|
|
||||||
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
import requests
|
|
||||||
# sjva 공용
|
|
||||||
from framework import app, frame, logger, path_data
|
|
||||||
from framework.util import Util
|
|
||||||
from support import SupportProcess
|
|
||||||
|
|
||||||
import system
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
|
|
||||||
class LogicPlugin(object):
|
|
||||||
plugin_loading = False
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
current_loading_plugin_list = {}
|
|
||||||
|
|
||||||
"""
|
|
||||||
custom_plugin_list = []
|
|
||||||
@staticmethod
|
|
||||||
def loading():
|
|
||||||
try:
|
|
||||||
custom_path = os.path.join(path_data, 'custom')
|
|
||||||
plugin_list = os.listdir(custom_path)
|
|
||||||
logger.debug(plugin_list)
|
|
||||||
for name in plugin_list:
|
|
||||||
try:
|
|
||||||
p = {}
|
|
||||||
p['name'] = name
|
|
||||||
p['plugin_name'] = name
|
|
||||||
mod = __import__('%s' % (p['plugin_name']), fromlist=[])
|
|
||||||
p['local_info'] = getattr(mod, 'plugin_info')
|
|
||||||
p['status'] = 'latest'
|
|
||||||
LogicPlugin.custom_plugin_list.append(p)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('NO Exception:%s', exception)
|
|
||||||
logger.debug('plunin not import : %s', p['plugin_name'])
|
|
||||||
p['local_info'] = None
|
|
||||||
p['status'] = 'no'
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
"""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_plugin_list():
|
|
||||||
return LogicPlugin.current_loading_plugin_list
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if not LogicPlugin.plugin_loading:
|
|
||||||
LogicPlugin.loading()
|
|
||||||
LogicPlugin.plugin_loading = True
|
|
||||||
return LogicPlugin.custom_plugin_list
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_plugin_info(plugin_name):
|
|
||||||
try:
|
|
||||||
lists = LogicPlugin.get_plugin_list()
|
|
||||||
for key, value in lists.items():
|
|
||||||
if key == plugin_name:
|
|
||||||
return value['info']
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
@staticmethod
|
|
||||||
def plugin_install(plugin_name):
|
|
||||||
logger.debug('plugin_name : %s', plugin_name)
|
|
||||||
try:
|
|
||||||
plugin_info = LogicPlugin.get_plugin_info(plugin_name)
|
|
||||||
|
|
||||||
custom_path = os.path.join(path_data, 'custom')
|
|
||||||
|
|
||||||
if 'platform' in plugin_info:
|
|
||||||
if platform.system() not in plugin_info['platform']:
|
|
||||||
return 'not_support_os'
|
|
||||||
if 'running_type' in plugin_info:
|
|
||||||
if app.config['config']['running_type'] not in plugin_info['running_type']:
|
|
||||||
return 'not_support_running_type'
|
|
||||||
git_clone_flag = True
|
|
||||||
if git_clone_flag:
|
|
||||||
# git clone
|
|
||||||
command = ['git', '-C', custom_path, 'clone', plugin_info['git'], '--depth', '1']
|
|
||||||
ret = Util.execute_command(command)
|
|
||||||
return 'success'
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
"""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def plugin_uninstall(plugin_name):
|
|
||||||
logger.debug('plugin_name : %s', plugin_name)
|
|
||||||
try:
|
|
||||||
mod = __import__('%s' % (plugin_name), fromlist=[])
|
|
||||||
mod_plugin_unload = getattr(mod, 'plugin_unload')
|
|
||||||
mod_plugin_unload()
|
|
||||||
time.sleep(1)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
try:
|
|
||||||
custom_path = os.path.join(path_data, 'custom')
|
|
||||||
plugin_path = os.path.join(custom_path, plugin_name)
|
|
||||||
if os.path.exists(plugin_path):
|
|
||||||
try:
|
|
||||||
import framework.common.celery as celery_task
|
|
||||||
celery_task.rmtree(plugin_path)
|
|
||||||
except Exception as exception:
|
|
||||||
try:
|
|
||||||
logger.debug('plugin_uninstall')
|
|
||||||
os.system('rmdir /S /Q "%s"' % plugin_path)
|
|
||||||
except:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
if os.path.exists(plugin_path):
|
|
||||||
return 'fail'
|
|
||||||
else:
|
|
||||||
return 'success'
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def custom_plugin_update():
|
|
||||||
try:
|
|
||||||
if os.environ.get('UPDATE_STOP') == 'true':
|
|
||||||
return
|
|
||||||
if os.environ.get('PLUGIN_UPDATE_FROM_PYTHON') == 'false':
|
|
||||||
return
|
|
||||||
if frame.config['debug'] == True:
|
|
||||||
return
|
|
||||||
if frame.config.get('plugin_update', True) != True:
|
|
||||||
return
|
|
||||||
|
|
||||||
custom_path = os.path.join(path_data, 'plugins')
|
|
||||||
tmps = os.listdir(custom_path)
|
|
||||||
for t in tmps:
|
|
||||||
plugin_path = os.path.join(custom_path, t)
|
|
||||||
try:
|
|
||||||
if t == 'torrent_info':
|
|
||||||
os.remove(os.path.join(plugin_path, 'info.json'))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if t.startswith('_'):
|
|
||||||
continue
|
|
||||||
if os.path.exists(os.path.join(plugin_path, '.git')):
|
|
||||||
command = ['git', '-C', plugin_path, 'reset', '--hard', 'HEAD']
|
|
||||||
ret = SupportProcess.execute(command)
|
|
||||||
command = ['git', '-C', plugin_path, 'pull']
|
|
||||||
ret = SupportProcess.execute(command)
|
|
||||||
logger.debug("%s\n%s", plugin_path, ret)
|
|
||||||
else:
|
|
||||||
logger.debug(f"plugin_path is not git repo")
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def plugin_install_by_api(plugin_git, zip_url, zip_filename):
|
|
||||||
logger.debug('plugin_git : %s', plugin_git)
|
|
||||||
logger.debug('zip_url : %s', zip_url)
|
|
||||||
logger.debug('zip_filename : %s', zip_filename)
|
|
||||||
|
|
||||||
is_git = True if plugin_git != None and plugin_git != '' else False
|
|
||||||
ret = {}
|
|
||||||
try:
|
|
||||||
if is_git:
|
|
||||||
name = plugin_git.split('/')[-1]
|
|
||||||
else:
|
|
||||||
name = zip_filename.split('.')[0]
|
|
||||||
|
|
||||||
custom_path = os.path.join(path_data, 'custom')
|
|
||||||
plugin_path = os.path.join(custom_path, name)
|
|
||||||
logger.debug(plugin_path)
|
|
||||||
plugin_info = None
|
|
||||||
if os.path.exists(plugin_path):
|
|
||||||
ret['ret'] = 'already_exist'
|
|
||||||
ret['log'] = '이미 설치되어 있습니다.'
|
|
||||||
else:
|
|
||||||
if plugin_git and plugin_git.startswith('http'):
|
|
||||||
for tag in ['main', 'master']:
|
|
||||||
try:
|
|
||||||
info_url = plugin_git.replace('github.com', 'raw.githubusercontent.com') + '/%s/info.json' % tag
|
|
||||||
plugin_info = requests.get(info_url).json()
|
|
||||||
if plugin_info is not None:
|
|
||||||
break
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if zip_filename and zip_filename != '':
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
from tool_base import ToolBaseFile
|
|
||||||
zip_filepath = os.path.join(path_data, 'tmp', zip_filename)
|
|
||||||
extract_filepath = os.path.join(path_data, 'tmp', name)
|
|
||||||
logger.error(zip_url)
|
|
||||||
logger.warning(zip_filepath)
|
|
||||||
if ToolBaseFile.download(zip_url, zip_filepath):
|
|
||||||
#logger.warning(os.path.exists(zip_filepath))
|
|
||||||
with zipfile.ZipFile(zip_filepath, 'r') as zip_ref:
|
|
||||||
zip_ref.extractall(extract_filepath)
|
|
||||||
plugin_info_filepath = os.path.join(extract_filepath, 'info.json')
|
|
||||||
if os.path.exists(plugin_info_filepath):
|
|
||||||
plugin_info = ToolBaseFile.read_json(plugin_info_filepath)
|
|
||||||
if plugin_info == None:
|
|
||||||
plugin_info = {}
|
|
||||||
flag = True
|
|
||||||
if 'platform' in plugin_info:
|
|
||||||
if platform.system() not in plugin_info['platform']:
|
|
||||||
ret['ret'] = 'not_support_os'
|
|
||||||
ret['log'] = '설치 가능한 OS가 아닙니다.'
|
|
||||||
flag = False
|
|
||||||
if flag and 'running_type' in plugin_info:
|
|
||||||
if app.config['config']['running_type'] not in plugin_info['running_type']:
|
|
||||||
ret['ret'] = 'not_support_running_type'
|
|
||||||
ret['log'] = '설치 가능한 실행타입이 아닙니다.'
|
|
||||||
flag = False
|
|
||||||
if flag and 'policy_level' in plugin_info:
|
|
||||||
if plugin_info['policy_level'] > app.config['config']['level']:
|
|
||||||
ret['ret'] = 'policy_level'
|
|
||||||
ret['log'] = '설치 가능 회원등급보다 낮습니다.'
|
|
||||||
flag = False
|
|
||||||
if flag and 'policy_point' in plugin_info:
|
|
||||||
if plugin_info['policy_level'] > app.config['config']['point']:
|
|
||||||
ret['ret'] = 'policy_level'
|
|
||||||
ret['log'] = '설치 가능 포인트보다 낮습니다.'
|
|
||||||
flag = False
|
|
||||||
|
|
||||||
if flag:
|
|
||||||
if plugin_git and plugin_git.startswith('http'):
|
|
||||||
command = ['git', '-C', custom_path, 'clone', plugin_git + '.git', '--depth', '1']
|
|
||||||
log = Util.execute_command(command)
|
|
||||||
if zip_filename and zip_filename != '':
|
|
||||||
import shutil
|
|
||||||
if os.path.exists(plugin_path) == False:
|
|
||||||
shutil.move(extract_filepath, plugin_path)
|
|
||||||
else:
|
|
||||||
for tmp in os.listdir(extract_filepath):
|
|
||||||
shutil.move(os.path.join(extract_filepath, tmp), plugin_path)
|
|
||||||
log = ''
|
|
||||||
logger.debug(plugin_info)
|
|
||||||
# 2021-12-31
|
|
||||||
if 'dependency' in plugin_info:
|
|
||||||
for dep in plugin_info['dependency']:
|
|
||||||
for key, value in LogicPlugin.get_plugin_list().items():
|
|
||||||
if key == dep['name']:
|
|
||||||
logger.debug(f"Dependency 설치 - 이미 설치됨 : {dep['name']}")
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
logger.debug(f"Dependency 설치 : {dep['home']}")
|
|
||||||
LogicPlugin.plugin_install_by_api(dep['home'], dep.get('zip_url'), dep.get('zip_filename'))
|
|
||||||
#command = ['git', '-C', custom_path, 'clone', dep['home'], '--depth', '1']
|
|
||||||
#ret = Util.execute_command(command)
|
|
||||||
ret['ret'] = 'success'
|
|
||||||
ret['log'] = [u'정상적으로 설치하였습니다. 재시작시 적용됩니다.', log]
|
|
||||||
ret['log'] = '<br>'.join(ret['log'])
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
ret['ret'] = 'exception'
|
|
||||||
ret['log'] = str(exception)
|
|
||||||
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
@@ -1,397 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
import platform
|
|
||||||
import time
|
|
||||||
import base64
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
|
||||||
|
|
||||||
try:
|
|
||||||
from selenium import webdriver
|
|
||||||
from selenium.webdriver.support.ui import WebDriverWait
|
|
||||||
from PIL import Image
|
|
||||||
Image.MAX_IMAGE_PIXELS = None
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
from io import BytesIO
|
|
||||||
|
|
||||||
# sjva 공용
|
|
||||||
|
|
||||||
from framework import path_app_root, path_data
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
from .plugin import logger, package_name
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
#apk --no-cache add --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing firefox
|
|
||||||
#https://github.com/mozilla/geckodriver/releases/download/v0.26.0/geckodriver-v0.26.0-linux64.tar.gz
|
|
||||||
#curl -s -L "$url" | tar -xz
|
|
||||||
|
|
||||||
class SystemLogicSelenium(object):
|
|
||||||
chrome_driver = None
|
|
||||||
chrome_driver_list = []
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
try:
|
|
||||||
if sub == 'selenium_test_go':
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
driver.get(req.form['url'])
|
|
||||||
return jsonify('success')
|
|
||||||
elif sub == 'capture':
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
img = Image.open(BytesIO((driver.get_screenshot_as_png())))
|
|
||||||
|
|
||||||
timestamp = time.time()
|
|
||||||
timestamp = str(timestamp).split('.')[0]
|
|
||||||
tmp = os.path.join(path_data, 'tmp', '%s.png' % timestamp)
|
|
||||||
img.save(tmp)
|
|
||||||
from system.model import ModelSetting as SystemModelSetting
|
|
||||||
ddns = SystemModelSetting.get('ddns')
|
|
||||||
url = '%s/open_file%s' % (ddns, tmp)
|
|
||||||
logger.debug(url)
|
|
||||||
ret = {}
|
|
||||||
ret['ret'] = 'success'
|
|
||||||
ret['data'] = url
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'full_capture':
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
img = SystemLogicSelenium.full_screenshot(driver)
|
|
||||||
|
|
||||||
timestamp = time.time()
|
|
||||||
timestamp = str(timestamp).split('.')[0]
|
|
||||||
tmp = os.path.join(path_data, 'tmp', '%s.png' % timestamp)
|
|
||||||
img.save(tmp)
|
|
||||||
return send_file(tmp, mimetype='image/png')
|
|
||||||
elif sub == 'cookie':
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
data = driver.get_cookies()
|
|
||||||
return jsonify(data)
|
|
||||||
elif sub == 'daum_capcha':
|
|
||||||
daum_capcha = req.form['daum_capcha']
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
#driver.find_element_by_xpath('//div[@class="secret_viewer"]/p/img').screenshot("captcha.png")
|
|
||||||
driver.find_element_by_xpath('//input[@id="answer"]').send_keys(daum_capcha)
|
|
||||||
driver.find_element_by_xpath('//input[@value="%s"]' % u'확인').click()
|
|
||||||
return jsonify({'ret':'success'})
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return jsonify('exception')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_pagesoruce_by_selenium(url, wait_xpath, retry=True):
|
|
||||||
try:
|
|
||||||
logger.debug('get_pagesoruce_by_selenium:%s %s', url, wait_xpath)
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
#logger.debug('driver : %s', driver)
|
|
||||||
driver.get(url)
|
|
||||||
|
|
||||||
WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_xpath(wait_xpath))
|
|
||||||
#import time
|
|
||||||
#driver.save_screenshot('%s.png' % time.time())
|
|
||||||
#logger.debug('return page_source')
|
|
||||||
return driver.page_source
|
|
||||||
except Exception as exception:
|
|
||||||
#logger.debug(driver.page_source)
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
SystemLogicSelenium.close_driver()
|
|
||||||
#SystemLogicSelenium.chrome_driver = None
|
|
||||||
if retry:
|
|
||||||
return SystemLogicSelenium.get_pagesoruce_by_selenium(url, wait_xpath, retry=False)
|
|
||||||
|
|
||||||
# 1회성
|
|
||||||
@staticmethod
|
|
||||||
def get_driver(chrome_options=None):
|
|
||||||
try:
|
|
||||||
if SystemLogicSelenium.chrome_driver is None:
|
|
||||||
SystemLogicSelenium.chrome_driver = SystemLogicSelenium.inner_create_driver(chrome_options)
|
|
||||||
return SystemLogicSelenium.chrome_driver
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
# 플러그인이 점유
|
|
||||||
@staticmethod
|
|
||||||
def create_driver(chrome_options=None):
|
|
||||||
try:
|
|
||||||
driver = SystemLogicSelenium.inner_create_driver(chrome_options)
|
|
||||||
if driver is not None:
|
|
||||||
SystemLogicSelenium.chrome_driver_list.append(driver)
|
|
||||||
return driver
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def close_driver():
|
|
||||||
try:
|
|
||||||
#if SystemLogicSelenium.chrome_driver is not None:
|
|
||||||
# SystemLogicSelenium.chrome_driver.quit()
|
|
||||||
# SystemLogicSelenium.chrome_driver = None
|
|
||||||
if SystemLogicSelenium.chrome_driver is not None:
|
|
||||||
try: SystemLogicSelenium.chrome_driver.close()
|
|
||||||
except: pass
|
|
||||||
time.sleep(2)
|
|
||||||
try: SystemLogicSelenium.chrome_driver.quit()
|
|
||||||
except: pass
|
|
||||||
SystemLogicSelenium.chrome_driver = None
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def inner_create_driver(chrome_options):
|
|
||||||
try:
|
|
||||||
driver = None
|
|
||||||
remote_url = ModelSetting.get('selenium_remote_url')
|
|
||||||
if remote_url.endswith('/wd/hub/'):
|
|
||||||
remote_url = remote_url[:-1]
|
|
||||||
if remote_url != '':
|
|
||||||
if chrome_options is None:
|
|
||||||
chrome_options = webdriver.ChromeOptions()
|
|
||||||
tmp = ModelSetting.get_list('selenium_remote_default_option')
|
|
||||||
for t in tmp:
|
|
||||||
chrome_options.add_argument(t)
|
|
||||||
driver = webdriver.Remote(command_executor=remote_url, desired_capabilities=chrome_options.to_capabilities())
|
|
||||||
driver.set_window_size(1920, 1080)
|
|
||||||
logger.debug('Using Remote :%s', driver)
|
|
||||||
else:
|
|
||||||
path_chrome = os.path.join(path_app_root, 'bin', platform.system(), 'chromedriver')
|
|
||||||
if platform.system() == 'Windows':
|
|
||||||
path_chrome += '.exe'
|
|
||||||
if chrome_options is None:
|
|
||||||
chrome_options = webdriver.ChromeOptions()
|
|
||||||
tmp = ModelSetting.get_list('selenium_binary_default_option')
|
|
||||||
for t in tmp:
|
|
||||||
chrome_options.add_argument(t)
|
|
||||||
driver = webdriver.Chrome(path_chrome, chrome_options=chrome_options)
|
|
||||||
logger.debug('Using local bin :%s', driver)
|
|
||||||
if driver is not None:
|
|
||||||
return driver
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def plugin_unload():
|
|
||||||
try:
|
|
||||||
SystemLogicSelenium.close_driver()
|
|
||||||
#logger.debug(SystemLogicSelenium.chrome_driver)
|
|
||||||
#if SystemLogicSelenium.chrome_driver is not None:
|
|
||||||
# SystemLogicSelenium.chrome_driver.quit()
|
|
||||||
# logger.debug(SystemLogicSelenium.chrome_driver)
|
|
||||||
|
|
||||||
for tmp in SystemLogicSelenium.chrome_driver_list:
|
|
||||||
if tmp is not None:
|
|
||||||
tmp.quit()
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_text_excluding_children(driver, element):
|
|
||||||
return driver.execute_script("""
|
|
||||||
return jQuery(arguments[0]).contents().filter(function() {
|
|
||||||
return this.nodeType == Node.TEXT_NODE;
|
|
||||||
}).text();
|
|
||||||
""", element)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def full_screenshot(driver, low_offset = 0):
|
|
||||||
try:
|
|
||||||
# initiate value
|
|
||||||
#save_path = save_path + '.png' if save_path[-4::] != '.png' else save_path
|
|
||||||
img_li = [] # to store image fragment
|
|
||||||
offset = 0 # where to start
|
|
||||||
|
|
||||||
# js to get height
|
|
||||||
height = driver.execute_script('return Math.max('
|
|
||||||
'document.documentElement.clientHeight, window.innerHeight);')
|
|
||||||
#height = height - low_offset
|
|
||||||
# js to get the maximum scroll height
|
|
||||||
# Ref--> https://stackoverflow.com/questions/17688595/finding-the-maximum-scroll-position-of-a-page
|
|
||||||
max_window_height = driver.execute_script('return Math.max('
|
|
||||||
'document.body.scrollHeight, '
|
|
||||||
'document.body.offsetHeight, '
|
|
||||||
'document.documentElement.clientHeight, '
|
|
||||||
'document.documentElement.scrollHeight, '
|
|
||||||
'document.documentElement.offsetHeight);')
|
|
||||||
|
|
||||||
# looping from top to bottom, append to img list
|
|
||||||
# Ref--> https://gist.github.com/fabtho/13e4a2e7cfbfde671b8fa81bbe9359fb
|
|
||||||
|
|
||||||
while offset < max_window_height:
|
|
||||||
|
|
||||||
# Scroll to height
|
|
||||||
driver.execute_script("""
|
|
||||||
window.scrollTo(0, arguments[0]);
|
|
||||||
""", offset)
|
|
||||||
img = Image.open(BytesIO((driver.get_screenshot_as_png())))
|
|
||||||
|
|
||||||
if low_offset != 0:
|
|
||||||
img = img.crop((0, 0, img.width, img.height-low_offset)) # defines crop points
|
|
||||||
|
|
||||||
img_li.append(img)
|
|
||||||
offset += height
|
|
||||||
logger.debug('offset : %s / %s', offset, max_window_height)
|
|
||||||
|
|
||||||
# Stitch image into one
|
|
||||||
# Set up the full screen frame
|
|
||||||
img_frame_height = sum([img_frag.size[1] for img_frag in img_li])
|
|
||||||
img_frame = Image.new('RGB', (img_li[0].size[0], img_frame_height))
|
|
||||||
offset = 0
|
|
||||||
for img_frag in img_li:
|
|
||||||
img_frame.paste(img_frag, (0, offset))
|
|
||||||
offset += img_frag.size[1]
|
|
||||||
logger.debug('paste offset : %s ', offset)
|
|
||||||
#img_frame.save(save_path)
|
|
||||||
#return
|
|
||||||
return img_frame
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def remove_element(driver, element):
|
|
||||||
driver.execute_script("""
|
|
||||||
var element = arguments[0];
|
|
||||||
element.parentNode.removeChild(element);
|
|
||||||
""", element)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
@staticmethod
|
|
||||||
def __get_downloaded_files(driver=None):
|
|
||||||
if driver is None:
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
if not driver.current_url.startswith("chrome://downloads"):
|
|
||||||
driver.get("chrome://downloads/")
|
|
||||||
#driver.implicitly_wait(4)
|
|
||||||
return driver.execute_script( \
|
|
||||||
"return downloads.Manager.get().items_ "
|
|
||||||
" .filter(e => e.state === 'COMPLETE') "
|
|
||||||
" .map(e => e.filePath || e.file_path); " )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_file_content(path, driver=None):
|
|
||||||
if driver is None:
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
|
|
||||||
elem = driver.execute_script( \
|
|
||||||
"var input = window.document.createElement('INPUT'); "
|
|
||||||
"input.setAttribute('type', 'file'); "
|
|
||||||
"input.hidden = true; "
|
|
||||||
"input.onchange = function (e) { e.stopPropagation() }; "
|
|
||||||
"return window.document.documentElement.appendChild(input); " )
|
|
||||||
|
|
||||||
elem._execute('sendKeysToElement', {'value': [ path ], 'text': path})
|
|
||||||
|
|
||||||
result = driver.execute_async_script( \
|
|
||||||
"var input = arguments[0], callback = arguments[1]; "
|
|
||||||
"var reader = new FileReader(); "
|
|
||||||
"reader.onload = function (ev) { callback(reader.result) }; "
|
|
||||||
"reader.onerror = function (ex) { callback(ex.message) }; "
|
|
||||||
"reader.readAsDataURL(input.files[0]); "
|
|
||||||
"input.remove(); "
|
|
||||||
, elem)
|
|
||||||
|
|
||||||
if not result.startswith('data:') :
|
|
||||||
raise Exception("Failed to get file content: %s" % result)
|
|
||||||
|
|
||||||
return base64.b64decode(result[result.find('base64,') + 7:])
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_downloaded_files(driver=None):
|
|
||||||
if driver is None:
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
|
|
||||||
#files = WebDriverWait(driver, 20, 1).until(SystemLogicSelenium.__get_downloaded_files)
|
|
||||||
files = SystemLogicSelenium.__get_downloaded_files()
|
|
||||||
return files
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def waitUntilDownloadCompleted(maxTime=600, driver=None):
|
|
||||||
if driver is None:
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
driver.execute_script("window.open()")
|
|
||||||
# switch to new tab
|
|
||||||
driver.switch_to.window(driver.window_handles[-1])
|
|
||||||
# navigate to chrome downloads
|
|
||||||
driver.get('chrome://downloads')
|
|
||||||
# define the endTime
|
|
||||||
endTime = time.time() + maxTime
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
# get the download percentage
|
|
||||||
downloadPercentage = driver.execute_script(
|
|
||||||
"return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#progress').value")
|
|
||||||
# check if downloadPercentage is 100 (otherwise the script will keep waiting)
|
|
||||||
if downloadPercentage == 100:
|
|
||||||
# exit the method once it's completed
|
|
||||||
return downloadPercentage
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
# wait for 1 second before checking the percentage next time
|
|
||||||
time.sleep(1)
|
|
||||||
# exit method if the download not completed with in MaxTime.
|
|
||||||
if time.time() > endTime:
|
|
||||||
break
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
driver = webdriver.Chrome(desired_capabilities=capabilities_chrome)
|
|
||||||
#driver = webdriver.Remote('http://127.0.0.1:5555/wd/hub', capabilities_chrome)
|
|
||||||
|
|
||||||
# download a pdf file
|
|
||||||
driver.get("https://www.mozilla.org/en-US/foundation/documents")
|
|
||||||
driver.find_element_by_css_selector("[href$='.pdf']").click()
|
|
||||||
|
|
||||||
# list all the completed remote files (waits for at least one)
|
|
||||||
files = WebDriverWait(driver, 20, 1).until(get_downloaded_files)
|
|
||||||
|
|
||||||
# get the content of the first file remotely
|
|
||||||
content = get_file_content(driver, files[0])
|
|
||||||
|
|
||||||
# save the content in a local file in the working directory
|
|
||||||
with open(os.path.basename(files[0]), 'wb') as f:
|
|
||||||
f.write(content)
|
|
||||||
|
|
||||||
|
|
||||||
capabilities_chrome = { \
|
|
||||||
'browserName': 'chrome',
|
|
||||||
# 'proxy': { \
|
|
||||||
# 'proxyType': 'manual',
|
|
||||||
# 'sslProxy': '50.59.162.78:8088',
|
|
||||||
# 'httpProxy': '50.59.162.78:8088'
|
|
||||||
# },
|
|
||||||
'goog:chromeOptions': { \
|
|
||||||
'args': [
|
|
||||||
],
|
|
||||||
'prefs': { \
|
|
||||||
# 'download.default_directory': "",
|
|
||||||
# 'download.directory_upgrade': True,
|
|
||||||
'download.prompt_for_download': False,
|
|
||||||
'plugins.always_open_pdf_externally': True,
|
|
||||||
'safebrowsing_for_trusted_sources_enabled': False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
import platform
|
|
||||||
import time
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from framework import F, path_app_root, path_data, socketio, scheduler
|
|
||||||
from tool_base import d
|
|
||||||
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
from .plugin import logger, package_name
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicSite(object):
|
|
||||||
# 매번 split 하기 머해서
|
|
||||||
daum_cookie = None
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
try:
|
|
||||||
ret = {}
|
|
||||||
if sub == 'site_daum_test':
|
|
||||||
site_daum_test = req.form['site_daum_test']
|
|
||||||
ModelSetting.set('site_daum_test', site_daum_test)
|
|
||||||
from framework.common.daum import DaumTV, MovieSearch
|
|
||||||
ret['TV'] = DaumTV.get_daum_tv_info(site_daum_test)
|
|
||||||
if ret['TV'] is not None and 'episode_list' in ret['TV']:
|
|
||||||
del ret['TV']['episode_list']
|
|
||||||
ret['MOVIE'] = MovieSearch.search_movie(site_daum_test, -1)
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'site_daum_cookie_refresh':
|
|
||||||
ret = SystemLogicSite.get_daum_cookie_by_selenium(notify=True)
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'scheduler':
|
|
||||||
go = req.form['scheduler']
|
|
||||||
if go == 'true':
|
|
||||||
SystemLogicSite.scheduler_start()
|
|
||||||
else:
|
|
||||||
SystemLogicSite.scheduler_stop()
|
|
||||||
return jsonify(go)
|
|
||||||
elif sub == 'tving_login':
|
|
||||||
try:
|
|
||||||
from support.site.tving import SupportTving
|
|
||||||
token = SupportTving().do_login(req.form['tving_id'], req.form['tving_pw'], req.form['tving_login_type'])
|
|
||||||
if token is None:
|
|
||||||
ret['ret'] = False
|
|
||||||
else:
|
|
||||||
ret['ret'] = True
|
|
||||||
ret['token'] = token
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Exception:%s', e)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'tving_deviceid':
|
|
||||||
try:
|
|
||||||
from support.site.tving import SupportTving
|
|
||||||
device_list = SupportTving(token=req.form['tving_token']).get_device_list()
|
|
||||||
if device_list is None:
|
|
||||||
ret['ret'] = False
|
|
||||||
else:
|
|
||||||
ret['ret'] = True
|
|
||||||
ret['device_list'] = device_list
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Exception:%s', e)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
ret['ret'] = False
|
|
||||||
ret['log'] = str(traceback.format_exc())
|
|
||||||
return jsonify(ret)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def process_api(sub, req):
|
|
||||||
ret = {}
|
|
||||||
try:
|
|
||||||
if sub == 'daum_cookie':
|
|
||||||
return ModelSetting.get('site_daum_cookie')
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
ret['ret'] = 'exception'
|
|
||||||
ret['data'] = str(exception)
|
|
||||||
return jsonify(ret)
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def plugin_load():
|
|
||||||
SystemLogicSite.create_tving_instance()
|
|
||||||
return
|
|
||||||
SystemLogicSite.get_daum_cookies(force=True)
|
|
||||||
if ModelSetting.get_bool('site_daum_auto_start'):
|
|
||||||
SystemLogicSite.scheduler_start()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def create_tving_instance():
|
|
||||||
from support.site.tving import SupportTving
|
|
||||||
proxy = None
|
|
||||||
if ModelSetting.get_bool('site_tving_use_proxy'):
|
|
||||||
proxy = ModelSetting.get('site_tving_proxy_url')
|
|
||||||
SupportTving.ins = SupportTving(token=ModelSetting.get('site_tving_token'), proxy=proxy, deviceid=ModelSetting.get('site_tving_deviceid'), uuid=ModelSetting.get('site_tving_uuid'))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def scheduler_start():
|
|
||||||
job = Job(package_name, '%s_site' % package_name, ModelSetting.get('site_daum_interval'), SystemLogicSite.scheduler_function, u"Daum cookie refresh", False)
|
|
||||||
scheduler.add_job_instance(job)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def scheduler_stop():
|
|
||||||
scheduler.remove_job('%s_site' % package_name)
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def scheduler_function():
|
|
||||||
try:
|
|
||||||
data = SystemLogicSite.get_daum_cookie_by_selenium()
|
|
||||||
if data['ret']:
|
|
||||||
ModelSetting.set('site_daum_cookie', data['data'])
|
|
||||||
SystemLogicSite.get_daum_cookies(force=True)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_daum_cookie_by_selenium(notify=False):
|
|
||||||
try:
|
|
||||||
ret = {}
|
|
||||||
ret['ret'] = False
|
|
||||||
from .logic_selenium import SystemLogicSelenium
|
|
||||||
if notify:
|
|
||||||
data = {'type':'success', 'msg' : u'<strong>사이트 접속중입니다.</strong>'}
|
|
||||||
socketio.emit("notify", data, namespace='/framework', broadcast=True)
|
|
||||||
SystemLogicSelenium.get_pagesoruce_by_selenium('https://www.daum.net', '//*[@id="daumFoot"]/div/a[1]/img')
|
|
||||||
if notify:
|
|
||||||
data = {'type':'success', 'msg' : u'쿠키 확인'}
|
|
||||||
socketio.emit("notify", data, namespace='/framework', broadcast=True)
|
|
||||||
driver = SystemLogicSelenium.get_driver()
|
|
||||||
cookies = driver.get_cookies()
|
|
||||||
for tmp in cookies:
|
|
||||||
if tmp['name'] == 'TIARA':
|
|
||||||
ret['ret'] = True
|
|
||||||
ret['data'] = 'TIARA=%s' % tmp['value']
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_daum_cookies(force=False):
|
|
||||||
try:
|
|
||||||
if SystemLogicSite.daum_cookie is None or force:
|
|
||||||
ret = {}
|
|
||||||
tmp = ModelSetting.get('site_daum_cookie')
|
|
||||||
tmps = tmp.split(';')
|
|
||||||
for t in tmps:
|
|
||||||
t2 = t.split('=')
|
|
||||||
if len(t2) == 2:
|
|
||||||
ret[t2[0]] = t2[1]
|
|
||||||
SystemLogicSite.daum_cookie = ret
|
|
||||||
return SystemLogicSite.daum_cookie
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return {'TIARA':'gaXEIPluo-wWAFlwZN6l8gN3yzhkoo_piP.Kymhuy.6QBt4Q6.cRtxbKDaWpWajcyteRHzrlTVpJRxLjwLoMvyYLVi_7xJ1L'}
|
|
||||||
|
|
||||||
|
|
||||||
daum_headers = {
|
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
|
|
||||||
'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
|
|
||||||
'Accept-Language' : 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_tree_daum(cls, url, post_data=None):
|
|
||||||
from lxml import html
|
|
||||||
from framework import SystemModelSetting
|
|
||||||
text = cls.get_text_daum(url, post_data=post_data)
|
|
||||||
if text is None:
|
|
||||||
return
|
|
||||||
return html.fromstring(text)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_text_daum(cls, url, post_data=None):
|
|
||||||
from system.logic_site import SystemLogicSite
|
|
||||||
from framework import SystemModelSetting
|
|
||||||
res = cls.get_response(url, proxy_url=SystemModelSetting.get('site_daum_proxy'), headers=SystemLogicSite.daum_headers, post_data=post_data, cookies=SystemLogicSite.get_daum_cookies())
|
|
||||||
return res.text
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_response_daum(cls, url, post_data=None):
|
|
||||||
from system.logic_site import SystemLogicSite
|
|
||||||
from framework import SystemModelSetting
|
|
||||||
res = cls.get_response(url, proxy_url=SystemModelSetting.get('site_daum_proxy'), headers=SystemLogicSite.daum_headers, post_data=post_data, cookies=SystemLogicSite.get_daum_cookies())
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_response(cls, url, proxy_url=None, headers=None, post_data=None, cookies=None):
|
|
||||||
import requests
|
|
||||||
proxies = None
|
|
||||||
if proxy_url is not None and proxy_url != '':
|
|
||||||
proxies = {"http" : proxy_url, "https" : proxy_url}
|
|
||||||
if headers is None:
|
|
||||||
headers = SystemLogicSite.default_headers
|
|
||||||
if post_data is None:
|
|
||||||
#logger.warning(d(headers))
|
|
||||||
#logger.warning(d(proxies))
|
|
||||||
#logger.warning(d(cookies))
|
|
||||||
|
|
||||||
res = requests.get(url, headers=headers, proxies=proxies, cookies=cookies)
|
|
||||||
else:
|
|
||||||
res = requests.post(url, headers=headers, proxies=proxies, data=post_data, cookies=cookies)
|
|
||||||
return res
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import os
|
|
||||||
import traceback
|
|
||||||
import logging
|
|
||||||
import platform
|
|
||||||
import time
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
from flask import Blueprint, request, Response, send_file, render_template, redirect, jsonify
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from framework import F, frame, app, path_app_root, path_data, scheduler
|
|
||||||
from tool_base import ToolBaseNotify
|
|
||||||
# 패키지
|
|
||||||
from .plugin import logger, package_name
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicTelegramBot(object):
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
try:
|
|
||||||
if sub == 'telegram_test':
|
|
||||||
ret = ToolBaseNotify.send_telegram_message(req.form['text'], bot_token=req.form['bot_token'], chat_id=req.form['chat_id'])
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'discord_test':
|
|
||||||
ret = ToolBaseNotify.send_discord_message(req.form['text'], webhook_url=req.form['url'])
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'advanced_test':
|
|
||||||
ret = ToolBaseNotify.send_advanced_message(req.form['text'], policy=req.form['policy'], message_id=req.form['message_id'])
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'scheduler':
|
|
||||||
go = request.form['scheduler']
|
|
||||||
logger.debug('scheduler :%s', go)
|
|
||||||
if go == 'true':
|
|
||||||
SystemLogicTelegramBot.scheduler_start()
|
|
||||||
else:
|
|
||||||
SystemLogicTelegramBot.scheduler_stop()
|
|
||||||
return jsonify(go)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return jsonify('exception')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def plugin_load():
|
|
||||||
try:
|
|
||||||
if frame.config['run_celery']:
|
|
||||||
return
|
|
||||||
|
|
||||||
if ModelSetting.get_bool('telegram_bot_auto_start'):
|
|
||||||
SystemLogicTelegramBot.scheduler_start()
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def scheduler_start():
|
|
||||||
try:
|
|
||||||
interval = 60*24
|
|
||||||
job = Job(package_name, '%s_telegram_bot' % (package_name), 9999, SystemLogicTelegramBot.scheduler_function, u"시스템 - 텔레그램 봇", False)
|
|
||||||
scheduler.add_job_instance(job)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def scheduler_function():
|
|
||||||
try:
|
|
||||||
bot_token = ModelSetting.get('telegram_bot_token')
|
|
||||||
from framework.common.telegram_bot import TelegramBot
|
|
||||||
TelegramBot.start(bot_token)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
try:
|
|
||||||
import yaml
|
|
||||||
a = yaml.FullLoader
|
|
||||||
except:
|
|
||||||
from framework import app
|
|
||||||
import os
|
|
||||||
try: os.system(f"{app.config['config']['pip']} install --upgrade pyyaml")
|
|
||||||
except: pass
|
|
||||||
|
|
||||||
import os, sys, traceback, json
|
|
||||||
from framework import path_data
|
|
||||||
from flask import request, render_template, redirect, jsonify
|
|
||||||
from .plugin import logger
|
|
||||||
|
|
||||||
|
|
||||||
class SystemLogicTerminal(object):
|
|
||||||
yaml_path = os.path.join(path_data, 'db', 'terminal.yaml')
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def process_ajax(cls, sub, req):
|
|
||||||
logger.error(sub)
|
|
||||||
logger.error(req)
|
|
||||||
try:
|
|
||||||
if sub == 'get_info':
|
|
||||||
ret = cls.get_info()
|
|
||||||
elif sub == 'run':
|
|
||||||
data = cls.get_info()
|
|
||||||
idx = int(req.form['index'])
|
|
||||||
from terminal.logic_terminal import LogicTerminal
|
|
||||||
LogicTerminal.wait_input(data['commands'][idx]['command'])
|
|
||||||
return jsonify({'ret':'success'})
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f'Exception: {str(e)}')
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_info(cls):
|
|
||||||
if os.path.exists(cls.yaml_path) == False:
|
|
||||||
with open(cls.yaml_path, 'w', encoding='utf8') as f:
|
|
||||||
f.write(yaml_templete)
|
|
||||||
with open(cls.yaml_path, 'r', encoding='utf8') as f:
|
|
||||||
info = yaml.load(f, Loader=yaml.FullLoader)
|
|
||||||
return info
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
yaml_templete = '''
|
|
||||||
|
|
||||||
commands:
|
|
||||||
- title: SJVA 데이터 폴더별 크기 확인
|
|
||||||
command: |
|
|
||||||
cd ./data
|
|
||||||
du -h -d 1
|
|
||||||
|
|
||||||
- title: SJVA 도커 재시작
|
|
||||||
command: |
|
|
||||||
ssh -i MY.pem ubuntu@172.17.0.1
|
|
||||||
sudo docker restart sjva
|
|
||||||
|
|
||||||
'''
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
import traceback
|
|
||||||
from flask import jsonify
|
|
||||||
from framework import app
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
from .plugin import package_name, logger
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
class SystemLogicToolDecrypt(object):
|
|
||||||
@staticmethod
|
|
||||||
def process_ajax(sub, req):
|
|
||||||
try:
|
|
||||||
if sub == 'crypt_test':
|
|
||||||
ret = SystemLogicToolDecrypt.crypt_test(req)
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
##########################################################################
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def crypt_test(req):
|
|
||||||
try:
|
|
||||||
mode = req.form['mode']
|
|
||||||
word = req.form['word']
|
|
||||||
|
|
||||||
logger.debug(mode)
|
|
||||||
logger.debug(word)
|
|
||||||
from tool_base import ToolAESCipher
|
|
||||||
mykey = None
|
|
||||||
if ModelSetting.get_bool('tool_crypt_use_user_key'):
|
|
||||||
mykey = ModelSetting.get('tool_crypt_user_key').lower().zfill(32)
|
|
||||||
if app.config['config']['is_py2']:
|
|
||||||
mykey = mykey.encode('utf8')
|
|
||||||
if len(mykey) > 32:
|
|
||||||
mykey = mykey[:32]
|
|
||||||
logger.debug(mykey)
|
|
||||||
|
|
||||||
if mode == 'encrypt':
|
|
||||||
ModelSetting.set('tool_crypt_encrypt_word', u'%s' % word)
|
|
||||||
ret = {'ret':'success', 'data':ToolAESCipher.encrypt(word, mykey=mykey)}
|
|
||||||
elif mode == 'decrypt':
|
|
||||||
ModelSetting.set('tool_crypt_decrypt_word', u'%s' % word)
|
|
||||||
ret = {'ret':'success', 'data':ToolAESCipher.decrypt(word, mykey=mykey).decode()}
|
|
||||||
|
|
||||||
logger.debug(ret)
|
|
||||||
return ret
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return {'ret':'exception', 'data':str(exception)}
|
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
import time
|
||||||
|
|
||||||
from support import SupportDiscord, SupportFile, SupportTelegram
|
from support import (SupportDiscord, SupportFile, SupportSubprocess,
|
||||||
from tool.modal_command import ToolModalCommand
|
SupportTelegram)
|
||||||
|
from tool import ToolModalCommand
|
||||||
|
|
||||||
from .setup import *
|
from .setup import *
|
||||||
|
|
||||||
@@ -35,7 +37,7 @@ class ModuleSetting(PluginModuleBase):
|
|||||||
'notify.yaml': '', #직접 사용하지 않으나 저장 편의상.
|
'notify.yaml': '', #직접 사용하지 않으나 저장 편의상.
|
||||||
'command_text': '',
|
'command_text': '',
|
||||||
'celery_start_by_web': 'False', #웹 실행시 celery 실행
|
'celery_start_by_web': 'False', #웹 실행시 celery 실행
|
||||||
'celery_start_command': "celery -A flaskfarm.main.celery worker --loglevel=info --pool=gevent --concurrency=2 --config_filepath={F.config['config_filepath']} --running_type=native",
|
'celery_start_command': "celery -A flaskfarm.main.celery worker --workdir={F.config['path_working']} --loglevel=info --pool=gevent --concurrency=2 --config_filepath={F.config['config_filepath']} --running_type=native",
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -65,7 +67,6 @@ class ModuleSetting(PluginModuleBase):
|
|||||||
elif page == 'celery':
|
elif page == 'celery':
|
||||||
arg['use_celery'] = F.config['use_celery']
|
arg['use_celery'] = F.config['use_celery']
|
||||||
arg['running_type'] = F.config['running_type']
|
arg['running_type'] = F.config['running_type']
|
||||||
|
|
||||||
return render_template(f'{__package__}_{name}_{page}.html', arg=arg)
|
return render_template(f'{__package__}_{name}_{page}.html', arg=arg)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
P.logger.error(f'Exception:{str(e)}')
|
P.logger.error(f'Exception:{str(e)}')
|
||||||
@@ -122,13 +123,13 @@ class ModuleSetting(PluginModuleBase):
|
|||||||
ret['msg'] = arg1
|
ret['msg'] = arg1
|
||||||
pass
|
pass
|
||||||
elif command == 'celery_execute':
|
elif command == 'celery_execute':
|
||||||
tmp = arg1.replace("{F.config['config_filepath']}", F.config['config_filepath']).replace('{F.config["config_filepath"]}', F.config['config_filepath'])
|
self.celery_execute(arg1, mode='foreground')
|
||||||
cmd = [
|
elif command == 'celery_execute_back':
|
||||||
['msg', f'명령 : {tmp}'],
|
self.celery_execute(arg1, mode='background')
|
||||||
['msg', ''],
|
ret['msg'] = '실행했습니다.'
|
||||||
tmp.split(' '),
|
elif command == 'celery_test':
|
||||||
]
|
return self.__celery_test()
|
||||||
ToolModalCommand.start("Celery 실행", cmd)
|
|
||||||
return jsonify(ret)
|
return jsonify(ret)
|
||||||
|
|
||||||
|
|
||||||
@@ -136,9 +137,8 @@ class ModuleSetting(PluginModuleBase):
|
|||||||
try:
|
try:
|
||||||
if F.config['run_flask'] == False:
|
if F.config['run_flask'] == False:
|
||||||
return
|
return
|
||||||
F.logger.info(f"arg_repeat : {F.config['arg_repeat']}")
|
if SystemModelSetting.get_bool('celery_start_by_web'):
|
||||||
F.logger.info(f"arg_repeat : {F.config['arg_repeat']}")
|
self.celery_execute()
|
||||||
|
|
||||||
if F.config['arg_repeat'] == 0 or SystemModelSetting.get('system_start_time') == '':
|
if F.config['arg_repeat'] == 0 or SystemModelSetting.get('system_start_time') == '':
|
||||||
SystemModelSetting.set('system_start_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
|
SystemModelSetting.set('system_start_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
|
||||||
SystemModelSetting.set('repeat', str(F.config['arg_repeat']))
|
SystemModelSetting.set('repeat', str(F.config['arg_repeat']))
|
||||||
@@ -161,15 +161,17 @@ class ModuleSetting(PluginModuleBase):
|
|||||||
from tool import ToolNotify
|
from tool import ToolNotify
|
||||||
msg = f"시스템이 시작되었습니다.\n재시작: {F.config['arg_repeat']}"
|
msg = f"시스템이 시작되었습니다.\n재시작: {F.config['arg_repeat']}"
|
||||||
ToolNotify.send_message(msg, message_id='system_start')
|
ToolNotify.send_message(msg, message_id='system_start')
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
P.logger.error(f'Exception:{str(e)}')
|
P.logger.error(f'Exception:{str(e)}')
|
||||||
P.logger.error(traceback.format_exc())
|
P.logger.error(traceback.format_exc())
|
||||||
|
|
||||||
def plugin_unload(self):
|
def plugin_unload(self):
|
||||||
ToolModalCommand.process_close()
|
ToolModalCommand.modal_close()
|
||||||
|
|
||||||
def setting_save_after(self, change_list):
|
def setting_save_after(self, change_list):
|
||||||
if 'theme' in change_list:
|
if 'theme' in change_list or 'web_title' in change_list:
|
||||||
F.socketio.emit("refresh", {}, namespace='/framework', broadcast=True)
|
F.socketio.emit("refresh", {}, namespace='/framework', broadcast=True)
|
||||||
elif 'notify.yaml' in change_list:
|
elif 'notify.yaml' in change_list:
|
||||||
SupportFile.write_file(F.config['notify_yaml_filepath'], SystemModelSetting.get('notify.yaml'))
|
SupportFile.write_file(F.config['notify_yaml_filepath'], SystemModelSetting.get('notify.yaml'))
|
||||||
@@ -196,3 +198,53 @@ class ModuleSetting(PluginModuleBase):
|
|||||||
scheduler.add_job_instance(job_instance, run=False)
|
scheduler.add_job_instance(job_instance, run=False)
|
||||||
|
|
||||||
|
|
||||||
|
def celery_execute(self, command=None, mode='background'):
|
||||||
|
if command == None:
|
||||||
|
command = SystemModelSetting.get('celery_start_command')
|
||||||
|
command = command.replace("{F.config['config_filepath']}", F.config['config_filepath']).replace('{F.config["config_filepath"]}', F.config['config_filepath']).replace("{F.config['path_working']}", F.config['path_working']).replace('{F.config["path_working"]}', F.config['path_working'])
|
||||||
|
if mode == 'foreground':
|
||||||
|
cmd = [
|
||||||
|
['msg', f'명령 : {command}'],
|
||||||
|
command.split(' '),
|
||||||
|
]
|
||||||
|
ToolModalCommand.start("Celery 실행", cmd)
|
||||||
|
elif mode == 'background':
|
||||||
|
SupportSubprocess(command).start(join=False)
|
||||||
|
|
||||||
|
|
||||||
|
def __celery_test(self):
|
||||||
|
if F.config['use_celery']:
|
||||||
|
from celery import Celery
|
||||||
|
from celery.exceptions import NotRegistered, TimeoutError
|
||||||
|
data = {}
|
||||||
|
try:
|
||||||
|
result = self.celery_test.apply_async()
|
||||||
|
try:
|
||||||
|
tmp = result.get(timeout=5, propagate=True)
|
||||||
|
except Exception as e:
|
||||||
|
P.logger.error(f'Exception:{str(e)}')
|
||||||
|
P.logger.error(traceback.format_exc())
|
||||||
|
data['ret'] = 'success'
|
||||||
|
data['msg'] = tmp
|
||||||
|
except TimeoutError:
|
||||||
|
data['ret'] = 'danger'
|
||||||
|
data['msg'] = 'celery가 동작중이 아니거나 모든 Worker가 작업중입니다.'
|
||||||
|
except NotRegistered:
|
||||||
|
data['ret'] = 'danger'
|
||||||
|
data['msg'] = 'Not Registered'
|
||||||
|
else:
|
||||||
|
data['ret'] = 'danger'
|
||||||
|
data['msg'] = 'celery 실행환경이 아닙니다.'
|
||||||
|
P.logger.debug(d(data))
|
||||||
|
return data
|
||||||
|
|
||||||
|
#@staticmethod
|
||||||
|
@celery.task
|
||||||
|
def celery_test():
|
||||||
|
try:
|
||||||
|
time.sleep(1)
|
||||||
|
data = '정상입니다. 이 메시지는 celery 에서 반환됩니다. '
|
||||||
|
return data
|
||||||
|
except Exception as e:
|
||||||
|
P.logger.error(f'Exception:{str(e)}')
|
||||||
|
P.logger.error(traceback.format_exc())
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
import traceback
|
|
||||||
from framework import db, get_logger
|
|
||||||
from framework.util import Util
|
|
||||||
|
|
||||||
logger = get_logger(__package__)
|
|
||||||
|
|
||||||
from plugin.model_setting import get_model_setting
|
|
||||||
ModelSetting = get_model_setting(__package__, logger)
|
|
||||||
@@ -1,543 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#########################################################
|
|
||||||
# python
|
|
||||||
import json
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import platform
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
# third-party
|
|
||||||
import requests
|
|
||||||
from flask import (Blueprint, Response, jsonify, redirect, render_template,
|
|
||||||
request, send_file, stream_with_context)
|
|
||||||
from flask_login import login_required
|
|
||||||
# sjva 공용
|
|
||||||
from framework import (app, check_api, frame, get_logger, # , celery
|
|
||||||
path_app_root, path_data, scheduler, socketio)
|
|
||||||
from support import SingletonClass
|
|
||||||
|
|
||||||
# 로그
|
|
||||||
package_name = __name__.split('.')[0]
|
|
||||||
logger = get_logger(__package__)
|
|
||||||
|
|
||||||
# 패키지
|
|
||||||
from .logic import SystemLogic
|
|
||||||
from .logic_auth import SystemLogicAuth
|
|
||||||
from .logic_command import SystemLogicCommand
|
|
||||||
from .logic_command2 import SystemLogicCommand2
|
|
||||||
# celery 때문에 import
|
|
||||||
from .logic_env import SystemLogicEnv
|
|
||||||
from .logic_notify import SystemLogicNotify
|
|
||||||
from .logic_plugin import LogicPlugin
|
|
||||||
from .logic_selenium import SystemLogicSelenium
|
|
||||||
from .logic_site import SystemLogicSite
|
|
||||||
from .logic_telegram_bot import SystemLogicTelegramBot
|
|
||||||
from .logic_terminal import SystemLogicTerminal
|
|
||||||
from .logic_tool_crypt import SystemLogicToolDecrypt
|
|
||||||
from .model import ModelSetting
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
# 플러그인 공용
|
|
||||||
#########################################################
|
|
||||||
blueprint = Blueprint(package_name, package_name, url_prefix='/%s' % package_name, template_folder='templates')
|
|
||||||
|
|
||||||
menu = {
|
|
||||||
'uri' : package_name,
|
|
||||||
'name': '설정',
|
|
||||||
'list': [
|
|
||||||
{
|
|
||||||
'uri': 'setting',
|
|
||||||
'name': '일반설정',
|
|
||||||
'list': [
|
|
||||||
{'uri': 'basic', 'name': '기본'},
|
|
||||||
{'uri': 'auth', 'name': '인증'},
|
|
||||||
{'uri': 'env', 'name': '시스템'},
|
|
||||||
{'uri': 'notify', 'name': '알림'},
|
|
||||||
{'uri': 'telegram_bot', 'name': '텔레그램 봇'},
|
|
||||||
{'uri': 'selenium', 'name': 'Selenium'},
|
|
||||||
{'uri': 'site', 'name': 'Site'},
|
|
||||||
{'uri': 'memo', 'name': '메모'},
|
|
||||||
{'uri': 'terminal', 'name': 'Terminal'},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'uri': 'plugin',
|
|
||||||
'name': '플러그인'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'uri': 'tool',
|
|
||||||
'name': 'Tool',
|
|
||||||
'list': [{'uri': 'crypt', 'name': '암호화'}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'uri': 'log',
|
|
||||||
'name': '로그'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if platform.system() == 'Windows':
|
|
||||||
# del menu['sub2']['setting'][-1]
|
|
||||||
|
|
||||||
|
|
||||||
def plugin_load():
|
|
||||||
logger.debug('plugin_load:%s', package_name)
|
|
||||||
SystemLogic.plugin_load()
|
|
||||||
SystemLogicTelegramBot.plugin_load()
|
|
||||||
SystemLogicSite.plugin_load()
|
|
||||||
|
|
||||||
def plugin_unload():
|
|
||||||
logger.debug('plugin_load:%s', package_name)
|
|
||||||
SystemLogicSelenium.plugin_unload()
|
|
||||||
SystemLogicCommand.plugin_unload()
|
|
||||||
SystemLogicCommand2.plugin_unload()
|
|
||||||
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
# WEB Menu
|
|
||||||
#########################################################
|
|
||||||
@blueprint.route('/')
|
|
||||||
def normal():
|
|
||||||
return redirect('/%s/setting' % package_name)
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def home():
|
|
||||||
return render_template('info.html', arg=None)
|
|
||||||
|
|
||||||
@blueprint.route('/<sub>', methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def first_menu(sub):
|
|
||||||
#logger.debug('System SUB:%s', sub)
|
|
||||||
arg = None
|
|
||||||
if sub == 'home':
|
|
||||||
return render_template('%s_%s.html' % (package_name, sub), arg=None)
|
|
||||||
elif sub == 'setting':
|
|
||||||
return redirect('/%s/%s/basic' % (package_name, sub))
|
|
||||||
elif sub == 'tool':
|
|
||||||
return redirect('/%s/%s/crypt' % (package_name, sub))
|
|
||||||
elif sub == 'plugin':
|
|
||||||
arg = ModelSetting.to_dict()
|
|
||||||
arg['install'] = request.args.get('install', '')
|
|
||||||
if arg['install'] == 'flaskfilemanager':
|
|
||||||
arg['install'] = 'https://github.com/soju6jan/' + arg['install']
|
|
||||||
try:
|
|
||||||
import flaskfilemanager
|
|
||||||
arg['install'] = ''
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
elif arg['install'] == 'flaskcode':
|
|
||||||
arg['install'] = 'https://github.com/soju6jan/' + arg['install']
|
|
||||||
try:
|
|
||||||
import flaskcode
|
|
||||||
arg['install'] = ''
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render_template('system_plugin.html', arg=arg)
|
|
||||||
elif sub == 'information':
|
|
||||||
return render_template('manual.html', sub=sub, arg='system.json')
|
|
||||||
elif sub == 'log':
|
|
||||||
log_files=os.listdir(os.path.join(path_data, 'log'))
|
|
||||||
log_files.sort()
|
|
||||||
log_list = []
|
|
||||||
arg = {'package_name' : package_name, 'sub' : sub}
|
|
||||||
for x in log_files:
|
|
||||||
if x.endswith('.log'):
|
|
||||||
log_list.append(x)
|
|
||||||
arg['log_list'] = '|'.join(log_list)
|
|
||||||
arg['all_list'] = '|'.join(log_files)
|
|
||||||
arg['filename'] = ''
|
|
||||||
if 'filename' in request.form:
|
|
||||||
arg['filename'] = request.form['filename']
|
|
||||||
logger.debug(arg)
|
|
||||||
return render_template('%s_%s.html' % (package_name, sub), arg=arg)
|
|
||||||
elif sub == 'restart':
|
|
||||||
restart()
|
|
||||||
return render_template('system_restart.html', sub=sub, referer=request.headers.get("Referer"))
|
|
||||||
elif sub == 'shutdown':
|
|
||||||
shutdown()
|
|
||||||
return render_template('system_restart.html', sub=sub, referer=request.headers.get("Referer"))
|
|
||||||
elif sub == 'telegram':
|
|
||||||
return redirect('/%s/%s/setting' % (package_name, sub))
|
|
||||||
return render_template('sample.html', title='%s - %s' % (package_name, sub))
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/<sub>/<sub2>')
|
|
||||||
@login_required
|
|
||||||
def second_menu(sub, sub2):
|
|
||||||
try:
|
|
||||||
if sub == 'setting':
|
|
||||||
arg = ModelSetting.to_dict()
|
|
||||||
arg['sub'] = sub2
|
|
||||||
if sub2 == 'basic':
|
|
||||||
arg['point'] = SystemLogic.point
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 in ['trans', 'selenium', 'notify']:
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 == 'auth':
|
|
||||||
arg['auth_result'] = SystemLogicAuth.get_auth_status()
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 == 'telegram_bot':
|
|
||||||
arg['scheduler'] = str(scheduler.is_include('%s_%s' % (package_name, sub2)))
|
|
||||||
arg['is_running'] = str(scheduler.is_running('%s_%s' % (package_name, sub2)))
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 == 'env':
|
|
||||||
arg['export'] = SystemLogicEnv.load_export()
|
|
||||||
if arg['export'] is None:
|
|
||||||
arg['export'] = u'export.sh 파일이 없습니다.'
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 == 'site':
|
|
||||||
arg['scheduler'] = str(scheduler.is_include('%s_%s' % (package_name, sub2)))
|
|
||||||
arg['is_running'] = str(scheduler.is_running('%s_%s' % (package_name, sub2)))
|
|
||||||
from system.model import ModelSetting as SystemModelSetting
|
|
||||||
arg['site_get_daum_cookie_url'] = '{ddns}/{package_name}/api/{sub2}/daum_cookie'.format(ddns=SystemModelSetting.get('ddns'), package_name=package_name, sub2=sub2)
|
|
||||||
if SystemModelSetting.get_bool('auth_use_apikey'):
|
|
||||||
arg['site_get_daum_cookie_url'] += '?apikey={apikey}'.format(apikey=SystemModelSetting.get('auth_apikey'))
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 == 'memo':
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub2 == 'terminal':
|
|
||||||
arg['yaml_path'] = SystemLogicTerminal.yaml_path.replace(path_app_root, '')
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
elif sub == 'tool':
|
|
||||||
arg = ModelSetting.to_dict()
|
|
||||||
arg['sub'] = sub2
|
|
||||||
if sub2 == 'crypt':
|
|
||||||
return render_template('%s_%s_%s.html' % (package_name, sub, sub2), arg=arg)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
# For UI
|
|
||||||
#########################################################
|
|
||||||
@blueprint.route('/ajax/<sub>/<sub2>', methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def second_ajax(sub, sub2):
|
|
||||||
logger.debug('System AJAX sub:%s', sub)
|
|
||||||
try:
|
|
||||||
if sub == 'auth':
|
|
||||||
from .logic_auth import SystemLogicAuth
|
|
||||||
return SystemLogicAuth.process_ajax(sub2, request)
|
|
||||||
elif sub == 'selenium':
|
|
||||||
return SystemLogicSelenium.process_ajax(sub2, request)
|
|
||||||
elif sub == 'notify':
|
|
||||||
return SystemLogicNotify.process_ajax(sub2, request)
|
|
||||||
elif sub == 'telegram_bot':
|
|
||||||
return SystemLogicTelegramBot.process_ajax(sub2, request)
|
|
||||||
elif sub == 'env':
|
|
||||||
return SystemLogicEnv.process_ajax(sub2, request)
|
|
||||||
elif sub == 'site':
|
|
||||||
return SystemLogicSite.process_ajax(sub2, request)
|
|
||||||
elif sub == 'crypt':
|
|
||||||
return SystemLogicToolDecrypt.process_ajax(sub2, request)
|
|
||||||
elif sub == 'terminal':
|
|
||||||
return SystemLogicTerminal.process_ajax(sub2, request)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/ajax/<sub>', methods=['GET', 'POST'])
|
|
||||||
@login_required
|
|
||||||
def ajax(sub):
|
|
||||||
#logger.debug('System AJAX sub:%s', sub)
|
|
||||||
try:
|
|
||||||
if sub == 'info':
|
|
||||||
try:
|
|
||||||
ret = {}
|
|
||||||
ret['system'] = SystemLogic.get_info()
|
|
||||||
ret['scheduler'] = scheduler.get_job_list_info()
|
|
||||||
|
|
||||||
#logger.debug(ret)
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return jsonify()
|
|
||||||
elif sub == 'setting_save_system':
|
|
||||||
try:
|
|
||||||
ret = SystemLogic.setting_save_system(request)
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'setting_save':
|
|
||||||
ret = ModelSetting.setting_save(request)
|
|
||||||
SystemLogic.setting_save_after()
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'ddns_test':
|
|
||||||
try:
|
|
||||||
url = request.form['ddns'] + '/version'
|
|
||||||
res = requests.get(url)
|
|
||||||
data = res.text
|
|
||||||
#data = res.json()
|
|
||||||
#logger.debug(data)
|
|
||||||
return jsonify(data)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
return jsonify('fail')
|
|
||||||
elif sub == 'celery_test':
|
|
||||||
try:
|
|
||||||
#result = add_together.delay(10, 20)
|
|
||||||
#print(result.wait())
|
|
||||||
#return 'Welcome to my app!'
|
|
||||||
try:
|
|
||||||
import framework
|
|
||||||
framework.exit_code = 1
|
|
||||||
socketio.stop()
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
#os.environ['SJVA_REPEAT_TYPE'] = 'update'
|
|
||||||
|
|
||||||
|
|
||||||
return jsonify()
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'command_run':
|
|
||||||
try:
|
|
||||||
command_text = request.form['command_text']
|
|
||||||
ret = SystemLogic.command_run(command_text)
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'get_link_list':
|
|
||||||
try:
|
|
||||||
link_json = SystemLogic.get_setting_value('link_json')
|
|
||||||
j = json.loads(link_json)
|
|
||||||
return jsonify(j)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'link_save':
|
|
||||||
try:
|
|
||||||
link_data_str = request.form['link_data']
|
|
||||||
#j = json.loads(link_data)
|
|
||||||
ret = SystemLogic.link_save(link_data_str)
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'plugin_list':
|
|
||||||
try:
|
|
||||||
return jsonify(LogicPlugin.get_plugin_list())
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
elif sub == 'plugin_install':
|
|
||||||
try:
|
|
||||||
#plugin_name = request.form['plugin_name']
|
|
||||||
plugin_git = request.form['plugin_git']
|
|
||||||
return jsonify(LogicPlugin.plugin_install_by_api(plugin_git, request.form.get('zip_url'), request.form.get('zip_filename')))
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'plugin_uninstall':
|
|
||||||
try:
|
|
||||||
plugin_name = request.form['plugin_name']
|
|
||||||
return jsonify(LogicPlugin.plugin_uninstall(plugin_name))
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
elif sub == 'recent_version':
|
|
||||||
ret = SystemLogic.get_recent_version()
|
|
||||||
ret = {'ret':ret, 'version':SystemLogic.recent_version}
|
|
||||||
return jsonify(ret)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('connect', namespace='/%s' % package_name)
|
|
||||||
def connect():
|
|
||||||
try:
|
|
||||||
InfoProcess.instance().connect(request.sid)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('disconnect', namespace='/%s' % package_name)
|
|
||||||
def disconnect():
|
|
||||||
try:
|
|
||||||
InfoProcess.instance().disconnect(request.sid)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('connect', namespace='/system_restart')
|
|
||||||
def connect_system_restart():
|
|
||||||
try:
|
|
||||||
socketio.emit("on_connect", 'restart', namespace='/system_restart', broadcast=True)
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@socketio.on('disconnect', namespace='/system_restart')
|
|
||||||
def disconnect_system_restart():
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#########################################################
|
|
||||||
# API
|
|
||||||
#########################################################
|
|
||||||
|
|
||||||
@blueprint.route('/api/<sub>', methods=['GET', 'POST'])
|
|
||||||
@check_api
|
|
||||||
def first_api(sub):
|
|
||||||
try:
|
|
||||||
if sub == 'plugin_add':
|
|
||||||
plugin_git = request.form['plugin_git']
|
|
||||||
from system.logic_plugin import LogicPlugin
|
|
||||||
ret = LogicPlugin.plugin_install_by_api(plugin_git, request.form.get('zip_url'), request.form.get('zip_filename'))
|
|
||||||
return jsonify(ret)
|
|
||||||
elif sub == 'restart':
|
|
||||||
logger.debug('web restart')
|
|
||||||
import system
|
|
||||||
system.restart()
|
|
||||||
return jsonify({'ret':'success'})
|
|
||||||
elif sub == 'gds':
|
|
||||||
url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds2.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}"
|
|
||||||
data = requests.get(url).json()['data']
|
|
||||||
logger.debug(data)
|
|
||||||
req_headers = dict(request.headers)
|
|
||||||
headers = {}
|
|
||||||
|
|
||||||
if 'Range' not in req_headers or req_headers['Range'].startswith('bytes=0-'):
|
|
||||||
headers['Range'] = "bytes=0-1048576"
|
|
||||||
else:
|
|
||||||
headers['Range'] = req_headers['Range']
|
|
||||||
headers['Authorization'] = f"Bearer {data['token']}"
|
|
||||||
headers['Connection'] = 'keep-alive'
|
|
||||||
|
|
||||||
r = requests.get(data['url'], headers=headers, stream=True)
|
|
||||||
rv = Response(r.iter_content(chunk_size=1048576), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True)
|
|
||||||
rv.headers.add('Content-Range', r.headers.get('Content-Range'))
|
|
||||||
return rv
|
|
||||||
elif sub == 'gds2':
|
|
||||||
url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}"
|
|
||||||
data = requests.get(url).json()['data']
|
|
||||||
logger.debug(data)
|
|
||||||
req_headers = dict(request.headers)
|
|
||||||
headers = {}
|
|
||||||
|
|
||||||
headers['Range'] = f"bytes={request.args.get('range')}"
|
|
||||||
headers['Authorization'] = f"Bearer {data['token']}"
|
|
||||||
headers['Connection'] = 'keep-alive'
|
|
||||||
logger.warning(headers)
|
|
||||||
"""
|
|
||||||
response = redirect(data['url'])
|
|
||||||
headers = dict(response.headers)
|
|
||||||
headers.update({'Authorization': f"Bearer {data['token']}"})
|
|
||||||
response.headers = headers
|
|
||||||
return response
|
|
||||||
|
|
||||||
response.headers.add('Authorization', headers['Authorization'])
|
|
||||||
#response.headers['Location'] = data['url']
|
|
||||||
return response
|
|
||||||
"""
|
|
||||||
|
|
||||||
r = requests.get(data['url'], headers=headers, stream=True)
|
|
||||||
logger.warning(r.history)
|
|
||||||
#rv = Response(r.iter_content(chunk_size=10485760), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True)
|
|
||||||
#rv.headers.add('Content-Range', r.headers.get('Content-Range'))
|
|
||||||
|
|
||||||
rv = Response(r.iter_content(chunk_size=1048576), r.status_code, content_type=r.headers['Content-Type'], direct_passthrough=True)
|
|
||||||
rv.headers.add('Content-Range', r.headers.get('Content-Range'))
|
|
||||||
|
|
||||||
logger.debug(rv.headers)
|
|
||||||
return rv
|
|
||||||
elif sub == 'gds_subtitle':
|
|
||||||
url = f"{app.config['DEFINE']['WEB_DIRECT_URL']}/sjva/gds2.php?type=file&id={request.args.get('id')}&user_id={ModelSetting.get('sjva_me_user_id')}&user_apikey={ModelSetting.get('auth_apikey')}"
|
|
||||||
data = requests.get(url).json()['data']
|
|
||||||
logger.debug(data)
|
|
||||||
req_headers = dict(request.headers)
|
|
||||||
headers = {}
|
|
||||||
headers['Range'] = f"bytes={request.args.get('range')}"
|
|
||||||
headers['Authorization'] = f"Bearer {data['token']}"
|
|
||||||
headers['Connection'] = 'keep-alive'
|
|
||||||
logger.warning(headers)
|
|
||||||
r = requests.get(data['url'], headers=headers, stream=True)
|
|
||||||
logger.warning(r.history)
|
|
||||||
if r.encoding != None:
|
|
||||||
if r.encoding == 'ISO-8859-1': # 한글자막 인코딩 예외처리
|
|
||||||
try:
|
|
||||||
text = r.content.decode('utf-8', "strict")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error('Exception:%s', e)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
text = r.content.decode('utf-8', "ignore")
|
|
||||||
else:
|
|
||||||
text = r.content.decode(r.encoding, "ignore")
|
|
||||||
else:
|
|
||||||
text = r.text
|
|
||||||
from framework.common.util import convert_srt_to_vtt as convSrt2Vtt
|
|
||||||
vtt = convSrt2Vtt(text)
|
|
||||||
r.headers['Content-Type'] = "text/vtt; charset=utf-8"
|
|
||||||
rv = Response(vtt, r.status_code, content_type=r.headers['Content-Type'])
|
|
||||||
rv.headers.add('Content-Disposition', 'inline; filename="subtitle.vtt"')
|
|
||||||
rv.headers.add('Content-Transfer-Encoding', 'binary')
|
|
||||||
logger.debug(rv.headers)
|
|
||||||
return rv
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/api/<sub>/<sub2>', methods=['GET', 'POST'])
|
|
||||||
@check_api
|
|
||||||
def second_api(sub, sub2):
|
|
||||||
try:
|
|
||||||
if sub == 'trans':
|
|
||||||
from .logic_trans import SystemLogicTrans
|
|
||||||
return SystemLogicTrans.process_api(sub2, request)
|
|
||||||
elif sub == 'site':
|
|
||||||
from .logic_site import SystemLogicSite
|
|
||||||
return SystemLogicSite.process_api(sub2, request)
|
|
||||||
|
|
||||||
except Exception as exception:
|
|
||||||
logger.error('Exception:%s', exception)
|
|
||||||
logger.error(traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/videojs", methods=['GET', 'POST'])
|
|
||||||
def videojs():
|
|
||||||
data = {}
|
|
||||||
data['play_title'] = request.form['play_title']
|
|
||||||
data['play_source_src'] = request.form['play_source_src']
|
|
||||||
data['play_source_type'] = request.form['play_source_type']
|
|
||||||
if 'play_subtitle_src' in request.form:
|
|
||||||
data['play_subtitle_src'] = request.form['play_subtitle_src']
|
|
||||||
#logger.warning(data)
|
|
||||||
return render_template('videojs.html', data=data)
|
|
||||||
@@ -14,7 +14,6 @@ __menu = {
|
|||||||
{'uri': 'export', 'name': 'export.sh 파일'},
|
{'uri': 'export', 'name': 'export.sh 파일'},
|
||||||
{'uri': 'celery', 'name': '비동기 작업(celery)'},
|
{'uri': 'celery', 'name': '비동기 작업(celery)'},
|
||||||
{'uri': 'notify', 'name': '알림'},
|
{'uri': 'notify', 'name': '알림'},
|
||||||
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,108 +16,45 @@
|
|||||||
|
|
||||||
{{ macros.setting_input_textarea('celery_start_command', 'celery 실행 명령', desc=['',
|
{{ macros.setting_input_textarea('celery_start_command', 'celery 실행 명령', desc=['',
|
||||||
|
|
||||||
'예: celery -A flaskfarm.main.celery worker --loglevel=info --pool=gevent --concurrency=2 --config_filepath="config.yaml파일경로" --running_type=native',
|
'예: celery -A flaskfarm.main.celery worker --workdir={F.config["path_working"]} --loglevel=info --pool=gevent --concurrency=2 --config_filepath={F.config["config_filepath"]} --running_type=native',
|
||||||
|
'',
|
||||||
'패키지로 실행시 : -A flaskfarm.main.celery',
|
'패키지로 실행시 : -A flaskfarm.main.celery',
|
||||||
'GIT 소스로 실행시 : -A main.celery (현재 작업폴더가 flaskfarm)',
|
'Git 소스로 실행시 : -A main.celery', '',
|
||||||
'Linux는 사용자에 따라 export C_FORCE_ROOT=true 필요'
|
'Linux는 사용자에 따라 export C_FORCE_ROOT=true 필요'
|
||||||
],
|
],
|
||||||
value=arg['celery_start_command'], row='5') }}
|
value=arg['celery_start_command'], row='5') }}
|
||||||
</form>
|
</form>
|
||||||
{{ macros.setting_buttons([['celery_excute_btn', '실행 테스트']]) }}
|
{{ macros.setting_buttons([['celery_excute_btn', '실행 테스트'], ['celery_excute_back_btn', '실행(Background) ']]) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
var running_type = "{{arg['running_type']}}";
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
console.log(running_type);
|
||||||
|
if (running_type == 'docker') {
|
||||||
|
$('#celery_start_by_web').bootstrapToggle('off');
|
||||||
|
$('#celery_start_by_web').prop('disabled', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$("body").on('click', '#celery_excute_btn', function(e){
|
$("body").on('click', '#celery_excute_btn', function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
globalSendCommand('celery_execute', $('#celery_start_command').val());
|
globalSendCommand('celery_execute', $('#celery_start_command').val());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("body").on('click', '#celery_excute_back_btn', function(e){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$("body").on('click', '#shutdown_btn', function(e){
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
shutdown_confirm();
|
globalSendCommand('celery_execute_back', $('#celery_start_command').val());
|
||||||
});
|
});
|
||||||
|
|
||||||
$("body").on('click', '#celery_test_btn', function(e){
|
$("body").on('click', '#celery_test_btn', function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$.ajax({
|
globalSendCommand('celery_test');
|
||||||
url: '/' + package_name + '/ajax/' + sub + '/celery_test',
|
|
||||||
type: "POST",
|
|
||||||
cache: false,
|
|
||||||
data: {},
|
|
||||||
dataType: "json",
|
|
||||||
success: function (ret) {
|
|
||||||
if (ret.ret == 'success') {
|
|
||||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
} else if (ret.ret == 'timeout' || ret.ret == 'no_celery') {
|
|
||||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//m_modal(ret)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
$("body").on('click', '#ps_btn', function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$.ajax({
|
|
||||||
url: '/' + package_name + '/ajax/' + sub + '/ps',
|
|
||||||
type: "POST",
|
|
||||||
cache: false,
|
|
||||||
data: {},
|
|
||||||
dataType: "json",
|
|
||||||
success: function (ret) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$("body").on('click', '#worker_start_btn', function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$.ajax({
|
|
||||||
url: '/' + package_name + '/ajax/' + sub + '/worker_start',
|
|
||||||
type: "POST",
|
|
||||||
cache: false,
|
|
||||||
data: {},
|
|
||||||
dataType: "json",
|
|
||||||
success: function (ret) {
|
|
||||||
if (ret.ret == 'success') {
|
|
||||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
|
||||||
type: 'success'
|
|
||||||
});
|
|
||||||
} else if (ret.ret == 'timeout' || ret.ret == 'no_celery' || ret.ret == 'not_registered') {
|
|
||||||
$.notify('<strong>'+ ret.data+'</strong>', {
|
|
||||||
type: 'warning'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//m_modal(ret)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -87,12 +87,15 @@ class ToolModalCommand(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def process_callback(cls, mode, text):
|
def process_callback(cls, mode, text):
|
||||||
|
#F.logger.warning(text)
|
||||||
if cls.__show_modal == False:
|
if cls.__show_modal == False:
|
||||||
return
|
return
|
||||||
if mode == 'end':
|
if mode == 'end':
|
||||||
F.socketio.emit("command_modal_add_text", "\n\n<<프로세스 종료>>", namespace='/framework', broadcast=True)
|
F.socketio.emit("command_modal_add_text", "\n\n<<프로세스 종료>>", namespace='/framework', broadcast=True)
|
||||||
F.socketio.emit("command_modal_input_disable", "", namespace='/framework', broadcast=True)
|
F.socketio.emit("command_modal_input_disable", "", namespace='/framework', broadcast=True)
|
||||||
|
elif mode == 'thread_end':
|
||||||
|
#F.socketio.emit("command_modal_add_text", "\n\n<<프로세스 종료>>", namespace='/framework', broadcast=True)
|
||||||
|
F.socketio.emit("command_modal_input_disable", "", namespace='/framework', broadcast=True)
|
||||||
else:
|
else:
|
||||||
F.socketio.emit("command_modal_add_text", text, namespace='/framework', broadcast=True)
|
F.socketio.emit("command_modal_add_text", text, namespace='/framework', broadcast=True)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user