2.7 KiB
2.7 KiB
12. ucode Programming Patterns & Conventions
A developer's guide to writing safe, high-performance, and idiomatic ucode modules for Tachyon on OpenWrt.
1. ucode vs JavaScript: Critical Distinctions
While ucode syntax resembles JavaScript, its runtime semantics differ significantly:
- Variables & Scope:
- Always declare variables with
letorconst. - Unassigned variables are
null(notundefined).
- Always declare variables with
- Arrays vs Dictionaries:
- Arrays:
[1, 2, 3]. Iterated withfor (let item in array). - Dictionaries (Objects):
{"key": "value"}. Iterated withfor (let key, val in dict).
- Arrays:
- Regular Expressions:
- Use
match(str, /regex/)orreplace(str, /regex/g, "replacement"). - Global flag
/gworks withreplace(), whilematch()returns capture groups array[full_match, group1, ...].
- Use
- Boolean Coercion:
- Empty strings
"",0, andnullare falsy. Everything else is truthy.
- Empty strings
2. Mandatory Core Design Patterns
2.1. Atomic Configuration Writes
Never overwrite active configuration files in-place. Always write to a temporary file in /tmp/ and atomically rename:
let fs = require("fs");
function write_atomic(path, content) {
let tmp_path = path + ".tmp." + int(time());
let f = fs.open(tmp_path, "w");
if (!f) return false;
f.write(content);
f.close();
return fs.rename(tmp_path, path);
}
2.2. Shell Argument Quoting
When executing external shell commands, all user inputs must be quoted safely:
function shell_quote(value) {
return "'" + replace("" + value, /'/g, "'\\''") + "'";
}
function safe_exec(cmd_args) {
let parts = [];
for (let arg in cmd_args)
push(parts, shell_quote(arg));
return system(join(" ", parts));
}
2.3. Safe Error Handling (try-catch)
All external library loading or file parsing must be wrapped in try-catch blocks to avoid unhandled script panics:
let uci_data = null;
try {
let uci = require("uci").cursor();
uci_data = uci.get_all("tachyon", "settings");
}
catch (e) {
warn("Failed to load UCI settings: " + e + "\n");
}
3. Performance & Memory Optimization Guidelines
- Stream Large Files: Avoid loading multi-megabyte blocklists entirely into RAM with
fs.readfile(). Use line-by-line streaming viafs.open()andf.read("line"). - Avoid Spawning Subprocesses in Loops: Invoking
system()orfs.popen()spawns a fork-exec sequence in Linux. Use native ucode functions for string manipulation and path operations whenever possible. - Keep Modules Stateless: Module files under
usr/lib/tachyon/should export reusable pure functions or class definitions rather than maintaining mutable global state.