Skip to content

Commit c3fe122

Browse files
committed
fix: 修复脑残把公共服务打了
1 parent b40694b commit c3fe122

File tree

4 files changed

+232
-10
lines changed

4 files changed

+232
-10
lines changed

assets/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<head><meta charset="utf-8"><title>Python OpenBMCLAPI Dashboard</title><style>*{box-sizing:border-box;}html,body{height:100%;width:100%;margin:0;padding:0;}.preloader {background-color:black;height:100%;width:100%;position:fixed;top:0;left:0;z-index:9999;margin:auto;overflow:hidden;}.preloader .loader {display:block;position:relative;left:50%;top:50%;width:150px;height:150px;margin:-75px 0 0 -75px;border-radius:50%;box-shadow:0 3px 3px 0 rgba(255,56,106,1);transform:translate3d(0,0,0);animation:spin 2s linear infinite;}.preloader .loader:before,.preloader .loader:after{content:'';position:absolute;border-radius:50%;}.preloader .loader:before{top:5px;left:5px;right:5px;bottom:5px;box-shadow:0 3px 3px 0 rgb(255,228,32);-webkit-animation:spin 3s linear infinite;animation:spin 3s linear infinite;}.preloader .loader:after {top:15px;left:15px;right:15px;bottom:15px;box-shadow:0 3px 3px 0 rgba(61,175,255,1);animation:spin 1.5s linear infinite;}@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></head><body><div class="preloader"><div class="loader"></div></div><script type="module" src="/assets/js/index.js"></script></body></head>
1+
<head><meta charset="utf-8"><title>Python OpenBMCLAPI Dashboard</title><style>*{box-sizing:border-box;}html,body{height:100%;width:100%;margin:0;padding:0;}.preloader{background-color:black;height:100%;width:100%;position:fixed;top:0;left:0;z-index:9999;margin:auto;overflow:hidden;opacity:1;transition: opacity 750ms linear 0s}.preloader.hidden{opacity: 0;}.preloader .loader{display:block;position:relative;left:50%;top:50%;width:150px;height:150px;margin:-75px 0 0 -75px;border-radius:50%;box-shadow:0 3px 3px 0 rgba(255,56,106,1);transform:translate3d(0,0,0);animation:spin 2s linear infinite;}.preloader .loader:before,.preloader .loader:after{content:'';position:absolute;border-radius:50%;}.preloader .loader:before{top:5px;left:5px;right:5px;bottom:5px;box-shadow:0 3px 3px 0 rgb(255,228,32);-webkit-animation:spin 3s linear infinite;animation:spin 3s linear infinite;}.preloader .loader:after {top:15px;left:15px;right:15px;bottom:15px;box-shadow:0 3px 3px 0 rgba(61,175,255,1);animation:spin 1.5s linear infinite;}@-webkit-keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}@-moz-keyframes spin{0%{-moz-transform:rotate(0)}100%{-moz-transform:rotate(360deg)}}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></head><body><div class="preloader"><div class="loader"></div></div><script type="module" src="/assets/js/index.js"></script></body></head>

assets/js/index.js

