WebP Server in Rust

Generate WebP images for JPG / PNG files on-the-fly with Rust! BlueCocoa/webp_server_rs

Speaking of switching to WebP image, at the first glance, I just did it in a very naive approach.

Then @Nova wrote a Node.JS server that can serve JPG/PNGs as WebP format on-the-fly. You can find that at n0vad3v/webp_server.

A few days ago, @Nova and @Benny rewrite the WebP Server in Golang, webp-sh/webp_server_go

And that looks really promising, the size of the webp server, according to its description, had greatly reduced from 43 MB to 15 MB, and it is a single binary instead of webp_server with node_modules.

I cloned that project and added a tiny feature. However, I just found that although it is absolutely easy to implement the tiny feature, there is a potential design issue with the fasthttp module. In order to get everything work, it took me about 4 hours to debug on it.

Finally, it turned out to be a pointer of an internal variable (ctx.Request.uri, or so) was directly returned from ctx.Path(), and if users invoke ctx.SendFile(filepath), the ctx.Request.uri will be set to filepath, which will also propagate to all variables that hold the shared value of ctx.Path(). You may visit my previous blog post for details.

Well, in aforementioned blog post, I said that it would be better if it was written in Rust. Now, let's make it come true and push the WebP server even further.

There are some comparisons among n0vad3v/webp_server, webp-sh/webp_server_go and BlueCocoa/webp_server_rs.

As for size,

• webp_server(nodejs) with node_modules takes 43 MB
• webp-server(go) has reduced to 15 MB, and it's single binary
• webp-server(Rust) pushes that even further, only 3.6 MB on macOS and 6.4 MB on Linux

In terms of convenience, you can just download the binary file and run if you choose either webp-server(go) or webp-server(Rust). However, webp_server(nodejs) requires pm2 to run.

Performance, to be honest, I haven't got time to run some benchmarks on them. But IMHO it (webp-server(Rust)) should be as fast as golang version.

记 Golang 下遇到的一回「毫无由头」的内存更改

Nice PR, but there seems a little problem that the older converted images are not deleted after the change of the original image, this might cause a possible leakage of the original one's content.

[1]ImgName: webp_server.png
[2]ImgName: webp_server.png
[3]ImgName: webp_server.png
[4]ImgName: webp_server.png
[5]ImgName: root/webp_serve

ImgPath := c.Path()
// ... 略去 10 行左右判断文件扩展名的代码
ImgName := path.Base(ImgPath)

WebpImgPath := fmt.Sprintf("%s/%s.%d.webp", DirPath, ImgName, ModifiedTime)

从零开始的 Rust 学习笔记(19) —— Rewrite insert_dylib in Rust

insert_dylib 本身來說並不複雜，但因為不像 C/C++/Objective-C 裡那樣可以直接 #import <mach-o/loader.h> 等，於是 MachO 的一些 struct 就需要自己在 Rust 中重寫一遍～

src/macho/macho.rs 裡隨機選一個 struct 出來展示的話，大約就是如下這樣子

use super::prelude::*;

macro_rules! swap_bytes {
($self:ident,$field_name:ident) => {
$self.$field_name = $self.$field_name.swap_bytes();
};
}

pub trait FixMachOStructEndian {
fn fix_endian(&mut self);
}

#[derive(Debug)]
pub struct SymtabCommand {
pub cmd: u32,
pub cmdsize: u32,
pub symoff: u32,
pub nsyms: u32,
pub stroff: u32,
pub strsize: u32,
}

impl SymtabCommand {
pub fn from(buffer: [u8; 24], is_little_endian: bool) -> SymtabCommand {
let sc_buffer: [u32; 6] =
unsafe { std::mem::transmute_copy::<[u8; 24], [u32; 6]>(&buffer) };
let mut symtab_command = SymtabCommand {
cmd: sc_buffer[0],
cmdsize: sc_buffer[1],
symoff: sc_buffer[2],
nsyms: sc_buffer[3],
stroff: sc_buffer[4],
strsize: sc_buffer[5],
};

if is_little_endian {
symtab_command.fix_endian();
}

symtab_command
}

pub fn to_u8(&self) -> [u8; 24] {
let mut data: [u32; 6] = [0u32; 6];
data[0] = self.cmd;
data[1] = self.cmdsize;
data[2] = self.symoff;
data[3] = self.nsyms;
data[4] = self.stroff;
data[5] = self.strsize;

unsafe { std::mem::transmute_copy::<[u32; 6], [u8; 24]>(&data) }
}
}

impl FixMachOStructEndian for SymtabCommand {
fn fix_endian(&mut self) {
swap_bytes!(self, cmd);
swap_bytes!(self, cmdsize);
swap_bytes!(self, symoff);
swap_bytes!(self, nsyms);
swap_bytes!(self, stroff);
swap_bytes!(self, strsize);
}
}
Continue reading 从零开始的 Rust 学习笔记(19) —— Rewrite insert_dylib in Rust

Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

The Linked List is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:

• val: an integer representing Node.val
• random_index: the index of the node (range from 0 to n-1) where random pointer points to, or null if it does not point to any node.

Example 1:

Input: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
Output: [[7,null],[13,0],[11,4],[10,2],[1,0]]

Example 2:

Input: head = [[1,1],[2,1]]
Output: [[1,1],[2,1]]

Example 3:

Input: head = [[3,null],[3,0],[3,null]]
Output: [[3,null],[3,0],[3,null]]

Example 4:

Input: head = []
Output: []
Explanation: Given linked list is empty (null pointer), so return null.

Constraints:

• -10000 <= Node.val <= 10000
• Node.random is null or pointing to a node in the linked list.
• Number of Nodes will not exceed 1000.
Continue reading Copy List with Random Pointer

Integer to Roman

Roman numerals are represented by seven different symbols: IVXLCD and M.

For example, two is written as II in Roman numeral, just two one's added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

• I can be placed before V (5) and X (10) to make 4 and 9.
• X can be placed before L (50) and C (100) to make 40 and 90.
• C can be placed before D (500) and M (1000) to make 400 and 900.

Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 to 3999.