Shuttle CCH24 记录帖

Shuttle CCH24 全称 Shuttle Christmas Code Hunt 2024,官方描述如下:

“Shuttlings” (inspired by rustlings) are hands-on code challenges we made for learning the basics of backend development in Rust and using the Shuttle platform.

Christmas Code Hunt is a set of Rust challenges where you build a web server for helping Santa get prepared for Christmas. Open the tutorial challenge (-1) for a guide on how to get started! Complete all challenges by December 31 to have a chance to win prizes!

大致就是圣诞节前的几天逐步开放一些 Rust challenges,全做完就能参与抽奖。笔者长期没有实践编码,技巧生疏,借着这个机会尝试重拾编码的乐趣。本帖是笔者参与该活动的记录。

Day -1 的挑战主要是练习使用 Shuttle 平台和相关的 Web server 库,由于本次挑战的提交全部都是采用构建 Web server 的形式,这部分知识是必要的。Rust 的相关生态相对丰富,笔者选用 Axum 进行游玩。

Day -1 的挑战也很简单,输出一些最基本的 HTTP 响应即可,基本上没有难度。

接下来看 Day 2 的挑战。我实际上开始玩的时候已经是 Day 3 了,不过没有关系,只有 2, 5, 9, 12, 16, 19, 23 这些日子有新的挑战开放。笔者 把这些数字扔 OEIS 查了查,也没看出什么名堂,大概真的只是圣诞倒计时。

Day 2 的挑战主要和 IP 有关,大概就是做些加加减减的小学数学。笔者随便截了张图放在上面。按照题意的话,只需要把 IP 的每个部分分别加加减减一下就好了。笔者有些好奇这种做法在实际生活中有没有用到,但实在兴趣缺缺,也就没有自行查阅资料。

这个挑战的每一天都有一个额外的 bonus part,不做也算任务完成,但做了能获得少许加分。笔者为了充分享受这个挑战的过程,尽量都会去试一试。Day 2 的 bonus part 主要是引入了 IPv6 的一个 XOR,做法上似乎没有什么不同,况且最难的解析与构造 IPv6 地址都有现成的库函数实现,于是很快也实现出来了。

由于编码时心态比较随便,看起来像:poop:山。

最后放一张 Day 2 通关证明:

P.S. 发这个帖子的时候 Day 5 也已经开放并被笔者收拾掉了,目前的心情还是很愉快的。时间有些晚了,Day 5 的记录就留待下次吧。

9 Likes

帅的,我也做做看


想打了

我也想打

蹲一个开奖

Day 5 主要是做 manifest 解析,需要接收一个 POST 上来的纯文本 Cargo.toml 格式数据,解析出 package.metadata.orders 部分。

反应快的小伙伴可能读完 task 1 就开始用工具生成对应的 scheme 了,但笔者的习惯是先看完所有 tasks,以便确定设计到何种粒度。这里对于 scheme 的要求是“Cargo manifest”,遂 add 一个 cargo-manifest 的 dependency,这样也就不用手写 scheme 了。把 plaintext 做成一个 Manifest 对象,然后随便怎么数据操作都很 easy。

bonus part 要求推广到 YAML 和 JSON 格式,这可以简单地用对应格式的 serde integration 来实现。serde_yaml 竟然已经因为作者没有需求而不维护了,几经查找决定用 serde_yml。这一天的挑战还是比较 straightforward 的。

笔者在写代码的时候感觉到这个 scheme 里成吨的 Option<T> 有一点卡手,也许是打开方式不对,没有细想。无论如何,it works. 最后还是放一张 Day 5 的通关证明:

下一个挑战应该是 9 号开放,暂且拭目以待。

3 Likes

一个小插曲,笔者刚刚重新审视了 serde_yml,发现这玩意比较可疑。具体来讲,它干掉了 unsafe-libyaml 这个依赖,然后加上了一个 libyml

unsafe-libyamlserde_yaml 的作者是同一人,即放弃维护这些 YAML 相关项目的 dtolnay;libymlserde_yml 的“作者”也是同一人,是 fork 了 dtolnay 这两个项目的 sebastienrousseau。后者的 id 也太长了,笔者暂且叫他 S 先生。

