diff --git a/app2.py b/app2.py index 226e3271086ff3197ffe3a9bb54912a099ccc384..3299b8653d48f48631cb2c7d7d4bf1d3cde2a156 100644 --- a/app2.py +++ b/app2.py @@ -15,6 +15,7 @@ import platform import sys import time import traceback +from multiprocessing import shared_memory sys.path.append(os.path.dirname(__file__)) sys.path.append(os.path.join(os.path.dirname(__file__), "resources")) @@ -342,6 +343,21 @@ class MainWindow(BaseMainWindow): self.main_first_form = base.FirstForm(parent=self) self.main_first_form.show() + def login_form_display(self): + """ + 显示"登录"窗口 + Displays the "Quick Action" window + """ + shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token + buff = shared_memo.buf + token = bytes(buff[:199]).decode().replace("\x00", "") + if token != "": + self.main_login_form = base.LoginedForm(parent=self) + self.main_login_form.exec_() + else: + self.main_login_form = base.LoginForm(parent=self) + self.main_login_form.show() + def main_appstore_dispaly(self): """ 显示"应用商店"窗口 diff --git a/features/main_window/base.py b/features/main_window/base.py index 57d2f341542631290a96bc4ec7184d0585bafd07..b3555ecabc3717f56f31c84b176bb9baaafea449 100644 --- a/features/main_window/base.py +++ b/features/main_window/base.py @@ -3,16 +3,19 @@ import sys import time import subprocess import webbrowser +import base64 +import json from typing import Tuple, List import qdarkstyle from PySide2.QtCore import QPoint, QRectF -from PySide2.QtGui import QMouseEvent, QPainter, QLinearGradient +from PySide2.QtGui import QMouseEvent, QPainter, QLinearGradient, QCursor from PySide2.QtGui import QCloseEvent from PySide2.QtCore import Signal, Qt, QUrl, QPropertyAnimation from PySide2.QtWidgets import QApplication, QListWidgetItem, QWizard, QHeaderView, QMessageBox from PySide2.QtWebEngineWidgets import * from PySide2.QtWidgets import QWidget, QDesktopWidget, QFileDialog, QApplication, QDialog + from pmgwidgets import PMGPanel from features.ui.ui_option import Ui_Form as Option_Ui_Form @@ -20,11 +23,14 @@ from features.ui.ui_appstore import Ui_Form as appStore_Ui_Form from features.ui.ui_aboutme import Ui_Form as About_Ui_Form from features.ui.ui_project_wizard import Ui_Wizard as Project_Ui_Form from features.ui.ui_first_form import Ui_Form as first_Ui_Form +from features.ui.ui_login import Ui_Form as login_Ui_Form +from features.ui.ui_logined import Ui_Form as logined_Ui_Form import utils -from utils import get_main_window +from utils import get_main_window, http_client from features.io.settings import Settings from features.extensions.extensionlib.extension_lib import extension_lib +from multiprocessing import shared_memory class OptionForm(QDialog, Option_Ui_Form): @@ -593,9 +599,109 @@ class FirstForm(QDialog, first_Ui_Form): self.close() +class LoginForm(QDialog, login_Ui_Form): + """ + 登录窗口 + """ + def __init__(self, parent=None): + super(LoginForm, self).__init__(parent) + self.setupUi(self) + self.init() + + def init(self): + self.loginButton.clicked.connect(self.login) + self.forgetPwdButton.clicked.connect(self.forgetPwd) + self.usernameLineEdit.textChanged.connect(self.usernameErrorChange) + + def login(self): + username = self.usernameLineEdit.text() + password = self.passwordLineEdit.text() + flag = False + if username == "": + self.usernameError.setText("用户名不能为空") + flag = True + if password == "": + self.passwordError.setText("密码不能为空") + flag = True + if not flag: + data = { + "usr": username, + "password": base64.b64encode(password.encode()) + } + url = http_client.API + http_client.LOGIN_URL + resp = http_client.client(url, "post", data) + resp_info = json.loads(resp.text) + if resp.status_code == 200: + if resp_info["code"] == 10000: + token = resp_info["token"] + token_len = len(token) + username_len = len(username.encode("utf-8")) + """ + 将登录后django返回的token令牌保存在共享内存token中,共享内存token在启动pyminer主程序时附带启动了本地flask服务然后 + 创建共享内存token,详情见pmlocalserver/server.py + """ + shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token + buff = shared_memo.buf + # token长度随着用户名长度的增加而增加,用户名最长为21个汉字加一个字符 + # buff[:3]存放token长度,目前最长的用户名21汉字加一字符生成的token长度为343 + # buff[3:5]存放用户名长度,用户名字段最长为64字节,最多21个汉字(字符集utf8) + # buff[5:token_len+5]位存放token + # buff[token_len+5:实际用户名长度(用utf8转换为bytes后的长度)]存放用户名 + buff[:3] = str(token_len).encode("utf-8") # 存放token长度 + buff[3:5] = str(username_len).encode("utf-8") # 将用户名长度存放共享内存 + buff[5:token_len+5] = token.encode("utf-8") # 将token存放进共享内存中,工作空间重启后也能获取到 + buff[token_len+5:token_len+5+username_len] = username.encode("utf-8") # 存放用户名 + self.usernameError.setText("登录成功") + time.sleep(0.5) + self.close() + else: + self.usernameError.setText(resp_info["msg"][0]) + + def forgetPwd(self): + utils.open_url("http://pyminer.com/forgetpassword") + + def usernameErrorChange(self): + self.usernameError.setText("") + self.passwordError.setText("") + username = self.usernameLineEdit.text() + if len(username.encode("utf-8")) > 64: + self.usernameError.setText("最多只能输入21个汉字") + self.loginButton.setEnabled(False) + self.loginButton.setCursor(QCursor(Qt.ForbiddenCursor)) + else: + self.usernameError.setText("") + self.loginButton.setEnabled(True) + self.loginButton.setCursor(QCursor(Qt.PointingHandCursor)) + + +class LoginedForm(QDialog, logined_Ui_Form): + + def __init__(self, parent=None): + super(LoginedForm, self).__init__(parent) + self.setupUi(self) + self.init() + shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token + buff = shared_memo.buf + token_len = int(bytes(buff[:3]).decode()) + username_len = int(bytes(buff[3:5]).decode()) + username = bytes(buff[token_len+5:token_len+5+username_len]).decode("utf-8") + self.usernameLabel.setText(username) + + def init(self): + self.loginOutButton.clicked.connect(self.logout) + + def logout(self): + shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token + buff = shared_memo.buf + for i in range(0, len(buff)): + buff[i:i+1] = "\x00".encode() + time.sleep(0.5) + self.close() + + if __name__ == '__main__': app = QApplication(sys.argv) # form = FirstForm() - form = ProjectWizardForm() + form = LoginedForm() form.show() sys.exit(app.exec_()) diff --git a/features/ui/ui_login.py b/features/ui/ui_login.py new file mode 100644 index 0000000000000000000000000000000000000000..843dd6abdd09f4667a8a1c1dcc386d045dfc5809 --- /dev/null +++ b/features/ui/ui_login.py @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'ui_login.ui' +## +## Created by: Qt User Interface Compiler version 5.15.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_Form(object): + def setupUi(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + Form.setWindowModality(Qt.ApplicationModal) + Form.resize(407, 361) + sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth()) + Form.setSizePolicy(sizePolicy) + Form.setMinimumSize(QSize(407, 361)) + Form.setMaximumSize(QSize(407, 361)) + Form.setStyleSheet(u"") + self.verticalLayout = QVBoxLayout(Form) + self.verticalLayout.setObjectName(u"verticalLayout") + self.widget = QWidget(Form) + self.widget.setObjectName(u"widget") + self.widget.setMaximumSize(QSize(407, 361)) + self.widget.setSizeIncrement(QSize(407, 361)) + self.widget.setBaseSize(QSize(407, 361)) + self.widget.setStyleSheet(u"QPushButton{\n" +" padding: 8px 20px;\n" +" font-size: 13px;\n" +" line-height: 1.65;\n" +" border-radius: 20px;\n" +" display: inline-block;\n" +" margin-bottom: 0;\n" +" font-weight: 600;\n" +" text-align: center;\n" +" vertical-align: middle;\n" +" touch-action: manipulation;\n" +" cursor: pointer;\n" +" background-image: none;\n" +" border: 1px solid transparent;\n" +" white-space: nowrap;\n" +" font-family: inherit;\n" +" text-transform: none;\n" +" background-color: #00a6fd;\n" +" border-color: #00a6fd;\n" +" color: #fff;\n" +" \n" +"}") + self.layoutWidget = QWidget(self.widget) + self.layoutWidget.setObjectName(u"layoutWidget") + self.layoutWidget.setGeometry(QRect(0, 0, 452, 331)) + self.verticalLayout_2 = QVBoxLayout(self.layoutWidget) + self.verticalLayout_2.setObjectName(u"verticalLayout_2") + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_6 = QVBoxLayout() + self.verticalLayout_6.setObjectName(u"verticalLayout_6") + self.usernameError = QLabel(self.layoutWidget) + self.usernameError.setObjectName(u"usernameError") + self.usernameError.setEnabled(True) + self.usernameError.setMinimumSize(QSize(380, 32)) + self.usernameError.setMaximumSize(QSize(380, 32)) + font = QFont() + font.setFamily(u"18thCentury") + font.setPointSize(10) + font.setBold(False) + font.setWeight(50) + self.usernameError.setFont(font) + self.usernameError.setAutoFillBackground(False) + self.usernameError.setStyleSheet(u"*{\n" +"color:red;\n" +"}") + self.usernameError.setAlignment(Qt.AlignCenter) + + self.verticalLayout_6.addWidget(self.usernameError) + + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.label = QLabel(self.layoutWidget) + self.label.setObjectName(u"label") + self.label.setMinimumSize(QSize(70, 0)) + self.label.setMaximumSize(QSize(70, 16777215)) + self.label.setBaseSize(QSize(70, 0)) + self.label.setAlignment(Qt.AlignCenter) + + self.horizontalLayout_2.addWidget(self.label) + + self.usernameLineEdit = QLineEdit(self.layoutWidget) + self.usernameLineEdit.setObjectName(u"usernameLineEdit") + self.usernameLineEdit.setMinimumSize(QSize(300, 32)) + self.usernameLineEdit.setMaximumSize(QSize(300, 32)) + self.usernameLineEdit.setStyleSheet(u"QLineEdit{\n" +"background-color: white;\n" +"selection-color: white;\n" +"selection-background-color: blue;\n" +"}") + self.usernameLineEdit.setMaxLength(64) + + self.horizontalLayout_2.addWidget(self.usernameLineEdit) + + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_2.addItem(self.horizontalSpacer) + + + self.verticalLayout_6.addLayout(self.horizontalLayout_2) + + self.passwordError = QLabel(self.layoutWidget) + self.passwordError.setObjectName(u"passwordError") + self.passwordError.setMinimumSize(QSize(380, 32)) + self.passwordError.setMaximumSize(QSize(380, 32)) + self.passwordError.setFont(font) + self.passwordError.setStyleSheet(u"*{\n" +"color:red;\n" +"}") + self.passwordError.setAlignment(Qt.AlignCenter) + + self.verticalLayout_6.addWidget(self.passwordError) + + self.horizontalLayout_3 = QHBoxLayout() + self.horizontalLayout_3.setObjectName(u"horizontalLayout_3") + self.label_2 = QLabel(self.layoutWidget) + self.label_2.setObjectName(u"label_2") + self.label_2.setMinimumSize(QSize(70, 0)) + self.label_2.setMaximumSize(QSize(70, 16777215)) + self.label_2.setBaseSize(QSize(70, 0)) + self.label_2.setAlignment(Qt.AlignCenter) + + self.horizontalLayout_3.addWidget(self.label_2) + + self.passwordLineEdit = QLineEdit(self.layoutWidget) + self.passwordLineEdit.setObjectName(u"passwordLineEdit") + self.passwordLineEdit.setMinimumSize(QSize(300, 0)) + self.passwordLineEdit.setMaximumSize(QSize(300, 32)) + self.passwordLineEdit.setBaseSize(QSize(300, 32)) + self.passwordLineEdit.setStyleSheet(u"QLineEdit{\n" +"background-color: white;\n" +"selection-color: white;\n" +"selection-background-color: blue;\n" +"}") + self.passwordLineEdit.setEchoMode(QLineEdit.Password) + + self.horizontalLayout_3.addWidget(self.passwordLineEdit) + + self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_3.addItem(self.horizontalSpacer_2) + + + self.verticalLayout_6.addLayout(self.horizontalLayout_3) + + + self.verticalLayout_2.addLayout(self.verticalLayout_6) + + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.loginButton = QPushButton(self.layoutWidget) + self.loginButton.setObjectName(u"loginButton") + self.loginButton.setMaximumSize(QSize(150, 16777215)) + self.loginButton.setCursor(QCursor(Qt.PointingHandCursor)) + self.loginButton.setStyleSheet(u"") + + self.horizontalLayout.addWidget(self.loginButton) + + self.forgetPwdButton = QPushButton(self.layoutWidget) + self.forgetPwdButton.setObjectName(u"forgetPwdButton") + self.forgetPwdButton.setMaximumSize(QSize(150, 16777215)) + self.forgetPwdButton.setCursor(QCursor(Qt.PointingHandCursor)) + + self.horizontalLayout.addWidget(self.forgetPwdButton) + + + self.verticalLayout_2.addLayout(self.horizontalLayout) + + + self.verticalLayout.addWidget(self.widget) + + + self.retranslateUi(Form) + + QMetaObject.connectSlotsByName(Form) + # setupUi + + def retranslateUi(self, Form): + Form.setWindowTitle(QCoreApplication.translate("Form", u"\u7528\u6237\u767b\u5f55", None)) + self.usernameError.setText("") + self.label.setText(QCoreApplication.translate("Form", u"\u7528 \u6237 \u540d", None)) + self.usernameLineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"\u8bf7\u8f93\u5165\u7528\u6237\u540d", None)) + self.passwordError.setText("") + self.label_2.setText(QCoreApplication.translate("Form", u"\u5bc6 \u7801", None)) + self.passwordLineEdit.setPlaceholderText(QCoreApplication.translate("Form", u"\u8bf7\u8f93\u5165\u5bc6\u7801", None)) + self.loginButton.setText(QCoreApplication.translate("Form", u"\u767b\u5f55", None)) + self.forgetPwdButton.setText(QCoreApplication.translate("Form", u"\u5fd8\u8bb0\u5bc6\u7801\uff1f", None)) + # retranslateUi + diff --git a/features/ui/ui_login.ui b/features/ui/ui_login.ui new file mode 100644 index 0000000000000000000000000000000000000000..290a39b5b485e97a2993a33c6ef100e07b4d21fa --- /dev/null +++ b/features/ui/ui_login.ui @@ -0,0 +1,376 @@ + + + Form + + + Qt::ApplicationModal + + + + 0 + 0 + 407 + 361 + + + + + 0 + 0 + + + + + 407 + 361 + + + + + 407 + 361 + + + + 用户登录 + + + + + + + + + + 407 + 361 + + + + + 407 + 361 + + + + + 407 + 361 + + + + QPushButton{ + padding: 8px 20px; + font-size: 13px; + line-height: 1.65; + border-radius: 20px; + display: inline-block; + margin-bottom: 0; + font-weight: 600; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + font-family: inherit; + text-transform: none; + background-color: #00a6fd; + border-color: #00a6fd; + color: #fff; + +} + + + + + 0 + 0 + 452 + 331 + + + + + + + + + true + + + + 380 + 32 + + + + + 380 + 32 + + + + + 18thCentury + 10 + 50 + false + + + + false + + + *{ +color:red; +} + + + + + + Qt::AlignCenter + + + + + + + + + + 70 + 0 + + + + + 70 + 16777215 + + + + + 70 + 0 + + + + 用 户 名 + + + Qt::AlignCenter + + + + + + + + 300 + 32 + + + + + 300 + 32 + + + + QLineEdit{ +background-color: white; +selection-color: white; +selection-background-color: blue; +} + + + 64 + + + 请输入用户名 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 380 + 32 + + + + + 380 + 32 + + + + + 18thCentury + 10 + 50 + false + + + + *{ +color:red; +} + + + + + + Qt::AlignCenter + + + + + + + + + + 70 + 0 + + + + + 70 + 16777215 + + + + + 70 + 0 + + + + 密 码 + + + Qt::AlignCenter + + + + + + + + 300 + 0 + + + + + 300 + 32 + + + + + 300 + 32 + + + + QLineEdit{ +background-color: white; +selection-color: white; +selection-background-color: blue; +} + + + QLineEdit::Password + + + 请输入密码 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 150 + 16777215 + + + + PointingHandCursor + + + + + + 登录 + + + + + + + + 150 + 16777215 + + + + PointingHandCursor + + + 忘记密码? + + + + + + + + + + + + + + diff --git a/features/ui/ui_logined.py b/features/ui/ui_logined.py new file mode 100644 index 0000000000000000000000000000000000000000..8d469fb4a4838c23747f684cb92c94b4b328be25 --- /dev/null +++ b/features/ui/ui_logined.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'ui_logined.ui' +## +## Created by: Qt User Interface Compiler version 5.15.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide2.QtCore import * +from PySide2.QtGui import * +from PySide2.QtWidgets import * + + +class Ui_Form(object): + def setupUi(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + Form.resize(407, 361) + Form.setMinimumSize(QSize(407, 361)) + Form.setMaximumSize(QSize(407, 361)) + Form.setBaseSize(QSize(407, 361)) + Form.setStyleSheet(u"QPushButton{\n" +" padding: 8px 20px;\n" +" font-size: 13px;\n" +" line-height: 1.65;\n" +" border-radius: 20px;\n" +" display: inline-block;\n" +" margin-bottom: 0;\n" +" font-weight: 600;\n" +" text-align: center;\n" +" vertical-align: middle;\n" +" touch-action: manipulation;\n" +" cursor: pointer;\n" +" background-image: none;\n" +" border: 1px solid transparent;\n" +" white-space: nowrap;\n" +" font-family: inherit;\n" +" text-transform: none;\n" +" background-color: #00a6fd;\n" +" border-color: #00a6fd;\n" +" color: #fff;\n" +" \n" +"}") + self.layoutWidget = QWidget(Form) + self.layoutWidget.setObjectName(u"layoutWidget") + self.layoutWidget.setGeometry(QRect(10, 0, 391, 341)) + self.verticalLayout = QVBoxLayout(self.layoutWidget) + self.verticalLayout.setObjectName(u"verticalLayout") + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout = QHBoxLayout() + self.horizontalLayout.setObjectName(u"horizontalLayout") + self.label = QLabel(self.layoutWidget) + self.label.setObjectName(u"label") + self.label.setFrameShape(QFrame.NoFrame) + self.label.setFrameShadow(QFrame.Plain) + self.label.setTextFormat(Qt.AutoText) + self.label.setAlignment(Qt.AlignCenter) + self.label.setMargin(0) + + self.horizontalLayout.addWidget(self.label) + + self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.horizontalLayout.addItem(self.verticalSpacer_2) + + self.usernameLabel = QLabel(self.layoutWidget) + self.usernameLabel.setObjectName(u"usernameLabel") + self.usernameLabel.setCursor(QCursor(Qt.IBeamCursor)) + self.usernameLabel.setLayoutDirection(Qt.LeftToRight) + self.usernameLabel.setWordWrap(True) + self.usernameLabel.setMargin(0) + self.usernameLabel.setTextInteractionFlags(Qt.TextSelectableByMouse) + + self.horizontalLayout.addWidget(self.usernameLabel) + + + self.verticalLayout.addLayout(self.horizontalLayout) + + self.horizontalLayout_2 = QHBoxLayout() + self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.horizontalLayout_2.addItem(self.horizontalSpacer) + + self.loginOutButton = QPushButton(self.layoutWidget) + self.loginOutButton.setObjectName(u"loginOutButton") + self.loginOutButton.setCursor(QCursor(Qt.PointingHandCursor)) + + self.horizontalLayout_2.addWidget(self.loginOutButton) + + self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + + self.horizontalLayout_2.addItem(self.verticalSpacer) + + + self.verticalLayout.addLayout(self.horizontalLayout_2) + + + self.retranslateUi(Form) + + QMetaObject.connectSlotsByName(Form) + # setupUi + + def retranslateUi(self, Form): + Form.setWindowTitle(QCoreApplication.translate("Form", u"\u7528\u6237\u4fe1\u606f", None)) + self.label.setText(QCoreApplication.translate("Form", u"\u7528 \u6237 \u540d", None)) + self.usernameLabel.setText("") + self.loginOutButton.setText(QCoreApplication.translate("Form", u"\u6ce8 \u9500", None)) + # retranslateUi + diff --git a/features/ui/ui_logined.ui b/features/ui/ui_logined.ui new file mode 100644 index 0000000000000000000000000000000000000000..45a4af71e0e0b09d7f4db3eab6ad02247804f348 --- /dev/null +++ b/features/ui/ui_logined.ui @@ -0,0 +1,174 @@ + + + Form + + + + 0 + 0 + 407 + 361 + + + + + 407 + 361 + + + + + 407 + 361 + + + + + 407 + 361 + + + + 用户信息 + + + QPushButton{ + padding: 8px 20px; + font-size: 13px; + line-height: 1.65; + border-radius: 20px; + display: inline-block; + margin-bottom: 0; + font-weight: 600; + text-align: center; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + background-image: none; + border: 1px solid transparent; + white-space: nowrap; + font-family: inherit; + text-transform: none; + background-color: #00a6fd; + border-color: #00a6fd; + color: #fff; + +} + + + + + 10 + 0 + 391 + 341 + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 用 户 名 + + + Qt::AutoText + + + Qt::AlignCenter + + + 0 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + IBeamCursor + + + Qt::LeftToRight + + + + + + true + + + 0 + + + Qt::TextSelectableByMouse + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + PointingHandCursor + + + 注 销 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + diff --git a/pmgui.py b/pmgui.py index a6b0c97dd0dd0d34ca202eca276c4c0ad64b5e87..52f2bddc5d7f9a1db8c15a2678236d3e3730a57f 100644 --- a/pmgui.py +++ b/pmgui.py @@ -24,6 +24,7 @@ from features.util.update import perform_update, UpdateTipClient from features.feedback import FeedbackClient from features.ui.widgets.controlpanel import PMPageExt from features.ui.pmwidgets import BaseMainWindow +from multiprocessing import shared_memory import utils import logging @@ -104,6 +105,13 @@ class PMToolBarHome(PMGToolBar): self.add_tool_button('button_settings', self.tr('Settings'), self.tr('Modify program Settings items'), create_icon( ':/color/theme/default/icons/setting.svg')) + self.addSeparator() + self.add_tool_button( + 'button_login', + self.tr('用户管理'), + self.tr('用户管理'), + create_icon(':/color/theme/default/icons/mActionUserRoleManager.svg') + ) def process_visibility_actions(self, e: ActionWithMessage): """ @@ -132,6 +140,7 @@ class PMToolBarHome(PMGToolBar): self.get_control_widget('button_help').clicked.connect(lambda: get_main_window().main_help_display()) self.get_control_widget('button_community').clicked.connect(lambda: get_main_window().main_community_display()) self.get_control_widget('button_feedback').clicked.connect(lambda: get_main_window().main_feedback_display()) + self.get_control_widget('button_login').clicked.connect(lambda: get_main_window().login_form_display()) self.append_menu('button_new_script', 'Python', lambda: get_main_window().main_new_script_display(), @@ -389,6 +398,21 @@ class MainWindow(BaseMainWindow): self.main_first_form = base.FirstForm(parent=self) self.main_first_form.show() + def login_form_display(self): + """ + 显示"登录"窗口 + Displays the "Quick Action" window + """ + shared_memo = shared_memory.SharedMemory(name="sharedMemory") # 通过name找到共享内存token + buff = shared_memo.buf + token = bytes(buff[:199]).decode().replace("\x00", "") + if token != "": + self.main_login_form = base.LoginedForm(parent=self) + self.main_login_form.exec_() + else: + self.main_login_form = base.LoginForm(parent=self) + self.main_login_form.exec_() + def main_appstore_dispaly(self): """ 显示"应用商店"窗口 diff --git a/pmlocalserver/server.py b/pmlocalserver/server.py index 9d86addd0d57ed30d5dca89f692c2fdda3e08a8a..80e2d11a18462b9bd5d77eabe54cb70a5f4d3cb8 100644 --- a/pmlocalserver/server.py +++ b/pmlocalserver/server.py @@ -2,6 +2,7 @@ from flask import Flask from flask_cors import CORS import threading +from multiprocessing import shared_memory server = Flask(__name__, static_folder='static', static_url_path='/static') CORS(server, supports_credentials=True) # 解决跨域 @@ -9,5 +10,10 @@ CORS(server, supports_credentials=True) # 解决跨域 server_thread = threading.Thread(target=server.run) # 这个线程与主界面没有任何交互,直接用系统内建的线程库即可,保证其安全性。 server_thread.setDaemon(True) +""" +创建共享内存sharedMemory,用于存放登录后返回的token和其他信息,token长度为199,索引为0-198,在用户登录后请勿将其覆盖 +""" +shared_memo = shared_memory.SharedMemory(name="sharedMemory", create=True, size=4096) + if __name__ == '__main__': server_thread.start() diff --git a/pyminer_comm/data_client/data_client.py b/pyminer_comm/data_client/data_client.py index 2ad6c31c9dcd472c9220ad82dfe3396d0694935f..6f3a71d9b64e4218a2b7a1e153be636404903aeb 100644 --- a/pyminer_comm/data_client/data_client.py +++ b/pyminer_comm/data_client/data_client.py @@ -1,5 +1,4 @@ import logging -import time import typing from typing import Dict, Any, List @@ -29,7 +28,15 @@ def http_get_vars(var_names: typing.List[str], preview: bool) -> typing.Dict[str return msg -def shm_get_vars(var_names: List[str]): +def shm_get_vars(var_names: List[str]) -> Dict[str, Any]: + """ + 通过共享内存获取多个变量,以字典的形式返回。 + Args: + var_names: + + Returns: + + """ protocol = get_protocol() shm_name = get('/start_share_variables', dict_to_b64({'var_names': var_names}, protocol), @@ -37,16 +44,24 @@ def shm_get_vars(var_names: List[str]): logger.info('get shared variables %s from shmname%s' % (var_names, shm_name)) from multiprocessing import shared_memory shm_b = shared_memory.SharedMemory(shm_name.decode(encoding='utf8')) - b = shm_b.buf.tobytes() - df = pickle_to_dict(b) + buf_bytes = shm_b.buf.tobytes() + shm_vars_dict = pickle_to_dict(buf_bytes) shm_b.close() # Close each SharedMemory instance response = get('/end_share_variables', shm_name.decode(encoding='utf8'), protocol=str(protocol)) - return df + return shm_vars_dict + +def shm_set_vars(var_dic: Dict[str, Any]) -> None: + """ + 通过共享内存,设置多个变量的值。 + Args: + var_dic: -def shm_set_vars(var_dic: Dict[str, Any]): + Returns: + + """ from multiprocessing import shared_memory protocol = get_protocol() dmp = dict_to_pickle(var_dic, protocol) @@ -92,22 +107,30 @@ def get_var(var_name: str, preview=False) -> object: """ try: - if preview or not shm_allowed(): - if preview: - var = http_get_vars([var_name], preview=True).get(var_name) - else: - var = http_get_vars([var_name], preview=False).get(var_name) - return var - else: - return shm_get_vars([var_name]).get(var_name) + return get_vars([var_name], preview).get(var_name) except ConnectionRefusedError: raise ConnectionRefusedError('Cannot connect to workspace. Please confirm that PyMiner has been started!') -def get_vars(var_names: List, preview: bool = False) -> object: +def get_vars(var_names: List, preview: bool = False) -> Dict[str, Any]: + """ + 获取多个数据 + Args: + var_names: 变量名称列表 + preview: 是否进行预览 + + Returns: + + """ try: if shm_allowed() and not preview: - return shm_get_vars(var_names) + try: + return shm_get_vars(var_names) + except Exception as e: + logger.error("共享内存传输失效,退回到http传输。") + import traceback + traceback.print_exc() + return http_get_vars(var_names, False) else: return http_get_vars(var_names, preview=preview) except ConnectionRefusedError: @@ -145,10 +168,12 @@ def set_var(var_name: str, var: object, provider: str = 'external') -> None: 人为添加代码。 当然,在IPython中调用了这个函数也不会出现错误,只是会降低效率。 + 在允许使用共享内存的情况下,会尽量使用共享内存。如果共享内存无法成功,那么就降级到http传输方式。 + http传输方式在传输较小的数据时,反而会比共享内存快一点。 + Examples --------- - >>> from pyminer_algorithms import * >>> set_var('x',[1,2,3,4,5]) >>> get_var('x') [1,2,3,4,5] @@ -158,14 +183,7 @@ def set_var(var_name: str, var: object, provider: str = 'external') -> None: """ try: - # try: - # get_ipython().neglect_post_run = True # 检测是否在Ipython中,如果是,就将这个标志位置为True防止重复更改。 - # except NameError: - # pass - if shm_allowed(): - shm_set_vars({var_name: var}) - else: - http_set_vars({var_name: var}) + set_vars({var_name: var}) except ConnectionRefusedError: raise ConnectionRefusedError('Cannot connect to workspace. Please confirm that PyMiner has been started!') @@ -215,7 +233,12 @@ def set_vars(var_dic: Dict[str, Any]): if not shm_allowed(): http_set_vars(var_dic) else: - shm_set_vars(var_dic) + try: + shm_set_vars(var_dic) + except Exception as e: + import traceback + traceback.print_exc() + http_set_vars(var_dic) except: import traceback traceback.print_exc() @@ -259,7 +282,7 @@ def get_var_names(filter: str = '') -> typing.List[str]: return var_names -def get_data_descs() -> typing.Dict[str,DataDesc]: +def get_data_descs() -> typing.Dict[str, DataDesc]: protocol = get_protocol() msg = get('/get_data_descs', "", protocol=str(protocol)) var_names = b64_to_dict(msg).get('data_descs') diff --git a/utils/http_client.py b/utils/http_client.py new file mode 100644 index 0000000000000000000000000000000000000000..d86d27d96ba365dcd7249557ec3e57fa0248c5b4 --- /dev/null +++ b/utils/http_client.py @@ -0,0 +1,16 @@ +import requests + +API = "http://pyminer.com/" +LOGIN_URL = 'api/v1/user/login/' + + +def client(url, method, data): + conn = requests.session() + if method == "post": + headers = { + "Content-type": "application/json; charset=utf-8;" + } + resp = conn.post(url, data, headers) + elif method == "get": + pass + return resp