migr: migration json to x.json2

This commit is contained in:
meiseayoung
2025-12-30 12:40:30 +08:00
parent 85b001225e
commit a95485dd25
21 changed files with 223 additions and 145 deletions
+4 -4
View File
@@ -3,7 +3,7 @@ module hono
import crypto.sha256
import crypto.rand
import time
import json
import x.json2
// 用户角色枚举
pub enum UserRole {
@@ -242,7 +242,7 @@ pub fn (mut auth AuthManager) logout(token string) ! {
// 创建菜单项
pub fn (mut auth AuthManager) create_menu_item(name string, path string, icon string, parent_id int, sort_order int, permissions []string) !MenuItem {
now := int(time.now().unix())
permissions_json := json.encode(permissions)
permissions_json := json2.encode[[]string](permissions)
permissions_sql := permissions_json.replace('"', "''")
auth.db.db.exec('INSERT INTO menu_items (name, path, icon, parent_id, sort_order, permissions, status, created_at, updated_at) VALUES ("$name", "$path", "$icon", $parent_id, $sort_order, "$permissions_sql", 1, $now, $now)')
@@ -280,7 +280,7 @@ pub fn (auth AuthManager) get_all_menu_items() ![]MenuItem {
mut menus := []MenuItem{}
for row in rows {
permissions_str := row.vals[6]
permissions := json.decode([]string, permissions_str) or { []string{} }
permissions := json2.decode[[]string](permissions_str) or { []string{} }
menus << MenuItem{
id: row.vals[0].int()
@@ -327,7 +327,7 @@ pub fn (auth AuthManager) get_user_menus(user User) ![]MenuItem {
mut menus := []MenuItem{}
for row in rows {
permissions_str := row.vals[6]
permissions := json.decode([]string, permissions_str) or { []string{} }
permissions := json2.decode[[]string](permissions_str) or { []string{} }
menus << MenuItem{
id: row.vals[0].int()
+109 -65
View File
@@ -1,6 +1,6 @@
module hono
import json
import x.json2
import net.http
// 登录请求结构
@@ -30,20 +30,64 @@ pub:
permissions []string
}
// 响应结构体
struct ErrorResponseBody {
error string
}
struct LoginResponseBody {
token string
expires_at string
}
struct RegisterResponseBody {
user_id string
username string
email string
role string
}
struct MessageResponseBody {
message string
}
struct ProfileResponseBody {
user_id string
username string
email string
role string
active string
}
struct MenusResponseBody {
menus []MenuItem
}
struct MenuCreateResponseBody {
menu_id string
name string
path string
icon string
parent_id string
sort_order string
permissions string
active string
}
// 认证中间件(只做校验,不注入 user)
pub fn auth_middleware(auth_manager AuthManager) ContextMiddleware {
return fn [auth_manager] (mut c Context, next fn (mut Context) http.Response) http.Response {
token := c.req.header.get_custom('Authorization') or { '' }
if token == '' {
c.status(401)
return c.json(json.encode({
'error': 'Authorization token required'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Authorization token required'
}))
}
_ := auth_manager.verify_token(token) or {
c.status(401)
return c.json(json.encode({
'error': 'Invalid or expired token'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid or expired token'
}))
}
return next(mut c)
@@ -56,14 +100,14 @@ pub fn permission_middleware(auth_manager AuthManager, required_permission strin
token := c.req.header.get_custom('Authorization') or { '' }
user := auth_manager.verify_token(token) or {
c.status(401)
return c.json(json.encode({
'error': 'Invalid or expired token'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid or expired token'
}))
}
if !auth_manager.check_permission(user, required_permission) {
c.status(403)
return c.json(json.encode({
'error': 'Insufficient permissions'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Insufficient permissions'
}))
}
return next(mut c)
@@ -75,31 +119,31 @@ pub fn register_auth_routes(mut app Hono, mut auth_manager AuthManager) {
// 登录路由
app.post('/api/auth/login', fn [mut auth_manager] (mut c Context) http.Response {
body := c.body
login_req := json.decode(LoginRequest, body) or {
login_req := json2.decode[LoginRequest](body) or {
c.status(400)
return c.json(json.encode({
'error': 'Invalid request body'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid request body'
}))
}
session := auth_manager.login(login_req.username, login_req.password) or {
c.status(401)
return c.json(json.encode({
'error': err.msg()
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: err.msg()
}))
}
return c.json(json.encode({
'token': session.token.str()
'expires_at': session.expires_at.str()
return c.json(json2.encode[LoginResponseBody](LoginResponseBody{
token: session.token.str()
expires_at: session.expires_at.str()
}))
})
// 注册路由
app.post('/api/auth/register', fn [mut auth_manager] (mut c Context) http.Response {
body := c.body
register_req := json.decode(RegisterRequest, body) or {
register_req := json2.decode[RegisterRequest](body) or {
c.status(400)
return c.json(json.encode({
'error': 'Invalid request body'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid request body'
}))
}
role := match register_req.role {
@@ -111,15 +155,15 @@ pub fn register_auth_routes(mut app Hono, mut auth_manager AuthManager) {
}
user := auth_manager.create_user(register_req.username, register_req.email, register_req.password, role) or {
c.status(400)
return c.json(json.encode({
'error': err.msg()
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: err.msg()
}))
}
return c.json(json.encode({
'user_id': user.id.str()
'username': user.username
'email': user.email
'role': user.role.str()
return c.json(json2.encode[RegisterResponseBody](RegisterResponseBody{
user_id: user.id.str()
username: user.username
email: user.email
role: user.role.str()
}))
})
@@ -128,18 +172,18 @@ pub fn register_auth_routes(mut app Hono, mut auth_manager AuthManager) {
token := c.req.header.get_custom('Authorization') or { '' }
if token == '' {
c.status(401)
return c.json(json.encode({
'error': 'Authorization token required'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Authorization token required'
}))
}
auth_manager.logout(token) or {
c.status(500)
return c.json(json.encode({
'error': err.msg()
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: err.msg()
}))
}
return c.json(json.encode({
'message': 'Logged out successfully'
return c.json(json2.encode[MessageResponseBody](MessageResponseBody{
message: 'Logged out successfully'
}))
})
@@ -148,16 +192,16 @@ pub fn register_auth_routes(mut app Hono, mut auth_manager AuthManager) {
token := c.req.header.get_custom('Authorization') or { '' }
user := auth_manager.verify_token(token) or {
c.status(401)
return c.json(json.encode({
'error': 'Invalid or expired token'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid or expired token'
}))
}
return c.json(json.encode({
'user_id': user.id.str()
'username': user.username
'email': user.email
'role': user.role.str()
'active': user.status.str()
return c.json(json2.encode[ProfileResponseBody](ProfileResponseBody{
user_id: user.id.str()
username: user.username
email: user.email
role: user.role.str()
active: user.status.str()
}))
})
@@ -166,45 +210,45 @@ pub fn register_auth_routes(mut app Hono, mut auth_manager AuthManager) {
token := c.req.header.get_custom('Authorization') or { '' }
user := auth_manager.verify_token(token) or {
c.status(401)
return c.json(json.encode({
'error': 'Invalid or expired token'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid or expired token'
}))
}
menus := auth_manager.get_user_menus(user) or {
c.status(500)
return c.json(json.encode({
'error': err.msg()
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: err.msg()
}))
}
return c.json(json.encode({
'menus': menus
return c.json(json2.encode[MenusResponseBody](MenusResponseBody{
menus: menus
}))
})
// 创建菜单项路由 (需要管理员权限)
app.post('/api/auth/menus', fn [mut auth_manager] (mut c Context) http.Response {
body := c.body
menu_req := json.decode(MenuCreateRequest, body) or {
menu_req := json2.decode[MenuCreateRequest](body) or {
c.status(400)
return c.json(json.encode({
'error': 'Invalid request body'
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: 'Invalid request body'
}))
}
menu := auth_manager.create_menu_item(menu_req.name, menu_req.path, menu_req.icon, menu_req.parent_id, menu_req.sort_order, menu_req.permissions) or {
c.status(400)
return c.json(json.encode({
'error': err.msg()
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: err.msg()
}))
}
return c.json(json.encode({
'menu_id': menu.id.str()
'name': menu.name
'path': menu.path
'icon': menu.icon
'parent_id': menu.parent_id.str()
'sort_order': menu.sort_order.str()
'permissions': json.encode(menu.permissions)
'active': menu.status.str()
return c.json(json2.encode[MenuCreateResponseBody](MenuCreateResponseBody{
menu_id: menu.id.str()
name: menu.name
path: menu.path
icon: menu.icon
parent_id: menu.parent_id.str()
sort_order: menu.sort_order.str()
permissions: json2.encode[[]string](menu.permissions)
active: menu.status.str()
}))
})
@@ -212,12 +256,12 @@ pub fn register_auth_routes(mut app Hono, mut auth_manager AuthManager) {
app.get('/api/auth/menus/all', fn [auth_manager] (mut c Context) http.Response {
menus := auth_manager.get_all_menu_items() or {
c.status(500)
return c.json(json.encode({
'error': err.msg()
return c.json(json2.encode[ErrorResponseBody](ErrorResponseBody{
error: err.msg()
}))
}
return c.json(json.encode({
'menus': menus
return c.json(json2.encode[MenusResponseBody](MenusResponseBody{
menus: menus
}))
})
}
+3 -3
View File
@@ -1,7 +1,7 @@
module hono
import os
import json
import x.json2
// 服务器配置结构
pub struct ServerConfig {
@@ -107,7 +107,7 @@ pub fn load_config(config_path string) !AppConfig {
return error('无法读取配置文件: ${err}')
}
config := json.decode(AppConfig, config_content) or {
config := json2.decode[AppConfig](config_content) or {
return error('配置文件格式错误: ${err}')
}
@@ -122,7 +122,7 @@ pub fn load_config(config_path string) !AppConfig {
// 保存配置到文件
pub fn save_config(config AppConfig, config_path string) ! {
config_json := json.encode_pretty(config)
config_json := json2.encode[AppConfig](config, prettify: true)
// 确保目录存在
config_dir := os.dir(config_path)
+2 -2
View File
@@ -1,7 +1,7 @@
module hono
import net.http
import json
import x.json2
// 错误类型枚举
pub enum ErrorType {
@@ -51,7 +51,7 @@ pub fn (eh DefaultErrorHandler) handle_error(mut c Context, error_type ErrorType
}
c.status(int(error_type))
return c.json(json.encode(error_response))
return c.json(json2.encode[ErrorResponse](error_response))
}
// 获取错误名称
+40 -19
View File
@@ -2,7 +2,28 @@ module main
import hono
import net.http
import json
import x.json2
// 响应结构体
struct ErrorResponse {
error string
}
struct ProtectedUserResponse {
message string
user_id string
username string
email string
role string
}
struct ProtectedAdminResponse {
message string
user_id string
username string
email string
role string
}
fn main() {
// 创建数据库管理器
@@ -37,16 +58,16 @@ fn main() {
token := c.req.header.get_custom('Authorization') or { '' }
user := auth_manager.verify_token(token) or {
c.status(401)
return c.json(json.encode({
'error': 'User not found'
return c.json(json2.encode[ErrorResponse](ErrorResponse{
error: 'User not found'
}))
}
return c.json(json.encode({
'message': 'This is a protected user route',
'user_id': user.id.str(),
'username': user.username,
'email': user.email,
'role': user.role.str()
return c.json(json2.encode[ProtectedUserResponse](ProtectedUserResponse{
message: 'This is a protected user route'
user_id: user.id.str()
username: user.username
email: user.email
role: user.role.str()
}))
})
@@ -54,22 +75,22 @@ fn main() {
token := c.req.header.get_custom('Authorization') or { '' }
user := auth_manager.verify_token(token) or {
c.status(401)
return c.json(json.encode({
'error': 'User not found'
return c.json(json2.encode[ErrorResponse](ErrorResponse{
error: 'User not found'
}))
}
if !auth_manager.check_permission(user, 'manage') {
c.status(403)
return c.json(json.encode({
'error': 'Admin access required'
return c.json(json2.encode[ErrorResponse](ErrorResponse{
error: 'Admin access required'
}))
}
return c.json(json.encode({
'message': 'This is a protected admin route',
'user_id': user.id.str(),
'username': user.username,
'email': user.email,
'role': user.role.str()
return c.json(json2.encode[ProtectedAdminResponse](ProtectedAdminResponse{
message: 'This is a protected admin route'
user_id: user.id.str()
username: user.username
email: user.email
role: user.role.str()
}))
})
+4 -4
View File
@@ -11,13 +11,13 @@ fn main() {
create_test_files()
// 创建应用
mut app := hono.Hono.new()
mut app := &hono.Hono{}
// 测试路由
setup_test_routes(mut app)
// 在后台启动服务器
go app.listen(':8081')
spawn app.listen(':8081')
// 等待服务器启动
time.sleep(2 * time.second)
@@ -227,8 +227,8 @@ fn test_smart_selection() {
if result2.exit_code == 0 {
// 检查下载的文件大小
if os.exists('large_output.txt') {
downloaded_size := os.file_size('large_output.txt') or { 0 }
original_size := os.file_size('test_large.txt') or { 0 }
downloaded_size := os.file_size('large_output.txt')
original_size := os.file_size('test_large.txt')
if downloaded_size == original_size {
println('✅ 智能选择大文件: 成功 (${downloaded_size} bytes)')
} else {
+2 -2
View File
@@ -2,7 +2,7 @@ module hono
import os
import time
import json
import x.json2
// 日志级别枚举
pub enum LogLevel {
@@ -150,7 +150,7 @@ fn (l &Logger) format_text_log(entry LogEntry) string {
// 格式化日志消息(JSON格式)
fn (l &Logger) format_json_log(entry LogEntry) string {
return json.encode(entry)
return json2.encode[LogEntry](entry)
}
// 写入日志到文件
+1 -1
View File
@@ -478,7 +478,7 @@ fn test_integration(mut stats TestStats) {
})
// 验证路由统计
static_count, dynamic_count, cache_count, _ := app.get_router_stats()
static_count, dynamic_count, _, _ := app.get_router_stats()
if static_count + dynamic_count < 2 {
stats.fail_test('路由添加失败')
+1 -2
View File
@@ -1,5 +1,4 @@
import hono
import time
import net.http
fn main() {
@@ -200,7 +199,7 @@ fn test_restful_api_patterns() {
mut restful_success := 0
for test in restful_tests {
if match_result := app.fast_router.match_route(test['method'], test['path']) {
if _ := app.fast_router.match_route(test['method'], test['path']) {
restful_success++
println(' ✅ ${test['method']} ${test['path']} - ${test['description']}')
} else {
@@ -400,7 +400,7 @@ fn test_comprehensive_performance() {
mut complex_matches := 0
for _ in 0 .. test_iterations {
if match_result := app.fast_router.match_route('GET', test['path']) {
if _ := app.fast_router.match_route('GET', test['path']) {
complex_matches++
}
}
-1
View File
@@ -1,6 +1,5 @@
import hono
import net.http
import json
fn main() {
println('=== 统一错误处理系统测试 ===')
+1 -1
View File
@@ -338,7 +338,7 @@ fn test_memory_management_integration() {
// 测试缓存操作
cache.put('test_key', test_data)
if cached := cache.get('test_key') {
if _ := cache.get('test_key') {
println(' ✅ 缓存存储和获取正常')
} else {
println(' ❌ 缓存存储或获取失败')
+2 -2
View File
@@ -198,7 +198,7 @@ fn test_backward_compatibility() {
mut router := hono.FastRouter.new()
// 测试原有接口是否保持兼容
compatibility_tests := [
_ := [
'add_route() 接口',
'match_route() 接口',
'get_stats() 接口',
@@ -264,7 +264,7 @@ fn test_new_features() {
mut router := hono.FastRouter.new_with_cache_size(50)
// 新功能清单
new_features := [
_ := [
'LRU 缓存机制',
'TTL 过期管理',
'健康状态检查',
+2 -2
View File
@@ -74,7 +74,7 @@ fn test_large_scale_repeated_matching() {
}
// 验证缓存没有增长(说明使用了缓存)
regex_total_after, regex_compiled_after := router.get_regex_cache_stats()
_, regex_compiled_after := router.get_regex_cache_stats()
if regex_compiled_after == regex_compiled {
println(' ✅ 缓存使用正常 - 没有额外的编译')
} else {
@@ -178,7 +178,7 @@ fn test_multi_route_cache_effect() {
}
// 验证缓存状态
regex_total_final, regex_compiled_final := router.get_regex_cache_stats()
_, regex_compiled_final := router.get_regex_cache_stats()
if regex_compiled_final == regex_compiled_after_first {
println(' ✅ 缓存工作正常 - 没有额外编译')
} else {
+1 -1
View File
@@ -153,7 +153,7 @@ fn test_cache_hit_rate() {
}
// 最终缓存状态
regex_total_final, regex_compiled_final := router.get_regex_cache_stats()
_, regex_compiled_final := router.get_regex_cache_stats()
if regex_compiled_final == regex_compiled_after_first {
println(' ✅ 缓存命中率100% - 没有额外的编译')
+1 -1
View File
@@ -87,7 +87,7 @@ fn test_step_by_step_breakdown() {
// 步骤4: 正则表达式缓存检查
start_time4 := time.now()
cached_regex := router.regex_cache[route_path]
_ := router.regex_cache[route_path]
step4_time := time.since(start_time4)
println(' 步骤4 - 正则缓存检查: ${step4_time}')
+2 -2
View File
@@ -57,7 +57,7 @@ fn (router NoCacheRouter) match_route_no_cache(method string, path string) ?hono
replaced_path = replaced_path.replace('{', r'\{')
replaced_path = replaced_path.replace('}', r'\}')
replaced_path = replaced_path.replace('^', r'\^')
replaced_path = replaced_path.replace('$', r'\$')
replaced_path = replaced_path.replace(r'$', r'\$')
replaced_path = replaced_path.replace('|', r'\|')
// 提取参数名并替换为命名捕获组
@@ -68,7 +68,7 @@ fn (router NoCacheRouter) match_route_no_cache(method string, path string) ?hono
return '(?P<${param_name}>[^/]+)'
})
replaced_path = '^${replaced_path}$'
replaced_path = '^${replaced_path}' + r'$'
// 每次都重新编译正则表达式(这是性能瓶颈)
mut reg := regex.regex_opt(replaced_path) or { continue }
+23 -5
View File
@@ -48,7 +48,7 @@ fn test_step_by_step_performance() {
// 步骤3: 第二次匹配(使用缓存)
start_time3 := time.now()
result2 := router.match_route('GET', test_path)
_ = router.match_route('GET', test_path)
second_match_time := time.since(start_time3)
println(' 第二次匹配时间 (使用缓存): ${second_match_time}')
@@ -58,9 +58,11 @@ fn test_step_by_step_performance() {
println(' 路由缓存: ${cache_size}/${cache_capacity}')
println(' 正则缓存: ${regex_compiled}/${regex_total}')
// 步骤5: 测试纯正则匹配时间
// 步骤5: 测试纯正则匹配时间(安全访问)
if cached := router.regex_cache[route_path] {
if cached.compiled {
// 先验证正则能匹配
if cached.regex.matches_string(test_path) {
start_time4 := time.now()
for _ in 0 .. 1000 {
cached.regex.matches_string(test_path)
@@ -68,21 +70,37 @@ fn test_step_by_step_performance() {
pure_regex_time := time.since(start_time4)
avg_regex_time := f64(pure_regex_time.microseconds()) / 1000.0
println(' 纯正则匹配平均时间: ${avg_regex_time:.3f}μs')
} else {
println(' ⚠️ 正则表达式无法匹配测试路径')
}
}
} else {
println(' ⚠️ 正则缓存中未找到路由')
}
// 步骤6: 测试参数提取时间
// 步骤6: 测试参数提取时间(安全访问)
if cached := router.regex_cache[route_path] {
if cached.compiled {
if cached.compiled && cached.param_names.len > 0 {
// 先执行一次匹配确保正则状态正确
if cached.regex.matches_string(test_path) {
start_time5 := time.now()
mut extract_count := 0
for _ in 0 .. 1000 {
// 每次提取前重新匹配
if cached.regex.matches_string(test_path) {
for param_name in cached.param_names {
cached.regex.get_group_by_name(test_path, param_name)
group := cached.regex.get_group_by_name(test_path, param_name)
if group.len > 0 {
extract_count++
}
}
}
}
param_extract_time := time.since(start_time5)
avg_param_time := f64(param_extract_time.microseconds()) / 1000.0
println(' 参数提取平均时间: ${avg_param_time:.3f}μs')
println(' 参数数量: ${cached.param_names.len}')
}
}
}
}
+4 -4
View File
@@ -49,7 +49,7 @@ fn test_basic_performance() {
mut fast_matches := 0
for _ in 0 .. iterations {
fast_router.clear_cache()
if match_result := fast_router.match_route('GET', test_path) {
if _ := fast_router.match_route('GET', test_path) {
fast_matches++
}
}
@@ -64,7 +64,7 @@ fn test_basic_performance() {
for _ in 0 .. iterations {
hybrid_router.clear_cache()
hybrid_router.clear_regex_cache()
if match_result := hybrid_router.match_route('GET', test_path) {
if _ := hybrid_router.match_route('GET', test_path) {
hybrid_matches++
}
}
@@ -93,7 +93,7 @@ fn test_basic_performance() {
start_time3 := time.now()
mut fast_cache_matches := 0
for _ in 0 .. iterations {
if match_result := fast_router.match_route('GET', test_path) {
if _ := fast_router.match_route('GET', test_path) {
fast_cache_matches++
}
}
@@ -102,7 +102,7 @@ fn test_basic_performance() {
start_time4 := time.now()
mut hybrid_cache_matches := 0
for _ in 0 .. iterations {
if match_result := hybrid_router.match_route('GET', test_path) {
if _ := hybrid_router.match_route('GET', test_path) {
hybrid_cache_matches++
}
}
+2 -5
View File
@@ -1,6 +1,3 @@
import hono
import net.http
import os
import time
import strings
@@ -32,14 +29,14 @@ fn test_json_building() {
// 方法1: 使用字符串插值(优化后)
start_time := time.now()
for i in 0 .. 10000 {
for _ in 0 .. 10000 {
_ := '{"message": "测试", "params": {"action": "${test_data['action']}", "id": "${test_data['id']}"}}'
}
interpolation_time := time.since(start_time)
// 方法2: 使用StringBuilder(复杂场景)
start_time2 := time.now()
for i in 0 .. 10000 {
for _ in 0 .. 10000 {
mut builder := strings.new_builder(256)
builder.write_string('{"message": "测试", "params": {"action": "')
builder.write_string(test_data['action'])
+2 -2
View File
@@ -3,7 +3,7 @@ module hono
import net.http
import os
import crypto.md5
import json
import x.json2
import time
// 分片上传配置
@@ -291,7 +291,7 @@ pub fn (manager ChunkUploadManager) get_upload_status(mut ctx Context) http.Resp
return ctx.resource_not_found('upload', file_hash)
}
return ctx.json(json.encode(upload_status))
return ctx.json(json2.encode[FileUploadStatus](upload_status))
}
// 更新上传状态