From 96fbc0ca754356607aabe6a549636d7149fc3dc2 Mon Sep 17 00:00:00 2001
From: muqiuhan 正确顺序: 这里的顺序很重要。Nginx 匹配规则是:精确匹配 location = /api/auth/me {
# 精确匹配,业务身份接口
rewrite ^/api(.*)$ $1 break;
proxy_pass http://host.docker.internal:<backend>;
}
location ^~ /api/auth/ {
# 认证框架路由,保留前缀
proxy_pass http://host.docker.internal:<auth-port>;
}
location ^~ /api/ {
# 其余 API,裁掉 /api
rewrite ^/api(.*)$ $1 break;
proxy_pass http://host.docker.internal:<backend>;
}
location / {
# 前端
proxy_pass http://host.docker.internal:<frontend>;
}= 优先,然后是前缀匹配 ^~,然后是正则匹配,最后是普通前缀匹配。^~ 表示一旦匹配成功就不再检查正则。
let int_pow base exponent = |
其中 int_math_int_pow() 由 C 实现:
external int_math_int_pow : int -> int -> int = "Base_int_math_int_pow_stub" [@@noalloc] |
其实现在 src/int_math_stubs.c 中:
+static int64_t int_pow(int64_t base, int64_t exponent) { |
这是一个四分快速幂的实现,它是二分快速幂的一种变种。二分快速幂将指数分为两部分,然后递归地计算每一部分的结果。
+而四分快速幂将指数分为四部分,然后递归地计算每一部分的结果。
+这里通过将指数右移2位(相当于除以4)和使用位与操作来实现,进一步减少了乘法次数。
主要步骤:
+++mul[1]是基数和mul[3]的乘积,mul[2]是mul[1]的平方,mul[3]是mul[2]和基数的乘积
+
++这样做的目的是为了选择正确的乘数,因为指数被分解为4的倍数
+
这个实现的优点是它可以在对数时间内计算出幂运算,而且每次循环只需要4次乘法。这比标准的二分快速幂算法需要的乘法次数更少。
]]>zbg (short for Zero Bullshit Git) is a CLI tool for using git efficiently.let int_pow base exponent = |
其中 int_math_int_pow() 由 C 实现:
external int_math_int_pow : int -> int -> int = "Base_int_math_int_pow_stub" [@@noalloc] |
其实现在 src/int_math_stubs.c 中:
-static int64_t int_pow(int64_t base, int64_t exponent) { |
这是一个四分快速幂的实现,它是二分快速幂的一种变种。二分快速幂将指数分为两部分,然后递归地计算每一部分的结果。
-而四分快速幂将指数分为四部分,然后递归地计算每一部分的结果。
-这里通过将指数右移2位(相当于除以4)和使用位与操作来实现,进一步减少了乘法次数。
主要步骤:
---mul[1]是基数和mul[3]的乘积,mul[2]是mul[1]的平方,mul[3]是mul[2]和基数的乘积
-
--这样做的目的是为了选择正确的乘数,因为指数被分解为4的倍数
-
这个实现的优点是它可以在对数时间内计算出幂运算,而且每次循环只需要4次乘法。这比标准的二分快速幂算法需要的乘法次数更少。
]]>其中有两个问题,一是 rescript-expo 对 rescript v11 的兼容性,我通过简单的注释让其通过编译:
- -二是对于 nativewind 的支持,编写的 binding 非常丑陋:
-type default_style = { |
而这似乎并没有好的解决方案,理想中的实现应该是:
-module Styled = (Component: { |
或者退一步:
-type styledProps = { |
但这在当前的 rescript 中,根本无法实现。
-详细的讨论看这个帖子:
- -]]>Sunday, March 30, 2025 7:58 PM:
感觉以上全错,不应该过度抽象 Repository 的,就让它分散在各个模块中,还可以参考 https://github.com/Papooch/nestjs-cls 实现不会抽象泄漏的事务性 Repository 方法。
+]]> +其中有两个问题,一是 rescript-expo 对 rescript v11 的兼容性,我通过简单的注释让其通过编译:
+ +二是对于 nativewind 的支持,编写的 binding 非常丑陋:
+type default_style = { |
而这似乎并没有好的解决方案,理想中的实现应该是:
+module Styled = (Component: { |
或者退一步:
+type styledProps = { |
但这在当前的 rescript 中,根本无法实现。
+详细的讨论看这个帖子:
+ ]]>她忽然笑了一下,像把窗纱上的一个小结解开。她说:“我替你把玻璃擦亮了。你也在替我把风擦亮。”屋里很安静,灯温柔地照着。她把手伸到光里,让手指被照成透明。透明的东西容易破碎,却也比别的更亮。
时间会带走了一个人,也带走了他的呼吸,他的声音,他掌心的温度。但似乎又留下了些什么
光的颗粒在空气里浮动,在记忆里游走,她闭上眼睛,光从睫毛上滑过,像许多个早晨,像许多个傍晚,像她们再次相遇的无数个灿然的瞬间。她在其中走走停停,像一粒微尘,又像一颗星。
+]]> +花店里里有一支黄玫瑰,花瓣像被烫过,从橙黄到金黄,层层叠叠,在傍晚的空气里慢慢散开一层暖色。它有甜味,甜里还带着一点苦,味道朦胧的像你在窗下读书,书页翻过时有阳光落下来,像你走过老城的石板路,脚下的石头被晒得很暖。
+我记得那张粗糙的柜台,记得老板的手掌上有花叶的汁液。记得那种 “被允许站在这里” 的轻松。它没有要你改变什么,也没有给你安排一个更好的未来。它只是让你看见,一个傍晚可以用来想事,一条路可以一直往前延伸而不追问终点是什么。
+从那以后,我偶尔还会闻到那种味道。公交车拐弯的时候,风从窗缝里钻进来,地铁门打开的时候,站台上一阵匆忙的脚步后,忽然静下来的那一刻。我不知道它为什么会出现,也不刻意寻找。它像朋友一样,来了就坐一会儿,走了也不会留下地址。
+然后我遇见了你。
+起初我们并肩走在一条街上,街灯刚亮,影子从脚边拖到墙根。你说话的时候,声音不急也不慢。我听见了你的过去,但不是像在听故事那样去比较谁更动人,我只是听着你。你给我看了你的手心,那上面有被太阳晒过后的浅色纹理,也有你习惯把指甲剪得很短的认真。我心里有一种安静,它不是从谁那里借来的,而是像从很远的地方自己走来的。
+我知道你不是她,她是一种很亮的影子,只能在黑暗里存在。而你会在这里,在光亮里也在风里,在你的沉默里也在你的笑声里。时间不会让你跟她合在一起,时间只会让你在我旁边,成为一个可以站着的人,一个愿意陪我走过同一条街、同一种气味、同一种阳光的人。
+于是我想给你那朵黄玫瑰的记忆。不是因为我想要你变成她的样子,而是因为我在你身上看见了自己喜欢的那种安静和从容。我想让你在今后的某一天,当公交门打开,站台忽然安静下来,当你走在一条熟悉的路上,风从树梢里穿过,当你坐在窗边,光从书页上滑过去的时候,能闻到那种味道,能想起那一刻的我们,我们在傍晚的风里站着,既不躲藏也不假装,我们把时间握在手里,像握着一朵温柔得让人不需要理由的花。
+如果你愿意,我可以每天傍晚经过花店门口,我们可以把那种味道带回家,用一只透明的瓶子装起来,不需要解释它来自哪里,也不需要把它和任何过去比较。它只会在你需要的时候出现,像一个老朋友,提醒你,不是每一次都要变成别人,不是每一次都需要证明你已经忘记。你可以是现在的你,我可以是现在的我。我们可以在同一个黄昏里站一会儿,看看天空从浅到深,看看风从我们旁边走过,看看影子在我们的脚边拉长。
+黄玫瑰的味道不会要求我们变成谁,它只会给我们一点轻的力气,让我们在时间里往前走走。我把这份力气给你,也给我自己,然后我们就接着往前走,带着这种不喧哗的光。
]]>他蜷缩在冰冷的水泥台上,看着自己的影子被月光钉死在斑驳的广告牌上。
"除夕快乐。"他对广告牌上褪色的月饼海报说。海报里笑得喜庆的孩子嘴角开裂,被寒风吹起一角。
雪落满了他的睫毛。
-]]> -花店里里有一支黄玫瑰,花瓣像被烫过,从橙黄到金黄,层层叠叠,在傍晚的空气里慢慢散开一层暖色。它有甜味,甜里还带着一点苦,味道朦胧的像你在窗下读书,书页翻过时有阳光落下来,像你走过老城的石板路,脚下的石头被晒得很暖。
-我记得那张粗糙的柜台,记得老板的手掌上有花叶的汁液。记得那种 “被允许站在这里” 的轻松。它没有要你改变什么,也没有给你安排一个更好的未来。它只是让你看见,一个傍晚可以用来想事,一条路可以一直往前延伸而不追问终点是什么。
-从那以后,我偶尔还会闻到那种味道。公交车拐弯的时候,风从窗缝里钻进来,地铁门打开的时候,站台上一阵匆忙的脚步后,忽然静下来的那一刻。我不知道它为什么会出现,也不刻意寻找。它像朋友一样,来了就坐一会儿,走了也不会留下地址。
-然后我遇见了你。
-起初我们并肩走在一条街上,街灯刚亮,影子从脚边拖到墙根。你说话的时候,声音不急也不慢。我听见了你的过去,但不是像在听故事那样去比较谁更动人,我只是听着你。你给我看了你的手心,那上面有被太阳晒过后的浅色纹理,也有你习惯把指甲剪得很短的认真。我心里有一种安静,它不是从谁那里借来的,而是像从很远的地方自己走来的。
-我知道你不是她,她是一种很亮的影子,只能在黑暗里存在。而你会在这里,在光亮里也在风里,在你的沉默里也在你的笑声里。时间不会让你跟她合在一起,时间只会让你在我旁边,成为一个可以站着的人,一个愿意陪我走过同一条街、同一种气味、同一种阳光的人。
-于是我想给你那朵黄玫瑰的记忆。不是因为我想要你变成她的样子,而是因为我在你身上看见了自己喜欢的那种安静和从容。我想让你在今后的某一天,当公交门打开,站台忽然安静下来,当你走在一条熟悉的路上,风从树梢里穿过,当你坐在窗边,光从书页上滑过去的时候,能闻到那种味道,能想起那一刻的我们,我们在傍晚的风里站着,既不躲藏也不假装,我们把时间握在手里,像握着一朵温柔得让人不需要理由的花。
-如果你愿意,我可以每天傍晚经过花店门口,我们可以把那种味道带回家,用一只透明的瓶子装起来,不需要解释它来自哪里,也不需要把它和任何过去比较。它只会在你需要的时候出现,像一个老朋友,提醒你,不是每一次都要变成别人,不是每一次都需要证明你已经忘记。你可以是现在的你,我可以是现在的我。我们可以在同一个黄昏里站一会儿,看看天空从浅到深,看看风从我们旁边走过,看看影子在我们的脚边拉长。
-黄玫瑰的味道不会要求我们变成谁,它只会给我们一点轻的力气,让我们在时间里往前走走。我把这份力气给你,也给我自己,然后我们就接着往前走,带着这种不喧哗的光。
]]>寄蜉蝣于天地,渺沧海之一粟。人类在宇宙面前的大小不比一只金鱼大多少,金鱼不会知道在它生活的空间只是一名人类的玻璃缸,人类也无法得知在其看来无边无际的宇宙是不是只是高等文明收藏的一颗琥珀。
思想——人的全部尊严就在于思想。
+]]>子弹退回枪膛,
+运动员回到起跑线上,
+我交回录取通知书,忘了十年寒窗。
厨房里飘来饭菜的香,
+你把我的卷子签好名字,
+关掉电视,帮我把书包背上。
你还在我身旁。
+功利性主义总会引导我们思考结局,可生活本质上就是一场旅途。
+别再去胡思乱想了,好好欣赏生活中的一切吧,去感受一朵鲜花的盛开,一束阳光的倾泻,一湖清水的静谧。
+奶奶说,炉膛的柴火若是爆裂,那是有贵客要登门了。我总是不信。直到有一次,舅公伴着柴火的爆裂声,出现在家门口,我才将信将疑。
+所以,让我们在下雨天烧柴火灶,在跳跃的火苗里,等待一种不确定的相逢,然后煮茶饮酒,自由一生 。
]]>子弹退回枪膛,
-运动员回到起跑线上,
-我交回录取通知书,忘了十年寒窗。
厨房里飘来饭菜的香,
-你把我的卷子签好名字,
-关掉电视,帮我把书包背上。
你还在我身旁。
-功利性主义总会引导我们思考结局,可生活本质上就是一场旅途。
-别再去胡思乱想了,好好欣赏生活中的一切吧,去感受一朵鲜花的盛开,一束阳光的倾泻,一湖清水的静谧。
-奶奶说,炉膛的柴火若是爆裂,那是有贵客要登门了。我总是不信。直到有一次,舅公伴着柴火的爆裂声,出现在家门口,我才将信将疑。
-所以,让我们在下雨天烧柴火灶,在跳跃的火苗里,等待一种不确定的相逢,然后煮茶饮酒,自由一生 。
]]>“拍了啊,倒数,三、二、一……茄子!”
咔擦,画面定格,幸福定格,大家终于从苦难里彻底毕业了。
萤火虫的微光与星空交相辉映,黑夜中潜滋暗长的花香沁人心脾,晚风挠过波光粼粼的海面,彼此相爱的人相拥而眠。
-]]> -libseccomp 绑定为例写的。
+CTypes 的核心概念是建立 OCaml 类型与 C 类型的双向映射,ctypes 中有如下基本类型:
+open Ctypes |
对于 C 的指针,CTypes 提供了多种指针表示:
+(* 通用指针:void* *) |
bonding 中的 seccomp_stubs.ml 中是这么写的:
+type scmp_filter_ctx = unit ptr |
这里 scmp_filter_ctx 是 libseccomp 的核心类型,它是一个不透明指针。C 库不暴露其内部结构,我们只能通过库函数操作它。使用 ptr void 是表示不透明指针的标准做法。
对于结构体,ctypes 通过 structure 和 field 函数定义:
(* 定义 C 结构体: |
注意:
+structure "name" 创建一个未完成的类型描述符field s "fieldname" typ 添加字段,返回字段访问器seal s 完成结构体定义,之后不可再添加字段s 可以作为类型使用例如:
+let scmp_arg_cmp : unit structure typ = |
定义结构体后,可以通过字段访问器读写值:
+(* 写入字段值 *) |
这里展示了如何创建辅助函数来操作结构体。注意:
+setf 的参数顺序:结构体指针、字段访问器、值使用 CTypes 绑定 C 库只需要:加载库、然后绑定函数。
+首先,加载共享库:
+let libseccomp = |
这段代码用了一个提升动态库加载稳定性的小技巧:
+注意 Dl.dlopen 的参数:
filename: 库文件名(可以是绝对路径或库文件名)flags: 加载标志
+RTLD_NOW: 立即解析所有符号RTLD_LAZY: 延迟解析符号加载完成后使用 Foreign.foreign 绑定到函数,基本语法:
let function_name = |
单参数函数:
+let seccomp_init = |
对应的 C 函数原型:
+scmp_filter_ctx seccomp_init(uint32_t def_action); |
Foreign.foreign 的参数:
~from:libseccomp: 指定函数所在的库"seccomp_init": C 函数名uint32_t @-> returning scmp_filter_ctx: 函数签名
+@-> 分隔参数returning 标记返回类型对于多参数函数:
+let seccomp_rule_add = |
C 函数原型:
+int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action, |
对于无参数函数:
+let seccomp_arch_native = |
对于指针参数:
+let seccomp_load = |
C 函数原型:
+int seccomp_load(scmp_filter_ctx ctx); |
对于字符串参数:
+let seccomp_syscall_resolve_name = |
这里 CTypes 会自动处理 OCaml 字符串与 C 字符串的转换。
+对于返回 NULL 的情况:
+let seccomp_syscall_resolve_num_arch = |
string_opt 处理可能返回 NULL 的字符串指针。
C 需要手动管理内存,CTypes 提供了相应的工具。
+分配单个值:
+(* 分配并初始化单个值 *) |
分配数组:
+(* 分配数组(未初始化) *) |
例如:
+let cmp_array = Ctypes.allocate_n Stubs.Types.scmp_arg_cmp ~count:n in |
let arr = allocate_n int ~count:10 |
例如:
+Stubs.Types.set_arg_cmp_values |
!@ 运算符解引用指针,+@ 进行指针算术。
(* 类型化指针转 void 指针 *) |
实例解析(seccomp.ml:96):
+if Ctypes.ptr_compare ctx Ctypes.null = 0 then |
检查 seccomp_init 是否返回了 NULL(失败)。
当 C 类型与 OCaml 类型不能直接对应时,使用 view 创建自定义转换:
(* 将 C int 转换为 OCaml bool *) |
在 seccomp 实现中,使用 OCaml 变体和转换函数映射 C 枚举:
+(* OCaml 端的类型定义(seccomp.ml:18-25) *) |
这种模式的优势:
+C 那边通常用返回值表示错误。OCaml 使用 result 类型,例如在 seccomp 的 binding 中我这么做:
+type error = |
让我们来看看一个完整的 rule_add_conditional 函数的实现:
let rule_add_conditional ctx action syscall cmps = |
allocate_n 分配 n 个 scmp_arg_cmp 结构体的空间cmp_array +@ i 获取第 i 个元素的指针!@ 解引用得到结构体set_arg_cmp_values 填充字段对应的 C API:
+int seccomp_rule_add_array(scmp_filter_ctx ctx, uint32_t action, |
seccomp 绑定用了清晰的三层架构:
+(* seccomp_stubs.ml 的模块组织 *) |
类型,常量,函数分离。
+C 分配的内存需要手动释放:
+(* 始终提供 release 函数 *) |
OCaml 和 C 的类型表示不同:
+(* 使用 Unsigned 模块的转换函数 *) |
C 函数可能返回 NULL:
+(* 始终检查返回的指针 *) |
C 返回的字符串生命周期不确定:
+(* 如果 C 返回需要释放的字符串,使用 string 并复制 *) |
let () = |
let () = |
let () = |