由于好奇,笔者 compare 了 unsafe-libyamllibyml,先看看 Cargo.toml 都改了啥:

这可太厉害了。对于一个 fork 来的项目,S 先生完全删掉了原作者,简直是厚颜无耻;对于一个仅仅是 c2rust 翻译过来的东西,S 先生大言不惭地 claim 它 “safe and efficient”,简直是精神错乱。

S 先生把原项目 fork 过来具体加了什么新的 features 笔者暂时不得而知,maybe just “code refactoring and new unit tests”。尽管如此,它在 crates.io 中 yaml 关键词下的最近下载排名已经到达了第四位,十分具有迷惑性。

综合 S 先生的各种 overclaim,笔者做出了换回 serde_yaml 的决定。希望笔者今天所看到的这些 overclaim 只是因为 S 先生还没有完全完成他的大业,而不是另有所图。

6 Likes

Day 9 启动!目前耗费时长最多、调试开销最大的挑战。一个 rate limiter,缝合奇妙单位换算。先放成功截图:

要求给 endpoint 加 rate limit,每 5 秒允许 5 次,所谓的“漏桶算法”,用 leaky-bucket 即可实现。

恶心就恶心在同一个 endpoint 有多种模式,JSON 的逻辑和不带 body 的逻辑完全不一样,却要共用路由;单位换算的公式也不给,只能自己查资料,查出巨量恶心小数。

bonus part 要实现一个 refill 功能,leaky-bucket 本身没有这个功能,手搓不太可能,加 Mutex 用重初始化代替草草了事。

哪怕是娱乐玩法,公式也是可以给一给的,笔者真的一点也不想知道 liters, gallons, litres, pints 这些单位之间的关系。

3 Likes

牛逼

1 Like

milk 可以接收 payload: Result<Json<>, JsonRejection<>>

JsonRejection 是个 enum,里面有一个 MissingContentTypeHeader,match 到这一分支就 acquire milk,match 到其他错误就 400 Bad Request。所以不用读 headers

现代英制单位是拿公制单位定义的,所以可以精准换算,就是小数比较长(

1 Like

Day 12: Connect 4 小游戏,一张有意思的视觉图:

玩法就是有 4x4 的格子,每一方可以选择(未满的)某一列,在该列的顶上放上 :cookie: 或者 :milk_glass: 。大概像这样:

比前一次好得多的一个挑战。一顿狂写之后解决。笔者现在已经把至今为止的 solutions 全部 push 到 GitHub 上,欢迎感兴趣的朋友们来交流:

最后仍然是一如既往的通关证明,生活中需要正反馈:

6 Likes

我小学时候玩过类似的玩具,可能是 6 \times 6 的或者 8 \times 8 的 :smile_cat: 规则好像是四子棋(五子棋的简略版)不知道你的这个游戏是否有斜向获胜这个赢法

1 Like

确实好有意思,感觉像是早八套餐,上面是奶糖,下面是小面包,迟到了就抓起一包拿到教室吃……

2 Likes

是有的,你说的游戏我也玩过 :hugging_face_cat:

1 Like

Day 16 太累了,且有别的优先级更高的事,所以没有当天立即开。现在补上。

这次的 Tasks 出奇简单,就是 JWT,纯送。笔者作为万年互联网搬砖调包侠,做这种既不恶心人又没有很多流程的题就是随便写写的事。

今天写代码有 buff 加成:室友剩了小半瓶二锅头,可以先喝再写甚至边喝边写,如有神助。如图。

看瓶子上写的 42%vol,感觉已经不低了。写代码而言的话,笔者更喜欢配不超过 15%vol 的酒,能够喝得相对频繁一点也不上头。

Day 16 挑战的 bouns task 给了 200 分,比前几天的 75 更上了一个档次,实际上难度也确实提高了。题目没有把所有的细节说清楚,而是需要一定的探索。给了一个额外的 PEM 文件作为解码 JWT 的 key,但是没有具体说使用什么算法。当然这也构不成什么阻碍,一通调试也就搞定了。

最后仍然是通关证明:

4 Likes

怎么没后续了(
今天至少把 core tasks 做完了,可以参与抽奖,赚到(

后续是去和女友玩了,烂尾

3 Likes

草。