Lines changed: 186 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ class Utils {
1919
}
2020
return uuid.join('').toLocaleLowerCase();
2121
}
22+
static isDOM(o) {
23+
return (
24+
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
25+
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
26+
);
27+
}
2228
}
23-
2429
class Socket {
2530
constructor(baseurl) {
2631
this._ws = null;
@@ -121,6 +126,184 @@ class Socket {
121126
}
122127

123128
}
124-
129+
class I18NManager {
130+
constructor() {
131+
this._i18n = {}
132+
this._lang = "zh_CN"
133+
}
134+
addLangage(lang, key, value) {
135+
if (!(lang in this._i18n)) {
136+
this._i18n[lang] = {}
137+
}
138+
this._i18n[lang][key] = value;
139+
}
140+
addLanguageTable(lang, table) {
141+
table.entries().forEach(([key, value]) => {
142+
this.addLangage(lang, key, value)
143+
})
144+
}
145+
t(key, params) {
146+
if (!(this._lang in this._i18n)) {
147+
return key;
148+
}
149+
var value = this._i18n[this._lang][key];
150+
if (value == null) {
151+
return key;
152+
}
153+
params.entries().forEach(([key, value]) => {
154+
value = value.replace(`%${key}%`, value);
155+
})
156+
return value;
157+
}
158+
setLang(lang) {
159+
this._lang = lang;
160+
window.dispatchEvent(new CustomEvent("langChange", { detail: lang }))
161+
}
162+
}
163+
class ElementManager {
164+
constructor() {
165+
this._elements = []
166+
window.addEventListener("langChange", (event) => {
167+
this._elements.forEach(element => element._render_i18n())
168+
})
169+
}
170+
add(element) {
171+
this._elements.push(element);
172+
}
173+
}
174+
class Element {
175+
constructor(object) {
176+
if (typeof object == "string") {
177+
this._base = document.createElement(object);
178+
} else if (Utils.isDOM(object)) {
179+
this._base = object;
180+
}
181+
this._i18n_key = null;
182+
this._i18n_params = {};
183+
this._children = []
184+
$ElementManager.add(this);
185+
}
186+
get origin() {
187+
return this._base;
188+
}
189+
html(html) {
190+
this._base.innerHTML = html;
191+
return this;
192+
}
193+
text(text) {
194+
this._base.innerText = text;
195+
return this;
196+
}
197+
i18n(key) {
198+
this._i18n_key = key;
199+
this._render_i18n();
200+
return this;
201+
}
202+
t18n(params) {
203+
this._i18n_params = params || {};
204+
this._render_i18n();
205+
return this;
206+
}
207+
_render_i18n() {
208+
if (this._i18n_key == null) {
209+
return;
210+
}
211+
this.text($i18n.t(this._i18n_key))
212+
}
213+
append(element) {
214+
if (Utils.isDOM(element)) {
215+
element = new Element(element);
216+
}
217+
this._children.push(element);
218+
this._base.appendChild(element.origin);
219+
}
220+
classes(...classes) {
221+
this._base.classList.add(...classes);
222+
return this;
223+
}
224+
removeClasses(...classes) {
225+
this._base.classList.remove(...classes);
226+
return this;
227+
}
228+
style(key, value) {
229+
this._base.style[key] = value;
230+
return this;
231+
}
232+
on(event, handler) {
233+
this._base.addEventListener(event, handler);
234+
return this;
235+
}
236+
get children() {
237+
return this._children;
238+
}
239+
get length() {
240+
return this._children.length;
241+
}
242+
removeChild(object) {
243+
// first number
244+
// second dom
245+
// last element
246+
if (typeof object == "number") {
247+
this._children.splice(object, 1);
248+
} else if (Utils.isDOM(object)) {
249+
this._children.splice(this._children.indexOf(new Element(object)), 1);
250+
} else {
251+
this._children.splice(this._children.indexOf(object), 1);
252+
}
253+
}
254+
get firstChild() {
255+
return this._children[0];
256+
}
257+
get lastChild() {
258+
return this._children[this._children.length - 1];
259+
}
260+
}
261+
class Style {
262+
constructor() {
263+
this._styles = {}
264+
this._style_dom = document.createElement("style");
265+
document.getElementsByTagName("head").item(0).appendChild(this._style_dom);
266+
}
267+
_parseToString(object) {
268+
// if object is array, we foreach and parse again
269+
// if obejct is table, we join ";" in it
270+
// if object is string, we return it
271+
if (Array.isArray(object)) {
272+
return object.map(this._parseToString).join(";");
273+
} else if (typeof object == "object") {
274+
return Object.entries(object).map(([key, value]) => `${key}:${this._parseToString(value)}`).join(";");
275+
} else {
276+
return object.toString();
277+
}
278+
}
279+
add(name, style) {
280+
this._styles[name] = this._parseToString(style);
281+
this.render();
282+
}
283+
render() {
284+
this._style_dom.innerHTML = Object.entries(this._styles).map(([name, style]) => `${name}{${style}}`).join("");
285+
}
286+
}
287+
function createElement(object) {
288+
return new Element(object);
289+
}
290+
const $ElementManager = new ElementManager();
291+
const $style = new Style();
292+
const $i18n = new I18NManager();
125293
const $socket = new Socket(window.location.origin + "/api");
126-
$socket.send("echo", "hello world")
294+
295+
window.addEventListener("DOMContentLoaded", () => {
296+
console.log("hello world")
297+
$style.add("body", {
298+
"background-color": "black"
299+
})
300+
Array.from(document.getElementsByClassName("preloader")).forEach(e => {
301+
const element = new Element(e);
302+
requestAnimationFrame(() => {
303+
element.classes("hidden");
304+
setTimeout(() => {
305+
element.remove();
306+
}, 5000)
307+
})
308+
})
309+
})

core/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,11 @@ def parse_service_error(body: Any) -> Optional['ServiceError']:
179179
body["name"]
180180
)
181181

182-
def raise_service_error(body: Any) -> bool:
182+
def raise_service_error(body: Any, key: str = "utils.error.service_error", **kwargs) -> bool:
183183
service = parse_service_error(body)
184184
if service is None:
185185
return False
186-
logger.terror("utils.error.service_error", code=service.code, httpCode=service.httpCode, message=service.message, name=service.name)
186+
logger.terror(key, code=service.code, httpCode=service.httpCode, message=service.message, name=service.name, **kwargs)
187187
return True
188188

