Compare commits
2 Commits
fix/databa
...
d748e242db
| Author | SHA1 | Date | |
|---|---|---|---|
| d748e242db | |||
| e2fd0809a5 |
@ -1,7 +1,6 @@
|
|||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
import os
|
import os
|
||||||
import asyncio
|
import asyncio
|
||||||
from loguru import logger
|
|
||||||
import sqlparse
|
import sqlparse
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Dict, Any, Optional, Union, TYPE_CHECKING
|
from typing import List, Dict, Any, Optional, Union, TYPE_CHECKING
|
||||||
@ -11,20 +10,10 @@ import aiosqlite
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import DatabaseManager
|
from . import DatabaseManager
|
||||||
|
|
||||||
|
# 全局数据库管理器实例
|
||||||
_global_db_manager: Optional["DatabaseManager"] = None
|
_global_db_manager: Optional["DatabaseManager"] = None
|
||||||
|
|
||||||
|
|
||||||
async def try_close_connection(conn: aiosqlite.Connection) -> bool:
|
|
||||||
try:
|
|
||||||
await conn.close()
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
logger.error("有的连接关闭失败了")
|
|
||||||
logger.exception(e)
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def get_global_db_manager() -> "DatabaseManager":
|
def get_global_db_manager() -> "DatabaseManager":
|
||||||
"""获取全局数据库管理器实例"""
|
"""获取全局数据库管理器实例"""
|
||||||
global _global_db_manager
|
global _global_db_manager
|
||||||
@ -35,10 +24,16 @@ def get_global_db_manager() -> "DatabaseManager":
|
|||||||
return _global_db_manager
|
return _global_db_manager
|
||||||
|
|
||||||
|
|
||||||
|
def close_global_db_manager() -> None:
|
||||||
|
"""关闭全局数据库管理器实例"""
|
||||||
|
global _global_db_manager
|
||||||
|
if _global_db_manager is not None:
|
||||||
|
# 注意:这个函数应该在async环境中调用close_all_connections
|
||||||
|
_global_db_manager = None
|
||||||
|
|
||||||
|
|
||||||
class DatabaseManager:
|
class DatabaseManager:
|
||||||
"""
|
"""异步数据库管理器"""
|
||||||
异步数据库管理器
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, db_path: Optional[Union[str, Path]] = None, pool_size: int = 5):
|
def __init__(self, db_path: Optional[Union[str, Path]] = None, pool_size: int = 5):
|
||||||
"""
|
"""
|
||||||
@ -61,7 +56,6 @@ class DatabaseManager:
|
|||||||
|
|
||||||
async def _get_connection(self) -> aiosqlite.Connection:
|
async def _get_connection(self) -> aiosqlite.Connection:
|
||||||
"""从连接池获取连接"""
|
"""从连接池获取连接"""
|
||||||
|
|
||||||
async with self._lock:
|
async with self._lock:
|
||||||
# 尝试从池中获取现有连接
|
# 尝试从池中获取现有连接
|
||||||
while self._connection_pool:
|
while self._connection_pool:
|
||||||
@ -73,7 +67,10 @@ class DatabaseManager:
|
|||||||
return conn
|
return conn
|
||||||
except:
|
except:
|
||||||
# 连接已失效,关闭它
|
# 连接已失效,关闭它
|
||||||
await try_close_connection(conn)
|
try:
|
||||||
|
await conn.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# 如果连接池为空,创建新连接
|
# 如果连接池为空,创建新连接
|
||||||
conn = await aiosqlite.connect(self.db_path)
|
conn = await aiosqlite.connect(self.db_path)
|
||||||
@ -89,31 +86,16 @@ class DatabaseManager:
|
|||||||
self._connection_pool.append(conn)
|
self._connection_pool.append(conn)
|
||||||
else:
|
else:
|
||||||
# 池已满,直接关闭连接
|
# 池已满,直接关闭连接
|
||||||
await try_close_connection(conn)
|
try:
|
||||||
|
await conn.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def get_conn(self):
|
async def get_conn(self):
|
||||||
"""
|
|
||||||
从 db 中获取一个 Connection
|
|
||||||
"""
|
|
||||||
|
|
||||||
conn = await self._get_connection()
|
conn = await self._get_connection()
|
||||||
|
yield conn
|
||||||
try:
|
await self._return_connection(conn)
|
||||||
yield conn
|
|
||||||
|
|
||||||
# 只有当一切正常时才归还数据库连接
|
|
||||||
await self._return_connection(conn)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error("有模块使用一个连接时出现了错误")
|
|
||||||
logger.exception(e)
|
|
||||||
|
|
||||||
try:
|
|
||||||
await conn.rollback()
|
|
||||||
await conn.close()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error("在 Rollback 和关闭时也出现了问题")
|
|
||||||
logger.exception(e)
|
|
||||||
|
|
||||||
async def query(
|
async def query(
|
||||||
self, query: str, params: Optional[tuple] = None
|
self, query: str, params: Optional[tuple] = None
|
||||||
@ -208,14 +190,42 @@ class DatabaseManager:
|
|||||||
else:
|
else:
|
||||||
await self.execute_script(script)
|
await self.execute_script(script)
|
||||||
|
|
||||||
|
async def execute_many(self, command: str, seq_of_params: List[tuple]) -> None:
|
||||||
|
"""执行多条非查询语句"""
|
||||||
|
conn = await self._get_connection()
|
||||||
|
try:
|
||||||
|
await conn.executemany(command, seq_of_params)
|
||||||
|
await conn.commit()
|
||||||
|
except Exception as e:
|
||||||
|
await conn.rollback()
|
||||||
|
raise Exception(f"数据库批量执行失败: {str(e)}") from e
|
||||||
|
finally:
|
||||||
|
await self._return_connection(conn)
|
||||||
|
|
||||||
|
async def execute_many_values_by_sql_file(
|
||||||
|
self, file_path: Union[str, Path], seq_of_params: List[tuple]
|
||||||
|
) -> None:
|
||||||
|
"""从 SQL 文件中读取一条语句,但是被不同值同时执行"""
|
||||||
|
path = str(file_path) if isinstance(file_path, Path) else file_path
|
||||||
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
|
command = f.read()
|
||||||
|
await self.execute_many(command, seq_of_params)
|
||||||
|
|
||||||
async def close_all_connections(self) -> None:
|
async def close_all_connections(self) -> None:
|
||||||
"""关闭所有连接"""
|
"""关闭所有连接"""
|
||||||
|
|
||||||
async with self._lock:
|
async with self._lock:
|
||||||
|
# 关闭池中的连接
|
||||||
for conn in self._connection_pool:
|
for conn in self._connection_pool:
|
||||||
await try_close_connection(conn)
|
try:
|
||||||
|
await conn.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
self._connection_pool.clear()
|
self._connection_pool.clear()
|
||||||
|
|
||||||
|
# 关闭正在使用的连接
|
||||||
for conn in self._in_use.copy():
|
for conn in self._in_use.copy():
|
||||||
await try_close_connection(conn)
|
try:
|
||||||
|
await conn.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
self._in_use.clear()
|
self._in_use.clear()
|
||||||
|
|||||||
@ -32,7 +32,7 @@ class PermManager:
|
|||||||
def __init__(self, db: DatabaseManager) -> None:
|
def __init__(self, db: DatabaseManager) -> None:
|
||||||
self.db = db
|
self.db = db
|
||||||
|
|
||||||
async def get_permission_info(self, entities: _EntityLike, key: str):
|
async def check_has_permission_info(self, entities: _EntityLike, key: str):
|
||||||
entities = await _to_entity_chain(entities)
|
entities = await _to_entity_chain(entities)
|
||||||
key = key.removesuffix("*").removesuffix(".")
|
key = key.removesuffix("*").removesuffix(".")
|
||||||
key_split = key.split(".")
|
key_split = key.split(".")
|
||||||
@ -52,7 +52,7 @@ class PermManager:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
async def check_has_permission(self, entities: _EntityLike, key: str) -> bool:
|
async def check_has_permission(self, entities: _EntityLike, key: str) -> bool:
|
||||||
res = await self.get_permission_info(entities, key)
|
res = await self.check_has_permission_info(entities, key)
|
||||||
if res is None:
|
if res is None:
|
||||||
return False
|
return False
|
||||||
return res[2]
|
return res[2]
|
||||||
|
|||||||
@ -43,12 +43,15 @@ class PermRepo:
|
|||||||
Raises:
|
Raises:
|
||||||
AssertionError: 如果创建后无法获取实体 ID。
|
AssertionError: 如果创建后无法获取实体 ID。
|
||||||
"""
|
"""
|
||||||
await self.conn.execute(
|
try:
|
||||||
s("create_entity.sql"),
|
await self.conn.execute(
|
||||||
(entity.platform, entity.entity_type, entity.external_id),
|
s("create_entity.sql"),
|
||||||
)
|
(entity.platform, entity.entity_type, entity.external_id),
|
||||||
await self.conn.commit()
|
)
|
||||||
|
await self.conn.commit()
|
||||||
|
except Exception:
|
||||||
|
await self.conn.rollback()
|
||||||
|
raise
|
||||||
eid = await self._get_entity_id_or_none(entity)
|
eid = await self._get_entity_id_or_none(entity)
|
||||||
assert eid is not None
|
assert eid is not None
|
||||||
return eid
|
return eid
|
||||||
@ -116,8 +119,12 @@ class PermRepo:
|
|||||||
value: 要设置的配置值(True/False/None)。
|
value: 要设置的配置值(True/False/None)。
|
||||||
"""
|
"""
|
||||||
eid = await self.get_entity_id(entity)
|
eid = await self.get_entity_id(entity)
|
||||||
await self.conn.execute(s("update_perm_info.sql"), (eid, config_key, value))
|
try:
|
||||||
await self.conn.commit()
|
await self.conn.execute(s("update_perm_info.sql"), (eid, config_key, value))
|
||||||
|
await self.conn.commit()
|
||||||
|
except Exception:
|
||||||
|
await self.conn.rollback()
|
||||||
|
raise
|
||||||
|
|
||||||
async def get_entity_id_batch(
|
async def get_entity_id_batch(
|
||||||
self, entities: list[PermEntity]
|
self, entities: list[PermEntity]
|
||||||
@ -136,11 +143,15 @@ class PermRepo:
|
|||||||
# s("create_entity.sql"),
|
# s("create_entity.sql"),
|
||||||
# (entity.platform, entity.entity_type, entity.external_id),
|
# (entity.platform, entity.entity_type, entity.external_id),
|
||||||
# )
|
# )
|
||||||
await self.conn.executemany(
|
try:
|
||||||
s("create_entity.sql"),
|
await self.conn.executemany(
|
||||||
[(e.platform, e.entity_type, e.external_id) for e in entities],
|
s("create_entity.sql"),
|
||||||
)
|
[(e.platform, e.entity_type, e.external_id) for e in entities],
|
||||||
await self.conn.commit()
|
)
|
||||||
|
await self.conn.commit()
|
||||||
|
except Exception:
|
||||||
|
await self.conn.rollback()
|
||||||
|
raise
|
||||||
val_placeholders = ", ".join(["(?, ?, ?)"] * len(entities))
|
val_placeholders = ", ".join(["(?, ?, ?)"] * len(entities))
|
||||||
params = []
|
params = []
|
||||||
for e in entities:
|
for e in entities:
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
# 指令介绍
|
# 指令介绍
|
||||||
简易 Raymarch 小玩具
|
简易 Raymarch 小玩具
|
||||||
用法:march `<scene>`
|
用法:march `[scene]`
|
||||||
例:march torus(1.0, 0.2).color(1.0, 0.2, 0.2) torus(1.0, 0.2).rot(90, 0, 0).color(0.2, 0.2, 1.0) camera(4.0).pos(4, 0, 0).lookat(0)
|
例:march torus(1.0, 0.2).color(1.0, 0.2, 0.2) torus(1.0, 0.2).rot(90, 0, 0).color(0.2, 0.2, 1.0) camera(4.0).pos(4, 0, 0).lookat(0)
|
||||||
|
|
||||||
# 主要语法
|
# 主要语法
|
||||||
`<scene>` ::= `<scene>` "." `<op>` |`<obj>`
|
`[scene]` ::= `[scene]` "." `[op]` |`[obj]`
|
||||||
|
|
||||||
`<obj>` ::= `<obj_ty>` | `<obj_ty>` "(" <args> ")"
|
`[obj]` ::= `[obj_ty]` | `[obj_ty]` "(" [args] ")"
|
||||||
|
|
||||||
`<op>` ::= `<op_ty>` | `<op_ty>` "(" `<args>` ")"
|
`[op]` ::= `[op_ty]` | `[op_ty]` "(" `[args]` ")"
|
||||||
|
|
||||||
`<args>` ::= `<args>` "," `<arg>` | `<arg>`
|
`[args]` ::= `[args]` "," `[arg]` | `[arg]`
|
||||||
|
|
||||||
其中 `obj_ty`、`op_ty` 分别为物体类型(如 `cube`、`sphere`、`torus` 等)与变换类型(如 `pos`、`rot`)。
|
其中 `obj_ty`、`op_ty` 分别为物体类型(如 `cube`、`sphere`、`torus` 等)与变换类型(如 `pos`、`rot`)。
|
||||||
|
|
||||||
@ -37,4 +37,4 @@
|
|||||||
`rounded`:圆角
|
`rounded`:圆角
|
||||||
|
|
||||||
# 特殊说明
|
# 特殊说明
|
||||||
`<op_ty>` 不包含 scale。非正交的变换会破坏 SDF 的性质。
|
`[op_ty]` 不包含 scale。非正交的变换会破坏 SDF 的性质。
|
||||||
@ -2,6 +2,7 @@
|
|||||||
const float EPS = 0.001;
|
const float EPS = 0.001;
|
||||||
const int MAX_ITER = 128;
|
const int MAX_ITER = 128;
|
||||||
const float INF = 1e10;
|
const float INF = 1e10;
|
||||||
|
const float PI = 3.14159;
|
||||||
|
|
||||||
uniform vec2 u_resolution;
|
uniform vec2 u_resolution;
|
||||||
out vec4 fragColor;
|
out vec4 fragColor;
|
||||||
@ -68,17 +69,76 @@ vec3 nrm(vec3 p) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float saturate(float x) {
|
||||||
|
return clamp(x, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float ggx_distribution(vec3 n, vec3 h, float roughness) {
|
||||||
|
float alpha = roughness * roughness;
|
||||||
|
float alpha2 = alpha * alpha;
|
||||||
|
float NdotH = saturate(dot(n, h));
|
||||||
|
float denom = NdotH * NdotH * (alpha2 - 1.0) + 1.0;
|
||||||
|
return alpha2 / max(PI * denom * denom, EPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
float geometry_schlick_ggx(float NdotX, float roughness) {
|
||||||
|
float r = roughness + 1.0;
|
||||||
|
float k = r * r / 8.0;
|
||||||
|
return NdotX / max(NdotX * (1.0 - k) + k, EPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
float geometry_smith(vec3 n, vec3 v, vec3 l, float roughness) {
|
||||||
|
float NdotV = saturate(dot(n, v));
|
||||||
|
float NdotL = saturate(dot(n, l));
|
||||||
|
return geometry_schlick_ggx(NdotV, roughness) * geometry_schlick_ggx(NdotL, roughness);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 fresnel_schlick(vec3 f0, float cos_theta) {
|
||||||
|
return f0 + (1.0 - f0) * pow(1.0 - saturate(cos_theta), 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 tonemap_aces(vec3 c) {
|
||||||
|
const float a = 2.51;
|
||||||
|
const float b = 0.03;
|
||||||
|
const float c1 = 2.43;
|
||||||
|
const float d = 0.59;
|
||||||
|
const float e = 0.14;
|
||||||
|
return clamp((c * (a * c + b)) / (c * (c1 * c + d) + e), 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
vec4 materialColor(int obj_id) {
|
vec4 materialColor(int obj_id) {
|
||||||
<COLOR_BLOCK>
|
<COLOR_BLOCK>
|
||||||
return vec4(1.0);
|
return vec4(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 color(vec3 p, int obj_id) {
|
vec4 color(vec3 p, vec3 r, int obj_id) {
|
||||||
vec3 normal = nrm(p);
|
vec3 light_col = vec3(1.0);
|
||||||
vec3 light_dir = normalize(vec3(0.5, 0.8, -0.6));
|
vec4 albedo = materialColor(obj_id);
|
||||||
float light = 0.2 + 0.8 * max(dot(normal, light_dir), 0.0);
|
vec3 N = nrm(p);
|
||||||
vec4 base = materialColor(obj_id);
|
vec3 V = normalize(-r);
|
||||||
return vec4(base.rgb * light, base.a);
|
vec3 L = normalize(vec3(0.5, 0.8, -0.6));
|
||||||
|
vec3 H = normalize(V + L);
|
||||||
|
float roughness = 0.45;
|
||||||
|
float metallic = 0.02;
|
||||||
|
float NdotL = saturate(dot(N, L));
|
||||||
|
float NdotV = saturate(dot(N, V));
|
||||||
|
float D = ggx_distribution(N, H, roughness);
|
||||||
|
float G = geometry_smith(N, V, L, roughness);
|
||||||
|
vec3 F0 = mix(vec3(0.04), albedo.rgb, metallic);
|
||||||
|
vec3 F = fresnel_schlick(F0, dot(V, H));
|
||||||
|
vec3 kD = (1.0 - F) * (1.0 - metallic);
|
||||||
|
vec3 diffuse = kD * albedo.rgb / PI;
|
||||||
|
vec3 specular = D * G * F / max(4.0 * NdotL * NdotV, EPS);
|
||||||
|
|
||||||
|
float hemi = N.y * 0.5 + 0.5;
|
||||||
|
vec3 sky_ambient = vec3(0.60, 0.72, 0.92);
|
||||||
|
vec3 ground_ambient = vec3(0.18, 0.16, 0.14);
|
||||||
|
vec3 ambient = mix(ground_ambient, sky_ambient, hemi) * (diffuse + 0.25 * F0) * 0.35;
|
||||||
|
|
||||||
|
vec3 col = ambient + (diffuse + specular) * light_col * NdotL;
|
||||||
|
col = tonemap_aces(col);
|
||||||
|
col = pow(col, vec3(1.0 / 2.2));
|
||||||
|
return vec4(col, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec4 march(vec3 p, vec3 r) {
|
vec4 march(vec3 p, vec3 r) {
|
||||||
@ -87,7 +147,7 @@ vec4 march(vec3 p, vec3 r) {
|
|||||||
for(int i = 0; i < MAX_ITER; ++i) {
|
for(int i = 0; i < MAX_ITER; ++i) {
|
||||||
qry = sd(p);
|
qry = sd(p);
|
||||||
if(qry.value < EPS){
|
if(qry.value < EPS){
|
||||||
col = color(p, qry.obj_id);
|
col = color(p, r, qry.obj_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
p += qry.value * r;
|
p += qry.value * r;
|
||||||
|
|||||||
@ -77,7 +77,7 @@ async def get_permission(
|
|||||||
perm: str,
|
perm: str,
|
||||||
event: Event,
|
event: Event,
|
||||||
):
|
):
|
||||||
data = await pm.get_permission_info(ec, perm)
|
data = await pm.check_has_permission_info(ec, perm)
|
||||||
|
|
||||||
obj_s = f"{ec[0].platform}.{ec[0].entity_type}.{ec[0].external_id}"
|
obj_s = f"{ec[0].platform}.{ec[0].entity_type}.{ec[0].external_id}"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user