refactor(panel): 前后端按模块拆分+屏幕/控制合并页 — 后端meowpanel.c 6372行拆src/*.c+mp.h(235函数原型,20端点output byte-identical,0warning)+前端拆mp_shared/mp_pages/meowpanel三层;屏幕·遥控合并(左屏实时画面+右MD3 SVG矢量按钮无emoji);重编后热更TF卡

This commit is contained in:
AskaEth committed 2026-09-04 00:56:13 +08:00
1 parent f3ae06d7cd
commit 2dc4cad454
26 files changed
+9317 -2755

No files matched your search

+453
View File
@@ -0,0 +1,453 @@
/* mp.h — MeowPanel 后端共享内部头(模块化拆分后各 .c 共同包含)。
* 定位(MEOWPANEL_DESIGN §1/§2):外置于 TF 卡 `MeowOS/opt/MeowPanel/` 的系统组件
* (HTTP/JSON 后端 + 前端静态托管),由 meow_svcd 读 TF 卡 services.d 启动。**不进固件**。
* 这是拆分后的单一共享内部头:共享常量/类型/外部全局 + 所有跨模块函数原型。
* 各 api_* 域 / store / ipc / util / json / server 均以 `#include "mp.h"` 起步。
* 编译(mipsel 静态):build_meowpanel.sh;宿主编译 build_meowpanel.sh host。 */
#ifndef MP_H
#define MP_H
#define _GNU_SOURCE /* gethostname/strcasestr/strnlen 等 GNU/musl 扩展 */
/* meowpanel.c — MeowOS Web 面板后端(MeowPanel)。
*
* 定位(MEOWPANEL_DESIGN §1/§2):外置于 TF 卡 `MeowOS/opt/MeowPanel/` 的系统组件
* (HTTP/JSON 后端 + 前端静态托管),由 meow_svcd 读 TF 卡 `MeowOS/services.d/meowpanel.conf`
* 启动、meow_sysui 监管。**不进固件**;无卡时系统核心绝不对它有任何依赖。
*
* 架构(MEOWPANEL_PROTOCOL §1/§2 + SYSTEM_FRAMEWORK_SERVICES §4):
* - 单进程单线程 + poll 串行处理(面板访问量极小);内嵌 HTTP server。
* - 读侧(/api/status,/api/perf,/api/system)经 meow_svc_perf IPC(MSG_PERF_QUERY→RESULT)
* 聚合,**绝不各自爬 /proc**(单一权威源)。
* - 动作侧(/api/system/{reboot,shutdown,ota})经 meow_svc_power IPC(MSG_POWER_ACTION→STATUS),
* 不再直连 poweroff/写 mtd5。
* - 设置镜像(/api/settings*,/api/theme*)直接读写板载 /usr/data/meow/settings.conf——
* **与 meow_ui_vol_read / meow_svc_power settings_get_int_trim 同款解析**('=' 切分 +
* key 去首尾空白精确匹配;写用 "key = value\n")。后端是独立进程,无法链接 launcher 内的
* meow_settings_*(那是 launcher 进程内存表),故直接镜像文件,保持同一存储契约。
* - 文件/应用/日志/通知:白名单根 /usr/data/mnt/sd_0 下 MeowOS/Music/MeowData/MeowAPPs/book。
*
* 编译(mipsel 静态):build_meowpanel.sh;宿主编译 build_meowpanel.sh host。
* 依赖:仅 POSIX + libc(含 linux/input.h 内核头),零第三方库(mp_jpeg.c 自研最小 JPEG;
* 字体库导入/导出走 busybox `gzip -dc | tar` 管道——与 nyai .mpk 同构,设备必带 tar/gzip)。
* 设备无 python3/lua。
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h> /* strcasecmp/strncasecmp */
#include <stdarg.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <poll.h>
#include <time.h>
#include <ctype.h>
#include <dirent.h>
#include <limits.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/input.h> /* KEY_* / EV_KEY / EV_SYN / struct input_event(按键注入) */
#include "meow_ipc.h" /* 帧格式/消息号 + m_perf_query_t/m_perf_result_t + POWER_* 枚举 */
#include "mp_jpeg.h" /* 实时画面:RGB565 → 最小 baseline JPEG(自包含,零依赖) */
/* 实时画面 / 触摸注入(阶段 C)。fb ioctl 常量按 launcher fb_compositor 同款手工定义
* (避免 libc/kernel struct ABI 差异,读入裸字节缓冲再按偏移取字段)。 */
#ifndef FBIOGET_VSCREENINFO
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOGET_FSCREENINFO 0x4602
#endif
#ifndef FB_DEV
#define FB_DEV "/dev/fb0" /* 16bpp RGB565,480x720,双层虚拟缓冲 */
#endif
#ifndef TOUCH_DEV
#define TOUCH_DEV "/dev/input/event1" /* goodix-ts:接收 write() 注入(本机实测可投递) */
#endif
/* ---------------- 常量 ---------------- */
#define PANEL_VERSION "0.1"
#define DEFAULT_PORT 8080
#define SETTINGS_FILE "/usr/data/meow/settings.conf"
#define SETTINGS_HDR "# meow-settings 1"
#define TF_ROOT g_tf_root_buf
#define TF_CARD_DIR g_tf_card
#define MEOWAPPS_DIR g_apps_dir
#define LOGS_DIR g_logs_dir
#define PERF_SOCK "/usr/data/meow_perf.sock"
#define POWER_SOCK "/usr/data/meow_power.sock"
#define LAUNCHER_SOCK "/usr/data/meow_ipc.sock" /* launcher 主 IPC(通知活跃集查询/撤清) */
#define AUDIO_SOCK "/usr/data/meow_audio.sock" /* meow_audiod 状态快照(MSG_AUDIO_QUERY→STATE) */
#define NET_SOCK "/usr/data/meow_net.sock" /* meow_netmgrd 网络管理(MSG_NET_*,期2 观测层/DNS 代理) */
#define PM_SOCK "/usr/data/meow_pm.sock" /* meow_powermgr 功耗管理(MSG_PM_QUERY→RESULT) */
#define NYAI_PATH "/usr/bin/nyai" /* 固件内置(权威) */
#define NYAI_PATH_CARD "/usr/data/mnt/sd_0/MeowOS/opt/bin/nyai" /* 旧卡上路径(回退) */
#define AMS_BIN "/usr/bin/am" /* 固件内置 amsd 用户侧 CLI(权威) */
#define AMS_BIN_CARD "/usr/data/mnt/sd_0/MeowOS/opt/bin/am" /* 旧卡上路径(回退) */
#define SVCD_BIN "/usr/bin/meow_svcd" /* 固件内置 svcd 服务表 CLI(权威) */
#define SVCD_BIN_CARD "/usr/data/mnt/sd_0/MeowOS/opt/bin/meow_svcd" /* 旧卡上路径(回退) */
#define BOOT_DEFAULT_FILE "/data/meow_boot_default"
#define VERSION_FILE "/etc/meowos_version"
#define HOSTNAME_FILE ""
#define IPC_TIMEOUT_MS 2000
#define MAX_HTTP_HEADER (64 * 1024)
#define MAX_HTTP_BODY (16 * 1024 * 1024) /* 通用 body 上限(JSON/小件) */
#define MAX_UPLOAD_BODY (8 * 1024 * 1024) /* multipart 上传上限(14MB 内存约束:不整读超 8MB) */
#define MAX_FONT_UPLOAD (32 * 1024 * 1024) /* 字体库 tar.gz 上传上限(gbk 字库 png+idx 可能 10-20MB) */
#define MAX_JSON_IN 65536 /* JSON body 解析上限 */
#define MAX_STATIC_FREEBUF (2 * 1024 * 1024)
#define LOG_MAX_LINES 1000
#define NOTIF_PREVIEW_MAX 200 /* 通知列表返回上限(每条约 0.2KB,总 <50KB) */
#define TEXT_PREVIEW_MAX (1024 * 1024) /* 文本预览上限(超出截断,truncated=true;14MB 约束下 1MB 缓冲安全) */
#define PANEL_VOL_MAX_DEFAULT 100 /* 音频音量上限默认(对齐 meow_launcher MEOW_VOL_MAX_DEFAULT;设备可经 settings.conf audio.volume_max 覆盖) */
#define ALLOWED_COUNT ((int)(sizeof g_allowed_dirs / sizeof g_allowed_dirs[0]))
#define SENSITIVE_COUNT ((int)(sizeof g_sensitive_names / sizeof g_sensitive_names[0]))
#define SCREEN_BLOCK 8 /* 比对块边长(像素) */
#ifndef MSG_PM_POLICY_GET
#define MSG_PM_POLICY_GET 0x00D2 /* ↑ 策略读(空负载 → MSG_PM_RESULT policy JSON;读级任意调用者) */
#define MSG_PM_POLICY_SET 0x00D3 /* ↑ 策略写(req: m_pm_policy_set_t;动作级=root+系统身份) */
#define MSG_PM_HISTORY 0x00D4 /* ↑ 历史采样查询(req: u32 count,0=默认) */
#define MSG_PM_HISTORY_RESULT 0x00D5 /* ↓ 历史 JSON */
#define MSG_PM_EVENTS 0x00D6 /* ↑ 事件流查询(req: u32 count,0=默认) */
#define MSG_PM_EVENTS_RESULT 0x00D7 /* ↓ 事件 JSON */
#define MSG_PM_CALIB_START 0x00D8 /* ↑ 标定启动(动作级;本期面板不暴露,预留) */
#define MSG_PM_CALIB_STOP 0x00D9 /* ↑ 标定停止(动作级;预留) */
#endif
#define AUTH_TOKEN_BYTES 16 /* 128bit → 32 hex */
#define AUTH_TOKEN_TTL (3 * 86400) /* 3 天(固定,不滑动续期) */
#define AUTH_MAX_SESS 8 /* 内存最多保存的并发会话数 */
#define AUTH_HASH_LEN 64 /* sha256 hex 长度 */
/* ---------------- 有界动态字符串(sbuf) ---------------- */
typedef struct { char *b; size_t n; size_t cap; } sbuf_t;
/* ---------------- 最简 JSON 解析器(无第三方库) ----------------
* 只覆盖 MeowPanel 实际用到的:对象 / 数组 / 字符串(含转义) / 数字 / bool / null。
* value 树:J_OBJ 的 child 为键值对链(str=key,child=value,next=下个 pair);
* J_ARR 的 child 为元素链(next=下个元素)。
*/
enum { J_NULL, J_BOOL, J_NUM, J_STR, J_ARR, J_OBJ };
typedef struct jv {
int type;
int bval; /* J_BOOL */
long long inum; /* J_NUM 整数值 */
double dnum; /* J_NUM 浮点值 */
char *str; /* J_STR: 值; J_OBJ: key */
struct jv *child; /* J_ARR: 头; J_OBJ: 头 pair */
struct jv *next; /* 链 */
} jv_t;
typedef struct { const char *p; const char *end; int err; } jvp_t;
enum { ST_INT, ST_STR, ST_ENUM, ST_BOOL };
typedef struct setdef {
const char *key;
int type;
const char *def;
int min, max; /* ST_INT 取值域;max<=0 表示无上界 */
const char *enum_names; /* ST_ENUM 逗号名 */
const char *enum_labels; /* 对应中文 */
const char *group; /* 分组标签(协议 groups 用) */
} setdef_t;
/* 期 3 · 策略写负载(item="profile"/"low-pct"/"crit-pct"/"bri-cap"/"scr-cap")。 */
typedef struct m_pm_policy_set { char item[16]; char val[32]; } m_pm_policy_set_t; /* 48 B */
struct fent { char name[256]; int isdir; long long size, mtime; };
/* ---------------- HTTP 请求读取 ---------------- */
typedef struct {
char method[8];
char path[512]; /* 解码后的路径(不含 query) */
char query[1024]; /* 原始 query(key=value&…,未解码;取值时用 qparam) */
char *body;
size_t body_len;
char content_type[128]; /* 请求 Content-Type(若非空) */
char authorization[256]; /* Authorization 头(Bearer <token>) */
char x_meow_token[256]; /* X-MeowToken 头 */
char cookie[512]; /* Cookie 头(meow_token=<token> 等) */
} req_t;
typedef struct { char path[1400]; char filename[320]; } upfile_t;
typedef struct {
long long ms; /* created_ms(epoch ms) */
unsigned id;
char app_id[40];
char app_icon[64];
char category[40];
int urgency;
int progress; /* -1=无 */
char summary[96];
char body[128];
char target[64];
int ongoing, media, dismissed;
} notif_rec_t;
typedef struct { uint32_t state[8]; uint64_t count; uint8_t buf[64]; size_t buflen; } mp_sha256_ctx;
/* ---- 会话(**纯内存**:重启自然失效,无卡上持久化) ---- */
typedef struct { char token[65]; time_t expires; } auth_sess_t;
/* ---------------- 跨模块全局(extern;定义见各拥有模块 .c) ---------------- */
extern const char *g_settings_file;
extern char g_tf_root_buf[1024];
extern char g_tf_card_buf[2048], g_apps_dir_buf[2048], g_logs_dir_buf[2048], g_notif_log_buf[2048];
extern const char *g_tf_card, *g_apps_dir, *g_logs_dir, *g_notif_log;
extern const char *g_allowed_dirs[];
extern const char *g_sensitive_names[];
extern const char *g_sock_perf, *g_sock_power, *g_sock_launcher, *g_sock_audio, *g_sock_net, *g_sock_pm;
extern time_t g_auth_ttl;
/* ---------------- 函数原型(全部跨模块;无 static,避免 -Wunused-function) ---------------- */
void init_tf_paths(void);
int sb_reserve(sbuf_t *s, size_t extra);
void sA(sbuf_t *s, const char *fmt, ...);
int utf8_seq_len(unsigned char lead);
int json_strict_balanced(const char *b, size_t n);
int utf8_seq_ok(const char *p, int len);
int utf8_valid_n(const char *s, size_t n);
int utf8_sanitize(char *dst, const char *src, size_t n);
void sA_str_n(sbuf_t *s, const char *v, size_t n);
void sA_str(sbuf_t *s, const char *v);
void sA_append(sbuf_t *s, const char *b, size_t n);
void sbuf_free(sbuf_t *s);
jv_t *jv_alloc(int type);
void jv_free(jv_t *v);
void jvp_skip_ws(jvp_t *t);
char *jv_parse_string(jvp_t *t);
jv_t *jv_parse_object(jvp_t *t);
jv_t *jv_parse_array(jvp_t *t);
jv_t *jv_parse_value(jvp_t *t);
jv_t *jv_parse(const char *text, int len);
jv_t *jv_obj_get(const jv_t *obj, const char *key);
void jv_to_json(sbuf_t *s, const jv_t *v);
const setdef_t *setdef_find(const char *key);
void settings_mkdir_p(void);
char *settings_get_value(const char *key);
int settings_get_int(const char *key, int defv);
int brightness_clamp(int v);
int settings_write_one(const char *key, const char *val);
int settings_coerce(const setdef_t *d, const char *input, char *out, size_t outcap);
int settings_reset_all(void);
int x_read_full(int fd, uint8_t *buf, size_t n);
int x_write_full(int fd, const uint8_t *buf, size_t n);
int send_frame(int fd, uint16_t type, uint32_t req_id, const void *payload, uint32_t len);
int recv_frame(int fd, uint16_t *type, uint32_t *req_id, uint8_t *buf, uint32_t cap);
int ipc_connect_tmo(const char *sock, int tmo_ms);
int ipc_hello(int fd);
const char *perf_code_str(int code);
int perf_subset_for_path(const char *path);
int ipc_perf_query(int subset, char *out, int cap);
const char *power_code_str(int code);
int ipc_power_action(uint32_t cmd, uint32_t flag, const char *arg, m_power_status_t *out_st);
void svc_msg_kv(const char *msg, const char *key, char *out, size_t cap);
const char *audio_kv(const char *txt, const char *key, char *out, size_t cap);
long long audio_kv_ll(const char *txt, const char *key, long long defv);
int audio_vol_max(void);
void audio_fill(sbuf_t *s);
int api_audio(int sock);
int audio_write_cmd(uint16_t type, const void *pl, uint32_t len, m_ack_t *out);
int api_audio_route(int sock, const char *body, size_t body_len);
int api_audio_volume(int sock, const char *body, size_t body_len);
int api_audio_monitor(int sock, const char *query);
int ipc_pm_query(uint32_t subset, char *out, int cap);
int api_power(int sock);
int ipc_pm_send(uint16_t req_type, const void *pl, uint32_t plen, uint16_t *rtype, char *out, int cap);
int api_power_policy_get(int sock);
int api_power_policy_set(int sock, const char *body, size_t body_len);
int api_power_window(int sock, uint16_t req_type, uint16_t want_type, const char *unavail);
int api_power_history(int sock);
int api_power_events(int sock);
const char *ams_bin(void);
const char *svcd_bin(void);
int net_ipc(uint16_t req_type, const void *req, uint32_t req_len, uint16_t *ret_type, uint32_t *code, uint16_t *meta, char *out, size_t cap);
int api_net_status(int sock);
int net_conns_parse_body(sbuf_t *s, const char *txt);
int api_net_conns(int sock, const char *query);
int net_dns_obj_fill(sbuf_t *s);
int api_net_dns(int sock);
int net_block_fill(sbuf_t *s);
int api_net_dns_flush(int sock);
int api_net_log(int sock);
int api_net_ifaces(int sock);
void net_policy_parse(const char *txt, sbuf_t *s);
int api_net_policy_get(int sock);
int api_net_policy_set(int sock, const char *body, size_t body_len);
void panel_strip_ansi(char *s);
int txt_tokens(char *buf, char **toks, int maxtoks);
void join_tokens(char **toks, int from, int to, char *out, size_t cap);
void ams_fill(sbuf_t *s);
void ams_fg_fill(sbuf_t *s);
int api_ams(int sock);
int ams_pkg_ok(const char *pkg);
void ams_history_parse(char *out, sbuf_t *s, const char *pkg);
void ams_history_fill(sbuf_t *s, const char *pkg);
int api_ams_history(int sock, const char *pkg);
int api_ams_ctl(int sock, const char *pkg, int kill);
void svcd_fill(sbuf_t *s);
int api_svcd(int sock);
int api_overview(int sock);
int tf_present(void);
int path_in_whitelist(const char *abs);
int is_sensitive_name(const char *base);
int normalize_path(const char *in, char *buf, size_t buflen);
void make_rel(const char *abs, char *buf, size_t buflen);
int open_safe_for_read(const char *abs, int follow_rel);
void fmt_json_item(sbuf_t *s, const char *name, int isdir, long long size, long long mtime);
int nat_strcmp(const char *a, const char *b);
int fent_cmp(const void *a, const void *b);
int files_list(int sock, const char *relpath);
char *read_text_file_limited(const char *abs, long long *size, int *truncated);
int keycode_to_device(int code, const char **dev);
int inject_key_event(const char *dev, int code, int down);
int inject_key_release(int code, int press_ms);
int read_small_file(const char *path, char *buf, int cap);
int apps_scan_dir(const char *appdir, const char *name, sbuf_t *out, int want_detail);
void req_free(req_t *r);
int is_hex(char c);
int hexval(char c);
void url_decode(const char *in, char *buf, int buflen);
int qparam(const char *query, const char *key, char *out, int outcap);
int path_segment(const char *prefix, const char *full, char *out, int outcap);
void split_path_query(const char *src, char *path, int plc, char *query, int qlc);
ptrdiff_t find_header_end(const char *buf, size_t n);
int read_request(int sock, req_t *r);
void mp_sha256_init(mp_sha256_ctx *c);
void mp_sha256_block(mp_sha256_ctx *c, const uint8_t *p);
void mp_sha256_update(mp_sha256_ctx *c, const uint8_t *data, size_t len);
void mp_sha256_final(mp_sha256_ctx *c, uint8_t out[32]);
int auth_read_random(unsigned char *buf, size_t n);
void auth_hex(const unsigned char *raw, size_t n, char *out);
int auth_token_gen(char *out, int outcap);
int auth_make_salt(char *out, int outcap);
int auth_pass_hash(const char *salt, const char *password, char *out, int outcap);
int auth_make_hash(const char *password, char *out, int outcap);
int hash_matches(const char *stored, const char *password);
int pin_set(void);
int auth_pass_set(void);
int auth_verify(const char *password);
int pin_verify(const char *pin);
int pin_validate(const char *pin);
long long pin_lock_remaining(void);
void pin_lock_reset(void);
void pin_record_fail(void);
int sess_find(const char *token);
int sess_valid(const char *token);
void sess_add(const char *token, time_t expires);
void sess_remove(const char *token);
void auth_cp(char *dst, int dcap, const char *src);
int extract_token(const req_t *r, char *out, int outcap);
int require_auth(int sock, const req_t *r);
int api_auth_status(int sock, const req_t *r);
int api_auth_login(int sock, const req_t *r);
int api_auth_setup(int sock, const req_t *r);
int api_auth_logout(int sock, const req_t *r);
int write_full(int sock, const void *b, size_t n);
int send_head(int sock, int status, const char *ctype, long long clen, const char *extra);
int send_raw(int sock, int status, const char *ctype, const void *body, size_t bodylen);
int send_ok(int sock, const char *data);
int send_err(int sock, int status, const char *code, const char *msg);
int send_json(int sock, int status, const char *data);
int send_file(int sock, int status, const char *ctype, const char *abspath, const char *filename);
const char *mem_find(const void *hay, size_t hlen, const char *needle);
int safe_filename(const char *name, char *out, size_t cap);
int parse_multipart(const req_t *r, upfile_t *files, int maxfiles);
void panel_log(const char *fmt, ...);
int str_truthy(const char *v);
int int_meta_max(const setdef_t *d);
const char *csv_at(const char *s, int idx, char *buf, int buflen);
int csv_count(const char *s);
void enum_options_json(sbuf_t *s, const char *names, const char *labels);
void settings_item_json(sbuf_t *s, const setdef_t *d, const char *val);
char *settings_current_value(const setdef_t *d);
int api_settings_get_any(int sock, const char *key);
int api_settings_get_all(int sock);
int api_settings_put(int sock, const char *key, const req_t *r);
int api_settings_batch(int sock, const req_t *r);
int api_settings_restore(int sock);
void theme_json(sbuf_t *s);
int api_theme_get(int sock);
int api_theme_put(int sock, const req_t *r);
int api_perf(int sock, const char *path);
int perf_extract_network(const char *json, char *out, int cap);
int api_system(int sock);
int api_pin_unlock_once(int sock);
int api_system_action(int sock, const char *which, const req_t *r);
int api_key_single(int sock, int code, const req_t *r);
int api_key_batch(int sock, const req_t *r);
const char *log_group(const char *name);
int api_logs_list(int sock);
int api_logs_read(int sock, const req_t *r);
int api_logs_crash(int sock);
int notif_csv_field(const char **pp, char *out, int outcap);
int notif_parse_line(const char *line, notif_rec_t *r);
int notif_load_list(notif_rec_t *recs, int maxrec);
const char *notif_app_name(const char *app_id);
void notif_emit_item(sbuf_t *out, const notif_rec_t *r);
int notif_ipc_query(notif_rec_t *recs, int maxrec);
int notif_ipc_dismiss(unsigned id);
int notif_ipc_dismiss_all(int *out_count);
int api_notifications(int sock);
int notif_rewrite(int mode, unsigned del_id);
int api_notification_delete(int sock, unsigned id);
int api_notification_dismiss_all(int sock);
int api_files_list(int sock, const req_t *r);
int api_files_read(int sock, const req_t *r);
int api_files_download(int sock, const req_t *r);
int api_files_upload(int sock, const req_t *r);
int rm_recursive(const char *path);
int api_files_mkdir(int sock, const req_t *r);
int api_files_rename(int sock, const req_t *r);
int api_files_delete(int sock, const req_t *r);
void fonts_root(char *buf, size_t cap);
int safe_dir_segment(const char *s, char *out, size_t cap);
int unsafe_path(const char *s);
int has_dotdot_comp(const char *p);
int sanitize_member(const char *in, char *out, int n);
int mkdir_p(const char *path);
const jv_t *font_json_str(const jv_t *root, const char *key);
int api_fonts_list(int sock);
int sha256_file_hex(const char *path, char out[65]);
int api_fonts_import(int sock, const req_t *r);
int api_fonts_export(int sock, const req_t *r);
int run_cmd(const char *cmd, char *out, int outcap);
int api_apps_list(int sock);
int api_apps_info(int sock, const char *pkg);
int multipart_extract_file(const req_t *r, const char *outpath);
const char *nyai_bin(void);
int api_apps_install(int sock, const req_t *r);
int api_apps_export(int sock, const char *pkg);
int api_apps_remove(int sock, const char *pkg, const req_t *r);
int screen_read_frame(const char *dev, uint8_t **out, int *w, int *h);
int fb_dims(const char *dev, int *w, int *h);
void screen_prev_store(const uint8_t *frame, int w, int h);
int screen_diff_blocks(const uint8_t *cur, const uint8_t *prev, int w, int h, int *bx, int *by, int *bw, int *bh, int *total_blocks);
int api_screen_jpeg(int sock, const req_t *r);
int64_t now_mono_ms(void);
int64_t touch_last_local_ms(const char *dev);
int inject_tap(const char *dev, int x, int y);
int api_input_tap(int sock, const req_t *r);
const char *web_root(void);
const char *mime_for(const char *path);
int serve_static(int sock, const char *path);
int handle(int sock, req_t *r);
int read_port_config(void);
void handle_conn(int sock);
int panel_selftest(void);
int main(int argc, char **argv);
#endif /* MP_H */