189189

core/web.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from collections import deque
33
from dataclasses import dataclass
44
import io
5+
import os
56
from pathlib import Path
67
import time
78
from typing import Any, Optional
@@ -75,6 +76,7 @@ async def middleware(request: web.Request, handler: Any) -> web.Response:
7576
REQUEST_BUFFER = 4096
7677
IO_BUFFER = 16384
7778
FINDING_FILTER = "127.0.0.1"
79+
CHECK_PORT_SECRET = os.urandom(8)
7880
ip_tables: dict[tuple[str, int], tuple[str, int]] = {}
7981

8082
def find_origin_ip(target: tuple[str, int]):
@@ -107,6 +109,7 @@ def __exit__(self, _, __, ___):
107109
site: Optional[web.TCPSite] = None
108110
public_server: Optional[asyncio.Server] = None
109111
private_ssl_server: Optional[asyncio.Server] = None
112+
private_ssl: Optional[tuple[ssl.SSLContext, ssl.SSLContext]] = None
110113

111114
async def close_writer(writer: asyncio.StreamWriter):
112115
if writer.is_closing():
@@ -123,7 +126,6 @@ async def _(_, __):
123126
await server.wait_closed()
124127
return port
125128

126-
127129
async def forward_data(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
128130
while not writer.is_closing():
129131
data = await reader.read(IO_BUFFER)
@@ -134,7 +136,6 @@ async def forward_data(reader: asyncio.StreamReader, writer: asyncio.StreamWrite
134136
writer.close()
135137
await writer.wait_closed()
136138

137-
138139
async def open_forward_data(reader: asyncio.StreamReader, writer: asyncio.StreamWriter, target_ip: str, target_port: int, data: bytes = b''):
139140
try:
140141
target_r, target_w = await asyncio.wait_for(
@@ -171,6 +172,10 @@ async def open_forward_data(reader: asyncio.StreamReader, writer: asyncio.Stream
171172
async def public_handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
172173
try:
173174
data = await reader.read(REQUEST_BUFFER)
175+
if data == CHECK_PORT_SECRET:
176+
writer.write(data)
177+
await writer.drain()
178+
return
174179
client_ssl = False
175180
try:
176181
SNIHelper(data)
@@ -207,6 +212,24 @@ async def ssl_handle(reader: asyncio.StreamReader, writer: asyncio.StreamWriter)
207212
finally:
208213
writer.close()
209214

215+
async def check_server():
216+
global public_server
217+
if public_server is None:
218+
return False
219+
async def _check():
220+
try:
221+
r, w = await asyncio.wait_for(asyncio.open_connection('127.0.0.1', public_server.sockets[0].getsockname()[1]), 5) # type: ignore
222+
w.write(CHECK_PORT_SECRET)
223+
await w.drain()
224+
data = await r.read(REQUEST_BUFFER)
225+
return data == w
226+
except:
227+
return False
228+
if not _check():
229+
await start_public_server()
230+
return False
231+
232+
210233
async def init():
211234
global runner, site, public_server, routes, app
212235

@@ -222,21 +245,37 @@ async def init():
222245

223246
logger.tdebug("web.debug.local_port", port=site._port)
224247

248+
await start_public_server()
225249

250+
async def start_public_server():
251+
global public_server
252+
if public_server is not None:
253+
public_server.close()
254+
await public_server.wait_closed()
226255
public_server = await asyncio.start_server(
227256
public_handle, host='0.0.0.0',port=config.const.public_port
228257
)
229258
logger.tsuccess("web.success.public_port", port=config.const.public_port)
230259

231-
232260
async def start_ssl_server(cert: Path, key: Path):
233-
global private_ssl_server
261+
global private_ssl_server, private_ssl
234262
context = ssl.create_default_context(
235263
ssl.Purpose.CLIENT_AUTH
236264
)
237265
context.load_cert_chain(cert, key)
238266
context.hostname_checks_common_name = False
239267
context.check_hostname = False
268+
269+
client = ssl.create_default_context(
270+
ssl.Purpose.SERVER_AUTH
271+
)
272+
client.load_verify_locations(cert)
273+
client.hostname_checks_common_name = False
274+
client.check_hostname = False
275+
private_ssl = (
276+
context,
277+
client
278+
)
240279

241280
if private_ssl_server is not None and private_ssl_server.is_serving():
242281
private_ssl_server.close()

0 commit comments

Comments
 (0)