This commit is contained in:
flaskfarm
2022-10-19 19:50:38 +09:00
parent c146e03cf1
commit 56419a8355
7 changed files with 126 additions and 84 deletions

View File

@@ -42,7 +42,9 @@ frameSocket.on('refresh', function(data){
}); });
$('#command_modal').on('hide.bs.modal', function (event) { $('#command_modal').on('hide.bs.modal', function (e) {
//e.preventDefault(); 있으면 동작 안함.
console.log("ff global command_modal hide.bs.modal CATCH")
$.ajax({ $.ajax({
url: `/global/ajax/command_modal_hide`, url: `/global/ajax/command_modal_hide`,
type: 'POST', type: 'POST',

View File

@@ -1 +1 @@
VERSION="4.0.27" VERSION="4.0.28"

View File

@@ -87,7 +87,7 @@ class SupportSubprocess(object):
logger.error('command : %s', command) logger.error('command : %s', command)
instance_list = [] __instance_list = []
def __init__(self, command, print_log=False, shell=False, env=None, timeout=None, uid=None, gid=None, stdout_callback=None, call_id=None): def __init__(self, command, print_log=False, shell=False, env=None, timeout=None, uid=None, gid=None, stdout_callback=None, call_id=None):
@@ -107,7 +107,7 @@ class SupportSubprocess(object):
def start(self, join=True): def start(self, join=True):
try: try:
self.thread = threading.Thread(target=self.execute_thread_function, args=()) self.thread = threading.Thread(target=self.__execute_thread_function, args=())
self.thread.setDaemon(True) self.thread.setDaemon(True)
self.thread.start() self.thread.start()
if join: if join:
@@ -117,7 +117,7 @@ class SupportSubprocess(object):
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
def execute_thread_function(self): def __execute_thread_function(self):
try: try:
if platform.system() == 'Windows': if platform.system() == 'Windows':
tmp = [] tmp = []
@@ -137,15 +137,16 @@ class SupportSubprocess(object):
self.process = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=self.shell, env=self.env, encoding='utf8', bufsize=0) self.process = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=self.shell, env=self.env, encoding='utf8', bufsize=0)
else: else:
self.process = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=self.shell, env=self.env, preexec_fn=demote(self.uid, self.gid), encoding='utf8', bufsize=0) self.process = subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=self.shell, env=self.env, preexec_fn=demote(self.uid, self.gid), encoding='utf8', bufsize=0)
SupportSubprocess.instance_list.append(self) SupportSubprocess.__instance_list.append(self)
self.start_communicate() self.__start_communicate()
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} END") logger.info(f"{self.command} 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())
logger.warning(self.command)
if self.stdout_callback != None: if self.stdout_callback != None:
self.stdout_callback('error', str(e)) self.stdout_callback('error', str(e))
self.stdout_callback('error', str(traceback.format_exc())) self.stdout_callback('error', str(traceback.format_exc()))
@@ -154,7 +155,7 @@ class SupportSubprocess(object):
self.stdout_callback('thread_end', None) self.stdout_callback('thread_end', None)
def start_communicate(self): def __start_communicate(self):
self.stdout_queue = queue.Queue() self.stdout_queue = queue.Queue()
sout = io.open(self.process.stdout.fileno(), 'rb', closefd=False) sout = io.open(self.process.stdout.fileno(), 'rb', closefd=False)
@@ -199,7 +200,7 @@ class SupportSubprocess(object):
Pump(sout) Pump(sout)
def start_send_callback(self): def __start_send_callback(self):
def func(): def func():
while self.stdout_queue: while self.stdout_queue:
line = self.stdout_queue.get() line = self.stdout_queue.get()
@@ -245,29 +246,29 @@ class SupportSubprocess(object):
@classmethod @classmethod
def all_process_close(cls): def all_process_close(cls):
for instance in cls.instance_list: for instance in cls.__instance_list:
instance.process_close() instance.process_close()
cls.instance_list = [] cls.__instance_list = []
@classmethod @classmethod
def remove_instance(cls, remove_instance): def remove_instance(cls, remove_instance):
new = [] new = []
for instance in cls.instance_list: for instance in cls.__instance_list:
if remove_instance.timestamp == instance.timestamp: if remove_instance.timestamp == instance.timestamp:
continue continue
new.append(instance) new.append(instance)
cls.instance_list = new cls.__instance_list = new
@classmethod @classmethod
def print(cls): def print(cls):
for instance in cls.instance_list: for instance in cls.__instance_list:
logger.info(instance.command) logger.info(instance.command)
@classmethod @classmethod
def get_instance_by_call_id(cls, call_id): def get_instance_by_call_id(cls, call_id):
for instance in cls.instance_list: for instance in cls.__instance_list:
if instance.call_id == call_id: if instance.call_id == call_id:
return instance return instance

View File

@@ -1,4 +1,5 @@
from support import SupportFile from support import SupportSubprocess
from tool import ToolModalCommand
from .page_command import PageCommand from .page_command import PageCommand
from .setup import * from .setup import *
@@ -36,4 +37,27 @@ class PageCrypt(PluginPageBase):
class PagePython(PluginPageBase): class PagePython(PluginPageBase):
def __init__(self, P, parent): def __init__(self, P, parent):
super(PagePython, self).__init__(P, parent, name='python') super(PagePython, self).__init__(P, parent, name='python')
self.db_default = {
f'{self.parent.name}_{self.name}_name': '',
}
def process_command(self, command, arg1, arg2, arg3, req):
ret = {'ret':'success'}
if command == 'get_freeze':
command = ['pip', 'freeze']
result = SupportSubprocess.execute_command_return(command)
if result['status'] == 'finish':
ret['data'] = []
for tmp in result['log'].split('\n'):
ret['data'].append(tmp.split('=='))
else:
ret['ret'] = 'danger'
ret['msg'] = "실패"
elif command == 'upgrade':
P.ModelSetting.set(f'{self.parent.name}_{self.name}_name', arg1)
cmd = ['pip', 'install', '--upgrade', arg1]
ToolModalCommand.start("pip 설치", [cmd])
elif command == 'remove':
cmd = ['pip', 'uninstall', '-y', arg1]
ToolModalCommand.start("pip 삭제", [cmd])
return jsonify(ret)

View File

@@ -112,7 +112,7 @@ class PageCommand(PluginPageBase):
import io import io
from contextlib import redirect_stdout from contextlib import redirect_stdout
load_log_list = io.StringIO() load_log_list = io.StringIO()
with redirect_stdout(self.load_log_list): with redirect_stdout(load_log_list):
start_communicate_load(load_log_list) start_communicate_load(load_log_list)
if job_id is not None: if job_id is not None:
command_logger = get_logger(f'command_{job_id}') command_logger = get_logger(f'command_{job_id}')

View File

@@ -22,7 +22,7 @@ __menu = {
'list': [ 'list': [
#{'uri': 'setting', 'name': '설정'}, #{'uri': 'setting', 'name': '설정'},
{'uri': 'list', 'name': '로딩 플러그인'}, {'uri': 'list', 'name': '로딩 플러그인'},
{'uri': 'all', 'name': '플러그인 목록'}, #{'uri': 'all', 'name': '플러그인 목록'},
], ],
}, },
{ {
@@ -32,8 +32,8 @@ __menu = {
{'uri': 'command', 'name': 'Command'}, {'uri': 'command', 'name': 'Command'},
{'uri': 'upload', 'name': '업로드'}, {'uri': 'upload', 'name': '업로드'},
{'uri': 'python', 'name': 'Python'}, {'uri': 'python', 'name': 'Python'},
{'uri': 'db', 'name': 'DB'}, #{'uri': 'db', 'name': 'DB'},
{'uri': 'crypt', 'name': '암호화'}, #{'uri': 'crypt', 'name': '암호화'},
] ]
}, },
{ {

View File

@@ -1,76 +1,91 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block content %} {% block content %}
<div>
{{ macros.m_button_group([['globalSettingSaveBtn', '설정 저장']])}} {{ macros.m_button_group([['all_upgrade_btn', '모두 업그레이드'], ['refresh_btn', '새로고침']])}}
{{ macros.m_row_start('5') }} {{ macros.m_row_start('5') }}
{{ macros.m_row_end() }} {{ macros.m_row_end() }}
<nav>
{{ macros.m_tab_head_start() }}
{{ macros.m_tab_head2('normal', '일반', true) }}
{{ macros.m_tab_head_end() }} {{ macros.setting_input_text_and_buttons('pip', 'pip 패키지 설치', [['install_btn', '설치 & 업그레이드']], value=arg['tool_python_name'], desc=None) }}
</nav>
<form id='setting' name='setting'>
<div class="tab-content" id="nav-tabContent">
{{ macros.m_tab_content_start('normal', true) }}
{{ macros.setting_checkbox('tool_crypt_use_user_key', '암호화 키 직접 입력', value=arg['tool_crypt_use_user_key'], desc=['On : 본인 키 사용', '주의) 변경 후 일반설정-인증-로그인 암호를 새로 저장해야 합니다.', 'Off : 앱 고정 키 사용']) }}
<div id="tool_crypt_use_user_key_div" class="collapse">
{{ macros.setting_input_text('tool_crypt_user_key', '암호화 키', value=arg['tool_crypt_user_key'], desc=['16진수(숫자, a~e)로 이루어진 32글자. 미만시 앞을 0으로 채움. 초과시 뒤에 무시']) }}
</div>
{{ macros.setting_input_text_and_buttons('tool_crypt_encrypt_word', '암호화', [['tool_crypt_encrypt_word_btn', '암호화']], value=arg['tool_crypt_encrypt_word']) }}
{{ macros.setting_input_text('tool_crypt_encrypt_word_result', '', disabled=True) }}
{{ macros.setting_input_text_and_buttons('tool_crypt_decrypt_word', '평문화', [['tool_crypt_decrypt_word_btn', '평문화']], value=arg['tool_crypt_decrypt_word']) }} <div id="list_div"></div>
{{ macros.setting_input_text('tool_crypt_decrypt_word_result', '', disabled=True) }}
{{ macros.m_tab_content_end() }}
</div><!--tab-content-->
</form>
</div> <!--전체-->
<script type="text/javascript"> <script type="text/javascript">
var package_name = "{{arg['package_name'] }}";
var sub = "{{arg['sub'] }}";
$(document).ready(function(){ $(document).ready(function(){
use_collapse("tool_crypt_use_user_key"); refresh();
}); });
$("body").on('change', '#tool_crypt_use_user_key', function(e){ function refresh() {
use_collapse('tool_crypt_use_user_key'); globalSendCommandPage('get_freeze', null, null, null, null, function(ret){
make_list(ret.data);
}); });
$("body").on('click', '#tool_crypt_encrypt_word_btn', function(e) {
e.preventDefault();
word = document.getElementById("tool_crypt_encrypt_word").value
crypt_test('encrypt', word);
});
$("body").on('click', '#tool_crypt_decrypt_word_btn', function(e) {
e.preventDefault();
word = document.getElementById("tool_crypt_decrypt_word").value
crypt_test('decrypt', word);
});
function crypt_test(mode, word) {
$.ajax({
url: '/' + package_name + '/ajax/'+sub+'/crypt_test',
type: "POST",
cache: false,
data: {mode:mode, word:word},
dataType: "json",
success: function (ret) {
if (ret.ret == 'success') {
if (mode == "encrypt")
document.getElementById("tool_crypt_encrypt_word_result").value = ret.data;
else
document.getElementById("tool_crypt_decrypt_word_result").value = ret.data;
} else {
notify(ret.log, 'warning');
} }
$("body").on('click', '#install_btn', function(e){
e.preventDefault();
name = $('#pip').val();
if (name == '') {
notify("package 명을 입력하세요.", 'danger');
return
} }
upgrade(name);
}); });
$("body").on('click', '#upgrade_btn', function(e){
e.preventDefault();
upgrade($(this).data('name'));
});
function upgrade(name) {
globalSendCommandPage('upgrade', name);
}
$("body").on('click', '#remove_btn', function(e){
e.preventDefault();
remove_confirm($(this).data('name'));
});
function remove(name) {
globalSendCommandPage('remove', name);
}
function remove_confirm(name) {
$("#confirm_title").html("삭제 확인");
$("#confirm_body").html(name + "패키지를<br>삭제 하시겠습니까?");
$('#confirm_button').attr('onclick', "remove('"+name+"');");
$("#confirm_modal").modal();
}
$("body").on('click', '#refresh_btn', function(e){
e.preventDefault();
refresh();
});
function make_list(data) {
current_data = data;
str = '';
str = '<table id="result_table" class="table table-sm" ><thead class="thead-dark"><tr> \
<th style="width:10%; text-align:center;">ID</th> \
<th style="width:30%; text-align:center;">Name</th> \
<th style="width:30%; text-align:center;">Version</th> \
<th style="width:30%; text-align:center;">Action</th> \
</tr></thead><tbody id="list">';
if (data.length == 0) str += '<tr><td colspan="6"><h4>Empty</h4></td></tr>';
for(i in data) {
//console.log(data[i]);
str += '<tr class="chover" style="cursor: pointer;">';
str += '<td scope="col" style="width:10%; text-align:center;">'+ (parseInt(i)+1) + '</td>';
str += '<td scope="col" style="width:30%; text-align:center;">'+ data[i][0] + '</td>';
str += '<td scope="col" style="width:30%; text-align:center;">'+ data[i][1] + '</td>';
tmp = j_button('upgrade_btn', 'Upgrade', {'name':data[i][0]}, 'primary', true, false);
tmp += j_button('remove_btn', '삭제', {'name':data[i][0]}, 'danger', true, false);
tmp = j_button_group(tmp);
str += '<td scope="col" style="width:30%; text-align:center;">'+ tmp + '</td>';
str += '</tr>'
}
str += '</table>';
document.getElementById("list_div").innerHTML = str;
} }
</script> </script>
{% endblock %} {% endblock %}