queue-sqlite
Advanced tools
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : to_json_utils.py | ||
| @Time : 2025-09-27 16:36:18 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : xxxxxxxxx | ||
| """ | ||
| import sqlite3 | ||
| import json | ||
| import tkinter as tk | ||
| from tkinter import ttk, filedialog, messagebox | ||
| from datetime import datetime | ||
| class SQLiteToJSONConverter: | ||
| def __init__(self, root): | ||
| self.root = root | ||
| self.root.title("SQLite 表转 JSON 工具") | ||
| self.root.geometry("800x600") | ||
| # 变量 | ||
| self.db_path = tk.StringVar() | ||
| self.tables = [] | ||
| self.selected_table = tk.StringVar() | ||
| self.create_widgets() | ||
| def create_widgets(self): | ||
| # 主框架 | ||
| main_frame = ttk.Frame(self.root, padding="10") | ||
| main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # type: ignore | ||
| # 数据库选择部分 | ||
| db_frame = ttk.LabelFrame(main_frame, text="数据库选择", padding="5") | ||
| db_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5) # type: ignore | ||
| ttk.Entry(db_frame, textvariable=self.db_path, width=70).grid( | ||
| row=0, column=0, padx=5 | ||
| ) | ||
| ttk.Button(db_frame, text="浏览", command=self.browse_db).grid( | ||
| row=0, column=1, padx=5 | ||
| ) | ||
| ttk.Button(db_frame, text="连接", command=self.connect_db).grid( | ||
| row=0, column=2, padx=5 | ||
| ) | ||
| # 表选择部分 | ||
| table_frame = ttk.LabelFrame(main_frame, text="表选择", padding="5") | ||
| table_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5) # type: ignore | ||
| ttk.Label(table_frame, text="选择表:").grid(row=0, column=0, sticky=tk.W) | ||
| self.table_combo = ttk.Combobox( | ||
| table_frame, textvariable=self.selected_table, state="readonly" | ||
| ) | ||
| self.table_combo.grid(row=0, column=1, sticky=(tk.W, tk.E), padx=5) # type: ignore | ||
| ttk.Button(table_frame, text="加载数据", command=self.load_table_data).grid( | ||
| row=0, column=2, padx=5 | ||
| ) | ||
| # 数据显示部分 | ||
| data_frame = ttk.LabelFrame(main_frame, text="表数据", padding="5") | ||
| data_frame.grid( | ||
| row=2, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5 # type: ignore | ||
| ) | ||
| # 创建Treeview显示数据 | ||
| columns = ("#0",) | ||
| self.tree = ttk.Treeview(data_frame, columns=columns, show="headings") | ||
| vsb = ttk.Scrollbar(data_frame, orient="vertical", command=self.tree.yview) | ||
| hsb = ttk.Scrollbar(data_frame, orient="horizontal", command=self.tree.xview) | ||
| self.tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set) | ||
| self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # type: ignore | ||
| vsb.grid(row=0, column=1, sticky=(tk.N, tk.S)) # type: ignore | ||
| hsb.grid(row=1, column=0, sticky=(tk.W, tk.E)) # type: ignore | ||
| # 按钮部分 | ||
| button_frame = ttk.Frame(main_frame) | ||
| button_frame.grid(row=3, column=0, columnspan=2, pady=10) | ||
| ttk.Button(button_frame, text="导出为JSON", command=self.export_to_json).pack( | ||
| side=tk.LEFT, padx=5 | ||
| ) | ||
| ttk.Button(button_frame, text="清空", command=self.clear_all).pack( | ||
| side=tk.LEFT, padx=5 | ||
| ) | ||
| ttk.Button(button_frame, text="退出", command=self.root.quit).pack( | ||
| side=tk.LEFT, padx=5 | ||
| ) | ||
| # 配置权重 | ||
| self.root.columnconfigure(0, weight=1) | ||
| self.root.rowconfigure(0, weight=1) | ||
| main_frame.columnconfigure(0, weight=1) | ||
| main_frame.rowconfigure(2, weight=1) | ||
| data_frame.columnconfigure(0, weight=1) | ||
| data_frame.rowconfigure(0, weight=1) | ||
| def browse_db(self): | ||
| file_path = filedialog.askopenfilename( | ||
| title="选择SQLite数据库文件", | ||
| filetypes=[ | ||
| ("SQLite数据库", "*.db *.sqlite *.sqlite3"), | ||
| ("所有文件", "*.*"), | ||
| ], | ||
| ) | ||
| if file_path: | ||
| self.db_path.set(file_path) | ||
| def connect_db(self): | ||
| if not self.db_path.get(): | ||
| messagebox.showerror("错误", "请先选择数据库文件") | ||
| return | ||
| try: | ||
| conn = sqlite3.connect(self.db_path.get()) | ||
| cursor = conn.cursor() | ||
| # 获取所有表名 | ||
| cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") | ||
| self.tables = [table[0] for table in cursor.fetchall()] | ||
| self.table_combo["values"] = self.tables | ||
| if self.tables: | ||
| self.selected_table.set(self.tables[0]) | ||
| conn.close() | ||
| messagebox.showinfo( | ||
| "成功", f"成功连接到数据库,找到 {len(self.tables)} 个表" | ||
| ) | ||
| except sqlite3.Error as e: | ||
| messagebox.showerror("数据库错误", f"连接数据库时出错: {str(e)}") | ||
| def load_table_data(self): | ||
| if not self.selected_table.get(): | ||
| messagebox.showerror("错误", "请先选择表") | ||
| return | ||
| try: | ||
| conn = sqlite3.connect(self.db_path.get()) | ||
| conn.row_factory = sqlite3.Row # 这样可以使用列名访问数据 | ||
| cursor = conn.cursor() | ||
| # 获取表数据 | ||
| cursor.execute(f"SELECT * FROM {self.selected_table.get()}") | ||
| rows = cursor.fetchall() | ||
| # 清空Treeview | ||
| for item in self.tree.get_children(): | ||
| self.tree.delete(item) | ||
| # 设置列 | ||
| columns = [description[0] for description in cursor.description] | ||
| self.tree["columns"] = columns | ||
| for col in columns: | ||
| self.tree.heading(col, text=col) | ||
| self.tree.column(col, width=100, minwidth=50) | ||
| # 添加数据 | ||
| for row in rows: | ||
| self.tree.insert("", "end", values=tuple(row)) | ||
| conn.close() | ||
| except sqlite3.Error as e: | ||
| messagebox.showerror("数据库错误", f"加载数据时出错: {str(e)}") | ||
| def export_to_json(self): | ||
| if not self.selected_table.get(): | ||
| messagebox.showerror("错误", "请先选择表") | ||
| return | ||
| # 选择保存位置 | ||
| file_path = filedialog.asksaveasfilename( | ||
| title="保存JSON文件", | ||
| defaultextension=".json", | ||
| filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")], | ||
| ) | ||
| if not file_path: | ||
| return | ||
| try: | ||
| conn = sqlite3.connect(self.db_path.get()) | ||
| conn.row_factory = sqlite3.Row # 使用列名访问数据 | ||
| cursor = conn.cursor() | ||
| # 获取表数据 | ||
| cursor.execute(f"SELECT * FROM {self.selected_table.get()}") | ||
| rows = cursor.fetchall() | ||
| # 转换为字典列表 | ||
| result = [dict(row) for row in rows] | ||
| # 写入JSON文件 | ||
| with open(file_path, "w", encoding="utf-8") as f: | ||
| json.dump(result, f, indent=4, ensure_ascii=False) | ||
| conn.close() | ||
| messagebox.showinfo("成功", f"数据已成功导出到 {file_path}") | ||
| except sqlite3.Error as e: | ||
| messagebox.showerror("数据库错误", f"导出数据时出错: {str(e)}") | ||
| except Exception as e: | ||
| messagebox.showerror("错误", f"保存文件时出错: {str(e)}") | ||
| def clear_all(self): | ||
| self.db_path.set("") | ||
| self.tables = [] | ||
| self.table_combo["values"] = [] | ||
| self.selected_table.set("") | ||
| for item in self.tree.get_children(): | ||
| self.tree.delete(item) | ||
| self.tree["columns"] = ("#0",) | ||
| if __name__ == "__main__": | ||
| root = tk.Tk() | ||
| app = SQLiteToJSONConverter(root) | ||
| root.mainloop() |
| /target | ||
| # Byte-compiled / optimized / DLL files | ||
| __pycache__/ | ||
| .pytest_cache/ | ||
| *.py[cod] | ||
| # C extensions | ||
| *.so | ||
| # Distribution / packaging | ||
| .Python | ||
| .venv/ | ||
| env/ | ||
| bin/ | ||
| build/ | ||
| develop-eggs/ | ||
| dist/ | ||
| eggs/ | ||
| lib/ | ||
| lib64/ | ||
| parts/ | ||
| sdist/ | ||
| var/ | ||
| include/ | ||
| man/ | ||
| venv/ | ||
| *.egg-info/ | ||
| .installed.cfg | ||
| *.egg | ||
| # Installer logs | ||
| pip-log.txt | ||
| pip-delete-this-directory.txt | ||
| pip-selfcheck.json | ||
| # Unit test / coverage reports | ||
| htmlcov/ | ||
| .tox/ | ||
| .coverage | ||
| .cache | ||
| nosetests.xml | ||
| coverage.xml | ||
| # Translations | ||
| *.mo | ||
| # Mr Developer | ||
| .mr.developer.cfg | ||
| .project | ||
| .pydevproject | ||
| # Rope | ||
| .ropeproject | ||
| # Django stuff: | ||
| *.log | ||
| *.pot | ||
| .DS_Store | ||
| # Sphinx documentation | ||
| docs/_build/ | ||
| # PyCharm | ||
| .idea/ | ||
| # VSCode | ||
| .vscode/ | ||
| # Pyenv | ||
| .python-version |
Sorry, the diff of this file is not supported yet
| # This file is automatically @generated by Cargo. | ||
| # It is not intended for manual editing. | ||
| version = 4 | ||
| [[package]] | ||
| name = "addr2line" | ||
| version = "0.24.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" | ||
| dependencies = [ | ||
| "gimli", | ||
| ] | ||
| [[package]] | ||
| name = "adler2" | ||
| version = "2.0.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" | ||
| [[package]] | ||
| name = "ahash" | ||
| version = "0.8.12" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "once_cell", | ||
| "version_check", | ||
| "zerocopy", | ||
| ] | ||
| [[package]] | ||
| name = "android-tzdata" | ||
| version = "0.1.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" | ||
| [[package]] | ||
| name = "android_system_properties" | ||
| version = "0.1.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" | ||
| dependencies = [ | ||
| "libc", | ||
| ] | ||
| [[package]] | ||
| name = "autocfg" | ||
| version = "1.5.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" | ||
| [[package]] | ||
| name = "backtrace" | ||
| version = "0.3.75" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" | ||
| dependencies = [ | ||
| "addr2line", | ||
| "cfg-if", | ||
| "libc", | ||
| "miniz_oxide", | ||
| "object", | ||
| "rustc-demangle", | ||
| "windows-targets", | ||
| ] | ||
| [[package]] | ||
| name = "bitflags" | ||
| version = "2.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" | ||
| [[package]] | ||
| name = "block-buffer" | ||
| version = "0.10.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" | ||
| dependencies = [ | ||
| "generic-array", | ||
| ] | ||
| [[package]] | ||
| name = "bumpalo" | ||
| version = "3.19.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" | ||
| [[package]] | ||
| name = "cc" | ||
| version = "1.2.31" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" | ||
| dependencies = [ | ||
| "shlex", | ||
| ] | ||
| [[package]] | ||
| name = "cfg-if" | ||
| version = "1.0.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" | ||
| [[package]] | ||
| name = "chrono" | ||
| version = "0.4.41" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" | ||
| dependencies = [ | ||
| "android-tzdata", | ||
| "iana-time-zone", | ||
| "js-sys", | ||
| "num-traits", | ||
| "wasm-bindgen", | ||
| "windows-link", | ||
| ] | ||
| [[package]] | ||
| name = "core-foundation-sys" | ||
| version = "0.8.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" | ||
| [[package]] | ||
| name = "cpufeatures" | ||
| version = "0.2.17" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" | ||
| dependencies = [ | ||
| "libc", | ||
| ] | ||
| [[package]] | ||
| name = "crypto-common" | ||
| version = "0.1.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" | ||
| dependencies = [ | ||
| "generic-array", | ||
| "typenum", | ||
| ] | ||
| [[package]] | ||
| name = "digest" | ||
| version = "0.10.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" | ||
| dependencies = [ | ||
| "block-buffer", | ||
| "crypto-common", | ||
| ] | ||
| [[package]] | ||
| name = "fallible-iterator" | ||
| version = "0.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" | ||
| [[package]] | ||
| name = "fallible-streaming-iterator" | ||
| version = "0.1.9" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" | ||
| [[package]] | ||
| name = "generic-array" | ||
| version = "0.14.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" | ||
| dependencies = [ | ||
| "typenum", | ||
| "version_check", | ||
| ] | ||
| [[package]] | ||
| name = "getrandom" | ||
| version = "0.3.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "libc", | ||
| "r-efi", | ||
| "wasi 0.14.2+wasi-0.2.4", | ||
| ] | ||
| [[package]] | ||
| name = "gimli" | ||
| version = "0.31.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" | ||
| [[package]] | ||
| name = "hashbrown" | ||
| version = "0.14.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" | ||
| dependencies = [ | ||
| "ahash", | ||
| ] | ||
| [[package]] | ||
| name = "hashlink" | ||
| version = "0.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" | ||
| dependencies = [ | ||
| "hashbrown", | ||
| ] | ||
| [[package]] | ||
| name = "heck" | ||
| version = "0.5.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | ||
| [[package]] | ||
| name = "iana-time-zone" | ||
| version = "0.1.63" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" | ||
| dependencies = [ | ||
| "android_system_properties", | ||
| "core-foundation-sys", | ||
| "iana-time-zone-haiku", | ||
| "js-sys", | ||
| "log", | ||
| "wasm-bindgen", | ||
| "windows-core", | ||
| ] | ||
| [[package]] | ||
| name = "iana-time-zone-haiku" | ||
| version = "0.1.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" | ||
| dependencies = [ | ||
| "cc", | ||
| ] | ||
| [[package]] | ||
| name = "indoc" | ||
| version = "2.0.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" | ||
| [[package]] | ||
| name = "io-uring" | ||
| version = "0.7.10" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" | ||
| dependencies = [ | ||
| "bitflags", | ||
| "cfg-if", | ||
| "libc", | ||
| ] | ||
| [[package]] | ||
| name = "itoa" | ||
| version = "1.0.15" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" | ||
| [[package]] | ||
| name = "js-sys" | ||
| version = "0.3.77" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" | ||
| dependencies = [ | ||
| "once_cell", | ||
| "wasm-bindgen", | ||
| ] | ||
| [[package]] | ||
| name = "libc" | ||
| version = "0.2.174" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" | ||
| [[package]] | ||
| name = "libsqlite3-sys" | ||
| version = "0.30.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" | ||
| dependencies = [ | ||
| "cc", | ||
| "pkg-config", | ||
| "vcpkg", | ||
| ] | ||
| [[package]] | ||
| name = "lock_api" | ||
| version = "0.4.13" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" | ||
| dependencies = [ | ||
| "autocfg", | ||
| "scopeguard", | ||
| ] | ||
| [[package]] | ||
| name = "log" | ||
| version = "0.4.27" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" | ||
| [[package]] | ||
| name = "memchr" | ||
| version = "2.7.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" | ||
| [[package]] | ||
| name = "memoffset" | ||
| version = "0.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" | ||
| dependencies = [ | ||
| "autocfg", | ||
| ] | ||
| [[package]] | ||
| name = "miniz_oxide" | ||
| version = "0.8.9" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" | ||
| dependencies = [ | ||
| "adler2", | ||
| ] | ||
| [[package]] | ||
| name = "mio" | ||
| version = "1.0.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" | ||
| dependencies = [ | ||
| "libc", | ||
| "wasi 0.11.1+wasi-snapshot-preview1", | ||
| "windows-sys", | ||
| ] | ||
| [[package]] | ||
| name = "num-traits" | ||
| version = "0.2.19" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" | ||
| dependencies = [ | ||
| "autocfg", | ||
| ] | ||
| [[package]] | ||
| name = "object" | ||
| version = "0.36.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" | ||
| dependencies = [ | ||
| "memchr", | ||
| ] | ||
| [[package]] | ||
| name = "once_cell" | ||
| version = "1.21.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" | ||
| [[package]] | ||
| name = "parking_lot" | ||
| version = "0.12.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" | ||
| dependencies = [ | ||
| "lock_api", | ||
| "parking_lot_core", | ||
| ] | ||
| [[package]] | ||
| name = "parking_lot_core" | ||
| version = "0.9.11" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "libc", | ||
| "redox_syscall", | ||
| "smallvec", | ||
| "windows-targets", | ||
| ] | ||
| [[package]] | ||
| name = "pin-project-lite" | ||
| version = "0.2.16" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" | ||
| [[package]] | ||
| name = "pkg-config" | ||
| version = "0.3.32" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" | ||
| [[package]] | ||
| name = "portable-atomic" | ||
| version = "1.11.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" | ||
| [[package]] | ||
| name = "ppv-lite86" | ||
| version = "0.2.21" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" | ||
| dependencies = [ | ||
| "zerocopy", | ||
| ] | ||
| [[package]] | ||
| name = "proc-macro2" | ||
| version = "1.0.95" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" | ||
| dependencies = [ | ||
| "unicode-ident", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a" | ||
| dependencies = [ | ||
| "indoc", | ||
| "libc", | ||
| "memoffset", | ||
| "once_cell", | ||
| "portable-atomic", | ||
| "pyo3-build-config", | ||
| "pyo3-ffi", | ||
| "pyo3-macros", | ||
| "unindent", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-build-config" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598" | ||
| dependencies = [ | ||
| "once_cell", | ||
| "target-lexicon", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-ffi" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c" | ||
| dependencies = [ | ||
| "libc", | ||
| "pyo3-build-config", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-macros" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "pyo3-macros-backend", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-macros-backend" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc" | ||
| dependencies = [ | ||
| "heck", | ||
| "proc-macro2", | ||
| "pyo3-build-config", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "queue_sqlite_core" | ||
| version = "0.2.0" | ||
| dependencies = [ | ||
| "chrono", | ||
| "pyo3", | ||
| "r2d2", | ||
| "r2d2_sqlite", | ||
| "rand", | ||
| "rusqlite", | ||
| "serde", | ||
| "serde_json", | ||
| "sha2", | ||
| "thiserror", | ||
| "tokio", | ||
| "uuid", | ||
| ] | ||
| [[package]] | ||
| name = "quote" | ||
| version = "1.0.40" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| ] | ||
| [[package]] | ||
| name = "r-efi" | ||
| version = "5.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" | ||
| [[package]] | ||
| name = "r2d2" | ||
| version = "0.8.10" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" | ||
| dependencies = [ | ||
| "log", | ||
| "parking_lot", | ||
| "scheduled-thread-pool", | ||
| ] | ||
| [[package]] | ||
| name = "r2d2_sqlite" | ||
| version = "0.25.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "eb14dba8247a6a15b7fdbc7d389e2e6f03ee9f184f87117706d509c092dfe846" | ||
| dependencies = [ | ||
| "r2d2", | ||
| "rusqlite", | ||
| "uuid", | ||
| ] | ||
| [[package]] | ||
| name = "rand" | ||
| version = "0.9.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" | ||
| dependencies = [ | ||
| "rand_chacha", | ||
| "rand_core", | ||
| ] | ||
| [[package]] | ||
| name = "rand_chacha" | ||
| version = "0.9.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" | ||
| dependencies = [ | ||
| "ppv-lite86", | ||
| "rand_core", | ||
| ] | ||
| [[package]] | ||
| name = "rand_core" | ||
| version = "0.9.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" | ||
| dependencies = [ | ||
| "getrandom", | ||
| ] | ||
| [[package]] | ||
| name = "redox_syscall" | ||
| version = "0.5.17" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" | ||
| dependencies = [ | ||
| "bitflags", | ||
| ] | ||
| [[package]] | ||
| name = "rusqlite" | ||
| version = "0.32.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" | ||
| dependencies = [ | ||
| "bitflags", | ||
| "fallible-iterator", | ||
| "fallible-streaming-iterator", | ||
| "hashlink", | ||
| "libsqlite3-sys", | ||
| "smallvec", | ||
| ] | ||
| [[package]] | ||
| name = "rustc-demangle" | ||
| version = "0.1.26" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" | ||
| [[package]] | ||
| name = "rustversion" | ||
| version = "1.0.21" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" | ||
| [[package]] | ||
| name = "ryu" | ||
| version = "1.0.20" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" | ||
| [[package]] | ||
| name = "scheduled-thread-pool" | ||
| version = "0.2.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" | ||
| dependencies = [ | ||
| "parking_lot", | ||
| ] | ||
| [[package]] | ||
| name = "scopeguard" | ||
| version = "1.2.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" | ||
| [[package]] | ||
| name = "serde" | ||
| version = "1.0.226" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" | ||
| dependencies = [ | ||
| "serde_core", | ||
| "serde_derive", | ||
| ] | ||
| [[package]] | ||
| name = "serde_core" | ||
| version = "1.0.226" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" | ||
| dependencies = [ | ||
| "serde_derive", | ||
| ] | ||
| [[package]] | ||
| name = "serde_derive" | ||
| version = "1.0.226" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "serde_json" | ||
| version = "1.0.145" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" | ||
| dependencies = [ | ||
| "itoa", | ||
| "memchr", | ||
| "ryu", | ||
| "serde", | ||
| "serde_core", | ||
| ] | ||
| [[package]] | ||
| name = "sha2" | ||
| version = "0.10.9" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "cpufeatures", | ||
| "digest", | ||
| ] | ||
| [[package]] | ||
| name = "shlex" | ||
| version = "1.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" | ||
| [[package]] | ||
| name = "slab" | ||
| version = "0.4.11" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" | ||
| [[package]] | ||
| name = "smallvec" | ||
| version = "1.15.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | ||
| [[package]] | ||
| name = "syn" | ||
| version = "2.0.104" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "unicode-ident", | ||
| ] | ||
| [[package]] | ||
| name = "target-lexicon" | ||
| version = "0.13.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" | ||
| [[package]] | ||
| name = "thiserror" | ||
| version = "2.0.16" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" | ||
| dependencies = [ | ||
| "thiserror-impl", | ||
| ] | ||
| [[package]] | ||
| name = "thiserror-impl" | ||
| version = "2.0.16" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "tokio" | ||
| version = "1.47.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" | ||
| dependencies = [ | ||
| "backtrace", | ||
| "io-uring", | ||
| "libc", | ||
| "mio", | ||
| "pin-project-lite", | ||
| "slab", | ||
| ] | ||
| [[package]] | ||
| name = "typenum" | ||
| version = "1.18.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" | ||
| [[package]] | ||
| name = "unicode-ident" | ||
| version = "1.0.18" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" | ||
| [[package]] | ||
| name = "unindent" | ||
| version = "0.2.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" | ||
| [[package]] | ||
| name = "uuid" | ||
| version = "1.18.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" | ||
| dependencies = [ | ||
| "getrandom", | ||
| "js-sys", | ||
| "rand", | ||
| "wasm-bindgen", | ||
| ] | ||
| [[package]] | ||
| name = "vcpkg" | ||
| version = "0.2.15" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" | ||
| [[package]] | ||
| name = "version_check" | ||
| version = "0.9.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" | ||
| [[package]] | ||
| name = "wasi" | ||
| version = "0.11.1+wasi-snapshot-preview1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" | ||
| [[package]] | ||
| name = "wasi" | ||
| version = "0.14.2+wasi-0.2.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" | ||
| dependencies = [ | ||
| "wit-bindgen-rt", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "once_cell", | ||
| "rustversion", | ||
| "wasm-bindgen-macro", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-backend" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" | ||
| dependencies = [ | ||
| "bumpalo", | ||
| "log", | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| "wasm-bindgen-shared", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-macro" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" | ||
| dependencies = [ | ||
| "quote", | ||
| "wasm-bindgen-macro-support", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-macro-support" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| "wasm-bindgen-backend", | ||
| "wasm-bindgen-shared", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-shared" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" | ||
| dependencies = [ | ||
| "unicode-ident", | ||
| ] | ||
| [[package]] | ||
| name = "windows-core" | ||
| version = "0.61.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" | ||
| dependencies = [ | ||
| "windows-implement", | ||
| "windows-interface", | ||
| "windows-link", | ||
| "windows-result", | ||
| "windows-strings", | ||
| ] | ||
| [[package]] | ||
| name = "windows-implement" | ||
| version = "0.60.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "windows-interface" | ||
| version = "0.59.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "windows-link" | ||
| version = "0.1.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" | ||
| [[package]] | ||
| name = "windows-result" | ||
| version = "0.3.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" | ||
| dependencies = [ | ||
| "windows-link", | ||
| ] | ||
| [[package]] | ||
| name = "windows-strings" | ||
| version = "0.4.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" | ||
| dependencies = [ | ||
| "windows-link", | ||
| ] | ||
| [[package]] | ||
| name = "windows-sys" | ||
| version = "0.59.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" | ||
| dependencies = [ | ||
| "windows-targets", | ||
| ] | ||
| [[package]] | ||
| name = "windows-targets" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" | ||
| dependencies = [ | ||
| "windows_aarch64_gnullvm", | ||
| "windows_aarch64_msvc", | ||
| "windows_i686_gnu", | ||
| "windows_i686_gnullvm", | ||
| "windows_i686_msvc", | ||
| "windows_x86_64_gnu", | ||
| "windows_x86_64_gnullvm", | ||
| "windows_x86_64_msvc", | ||
| ] | ||
| [[package]] | ||
| name = "windows_aarch64_gnullvm" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" | ||
| [[package]] | ||
| name = "windows_aarch64_msvc" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" | ||
| [[package]] | ||
| name = "windows_i686_gnu" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" | ||
| [[package]] | ||
| name = "windows_i686_gnullvm" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" | ||
| [[package]] | ||
| name = "windows_i686_msvc" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" | ||
| [[package]] | ||
| name = "windows_x86_64_gnu" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" | ||
| [[package]] | ||
| name = "windows_x86_64_gnullvm" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" | ||
| [[package]] | ||
| name = "windows_x86_64_msvc" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | ||
| [[package]] | ||
| name = "wit-bindgen-rt" | ||
| version = "0.39.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" | ||
| dependencies = [ | ||
| "bitflags", | ||
| ] | ||
| [[package]] | ||
| name = "zerocopy" | ||
| version = "0.8.26" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" | ||
| dependencies = [ | ||
| "zerocopy-derive", | ||
| ] | ||
| [[package]] | ||
| name = "zerocopy-derive" | ||
| version = "0.8.26" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] |
| [package] | ||
| name = "queue_sqlite_core" | ||
| version = "0.2.0" | ||
| edition = "2021" | ||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
| [lib] | ||
| name = "queue_sqlite_core" | ||
| crate-type = ["cdylib"] | ||
| [dependencies] | ||
| chrono = "0.4.41" | ||
| pyo3 = "0.25.0" | ||
| r2d2 = "0.8" | ||
| r2d2_sqlite = "0.25" | ||
| rand = "0.9.2" | ||
| rusqlite = { version = "0.32", features = ["bundled"] } | ||
| serde = { version = "1.0", features = ["derive"] } | ||
| serde_json = "1.0.145" | ||
| sha2 = "0.10.9" | ||
| thiserror = "2.0.16" | ||
| tokio = "1.47.1" | ||
| uuid = "1.18.1" | ||
| [package.metadata.maturin] | ||
| generate-importlib = true |
| [project] | ||
| name = "queue_sqlite_core" | ||
| requires-python = ">=3.7" | ||
| classifiers = [ | ||
| "Programming Language :: Rust", | ||
| "Programming Language :: Python :: Implementation :: CPython", | ||
| "Programming Language :: Python :: Implementation :: PyPy", | ||
| ] | ||
| dynamic = ["version"] | ||
| description = "Python bindings for queue_sqlite_core Rust library" | ||
| dependencies = [] | ||
| [build-system] | ||
| requires = ["maturin>=1.9,<2.0"] | ||
| build-backend = "maturin" | ||
| [tool.maturin] | ||
| features = ["pyo3/extension-module"] | ||
| [[tool.uv.index]] | ||
| default = true | ||
| url = "http://124.71.68.6:3141/root/pypi" | ||
| [dependency-groups] | ||
| dev = [ | ||
| "twine>=4.0.2", | ||
| "maturin>=1.9.4", | ||
| ] | ||
| [[tool.uv.index]] | ||
| url = "https://pypi.tuna.tsinghua.edu.cn/simple" |
| from typing import Callable | ||
| class QueueOperation: | ||
| def __init__(self, queue_path: str): ... | ||
| def init_db(self) -> None: ... | ||
| def enqueue(self, message: dict) -> str: ... | ||
| def dequeue(self, size: int = 1) -> list[dict]: ... | ||
| def get_queue_length(self) -> int: ... | ||
| def get_completed_messages(self) -> list[dict]: ... | ||
| def get_result(self, id: str) -> dict: ... | ||
| def update_status(self, id: str, status: str) -> None: ... | ||
| def update_result(self, id: str, result: str) -> None: ... | ||
| def delete_message(self, id: str) -> None: ... | ||
| def clean_expired_messages(self) -> None: ... | ||
| def clean_old_messages(self, days: int) -> None: ... | ||
| def remove_expired_messages(self, days: int) -> None: ... | ||
| class ShardedQueueOperation: | ||
| @property | ||
| def db_dir(self) -> str: ... | ||
| def __init__(self, shard_num: int, queue_name: str): ... | ||
| def _get_shard_index(self, message_id: str) -> int: ... | ||
| def enqueue(self, message: dict) -> str: ... | ||
| def dequeue(self, size: int = 1) -> list[dict]: ... | ||
| def get_queue_length(self) -> int: ... | ||
| def get_completed_messages(self) -> list[dict]: ... | ||
| def get_result(self, id: str) -> dict: ... | ||
| def update_status(self, id: str, status: str) -> None: ... | ||
| def update_result(self, id: str, result: str) -> None: ... | ||
| def delete_message(self, id: str) -> None: ... | ||
| def clean_expired_messages(self) -> None: ... | ||
| def clean_old_messages(self, days: int) -> None: ... | ||
| def remove_expired_messages(self, days: int) -> None: ... | ||
| class TaskMounter: | ||
| def __init__(self, task_mounter_class: type): ... | ||
| def get_task_list(self) -> list[str]: ... | ||
| def get_task_function(self, task_name: str) -> Callable: ... |
| mod queue_operation; | ||
| mod task_mounter; | ||
| use pyo3::prelude::*; | ||
| use queue_operation::{QueueOperation, ShardedQueueOperation}; | ||
| use task_mounter::TaskMounter; // 导入结构体 // 导入结构体 | ||
| #[pymodule] | ||
| // #[pymodule(gil_used = false)] | ||
| fn queue_sqlite_core(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { | ||
| m.add_class::<TaskMounter>()?; | ||
| m.add_class::<QueueOperation>()?; | ||
| m.add_class::<ShardedQueueOperation>()?; | ||
| Ok(()) | ||
| } |
| // src/lib.rs | ||
| use chrono::{DateTime, Duration, Utc}; | ||
| use pyo3::prelude::*; | ||
| use pyo3::types::{PyDict, PyList}; | ||
| use r2d2::Pool; | ||
| use r2d2_sqlite::SqliteConnectionManager; | ||
| use rand::seq::SliceRandom; | ||
| use rusqlite::{params, Connection, Row}; | ||
| use serde::{Deserialize, Serialize}; | ||
| use sha2::{Digest, Sha256}; | ||
| use std::collections::HashMap; | ||
| use std::path::Path; | ||
| use std::sync::{Arc, Mutex}; | ||
| /// 单个分片的队列操作 | ||
| #[pyclass] | ||
| pub struct QueueOperation { | ||
| pool: Pool<SqliteConnectionManager>, | ||
| } | ||
| #[derive(Debug, Serialize, Deserialize)] | ||
| struct Message { | ||
| id: String, | ||
| message_type: String, | ||
| status: i32, | ||
| content: String, | ||
| createtime: String, | ||
| updatetime: String, | ||
| result: Option<String>, | ||
| priority: i32, | ||
| source: String, | ||
| destination: String, | ||
| retry_count: i32, | ||
| expire_time: Option<String>, | ||
| tags: Option<String>, | ||
| metadata: Option<String>, | ||
| is_deleted: i32, | ||
| } | ||
| impl TryFrom<&Row<'_>> for Message { | ||
| type Error = rusqlite::Error; | ||
| fn try_from(row: &Row) -> Result<Self, Self::Error> { | ||
| Ok(Message { | ||
| id: row.get("id")?, | ||
| message_type: row.get("type")?, | ||
| status: row.get("status")?, | ||
| content: row.get("content")?, | ||
| createtime: row.get("createtime")?, | ||
| updatetime: row.get("updatetime")?, | ||
| result: row.get("result")?, | ||
| priority: row.get("priority")?, | ||
| source: row.get("source")?, | ||
| destination: row.get("destination")?, | ||
| retry_count: row.get("retry_count")?, | ||
| expire_time: row.get("expire_time")?, | ||
| tags: row.get("tags")?, | ||
| metadata: row.get("metadata")?, | ||
| is_deleted: row.get("is_deleted")?, | ||
| }) | ||
| } | ||
| } | ||
| #[pymethods] | ||
| impl QueueOperation { | ||
| #[new] | ||
| pub fn new(queue_path: String) -> PyResult<Self> { | ||
| let manager = SqliteConnectionManager::file(queue_path); | ||
| let pool = Pool::new(manager) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(QueueOperation { pool }) | ||
| } | ||
| /// 初始化数据库和表 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// Returns: | ||
| /// - None | ||
| pub fn init_db(&self) -> PyResult<()> { | ||
| let conn = self.get_connection()?; | ||
| // 创建消息表 | ||
| conn.execute( | ||
| "CREATE TABLE IF NOT EXISTS messages ( | ||
| id TEXT PRIMARY KEY, | ||
| type TEXT NOT NULL, | ||
| status INTEGER NOT NULL, | ||
| content TEXT NOT NULL, | ||
| createtime DATETIME NOT NULL, | ||
| updatetime DATETIME NOT NULL, | ||
| result TEXT, | ||
| priority INTEGER NOT NULL, | ||
| source TEXT NOT NULL, | ||
| destination TEXT NOT NULL, | ||
| retry_count INTEGER NOT NULL, | ||
| expire_time DATETIME, | ||
| tags TEXT, | ||
| metadata TEXT, | ||
| is_deleted INTEGER NOT NULL DEFAULT 0 | ||
| )", | ||
| [], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| // 创建索引 | ||
| let indexes = [ | ||
| "CREATE INDEX IF NOT EXISTS idx_status ON messages(status)", | ||
| "CREATE INDEX IF NOT EXISTS idx_priority ON messages(priority)", | ||
| "CREATE INDEX IF NOT EXISTS idx_dequeue ON messages(status, priority DESC, createtime ASC) WHERE is_deleted = 0 AND status = 0", | ||
| "CREATE INDEX IF NOT EXISTS idx_expire_time ON messages(expire_time) WHERE expire_time IS NOT NULL", | ||
| ]; | ||
| for index_sql in indexes.iter() { | ||
| conn.execute(index_sql, []) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| } | ||
| // 设置 SQLite 优化参数 | ||
| let pragmas = [ | ||
| "PRAGMA journal_mode=WAL", | ||
| "PRAGMA synchronous=NORMAL", | ||
| "PRAGMA cache_size=-20000", | ||
| "PRAGMA mmap_size=134217728", | ||
| "PRAGMA temp_store=MEMORY", | ||
| "PRAGMA busy_timeout=3000", | ||
| ]; | ||
| for pragma in pragmas.iter() { | ||
| conn.execute_batch(pragma) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| } | ||
| Ok(()) | ||
| } | ||
| /// 入队 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - message: PyDict 实例,包含消息内容 | ||
| /// Returns: | ||
| /// - String: 消息ID | ||
| pub fn enqueue(&self, message: &Bound<'_, PyDict>) -> PyResult<String> { | ||
| let mut conn = self.get_connection()?; | ||
| let required_fields = [ | ||
| "id", | ||
| "type", | ||
| "status", | ||
| "content", | ||
| "createtime", | ||
| "updatetime", | ||
| "priority", | ||
| "source", | ||
| "destination", | ||
| "retry_count", | ||
| ]; | ||
| for field in required_fields.iter() { | ||
| if !message.contains(field)? { | ||
| return Err(PyErr::new::<pyo3::exceptions::PyKeyError, _>(format!( | ||
| "Missing required field: {}", | ||
| field | ||
| ))); | ||
| } | ||
| } | ||
| let tx = conn | ||
| .transaction() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| // 从PyDict获取值 | ||
| let id: String = message.get_item("id")?.unwrap().extract()?; | ||
| let message_type: String = message.get_item("type")?.unwrap().extract()?; | ||
| let status: i32 = message.get_item("status")?.unwrap().extract()?; | ||
| let content: String = message.get_item("content")?.unwrap().extract()?; | ||
| let createtime: String = message.get_item("createtime")?.unwrap().extract()?; | ||
| let updatetime: String = message.get_item("updatetime")?.unwrap().extract()?; | ||
| let priority: i32 = message.get_item("priority")?.unwrap().extract()?; | ||
| let source: String = message.get_item("source")?.unwrap().extract()?; | ||
| let destination: String = message.get_item("destination")?.unwrap().extract()?; | ||
| let retry_count: i32 = message.get_item("retry_count")?.unwrap().extract()?; | ||
| // 可选字段 | ||
| let result: Option<String> = match message.get_item("result")? { | ||
| Some(item) => { | ||
| if item.is_none() { | ||
| None | ||
| } else { | ||
| Some(item.extract()?) | ||
| } | ||
| } | ||
| None => None, | ||
| }; | ||
| let expire_time: Option<String> = match message.get_item("expire_time")? { | ||
| Some(item) => { | ||
| if item.is_none() { | ||
| None | ||
| } else { | ||
| Some(item.extract()?) | ||
| } | ||
| } | ||
| None => None, | ||
| }; | ||
| let tags: Option<String> = match message.get_item("tags")? { | ||
| Some(item) => { | ||
| if item.is_none() { | ||
| None | ||
| } else { | ||
| Some(item.extract()?) | ||
| } | ||
| } | ||
| None => None, | ||
| }; | ||
| let metadata: Option<String> = match message.get_item("metadata")? { | ||
| Some(item) => { | ||
| if item.is_none() { | ||
| None | ||
| } else { | ||
| Some(item.extract()?) | ||
| } | ||
| } | ||
| None => None, | ||
| }; | ||
| tx.execute( | ||
| "INSERT INTO messages ( | ||
| id, type, status, content, createtime, updatetime, result, | ||
| priority, source, destination, retry_count, expire_time, tags, metadata | ||
| ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)", | ||
| params![ | ||
| id, | ||
| message_type, | ||
| status, | ||
| content, | ||
| createtime, | ||
| updatetime, | ||
| result, | ||
| priority, | ||
| source, | ||
| destination, | ||
| retry_count, | ||
| expire_time, | ||
| tags, | ||
| metadata, | ||
| ], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| tx.commit() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(id) | ||
| } | ||
| /// 出队 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - size: i32, 获取消息数量 | ||
| /// Returns: | ||
| /// - Vec<HashMap<String, String>>: 获取的消息列表 | ||
| pub fn dequeue(&self, size: i32) -> PyResult<Vec<HashMap<String, String>>> { | ||
| let limited_size = std::cmp::min(size, 500); | ||
| let conn = self.get_connection()?; | ||
| let now = Utc::now().to_rfc3339(); | ||
| let mut stmt = conn | ||
| .prepare( | ||
| "UPDATE messages | ||
| SET status = 1, updatetime = ?1 | ||
| WHERE id IN ( | ||
| SELECT id FROM messages | ||
| WHERE is_deleted = 0 | ||
| AND status = 0 | ||
| AND (expire_time IS NULL OR expire_time > ?1) | ||
| ORDER BY priority DESC, createtime ASC | ||
| LIMIT ?2 | ||
| ) | ||
| RETURNING *", | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let rows = stmt | ||
| .query_map(params![now, limited_size], |row| { | ||
| let message: Message = row.try_into()?; | ||
| let mut map = HashMap::new(); | ||
| map.insert("id".to_string(), message.id); | ||
| map.insert("type".to_string(), message.message_type); | ||
| map.insert("status".to_string(), message.status.to_string()); | ||
| map.insert("content".to_string(), message.content); | ||
| map.insert("createtime".to_string(), message.createtime); | ||
| map.insert("updatetime".to_string(), message.updatetime); | ||
| map.insert("result".to_string(), message.result.unwrap_or_default()); | ||
| map.insert("priority".to_string(), message.priority.to_string()); | ||
| map.insert("source".to_string(), message.source); | ||
| map.insert("destination".to_string(), message.destination); | ||
| map.insert("retry_count".to_string(), message.retry_count.to_string()); | ||
| map.insert( | ||
| "expire_time".to_string(), | ||
| message.expire_time.unwrap_or_default(), | ||
| ); | ||
| map.insert("tags".to_string(), message.tags.unwrap_or_default()); | ||
| map.insert("metadata".to_string(), message.metadata.unwrap_or_default()); | ||
| Ok(map) | ||
| }) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut result = Vec::new(); | ||
| for row in rows { | ||
| result.push( | ||
| row.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?, | ||
| ); | ||
| if result.len() > 1000 { | ||
| break; | ||
| } | ||
| } | ||
| Ok(result) | ||
| } | ||
| /// 获取队列长度 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// Returns: | ||
| /// - i32: 队列长度 | ||
| pub fn get_queue_length(&self) -> PyResult<i32> { | ||
| let conn = self.get_connection()?; | ||
| let now = Utc::now().to_rfc3339(); | ||
| let count: i32 = conn | ||
| .query_row( | ||
| "SELECT COUNT(*) FROM messages | ||
| WHERE is_deleted = 0 | ||
| AND status = 0 | ||
| AND (expire_time IS NULL OR expire_time > ?1)", | ||
| params![now], | ||
| |row| row.get(0), | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(count) | ||
| } | ||
| /// 获取已完成的消息 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// Returns: | ||
| /// - Vec<HashMap<String, String>>: 已完成的消息列表 | ||
| pub fn get_completed_messages(&self) -> PyResult<Vec<HashMap<String, String>>> { | ||
| let conn = self.get_connection()?; | ||
| let mut stmt = conn | ||
| .prepare( | ||
| "SELECT * FROM messages | ||
| WHERE is_deleted = 0 | ||
| AND (status = 2 OR status = 3) | ||
| LIMIT 10000", | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let rows = stmt | ||
| .query_map([], |row| { | ||
| let message: Message = row.try_into()?; | ||
| let mut map = HashMap::new(); | ||
| map.insert("id".to_string(), message.id); | ||
| map.insert("type".to_string(), message.message_type); | ||
| map.insert("status".to_string(), message.status.to_string()); | ||
| map.insert("content".to_string(), message.content); | ||
| map.insert("createtime".to_string(), message.createtime); | ||
| map.insert("updatetime".to_string(), message.updatetime); | ||
| map.insert("result".to_string(), message.result.unwrap_or_default()); | ||
| map.insert("priority".to_string(), message.priority.to_string()); | ||
| map.insert("source".to_string(), message.source); | ||
| map.insert("destination".to_string(), message.destination); | ||
| map.insert("retry_count".to_string(), message.retry_count.to_string()); | ||
| map.insert( | ||
| "expire_time".to_string(), | ||
| message.expire_time.unwrap_or_default(), | ||
| ); | ||
| map.insert("tags".to_string(), message.tags.unwrap_or_default()); | ||
| map.insert("metadata".to_string(), message.metadata.unwrap_or_default()); | ||
| Ok(map) | ||
| }) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut result = Vec::new(); | ||
| for row in rows { | ||
| result.push( | ||
| row.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?, | ||
| ); | ||
| if result.len() > 1000 { | ||
| break; | ||
| } | ||
| } | ||
| Ok(result) | ||
| } | ||
| /// 获取消息详情 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - id: String, 消息ID | ||
| /// Returns: | ||
| /// - HashMap<String, String>: 消息详情 | ||
| pub fn get_result(&self, id: String) -> PyResult<HashMap<String, String>> { | ||
| let conn = self.get_connection()?; | ||
| let mut stmt = conn | ||
| .prepare( | ||
| "SELECT * FROM messages | ||
| WHERE id = ?1 | ||
| AND (status = 2 OR status = 3)", | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let message: Message = stmt | ||
| .query_row(params![id], |row| row.try_into()) | ||
| .map_err(|e| { | ||
| // 更好地处理查询不到结果的情况 | ||
| if e == rusqlite::Error::QueryReturnedNoRows { | ||
| PyErr::new::<pyo3::exceptions::PyValueError, _>( | ||
| "Message not found or not completed", | ||
| ) | ||
| } else { | ||
| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()) | ||
| } | ||
| })?; | ||
| let mut result = HashMap::new(); | ||
| result.insert("id".to_string(), message.id); | ||
| result.insert("type".to_string(), message.message_type); | ||
| result.insert("status".to_string(), message.status.to_string()); | ||
| result.insert("content".to_string(), message.content); | ||
| result.insert("createtime".to_string(), message.createtime); | ||
| result.insert("updatetime".to_string(), message.updatetime); | ||
| result.insert("result".to_string(), message.result.unwrap_or_default()); | ||
| result.insert("priority".to_string(), message.priority.to_string()); | ||
| result.insert("source".to_string(), message.source); | ||
| result.insert("destination".to_string(), message.destination); | ||
| result.insert("retry_count".to_string(), message.retry_count.to_string()); | ||
| result.insert( | ||
| "expire_time".to_string(), | ||
| message.expire_time.unwrap_or_default(), | ||
| ); | ||
| result.insert("tags".to_string(), message.tags.unwrap_or_default()); | ||
| result.insert("metadata".to_string(), message.metadata.unwrap_or_default()); | ||
| Ok(result) | ||
| } | ||
| /// 更新消息状态 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - id: String, 消息ID | ||
| /// - status: i32, 新状态 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn update_status(&self, id: String, status: i32) -> PyResult<()> { | ||
| let conn = self.get_connection()?; | ||
| let now = Utc::now().to_rfc3339(); | ||
| conn.execute( | ||
| "UPDATE messages SET status = ?1, updatetime = ?2 WHERE id = ?3", | ||
| params![status, now, id], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| /// 更新消息结果 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - id: String, 消息ID | ||
| /// - result: String, 新结果 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn update_result(&self, id: String, result: String) -> PyResult<()> { | ||
| let conn = self.get_connection()?; | ||
| let now = Utc::now().to_rfc3339(); | ||
| conn.execute( | ||
| "UPDATE messages SET result = ?1, updatetime = ?2 WHERE id = ?3", | ||
| params![result, now, id], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| /// 删除消息 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - id: String, 删除的消息ID | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn delete_message(&self, id: String) -> PyResult<()> { | ||
| let conn = self.get_connection()?; | ||
| conn.execute( | ||
| "UPDATE messages SET is_deleted = 1 WHERE id = ?1", | ||
| params![id], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| /// 清理过期消息 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn clean_expired_messages(&self) -> PyResult<()> { | ||
| let conn = self.get_connection()?; | ||
| let now = Utc::now().to_rfc3339(); | ||
| conn.execute( | ||
| "UPDATE messages SET is_deleted = 1 | ||
| WHERE is_deleted = 0 | ||
| AND expire_time IS NOT NULL | ||
| AND expire_time < ?1", | ||
| params![now], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| /// 清理旧消息 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - days: i64, 清理旧消息的天数 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn clean_old_messages(&self, days: i64) -> PyResult<()> { | ||
| let conn = self.get_connection()?; | ||
| let cutoff_time = (Utc::now() - Duration::days(days)).to_rfc3339(); | ||
| conn.execute( | ||
| "UPDATE messages SET is_deleted = 1 | ||
| WHERE is_deleted = 0 | ||
| AND status IN (2, 3) | ||
| AND updatetime < ?1", | ||
| params![cutoff_time], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| /// 删除过期消息 | ||
| /// Args: | ||
| /// - self: QueueOperation 实例 | ||
| /// - days: i64, 删除过期消息的天数 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn remove_expired_messages(&self, days: i64) -> PyResult<()> { | ||
| let now: DateTime<Utc> = Utc::now(); | ||
| let expire_time = now - Duration::days(days); | ||
| let iso_format = expire_time.to_rfc3339(); | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| DELETE FROM messages | ||
| WHERE is_deleted = 0 | ||
| AND expire_time IS NOT NULL | ||
| AND expire_time < ?1 | ||
| ", | ||
| params![iso_format], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| } | ||
| /// 获取数据库连接 | ||
| impl QueueOperation { | ||
| fn get_connection(&self) -> PyResult<r2d2::PooledConnection<SqliteConnectionManager>> { | ||
| self.pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string())) | ||
| } | ||
| } | ||
| /// 分片队列操作 | ||
| #[pyclass] | ||
| pub struct ShardedQueueOperation { | ||
| shards: Vec<QueueOperation>, | ||
| #[pyo3(get)] | ||
| shard_num: usize, | ||
| #[pyo3(get)] | ||
| db_dir: String, | ||
| } | ||
| #[pymethods] | ||
| impl ShardedQueueOperation { | ||
| #[new] | ||
| pub fn new(shard_num: usize, queue_name: String) -> PyResult<Self> { | ||
| // 创建缓存目录 | ||
| let db_dir = format!("cache/{}", queue_name); | ||
| std::fs::create_dir_all(&db_dir) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut shards = Vec::with_capacity(shard_num); | ||
| for i in 0..shard_num { | ||
| let db_path = format!("{}/queue_shard_{}.db", db_dir, i); | ||
| let queue_op = QueueOperation::new(db_path)?; | ||
| queue_op.init_db()?; | ||
| shards.push(queue_op); | ||
| } | ||
| Ok(ShardedQueueOperation { | ||
| shards, | ||
| shard_num, | ||
| db_dir, | ||
| }) | ||
| } | ||
| /// 获取分片索引 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - message_id: &str, 消息ID | ||
| /// Returns: | ||
| /// - usize: 分片索引 | ||
| fn _get_shard_index(&self, message_id: &str) -> usize { | ||
| let mut hasher = Sha256::new(); | ||
| hasher.update(message_id.as_bytes()); | ||
| let result = hasher.finalize(); | ||
| // 将哈希值转换为 usize | ||
| let hash_bytes: [u8; 8] = result[..8].try_into().unwrap(); | ||
| let hash_value = u64::from_be_bytes(hash_bytes) as usize; | ||
| hash_value % self.shard_num | ||
| } | ||
| /// 添加消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - message: &Bound<'_, PyDict>, 待添加的消息 | ||
| /// Returns: | ||
| /// - String: 添加的消息ID | ||
| pub fn enqueue(&self, message: &Bound<'_, PyDict>) -> PyResult<String> { | ||
| let message_id_bound = message | ||
| .get_item("id")? | ||
| .ok_or_else(|| PyErr::new::<pyo3::exceptions::PyKeyError, _>("Missing id field"))?; | ||
| let message_id: String = message_id_bound.extract()?; | ||
| let shard_index = self._get_shard_index(&message_id); | ||
| self.shards[shard_index].enqueue(message) | ||
| } | ||
| /// 获取消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - size: i32, 获取的消息数量 | ||
| /// Returns: | ||
| /// - Vec<HashMap<String, String>>: 获取的消息列表 | ||
| pub fn dequeue(&self, size: i32) -> PyResult<Vec<HashMap<String, String>>> { | ||
| let mut all_messages = Vec::new(); | ||
| let mut collected = 0; | ||
| // 限制单次获取的最大消息数量 | ||
| let max_size = std::cmp::min(size, 1000); | ||
| // 随机轮询分片顺序 | ||
| let mut shard_order: Vec<usize> = (0..self.shard_num).collect(); | ||
| let mut rng = rand::thread_rng(); | ||
| shard_order.shuffle(&mut rng); | ||
| for shard_index in shard_order { | ||
| if collected >= max_size { | ||
| break; | ||
| } | ||
| let remaining = size - collected; | ||
| let shard_messages = self.shards[shard_index].dequeue(remaining)?; | ||
| collected += shard_messages.len() as i32; | ||
| all_messages.extend(shard_messages); | ||
| if all_messages.len() > 1000 { | ||
| break; | ||
| } | ||
| } | ||
| Ok(all_messages) | ||
| } | ||
| /// 获取队列长度 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// Returns: | ||
| /// - i32: 队列长度 | ||
| pub fn get_queue_length(&self) -> PyResult<i32> { | ||
| let mut total = 0; | ||
| for shard in &self.shards { | ||
| total += shard.get_queue_length()?; | ||
| } | ||
| Ok(total) | ||
| } | ||
| /// 获取已完成的消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// Returns: | ||
| /// - Vec<HashMap<String, String>>: 已完成的消息列表 | ||
| pub fn get_completed_messages(&self) -> PyResult<Vec<HashMap<String, String>>> { | ||
| let mut all_messages = Vec::new(); | ||
| for shard in &self.shards { | ||
| let shard_messages = shard.get_completed_messages()?; | ||
| all_messages.extend(shard_messages); | ||
| if all_messages.len() > 1000 { | ||
| break; | ||
| } | ||
| } | ||
| Ok(all_messages) | ||
| } | ||
| /// 获取消息详情 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - message_id: String, 消息ID | ||
| /// Returns: | ||
| /// - HashMap<String, String>: 消息详情 | ||
| pub fn get_result(&self, message_id: String) -> PyResult<HashMap<String, String>> { | ||
| let shard_index = self._get_shard_index(&message_id); | ||
| self.shards[shard_index].get_result(message_id) | ||
| } | ||
| /// 更新消息状态 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - message_id: String, 消息ID | ||
| /// - status: i32, 新状态 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn update_status(&self, message_id: String, status: i32) -> PyResult<()> { | ||
| let shard_index = self._get_shard_index(&message_id); | ||
| self.shards[shard_index].update_status(message_id, status) | ||
| } | ||
| /// 更新消息结果 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - message_id: String, 消息ID | ||
| /// - result: String, 新结果 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn update_result(&self, message_id: String, result: String) -> PyResult<()> { | ||
| let shard_index = self._get_shard_index(&message_id); | ||
| self.shards[shard_index].update_result(message_id, result) | ||
| } | ||
| /// 删除消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - message_id: String, 待删除的消息ID | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn delete_message(&self, message_id: String) -> PyResult<()> { | ||
| let shard_index = self._get_shard_index(&message_id); | ||
| self.shards[shard_index].delete_message(message_id) | ||
| } | ||
| /// 清理过期消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn clean_expired_messages(&self) -> PyResult<()> { | ||
| for shard in &self.shards { | ||
| shard.clean_expired_messages()?; | ||
| } | ||
| Ok(()) | ||
| } | ||
| /// 清理旧消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - days: i64, 清理旧消息的天数 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn remove_expired_messages(&self, days: i64) -> PyResult<()> { | ||
| for shard in &self.shards { | ||
| shard.remove_expired_messages(days)?; | ||
| } | ||
| Ok(()) | ||
| } | ||
| /// 清理旧消息 | ||
| /// Args: | ||
| /// - self: ShardedQueueOperation 实例 | ||
| /// - days: i64, 清理旧消息的天数 | ||
| /// Returns: | ||
| /// - () : 无返回值 | ||
| pub fn clean_old_messages(&self, days: i64) -> PyResult<()> { | ||
| for shard in &self.shards { | ||
| shard.clean_old_messages(days)?; | ||
| } | ||
| Ok(()) | ||
| } | ||
| } |
| use pyo3::prelude::*; | ||
| #[pyclass] | ||
| pub struct TaskMounter { | ||
| obj: Py<PyAny>, | ||
| } | ||
| #[pymethods] | ||
| impl TaskMounter { | ||
| #[new] | ||
| fn new(obj: Py<PyAny>) -> Self { | ||
| TaskMounter { obj } | ||
| } | ||
| fn get_task_list(&self, py: Python<'_>) -> PyResult<()> { | ||
| let obj = self.obj.bind(py); | ||
| let result_obj = obj.call_method("get_task_list", (), None)?; | ||
| println!("Method result: {:?}", result_obj); | ||
| Ok(()) | ||
| } | ||
| fn get_task_function(&self, py: Python<'_>, task_name: &str) -> PyResult<PyObject> { | ||
| let obj = self.obj.bind(py); | ||
| let result = obj.call_method1("get_task_function", (task_name,))?; | ||
| Ok(result.into()) | ||
| } | ||
| } |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : async_task_cycle.py | ||
| @Time : 2025-09-27 16:59:17 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 异步任务周期类 | ||
| """ | ||
| from ..model import MessageItem | ||
| from ..constant import MessageStatus | ||
| import json | ||
| import asyncio | ||
| import functools | ||
| def retry_async(max_retries=3, delay=1): | ||
| """ | ||
| 异步重试装饰器 | ||
| Args: | ||
| max_retries: 最大重试次数 | ||
| delay: 重试间隔(秒) | ||
| """ | ||
| def decorator(func): | ||
| @functools.wraps(func) | ||
| async def wrapper(self, *args, **kwargs): | ||
| last_exception = None | ||
| # 使用message_item中的retry_count作为最大重试次数 | ||
| retries = getattr(self.message_item, "retry_count", max_retries) | ||
| # 至少尝试一次(retries+1),最多尝试max_retries+1次 | ||
| actual_retries = min(retries, max_retries) if max_retries > 0 else retries | ||
| for attempt in range(actual_retries + 1): | ||
| try: | ||
| return await func(self, *args, **kwargs) | ||
| except Exception as e: | ||
| last_exception = e | ||
| if attempt < actual_retries: | ||
| await asyncio.sleep(delay) | ||
| else: | ||
| break | ||
| if last_exception: | ||
| raise last_exception | ||
| else: | ||
| raise Exception("Unknown error occurred during async task execution") | ||
| return wrapper | ||
| return decorator | ||
| class AsyncTaskCycle: | ||
| def __init__(self, message_item: MessageItem, callback): | ||
| self.message_item = message_item | ||
| self.callback = callback | ||
| self.task_result = None | ||
| self.task_status = None | ||
| self.task_error = None | ||
| @retry_async(max_retries=3, delay=1) | ||
| async def run(self): | ||
| try: | ||
| task_result = await self.callback(self.message_item) # type: ignore | ||
| except Exception as e: | ||
| self.task_result = None | ||
| self.task_status = MessageStatus.FAILED | ||
| self.task_error = str(e) | ||
| else: | ||
| self.task_result = task_result | ||
| self.task_status = MessageStatus.COMPLETED | ||
| self.task_error = None | ||
| def get_task_result(self): | ||
| if isinstance(self.task_result, (dict, list)): | ||
| try: | ||
| return json.dumps(self.task_result) | ||
| except: | ||
| return json.dumps({"result": str(self.task_result)}) | ||
| elif isinstance(self.task_result, str): | ||
| try: | ||
| json.loads(self.task_result) | ||
| return self.task_result | ||
| except: | ||
| return json.dumps({"result": self.task_result}) | ||
| elif isinstance(self.task_result, (int, float, bool)): | ||
| return json.dumps({"result": self.task_result}) | ||
| elif self.task_result is None: | ||
| return "null" | ||
| else: | ||
| return json.dumps({"result": str(self.task_result)}) | ||
| def get_task_status(self): | ||
| return self.task_status | ||
| def get_task_error(self): | ||
| return self.task_error | ||
| def get_task_message_item(self): | ||
| return self.message_item | ||
| def get_task_callback(self): | ||
| return self.callback |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 17:04:34 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 异步调度器 | ||
| """ | ||
| from .async_receive_scheduler import AsyncReceiveScheduler | ||
| from .async_task_scheduler import AsyncTaskScheduler | ||
| from .async_listen_data_scheduler import AsyncListenDataScheduler | ||
| from ...model import MessageItem | ||
| from ...queue_operation.listen_operation import ListenOperation | ||
| from typing import Callable | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| import os | ||
| from ..base import BaseScheduler | ||
| from ..cleanup_scheduler import CleanupScheduler | ||
| class AsyncQueueScheduler(BaseScheduler): | ||
| def __init__( | ||
| self, receive_thread_num=1, task_thread_num=1, shard_num=4, queue_name="default" | ||
| ): | ||
| self.queue_operation = ShardedQueueOperation(shard_num, queue_name=queue_name) | ||
| self.receive_scheduler = AsyncReceiveScheduler( | ||
| self.queue_operation, receive_thread_num | ||
| ) | ||
| self.listen_operation = ListenOperation( | ||
| os.path.join(self.queue_operation.db_dir, "listen.db") | ||
| ) | ||
| self.listen_operation.create_table() | ||
| self.listen_scheduler = AsyncListenDataScheduler(self.listen_operation) | ||
| self.task_scheduler = AsyncTaskScheduler(self.queue_operation, task_thread_num) | ||
| self.cleanup_scheduler = CleanupScheduler(self.queue_operation) | ||
| def send_message(self, message: MessageItem, callback: Callable): | ||
| self.receive_scheduler.send_message(message, callback) | ||
| def update_listen_data(self, key, value): | ||
| self.listen_operation.update_listen_data(key, value) | ||
| def get_listen_datas(self): | ||
| return self.listen_operation.get_values() | ||
| def get_listen_data(self, key): | ||
| return self.listen_operation.get_value(key) | ||
| def start(self): | ||
| self.receive_scheduler.start_receive_thread() | ||
| self.task_scheduler.start_task_thread() | ||
| def stop(self): | ||
| self.receive_scheduler.stop_receive_thread() | ||
| self.task_scheduler.stop_task_thread() | ||
| __all__ = ["AsyncQueueScheduler"] |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : async_listen_data_scheduler.py | ||
| @Time : 2025-09-27 17:04:54 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 异步监听数据调度器 | ||
| """ | ||
| from ...queue_operation.listen_operation import ListenOperation | ||
| import asyncio | ||
| from ...mounter.listen_mounter import ListenMounter | ||
| import threading | ||
| import multiprocessing | ||
| import concurrent.futures | ||
| class AsyncListenDataScheduler: | ||
| def __init__(self, listen_operation: ListenOperation): | ||
| self.listen_operation = listen_operation | ||
| self.is_running = False | ||
| self.thread_num = multiprocessing.cpu_count() | ||
| self.listen_thread = None | ||
| async def _process_listen_data(self, key, value, delete_id): | ||
| listen_function = ListenMounter.get_Listener_function(key) | ||
| if listen_function: | ||
| if asyncio.iscoroutinefunction(listen_function): | ||
| await listen_function(value) | ||
| else: | ||
| try: | ||
| loop = asyncio.get_event_loop() | ||
| with concurrent.futures.ThreadPoolExecutor( | ||
| max_workers=self.thread_num | ||
| ) as executor: | ||
| await loop.run_in_executor(executor, listen_function, value) | ||
| listen_function(value) | ||
| except Exception as e: | ||
| ValueError(f"Error in {key} listener function: {e}") | ||
| finally: | ||
| self.listen_operation.delete_change_log(delete_id=delete_id) | ||
| async def listen(self): | ||
| async with asyncio.Semaphore(self.thread_num): | ||
| while self.is_running: | ||
| status, change_data_items = self.listen_operation.listen_data() | ||
| tasks = [] | ||
| if status: | ||
| for data in change_data_items: | ||
| key = data[6] | ||
| new_value = data[7] | ||
| delete_id = data[0] | ||
| tasks.append( | ||
| asyncio.create_task( | ||
| self._process_listen_data(key, new_value, delete_id) | ||
| ) | ||
| ) | ||
| if tasks: | ||
| await asyncio.gather(*tasks, return_exceptions=True) | ||
| else: | ||
| await asyncio.sleep(0.05) | ||
| def start_listen_data(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| self.listen_thread = threading.Thread(target=self.listen) | ||
| self.listen_thread.start() | ||
| def stop_listen_data(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| if self.listen_thread and self.listen_thread.is_alive(): | ||
| self.listen_thread.join(timeout=2) |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : async_receive_scheduler.py | ||
| @Time : 2025-09-27 17:05:08 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 异步接收调度器 | ||
| """ | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| from ...model import MessageItem | ||
| from typing import Callable | ||
| import asyncio | ||
| import threading | ||
| import concurrent.futures | ||
| import logging | ||
| class AsyncReceiveScheduler: | ||
| def __init__( | ||
| self, queue_operation: ShardedQueueOperation, receive_thread_num: int = 1 | ||
| ): | ||
| self.callbacks = dict() | ||
| self.receive_thread_num = receive_thread_num | ||
| self.is_running = False | ||
| self.lock = threading.Lock() | ||
| self.queue_operation = queue_operation | ||
| self.receive_thread = None # 单一轮询线程 | ||
| def send_message(self, message: MessageItem, callback: Callable = None): # type: ignore | ||
| if callback is None: | ||
| callback = lambda message: logging.info(message) | ||
| # self.queue_operation.enqueue(message.to_dict()) | ||
| self.queue_operation.enqueue(message.to_dict_by_core()) | ||
| with self.lock: | ||
| self.callbacks[message.id] = callback | ||
| async def receive_message(self): | ||
| """单一轮询线程,并行执行回调""" | ||
| def callback_default(message): | ||
| return message | ||
| async with asyncio.Semaphore(self.receive_thread_num): | ||
| while self.is_running: | ||
| message_list = self.queue_operation.get_completed_messages() | ||
| tasks = [] | ||
| if message_list: | ||
| for message in message_list: | ||
| message = MessageItem.from_dict(message) | ||
| with self.lock: | ||
| callback = self.callbacks.pop(message.id, None) | ||
| if callback is None: | ||
| callback = callback_default | ||
| tasks.append( | ||
| asyncio.create_task(self._safe_callback(callback, message)) | ||
| ) | ||
| if tasks: | ||
| await asyncio.gather(*tasks, return_exceptions=True) | ||
| else: | ||
| await asyncio.sleep(0.05) | ||
| async def _safe_callback(self, callback, message): | ||
| """安全执行回调函数""" | ||
| try: | ||
| # 检查回调函数是否是异步函数 | ||
| if asyncio.iscoroutinefunction(callback): | ||
| await callback(message) | ||
| else: | ||
| # 如果是同步函数,则在执行器中运行以避免阻塞事件循环 | ||
| loop = asyncio.get_event_loop() | ||
| with concurrent.futures.ThreadPoolExecutor( | ||
| max_workers=self.receive_thread_num | ||
| ) as executor: | ||
| await loop.run_in_executor(executor, callback, message) | ||
| except Exception as e: | ||
| logging.error(f"回调执行错误: {str(e)}") | ||
| finally: | ||
| self.queue_operation.delete_message(message.id) | ||
| def _run_receive_loop(self): | ||
| """在新事件循环中运行接收消息循环""" | ||
| # 创建新的事件循环 | ||
| loop = asyncio.new_event_loop() | ||
| asyncio.set_event_loop(loop) | ||
| try: | ||
| # 运行异步接收函数直到停止 | ||
| loop.run_until_complete(self.receive_message()) | ||
| except Exception as e: | ||
| logging.error(f"任务调度出错: {str(e)}") | ||
| finally: | ||
| loop.close() | ||
| def start_receive_thread(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| # 创建单一轮询线程 | ||
| self.receive_thread = threading.Thread( | ||
| target=self._run_receive_loop, daemon=True | ||
| ) | ||
| self.receive_thread.start() | ||
| def stop_receive_thread(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| # 等待轮询线程结束 | ||
| if self.receive_thread and self.receive_thread.is_alive(): | ||
| self.receive_thread.join(timeout=5.0) |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : async_task_scheduler.py | ||
| @Time : 2025-09-27 17:05:22 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 异步任务调度器 | ||
| """ | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| from ...model import MessageItem | ||
| from ...constant import MessageStatus | ||
| from ...cycle.async_task_cycle import AsyncTaskCycle | ||
| from ...mounter.task_mounter import TaskMounter | ||
| import asyncio | ||
| from datetime import datetime | ||
| import threading | ||
| import multiprocessing | ||
| import logging | ||
| class AsyncTaskScheduler: | ||
| def __init__( | ||
| self, | ||
| queue_operation: ShardedQueueOperation, | ||
| task_thread_num: int = multiprocessing.cpu_count() * 2, | ||
| ): | ||
| self.task_thread_num = task_thread_num | ||
| self.is_running = False | ||
| self.queue_operation = queue_operation | ||
| self.task_thread = None # 单一轮询线程 | ||
| async def _process_message(self, message: MessageItem): | ||
| """处理单个消息""" | ||
| try: | ||
| if message.destination == "client": | ||
| message.status = MessageStatus.COMPLETED | ||
| message.result = {"result": "success"} | ||
| message.updatetime = datetime.now() | ||
| return message | ||
| task_function = TaskMounter.get_task_function(message.destination) | ||
| if task_function is None: | ||
| raise ValueError( | ||
| f"Task function not found for destination: {message.destination}" | ||
| ) | ||
| task_cycle = AsyncTaskCycle(message, task_function) | ||
| await task_cycle.run() | ||
| message.status = task_cycle.get_task_status() # type: ignore | ||
| if message.status == MessageStatus.FAILED: | ||
| message.result = {"error": task_cycle.get_task_error()} | ||
| else: | ||
| message.result = task_cycle.get_task_result() # type: ignore | ||
| message.updatetime = datetime.now() | ||
| except Exception as e: | ||
| message.status = MessageStatus.FAILED | ||
| message.result = {"error": str(e)} | ||
| message.updatetime = datetime.now() | ||
| return message | ||
| def _process_messages(self, message): | ||
| """更新任务结果到数据库""" | ||
| try: | ||
| self.queue_operation.update_result(message.id, message.result) | ||
| self.queue_operation.update_status(message.id, message.status) | ||
| except Exception as e: | ||
| logging.error(f"任务结果更新失败: {str(e)}") | ||
| async def task_callback(self): | ||
| """单一轮询线程,并行执行任务""" | ||
| # 使用信号量控制并发任务数 | ||
| semaphore = asyncio.Semaphore(self.task_thread_num) | ||
| async def limited_process_message(message): | ||
| async with semaphore: | ||
| return await self._process_message(MessageItem.from_dict(message)) | ||
| while self.is_running: | ||
| try: | ||
| message_list = self.queue_operation.dequeue( | ||
| size=self.task_thread_num * 2 | ||
| ) | ||
| if not message_list: | ||
| # 使用指数退避策略减少轮询开销 | ||
| await asyncio.sleep(0.05) # 增加延迟减少CPU使用 | ||
| continue | ||
| # 并发处理消息 | ||
| tasks = [ | ||
| asyncio.create_task(limited_process_message(message)) | ||
| for message in message_list | ||
| ] | ||
| # 等待所有任务完成 | ||
| completed, _ = await asyncio.wait( | ||
| tasks, | ||
| return_when=asyncio.ALL_COMPLETED, | ||
| timeout=30.0, # 添加超时防止无限等待 | ||
| ) | ||
| # 批量处理结果 | ||
| for task in completed: | ||
| try: | ||
| message = task.result() | ||
| self._process_messages(message) | ||
| except Exception as e: | ||
| logging.error(f"处理任务结果时出错: {str(e)}") | ||
| except Exception as e: | ||
| logging.error(f"任务调度出错: {str(e)}") | ||
| await asyncio.sleep(0.1) # 出错时短暂延迟 | ||
| def _run_task_loop(self): | ||
| """在新事件循环中运行任务处理循环""" | ||
| # 创建新的事件循环 | ||
| loop = asyncio.new_event_loop() | ||
| asyncio.set_event_loop(loop) | ||
| try: | ||
| # 运行异步任务处理函数直到停止 | ||
| loop.run_until_complete(self.task_callback()) | ||
| except Exception as e: | ||
| logging.error(f"任务调度出错: {str(e)}") | ||
| finally: | ||
| loop.close() | ||
| def start_task_thread(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| self.task_thread = threading.Thread(target=self._run_task_loop) | ||
| self.task_thread.daemon = True | ||
| self.task_thread.start() | ||
| def stop_task_thread(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| if self.task_thread: | ||
| self.task_thread.join(timeout=5.0) | ||
| self.task_thread = None |
| from .base_scheduler import BaseScheduler | ||
| __all__ = ["BaseScheduler"] |
| from abc import ABC, abstractmethod | ||
| from typing import Callable | ||
| from ...model import MessageItem | ||
| class BaseScheduler(ABC): | ||
| """调度器抽象类""" | ||
| @abstractmethod | ||
| def send_message(self, message: MessageItem, callback: Callable): | ||
| """发送消息到队列 | ||
| Args: | ||
| message (MessageItem): 消息对象 | ||
| callback (Callable): 发送完成后的回调函数 | ||
| """ | ||
| pass | ||
| @abstractmethod | ||
| def start(self): | ||
| """启动调度器""" | ||
| pass | ||
| @abstractmethod | ||
| def stop(self): | ||
| """停止调度器""" | ||
| pass | ||
| @abstractmethod | ||
| def update_listen_data(self, key, value): | ||
| """更新监听数据""" | ||
| pass | ||
| @abstractmethod | ||
| def get_listen_datas(self) -> list: | ||
| """获取监听数据""" | ||
| pass | ||
| @abstractmethod | ||
| def get_listen_data(self, key): | ||
| """获取单个监听数据""" | ||
| pass |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 17:03:16 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 标准调度器 | ||
| """ | ||
| from .receive_scheduler import ReceiveScheduler | ||
| from .task_scheduler import TaskScheduler | ||
| from .listen_data_scheduler import ListenDataScheduler | ||
| from ...model import MessageItem | ||
| from typing import Callable | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| from ...queue_operation.listen_operation import ListenOperation | ||
| from ..cleanup_scheduler import CleanupScheduler | ||
| import os | ||
| from ..base import BaseScheduler | ||
| class StandardQueueScheduler(BaseScheduler): | ||
| def __init__( | ||
| self, receive_thread_num=1, task_thread_num=1, shard_num=4, queue_name="default" | ||
| ): | ||
| self.queue_operation = ShardedQueueOperation(shard_num, queue_name) | ||
| self.listen_operation = ListenOperation( | ||
| os.path.join(self.queue_operation.db_dir, "listen.db") | ||
| ) | ||
| self.listen_operation.create_table() | ||
| self.listen_scheduler = ListenDataScheduler(self.listen_operation) | ||
| self.receive_scheduler = ReceiveScheduler( | ||
| self.queue_operation, receive_thread_num | ||
| ) | ||
| self.task_scheduler = TaskScheduler(self.queue_operation, task_thread_num) | ||
| self.cleanup_scheduler = CleanupScheduler(self.queue_operation) | ||
| def send_message(self, message: MessageItem, callback: Callable): | ||
| self.receive_scheduler.send_message(message, callback) | ||
| def update_listen_data(self, key, value): | ||
| self.listen_operation.update_listen_data(key, value) | ||
| def get_listen_datas(self): | ||
| return self.listen_operation.get_values() | ||
| def get_listen_data(self, key): | ||
| return self.listen_operation.get_value(key) | ||
| def start(self): | ||
| self.receive_scheduler.start_receive_thread() | ||
| self.task_scheduler.start_task_thread() | ||
| self.cleanup_scheduler.start_cleanup() | ||
| self.listen_scheduler.start_listen_data() | ||
| def stop(self): | ||
| self.receive_scheduler.stop_receive_thread() | ||
| self.listen_scheduler.stop_listen_data() | ||
| self.task_scheduler.stop_task_thread() | ||
| self.cleanup_scheduler.stop_cleanup() | ||
| # self.queue_operation.close_all_connections() | ||
| __all__ = ["StandardQueueScheduler"] |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : listen_data_scheduler.py | ||
| @Time : 2025-09-27 17:03:39 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 监听数据调度器 | ||
| """ | ||
| from ...queue_operation.listen_operation import ListenOperation | ||
| from concurrent.futures import ThreadPoolExecutor | ||
| from ...mounter.listen_mounter import ListenMounter | ||
| import threading | ||
| import multiprocessing | ||
| class ListenDataScheduler: | ||
| def __init__(self, listen_operation: ListenOperation): | ||
| self.listen_operation = listen_operation | ||
| self.is_running = False | ||
| self.executor = ThreadPoolExecutor(max_workers=multiprocessing.cpu_count()) | ||
| self.listen_thread = None | ||
| def _process_listen_data(self, key, value, delete_id): | ||
| listen_function = ListenMounter.get_Listener_function(key) | ||
| if listen_function: | ||
| try: | ||
| listen_function(value) | ||
| except Exception as e: | ||
| ValueError(f"Error in {key} listener function: {e}") | ||
| finally: | ||
| self.listen_operation.delete_change_log(delete_id=delete_id) | ||
| def listen(self): | ||
| while self.is_running: | ||
| status, change_data_items = self.listen_operation.listen_data() | ||
| if status: | ||
| for data in change_data_items: | ||
| key = data[6] | ||
| new_value = data[7] | ||
| delete_id = data[0] | ||
| self.executor.submit( | ||
| self._process_listen_data, key, new_value, delete_id | ||
| ) | ||
| def start_listen_data(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| self.listen_thread = threading.Thread(target=self.listen) | ||
| self.listen_thread.start() | ||
| def stop_listen_data(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| if self.listen_thread and self.listen_thread.is_alive(): | ||
| self.listen_thread.join(timeout=2) | ||
| self.executor.shutdown(wait=True) |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : receive_scheduler.py | ||
| @Time : 2025-09-27 17:03:55 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 接收调度器 | ||
| """ | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| from ...model import MessageItem | ||
| from typing import Callable | ||
| from concurrent.futures import ThreadPoolExecutor | ||
| import threading | ||
| import time | ||
| import logging | ||
| class ReceiveScheduler: | ||
| def __init__( | ||
| self, queue_operation: ShardedQueueOperation, receive_thread_num: int = 1 | ||
| ): | ||
| self.callbacks = dict() | ||
| self.receive_thread_num = receive_thread_num | ||
| self.is_running = False | ||
| self.executor = ThreadPoolExecutor( | ||
| max_workers=receive_thread_num | ||
| ) # 并行执行回调 | ||
| self.lock = threading.Lock() | ||
| self.queue_operation = queue_operation | ||
| self.receive_thread = None # 单一轮询线程 | ||
| def send_message(self, message: MessageItem, callback: Callable = None): # type: ignore | ||
| if callback is None: | ||
| callback = lambda message: logging.info(f"receive message: {message.id}") | ||
| # self.queue_operation.enqueue(message.to_dict()) | ||
| self.queue_operation.enqueue(message.to_dict_by_core()) | ||
| with self.lock: | ||
| self.callbacks[message.id] = callback | ||
| def receive_message(self): | ||
| """单一轮询线程,并行执行回调""" | ||
| while self.is_running: | ||
| message_list = self.queue_operation.get_completed_messages() | ||
| if message_list: | ||
| for message in message_list: | ||
| message = MessageItem.from_dict(message) | ||
| callback_default = lambda message: message | ||
| with self.lock: | ||
| callback = self.callbacks.pop(message.id, None) | ||
| if callback is None: | ||
| callback = callback_default | ||
| # 使用线程池并行执行回调 | ||
| self.executor.submit(self._safe_callback, callback, message) | ||
| else: | ||
| time.sleep(0.1) # 适当休眠避免CPU空转 | ||
| def _safe_callback(self, callback, message): | ||
| """安全执行回调函数""" | ||
| try: | ||
| callback(message) | ||
| except Exception as e: | ||
| logging.error(f"回调执行错误: {str(e)}") | ||
| finally: | ||
| self.queue_operation.delete_message(message.id) | ||
| def start_receive_thread(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| # 创建单一轮询线程 | ||
| self.receive_thread = threading.Thread(target=self.receive_message, daemon=True) | ||
| self.receive_thread.start() | ||
| def stop_receive_thread(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| # 等待轮询线程结束 | ||
| if self.receive_thread and self.receive_thread.is_alive(): | ||
| self.receive_thread.join(timeout=2.0) | ||
| # 关闭线程池 | ||
| self.executor.shutdown(wait=True) |
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : task_scheduler.py | ||
| @Time : 2025-09-27 17:04:09 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 任务调度器 | ||
| """ | ||
| import logging | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| from ...model import MessageItem | ||
| from ...constant import MessageStatus | ||
| from ...cycle.task_cycle import TaskCycle | ||
| from ...mounter.task_mounter import TaskMounter | ||
| from concurrent.futures import ThreadPoolExecutor | ||
| from datetime import datetime | ||
| import time | ||
| import threading | ||
| import multiprocessing | ||
| import json | ||
| class TaskScheduler: | ||
| def __init__( | ||
| self, | ||
| queue_operation: ShardedQueueOperation, | ||
| task_thread_num: int = multiprocessing.cpu_count() * 2, | ||
| ): | ||
| self.task_thread_num = task_thread_num | ||
| self.is_running = False | ||
| self.executor = ThreadPoolExecutor(max_workers=task_thread_num) # 并行执行任务 | ||
| self.queue_operation = queue_operation | ||
| self.task_thread = None # 单一轮询线程 | ||
| def _process_message(self, message: MessageItem): | ||
| """处理单个消息""" | ||
| try: | ||
| if message.destination == "client": | ||
| message.status = MessageStatus.COMPLETED | ||
| message.result = {"result": "success"} | ||
| message.updatetime = datetime.now() | ||
| return message | ||
| task_function = TaskMounter.get_task_function(message.destination) | ||
| task_cycle = TaskCycle(message, task_function) | ||
| task_cycle.run() | ||
| message.status = task_cycle.get_task_status() # type: ignore | ||
| if message.status == MessageStatus.FAILED: | ||
| message.result = {"error": task_cycle.get_task_error()} | ||
| else: | ||
| message.result = task_cycle.get_task_result() # type: ignore | ||
| message.updatetime = datetime.now() | ||
| except Exception as e: | ||
| message.status = MessageStatus.FAILED | ||
| message.result = {"error": str(e)} | ||
| message.updatetime = datetime.now() | ||
| return message | ||
| def _update_result(self, message): | ||
| """更新任务结果到数据库""" | ||
| try: | ||
| self.queue_operation.update_result(message.id, json.dumps(message.result)) | ||
| self.queue_operation.update_status(message.id, message.status) | ||
| except Exception as e: | ||
| logging.error(f"任务结果更新失败: {str(e)}") | ||
| def task_callback(self): | ||
| """单一轮询线程,并行执行任务""" | ||
| while self.is_running: | ||
| try: | ||
| message_list = self.queue_operation.dequeue( | ||
| size=self.task_thread_num * 2 | ||
| ) | ||
| if message_list: | ||
| # 并行处理所有获取到的消息 | ||
| for message in message_list: | ||
| self.executor.submit( | ||
| lambda m: self._update_result(self._process_message(m)), | ||
| MessageItem.from_dict(message), | ||
| ) | ||
| else: | ||
| time.sleep(0.1) # 适当休眠 | ||
| except Exception as e: | ||
| logging.error(f"任务调度错误: {str(e)}") | ||
| time.sleep(1) | ||
| def start_task_thread(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| # 创建单一轮询线程 | ||
| self.task_thread = threading.Thread(target=self.task_callback, daemon=True) | ||
| self.task_thread.start() | ||
| def stop_task_thread(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| # 等待轮询线程结束 | ||
| if self.task_thread and self.task_thread.is_alive(): | ||
| self.task_thread.join(timeout=2.0) | ||
| # 关闭线程池 | ||
| self.executor.shutdown(wait=True) |
| from .example import async_example | ||
| __all__ = ["async_example"] |
| from queue_sqlite.mounter import task | ||
| from queue_sqlite.model import MessageItem | ||
| @task(meta={"task_name": "test"}) | ||
| async def async_example(message_item: MessageItem): | ||
| def fibonacci_generator(): | ||
| a, b = 0, 1 | ||
| while True: | ||
| yield a | ||
| a, b = b, a + b | ||
| # 示例:获取前10项 | ||
| fib = fibonacci_generator() | ||
| message_item.result = {"fibonacci": [next(fib) for _ in range(500)]} | ||
| return message_item.to_json() | ||
| # 输出:[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] |
| from queue_sqlite.model import MessageItem | ||
| from queue_sqlite.scheduler import QueueScheduler | ||
| import time | ||
| from async_taks import * | ||
| import threading | ||
| import psutil | ||
| class TestAsyncScheduler: | ||
| callback_counter = 0 | ||
| lock = threading.Lock() | ||
| is_monitoring = False | ||
| @classmethod | ||
| def monitor_resources(cls): | ||
| """监控资源使用情况""" | ||
| while cls.is_monitoring: | ||
| cpu = psutil.cpu_percent() | ||
| memory = psutil.virtual_memory().percent | ||
| print(f"CPU使用率: {cpu}%, 内存使用率: {memory}%") | ||
| time.sleep(0.5) | ||
| @classmethod | ||
| async def _callback(cls, message_item: MessageItem): | ||
| with cls.lock: | ||
| cls.callback_counter += 1 | ||
| # if cls.callback_counter % 100 == 0: # 每100个任务打印一次 | ||
| # print(f"callback: {cls.callback_counter}") | ||
| print(f"callback: {message_item}") | ||
| # print(f"callback: {message_item.id}") | ||
| # print(f"callback: {message_item.expire_time}") | ||
| # print(f"callback: {message_item.tags}") | ||
| @classmethod | ||
| def test_async_scheduler(cls): | ||
| """测试异步调度器""" | ||
| TASK_NUM = 10000 | ||
| messages = [] | ||
| for i in range(TASK_NUM): | ||
| message_item = MessageItem(content={"num": i}, destination="async_example") | ||
| messages.append(message_item) | ||
| cls.is_monitoring = True | ||
| monitor_thread = threading.Thread(target=cls.monitor_resources, daemon=True) | ||
| monitor_thread.start() | ||
| queue_scheduler = QueueScheduler( | ||
| receive_thread_num=4, | ||
| task_thread_num=8, | ||
| shard_num=12, | ||
| scheduler_type="async", | ||
| ) | ||
| start_time = time.perf_counter() | ||
| queue_scheduler.start() | ||
| for message_item in messages: | ||
| message_item: MessageItem | ||
| queue_scheduler.send_message(message_item, cls._callback) | ||
| while ( | ||
| queue_scheduler.queue_operation.get_queue_length() > 0 | ||
| or cls.callback_counter < TASK_NUM | ||
| ): # 30秒超时 | ||
| time.sleep(0.5) | ||
| print(f"当前队列长度:{queue_scheduler.queue_operation.get_queue_length()}") | ||
| print(f"当前回调数量:{cls.callback_counter}") | ||
| queue_scheduler.stop() | ||
| print(f"当前队列长度:{queue_scheduler.queue_operation.get_queue_length()}") | ||
| print(f"测试函数:斐波那契数列") | ||
| print(f"次数:{TASK_NUM}") | ||
| print(f"总耗时: {time.perf_counter() - start_time:.2f}秒") | ||
| cls.is_monitoring = False | ||
| monitor_thread.join(timeout=1) |
+6
-1
@@ -21,2 +21,7 @@ # Python-generated files | ||
| # test files | ||
| .pytest_cache/ | ||
| .pytest_cache/ | ||
| # dynamic library | ||
| *.so | ||
| *.dll | ||
| *.pyd |
+8
-3
| Metadata-Version: 2.4 | ||
| Name: queue-sqlite | ||
| Version: 0.1.0 | ||
| Version: 0.2.0 | ||
| Summary: A high-performance, SQLite-based distributed task queue system with Rust-backed core operations. Supports task mounting, message listening, priority handling, retry mechanisms, and automatic cleanup of expired messages. Ideal for building reliable, scalable background task processing systems. | ||
@@ -12,6 +12,11 @@ Author-email: chakcy <947105045@qq.com> | ||
| Classifier: Operating System :: POSIX :: Linux | ||
| Classifier: Programming Language :: Python :: 3.13 | ||
| Classifier: Programming Language :: Python :: 3 | ||
| Classifier: Topic :: System :: Distributed Computing | ||
| Classifier: Typing :: Typed | ||
| Requires-Python: >=3.7 | ||
| Requires-Dist: queue-sqlite-core>=0.2.0 | ||
| Provides-Extra: pyqt6 | ||
| Requires-Dist: pyqt6; extra == 'pyqt6' | ||
| Provides-Extra: pyside6 | ||
| Requires-Dist: pyside6; extra == 'pyside6' | ||
| Description-Content-Type: text/markdown | ||
@@ -189,3 +194,3 @@ | ||
| ```bash | ||
| git clone https://github.com/your-repo/sqlite-task-queue.git | ||
| git clone https://gitee.com/cai-xinpenge/queue_sqlite.git | ||
| cd sqlite-task-queue | ||
@@ -192,0 +197,0 @@ ``` |
+10
-9
@@ -9,3 +9,3 @@ [project] | ||
| "License :: OSI Approved :: MIT License", | ||
| "Programming Language :: Python :: 3.13", | ||
| "Programming Language :: Python :: 3", | ||
| "Topic :: System :: Distributed Computing", | ||
@@ -16,3 +16,5 @@ "Typing :: Typed", | ||
| ] | ||
| dependencies = [] | ||
| dependencies = [ | ||
| "queue_sqlite_core>=0.2.0", | ||
| ] | ||
| description = "A high-performance, SQLite-based distributed task queue system with Rust-backed core operations. Supports task mounting, message listening, priority handling, retry mechanisms, and automatic cleanup of expired messages. Ideal for building reliable, scalable background task processing systems." | ||
@@ -22,4 +24,8 @@ name = "queue-sqlite" | ||
| requires-python = ">=3.7" | ||
| version = "0.1.0" | ||
| version = "0.2.0" | ||
| [project.optional-dependencies] | ||
| pyside6 = ["PySide6"] | ||
| pyqt6 = ["PyQt6"] | ||
| [[tool.uv.index]] | ||
@@ -38,2 +44,3 @@ default = true | ||
| "pytest>=7.4.4", | ||
| "twine>=4.0.2", | ||
| ] | ||
@@ -43,7 +50,1 @@ | ||
| packages = ["src/queue_sqlite"] | ||
| platforms = ["windows_x86_64", "linux_x86_64"] | ||
| [tool.hatch.build] | ||
| artifacts = [ | ||
| "src/queue_sqlite/core/*.pyd", | ||
| ] |
+1
-1
@@ -171,3 +171,3 @@ # SQLite 任务队列系统 | ||
| ```bash | ||
| git clone https://github.com/your-repo/sqlite-task-queue.git | ||
| git clone https://gitee.com/cai-xinpenge/queue_sqlite.git | ||
| cd sqlite-task-queue | ||
@@ -174,0 +174,0 @@ ``` |
+15
-13
| import os | ||
| import sys | ||
| def generate_markdown_from_py_files(directory, output_file): | ||
| with open(output_file, 'w', encoding='utf-8') as md_file: | ||
| with open(output_file, "w", encoding="utf-8") as md_file: | ||
| for root, dirs, files in os.walk(directory): | ||
| # 排除 venv 目录 | ||
| dirs[:] = [d for d in dirs if d != '.venv'] | ||
| dirs[:] = [d for d in dirs if d != '.vscode'] | ||
| dirs[:] = [d for d in dirs if d != 'scripts'] | ||
| dirs[:] = [d for d in dirs if d != 'build'] | ||
| dirs[:] = [d for d in dirs if d != ".venv"] | ||
| dirs[:] = [d for d in dirs if d != ".vscode"] | ||
| dirs[:] = [d for d in dirs if d != "scripts"] | ||
| dirs[:] = [d for d in dirs if d != "build"] | ||
| for file in files: | ||
| if file.endswith('.py') or file.endswith('.rs'): | ||
| if file.endswith(".py") or file.endswith(".rs"): | ||
| file_path = os.path.join(root, file) | ||
| md_file.write(f'`{file_path}`\n') | ||
| md_file.write('```python\n') | ||
| with open(file_path, 'r', encoding='utf-8') as py_file: | ||
| md_file.write(f"`{file_path}`\n") | ||
| md_file.write("```python\n") | ||
| with open(file_path, "r", encoding="utf-8") as py_file: | ||
| md_file.write(py_file.read()) | ||
| md_file.write('\n```\n\n') | ||
| md_file.write("\n```\n\n") | ||
| if __name__ == "__main__": | ||
| # 指定目录和输出文件名 | ||
| target_directory = sys.argv[1] # 替换为你的目标目录 | ||
| output_markdown_file = 'output.md' # 输出的 Markdown 文件名 | ||
| target_directory = sys.argv[1] # 替换为你的目标目录 | ||
| output_markdown_file = "output.md" # 输出的 Markdown 文件名 | ||
| generate_markdown_from_py_files(target_directory, output_markdown_file) | ||
| print(f'Markdown 文件已生成:{output_markdown_file}') | ||
| print(f"Markdown 文件已生成:{output_markdown_file}") |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 16:56:34 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 常量模块 | ||
| """ | ||
| from .message_priority import MessagePriority | ||
@@ -5,2 +16,2 @@ from .message_status import MessageStatus | ||
| __all__ = ["MessagePriority", "MessageStatus", "MessageType"] | ||
| __all__ = ["MessagePriority", "MessageStatus", "MessageType"] |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : message_priority.py | ||
| @Time : 2025-09-27 16:56:58 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 消息优先级枚举类 | ||
| """ | ||
| from enum import IntEnum | ||
@@ -2,0 +13,0 @@ |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : message_status.py | ||
| @Time : 2025-09-27 16:57:25 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 消息状态枚举类 | ||
| """ | ||
| from enum import IntEnum | ||
@@ -10,2 +21,1 @@ | ||
| RETRYING = 4 | ||
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : message_type.py | ||
| @Time : 2025-09-27 16:57:58 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 消息类型枚举类 | ||
| """ | ||
| from enum import Enum | ||
@@ -5,3 +16,3 @@ | ||
| class MessageType(Enum): | ||
| TASK = "task" # 任务 | ||
| LISTEN = "listen" # 监听 | ||
| TASK = "task" # 任务 | ||
| LISTEN = "listen" # 监听 |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : task_cycle.py | ||
| @Time : 2025-09-27 16:59:31 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 任务周期模块 | ||
| """ | ||
| from ..model import MessageItem | ||
@@ -6,2 +17,46 @@ from typing import Callable, Optional | ||
| import functools | ||
| import time | ||
| def retry_sync(max_retries=3, delay=1): | ||
| """ | ||
| 同步重试装饰器 | ||
| Args: | ||
| max_retries: 最大重试次数 | ||
| delay: 重试间隔(秒) | ||
| """ | ||
| def decorator(func): | ||
| @functools.wraps(func) | ||
| def wrapper(self, *args, **kwargs): | ||
| last_exception = None | ||
| # 使用message_item中的retry_count作为最大重试次数 | ||
| retries = getattr(self.message_item, "retry_count", max_retries) | ||
| # 至少尝试一次(retries+1),最多尝试max_retries+1次 | ||
| actual_retries = min(retries, max_retries) if max_retries > 0 else retries | ||
| for attempt in range(actual_retries + 1): | ||
| try: | ||
| return func(self, *args, **kwargs) | ||
| except Exception as e: | ||
| last_exception = e | ||
| if attempt < actual_retries: | ||
| time.sleep(delay) | ||
| else: | ||
| break | ||
| # 如果没有捕获到异常,则创建一个新的异常 | ||
| if last_exception is not None: | ||
| raise last_exception | ||
| else: | ||
| raise Exception("Unknown error occurred during sync task execution") | ||
| return wrapper | ||
| return decorator | ||
| class TaskCycle: | ||
@@ -15,5 +70,6 @@ def __init__(self, message_item: MessageItem, callback: Optional[Callable]): | ||
| @retry_sync(max_retries=3, delay=1) | ||
| def run(self): | ||
| try: | ||
| task_result = self.callback(self.message_item) # type: ignore | ||
| task_result = self.callback(self.message_item) # type: ignore | ||
| except Exception as e: | ||
@@ -24,3 +80,3 @@ self.task_result = None | ||
| else: | ||
| self.task_result = task_result # type: ignore | ||
| self.task_result = task_result # type: ignore | ||
| self.task_status = MessageStatus.COMPLETED | ||
@@ -34,3 +90,3 @@ self.task_error = None | ||
| except: | ||
| return json.dumps({'result': str(self.task_result)}) | ||
| return json.dumps({"result": str(self.task_result)}) | ||
@@ -42,9 +98,9 @@ elif isinstance(self.task_result, str): | ||
| except: | ||
| return json.dumps({'result': self.task_result}) | ||
| return json.dumps({"result": self.task_result}) | ||
| elif isinstance(self.task_result, (int, float, bool)): | ||
| return json.dumps({'result': self.task_result}) | ||
| return json.dumps({"result": self.task_result}) | ||
| elif self.task_result is None: | ||
| return 'null' | ||
| return "null" | ||
| else: | ||
| return json.dumps({'result': str(self.task_result)}) | ||
| return json.dumps({"result": str(self.task_result)}) | ||
@@ -56,9 +112,7 @@ def get_task_status(self): | ||
| return self.task_error | ||
| def get_task_message_item(self): | ||
| return self.message_item | ||
| def get_task_callback(self): | ||
| return self.callback | ||
@@ -0,3 +1,15 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 16:59:58 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 模型模块 | ||
| """ | ||
| from .message_item import MessageItem | ||
| __all__ = ["MessageItem"] | ||
| __all__ = ["MessageItem"] |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : message_item.py | ||
| @Time : 2025-09-27 17:00:27 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 消息数据模型 | ||
| """ | ||
| from dataclasses import dataclass, field | ||
@@ -8,2 +19,3 @@ from typing import Optional, Dict, Any | ||
| import uuid | ||
| import logging | ||
@@ -119,3 +131,9 @@ | ||
| if isinstance(data["type"], str): | ||
| data["type"] = MessageType(data["type"]) # 使用枚举名称 | ||
| # 根据字符串值查找对应的枚举成员 | ||
| for member in MessageType: | ||
| if member.value == data["type"]: | ||
| data["type"] = member | ||
| break | ||
| else: | ||
| raise ValueError(f"Invalid message type: {data['type']}") | ||
| elif isinstance(data["type"], MessageType): | ||
@@ -128,3 +146,9 @@ pass # 已经是枚举类型 | ||
| if isinstance(data["status"], str): | ||
| data["status"] = MessageStatus(data["status"]) # 使用枚举名称 | ||
| # 尝试将字符串转换为整数,如果失败则使用字符串作为枚举名称 | ||
| try: | ||
| data["status"] = MessageStatus( | ||
| int(data["status"]) | ||
| ) # 尝试作为枚举值 | ||
| except ValueError: | ||
| data["status"] = MessageStatus(data["status"]) # 使用枚举名称 | ||
| elif isinstance(data["status"], int): | ||
@@ -138,9 +162,34 @@ data["status"] = MessageStatus(data["status"]) # 使用枚举值 | ||
| if "priority" in data: | ||
| if isinstance(data["priority"], (int, str)): | ||
| data["priority"] = MessagePriority(data["priority"]) # type: ignore | ||
| if isinstance(data["priority"], str): | ||
| # 尝试将字符串转换为整数,如果失败则使用字符串作为枚举名称 | ||
| try: | ||
| data["priority"] = MessagePriority( | ||
| int(data["priority"]) | ||
| ) # 尝试作为枚举值 | ||
| except ValueError: | ||
| # 如果转换失败,尝试通过枚举名称查找 | ||
| for member in MessagePriority: | ||
| if member.name == data["priority"]: | ||
| data["priority"] = member | ||
| break | ||
| else: | ||
| raise ValueError( | ||
| f"Invalid message priority: {data['priority']}" | ||
| ) | ||
| elif isinstance(data["priority"], int): | ||
| data["priority"] = MessagePriority(data["priority"]) # 使用枚举值 | ||
| elif isinstance(data["priority"], MessagePriority): | ||
| pass | ||
| pass # 已经是枚举类型 | ||
| else: | ||
| raise ValueError("请使用 'int' 或 'str' 类型设置 priority 字段") | ||
| if "retry_count" in data: | ||
| if isinstance(data["retry_count"], str): | ||
| if data["retry_count"].isdigit(): | ||
| data["retry_count"] = int(data["retry_count"]) | ||
| else: | ||
| raise ValueError("请使用 'int' 类型设置 retry_count 字段") | ||
| elif isinstance(data["retry_count"], int): | ||
| pass # 已经是整数类型 | ||
| return cls(**data) | ||
@@ -242,11 +291,11 @@ | ||
| print(f"=== {cls.__name__} 字段信息 ===") | ||
| logging.info(f"=== {cls.__name__} 字段信息 ===") | ||
| for field_info in fields(cls): | ||
| print(f"字段名: {field_info.name}") | ||
| print(f"类型: {field_info.type}") | ||
| print(f"默认值: {field_info.default}") | ||
| logging.info(f"字段名: {field_info.name}") | ||
| logging.info(f"类型: {field_info.type}") | ||
| logging.info(f"默认值: {field_info.default}") | ||
| if field_info.default_factory is not None: | ||
| print(f"默认工厂: {field_info.default_factory}") | ||
| logging.info(f"默认工厂: {field_info.default_factory}") | ||
| if "description" in field_info.metadata: | ||
| print(f"描述: {field_info.metadata['description']}") | ||
| print("-" * 50) | ||
| logging.info(f"描述: {field_info.metadata['description']}") | ||
| logging.info("-" * 50) |
@@ -1,4 +0,15 @@ | ||
| from .task_mounter import TaskMounter | ||
| from .listen_mounter import ListenMounter | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 17:00:47 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 挂载器模块 | ||
| """ | ||
| __all__ = ["TaskMounter", "ListenMounter"] | ||
| from .task_mounter import task | ||
| from .listen_mounter import listener | ||
| __all__ = ["task", "listener"] |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : listen_mounter.py | ||
| @Time : 2025-09-27 17:01:23 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 监听装饰器 | ||
| """ | ||
| from typing import Callable, List | ||
@@ -8,6 +19,7 @@ | ||
| setattr(cls, function.__name__, function) | ||
| @staticmethod | ||
| def listener(): | ||
| """带参数的装饰器""" | ||
| def decorator(function: Callable): | ||
@@ -17,4 +29,5 @@ # 使用自定义名称或函数原名 | ||
| return function | ||
| return decorator | ||
| @classmethod | ||
@@ -28,3 +41,3 @@ def get_Listener_function(cls, name: str): | ||
| listener_list = [] | ||
| # 遍历类属性字典 | ||
@@ -37,9 +50,18 @@ for attr_name, attr_value in vars(cls).items(): | ||
| if ( | ||
| callable(attr_value) | ||
| and not attr_name.startswith("__") | ||
| and attr_name not in ["mount_Listener", "listener", "get_Listener_function", "get_Listener_list"] | ||
| callable(attr_value) | ||
| and not attr_name.startswith("__") | ||
| and attr_name | ||
| not in [ | ||
| "mount_Listener", | ||
| "listener", | ||
| "get_Listener_function", | ||
| "get_Listener_list", | ||
| ] | ||
| ): | ||
| listener_list.append(attr_name) | ||
| return listener_list | ||
| def listener(): | ||
| return ListenMounter.listener() |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : task_mounter.py | ||
| @Time : 2025-09-27 17:01:38 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 任务挂载器 | ||
| """ | ||
| from typing import Callable, List | ||
@@ -8,13 +19,15 @@ | ||
| setattr(cls, function.__name__, function) | ||
| @staticmethod | ||
| def task(meta: dict = {}): | ||
| """带参数的装饰器""" | ||
| def decorator(function: Callable): | ||
| # 使用自定义名称或函数原名 | ||
| function.meta = meta # type: ignore | ||
| function.meta = meta # type: ignore | ||
| setattr(TaskMounter, function.__name__, function) | ||
| return function | ||
| return decorator | ||
| @classmethod | ||
@@ -28,3 +41,3 @@ def get_task_function(cls, name: str): | ||
| task_list = [] | ||
| # 遍历类属性字典 | ||
@@ -37,9 +50,14 @@ for attr_name, attr_value in vars(cls).items(): | ||
| if ( | ||
| callable(attr_value) | ||
| and not attr_name.startswith("__") | ||
| and attr_name not in ["mount_task", "task", "get_task_function", "get_task_list"] | ||
| callable(attr_value) | ||
| and not attr_name.startswith("__") | ||
| and attr_name | ||
| not in ["mount_task", "task", "get_task_function", "get_task_list"] | ||
| ): | ||
| task_list.append(attr_name) | ||
| return task_list | ||
| # task 装饰器 | ||
| def task(meta: dict = {}): | ||
| return TaskMounter.task(meta) |
@@ -1,3 +0,9 @@ | ||
| from .queue_operation import QueueOperation | ||
| __all__ = ["QueueOperation"] | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 17:01:59 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 队列操作模块 | ||
| """ |
@@ -0,1 +1,12 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : listen_operation.py | ||
| @Time : 2025-09-27 17:02:18 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 监听操作模块 | ||
| """ | ||
| from ..mounter.listen_mounter import ListenMounter | ||
@@ -12,6 +23,17 @@ import sqlite3 | ||
| def _get_connection(self): | ||
| """获取数据库连接""" | ||
| return sqlite3.connect( | ||
| self.db_dir, | ||
| check_same_thread=False, | ||
| ) | ||
| def create_table(self): | ||
| if len(self.listen_fields) == 0: | ||
| return | ||
| sql = f""" | ||
| conn = self._get_connection() | ||
| # 分别执行每个SQL语句而不是使用executescript | ||
| conn.execute( | ||
| """ | ||
| CREATE TABLE IF NOT EXISTS listen_table ( | ||
@@ -21,3 +43,8 @@ id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| value JSON | ||
| ); | ||
| ) | ||
| """ | ||
| ) | ||
| conn.execute( | ||
| """ | ||
| CREATE TABLE IF NOT EXISTS change_log ( | ||
@@ -32,34 +59,34 @@ id INTEGER PRIMARY KEY AUTOINCREMENT, | ||
| timestamp DATETIME DEFAULT CURRENT_TIMESTAMP | ||
| ); | ||
| CREATE TRIGGER IF NOT EXISTS track_value_change | ||
| AFTER UPDATE OF value ON listen_table -- 监听特定列 | ||
| FOR EACH ROW | ||
| WHEN OLD.value <> NEW.value -- 仅当值实际变化时触发 | ||
| BEGIN | ||
| INSERT INTO change_log (table_name, row_id, column_name, old_value, new_value) | ||
| VALUES ('listen_table', NEW.id, 'key', OLD.key, NEW.key); | ||
| END; | ||
| ) | ||
| """ | ||
| self.conn = sqlite3.connect( | ||
| self.db_dir, | ||
| check_same_thread = False, | ||
| ) | ||
| self.conn.executescript(sql) | ||
| self.conn.execute("PRAGMA journal_mode=WAL;") | ||
| self.conn.execute("PRAGMA synchronous=NORMAL;") | ||
| self.conn.execute("PRAGMA cache_size=-20000;") | ||
| self.conn.execute("PRAGMA mmap_size=1073741824;") | ||
| self.conn.execute("PRAGMA temp_store=MEMORY;") | ||
| self.conn.execute("PRAGMA busy_timeout=5000;") | ||
| self.conn.commit() | ||
| # 删除原有数据 | ||
| # sql = f""" | ||
| # DELETE FROM listen_table | ||
| # """ | ||
| # self.conn.execute(sql) | ||
| # self.conn.commit() | ||
| # 检查触发器是否已存在,如果不存在则创建 | ||
| try: | ||
| conn.execute( | ||
| """ | ||
| CREATE TRIGGER IF NOT EXISTS track_value_change | ||
| AFTER UPDATE OF value ON listen_table | ||
| FOR EACH ROW | ||
| WHEN OLD.value <> NEW.value | ||
| BEGIN | ||
| INSERT INTO change_log (table_name, row_id, column_name, old_value, new_value) | ||
| VALUES ('listen_table', NEW.id, 'key', OLD.key, NEW.key); | ||
| END | ||
| """ | ||
| ) | ||
| except sqlite3.Error: | ||
| # 如果触发器创建失败,我们继续执行其他操作 | ||
| pass | ||
| conn.execute("PRAGMA journal_mode=WAL;") | ||
| conn.execute("PRAGMA synchronous=NORMAL;") | ||
| conn.execute("PRAGMA cache_size=-20000;") | ||
| conn.execute("PRAGMA mmap_size=1073741824;") | ||
| conn.execute("PRAGMA temp_store=MEMORY;") | ||
| conn.execute("PRAGMA busy_timeout=5000;") | ||
| conn.commit() | ||
| for listen_field in self.listen_fields: | ||
| sql = f""" | ||
| sql = """ | ||
| INSERT INTO | ||
@@ -70,5 +97,5 @@ listen_table (key, value) | ||
| """ | ||
| self.conn.execute(sql, (listen_field, "null")) | ||
| self.conn.commit() | ||
| conn.execute(sql, (listen_field, "null")) | ||
| conn.commit() | ||
| def listen_data(self) -> Tuple[bool, Union[List[Tuple], str]]: | ||
@@ -78,8 +105,8 @@ sql = f""" | ||
| """ | ||
| result = self.conn.execute(sql).fetchall() | ||
| conn = self._get_connection() | ||
| result = conn.execute(sql).fetchall() | ||
| if len(result) == 0: | ||
| return False, "No data found" | ||
| return True, result | ||
| def delete_change_log(self, delete_id): | ||
@@ -89,4 +116,5 @@ sql = f""" | ||
| """ | ||
| self.conn.execute(sql) | ||
| conn = self._get_connection() | ||
| conn.execute(sql) | ||
| def update_listen_data(self, key, value): | ||
@@ -96,4 +124,5 @@ sql = f""" | ||
| """ | ||
| self.conn.execute(sql) | ||
| self.conn.commit() | ||
| conn = self._get_connection() | ||
| conn.execute(sql) | ||
| conn.commit() | ||
@@ -104,7 +133,8 @@ def get_value(self, key): | ||
| """ | ||
| result = self.conn.execute(sql).fetchone() | ||
| conn = self._get_connection() | ||
| result = conn.execute(sql).fetchone() | ||
| if result is None: | ||
| return None | ||
| return result[0] | ||
| def get_values(self): | ||
@@ -114,3 +144,4 @@ sql = f""" | ||
| """ | ||
| result = self.conn.execute(sql).fetchall() | ||
| conn = self._get_connection() | ||
| result = conn.execute(sql).fetchall() | ||
| return result |
@@ -1,49 +0,70 @@ | ||
| from .receive_scheduler import ReceiveScheduler | ||
| from .task_scheduler import TaskScheduler | ||
| from .listen_data_scheduler import ListenDataScheduler | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : __init__.py | ||
| @Time : 2025-09-27 17:02:39 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 队列调度器 | ||
| """ | ||
| from .standard import StandardQueueScheduler | ||
| from ._async import AsyncQueueScheduler | ||
| from .base import BaseScheduler | ||
| from ..model import MessageItem | ||
| from typing import Callable | ||
| from ..queue_operation import QueueOperation | ||
| from ..queue_operation.listen_operation import ListenOperation | ||
| from .cleanup_scheduler import CleanupScheduler | ||
| import os | ||
| import multiprocessing | ||
| class QueueScheduler: | ||
| def __init__(self, receive_thread_num=1, task_thread_num=1, shard_num=4): | ||
| self.queue_operation = QueueOperation(shard_num) | ||
| self.listen_operation = ListenOperation(os.path.join(self.queue_operation.db_dir, "listen.db")) | ||
| self.listen_operation.create_table() | ||
| self.listen_scheduler = ListenDataScheduler(self.listen_operation) | ||
| self.receive_scheduler = ReceiveScheduler(self.queue_operation, receive_thread_num) | ||
| self.task_scheduler = TaskScheduler(self.queue_operation, task_thread_num) | ||
| self.cleanup_scheduler = CleanupScheduler(self.queue_operation) | ||
| SCHEDULER_TYPES = {"standard": StandardQueueScheduler, "async": AsyncQueueScheduler} | ||
| class QueueScheduler(BaseScheduler): | ||
| def __init__( | ||
| self, | ||
| receive_thread_num=1, | ||
| task_thread_num=multiprocessing.cpu_count() * 2, | ||
| shard_num=4, | ||
| scheduler_type="standard", | ||
| ): | ||
| scheduler_class = SCHEDULER_TYPES.get(scheduler_type, None) | ||
| if not scheduler_class: | ||
| raise ValueError(f"Invalid scheduler type: {scheduler_type}") | ||
| self.scheduler = scheduler_class(receive_thread_num, task_thread_num, shard_num) | ||
| if self.scheduler: | ||
| self.queue_operation = self.scheduler.queue_operation | ||
| def send_message(self, message: MessageItem, callback: Callable): | ||
| self.receive_scheduler.send_message(message, callback) | ||
| if not self.scheduler: | ||
| raise Exception("Scheduler not initialized") | ||
| self.scheduler.send_message(message, callback) | ||
| def start(self): | ||
| if not self.scheduler: | ||
| raise Exception("Scheduler not initialized") | ||
| self.scheduler.start() | ||
| def stop(self): | ||
| if not self.scheduler: | ||
| raise Exception("Scheduler not initialized") | ||
| self.scheduler.stop() | ||
| def update_listen_data(self, key, value): | ||
| self.listen_operation.update_listen_data(key, value) | ||
| if not self.scheduler: | ||
| raise Exception("Scheduler not initialized") | ||
| self.scheduler.update_listen_data(key, value) | ||
| def get_listen_datas(self): | ||
| return self.listen_operation.get_values() | ||
| if not self.scheduler: | ||
| raise Exception("Scheduler not initialized") | ||
| return self.scheduler.get_listen_datas() | ||
| def get_listen_data(self, key): | ||
| return self.listen_operation.get_value(key) | ||
| if not self.scheduler: | ||
| raise Exception("Scheduler not initialized") | ||
| return self.scheduler.get_listen_data(key) | ||
| def start_queue_scheduler(self): | ||
| self.receive_scheduler.start_receive_thread() | ||
| self.task_scheduler.start_task_thread() | ||
| self.cleanup_scheduler.start_cleanup() | ||
| self.listen_scheduler.start_listen_data() | ||
| def stop_queue_scheduler(self): | ||
| self.receive_scheduler.stop_receive_thread() | ||
| self.listen_scheduler.stop_listen_data() | ||
| self.task_scheduler.stop_task_thread() | ||
| self.cleanup_scheduler.stop_cleanup() | ||
| # self.queue_operation.close_all_connections() | ||
| __all__ = [ | ||
| "QueueScheduler" | ||
| ] | ||
| __all__ = ["QueueScheduler"] |
@@ -0,9 +1,26 @@ | ||
| #!/usr/bin/env python | ||
| # -*- encoding: utf-8 -*- | ||
| """ | ||
| @File : cleanup_scheduler.py | ||
| @Time : 2025-09-27 17:02:55 | ||
| @Author : chakcy | ||
| @Email : 947105045@qq.com | ||
| @description : 清理调度器 | ||
| """ | ||
| # 新建清理调度器 | ||
| import threading | ||
| import time | ||
| from ..queue_operation import QueueOperation | ||
| from queue_sqlite_core import ShardedQueueOperation | ||
| import logging | ||
| class CleanupScheduler: | ||
| def __init__(self, queue_operation: QueueOperation, interval_minutes=60): | ||
| def __init__( | ||
| self, | ||
| queue_operation: ShardedQueueOperation, | ||
| interval_minutes=60, | ||
| remove_days=30, | ||
| ): | ||
| self.queue_operation = queue_operation | ||
@@ -13,3 +30,10 @@ self.interval = interval_minutes * 60 # 转换为秒 | ||
| self.cleanup_thread = None | ||
| self.remove_days = remove_days | ||
| # for i in range(self.queue_operation.shard_num): | ||
| # 清理过期但未处理的消息 | ||
| self.queue_operation.clean_expired_messages() | ||
| # 彻底删除30天前的消息 | ||
| self.queue_operation.remove_expired_messages(self.remove_days) | ||
| def cleanup_expired_messages(self): | ||
@@ -19,13 +43,7 @@ """清理过期消息""" | ||
| try: | ||
| # 清理7天前的已完成/失败消息 | ||
| for i in range(self.queue_operation.shard_num): | ||
| self.queue_operation.clean_old_messages(i, 7) | ||
| # 清理过期但未处理的消息 | ||
| for i in range(self.queue_operation.shard_num): | ||
| self.queue_operation.clean_expired_messages(i) | ||
| self.queue_operation.clean_expired_messages() | ||
| except Exception as e: | ||
| print(f"清理消息错误: {str(e)}") | ||
| logging.error(f"清理消息错误: {str(e)}") | ||
| # 休眠等待下次清理 | ||
@@ -40,5 +58,7 @@ for _ in range(self.interval): | ||
| return | ||
| self.is_running = True | ||
| self.cleanup_thread = threading.Thread(target=self.cleanup_expired_messages, daemon=True) | ||
| self.cleanup_thread = threading.Thread( | ||
| target=self.cleanup_expired_messages, daemon=True | ||
| ) | ||
| self.cleanup_thread.start() | ||
@@ -49,5 +69,5 @@ | ||
| return | ||
| self.is_running = False | ||
| if self.cleanup_thread and self.cleanup_thread.is_alive(): | ||
| self.cleanup_thread.join(timeout=2.0) | ||
| self.cleanup_thread.join(timeout=2.0) |
@@ -1,5 +0,6 @@ | ||
| from queue_sqlite.mounter.listen_mounter import ListenMounter | ||
| from queue_sqlite.mounter.listen_mounter import listener | ||
| @ListenMounter.listener() | ||
| @listener() | ||
| def key_1(data): | ||
| print(data) | ||
| print(data) |
@@ -1,6 +0,6 @@ | ||
| from queue_sqlite.mounter.task_mounter import TaskMounter | ||
| from queue_sqlite.mounter import task | ||
| from queue_sqlite.model import MessageItem | ||
| @TaskMounter.task(meta={"task_name": "test"}) | ||
| @task(meta={"task_name": "test"}) | ||
| def example(message_item: MessageItem): | ||
@@ -19,2 +19,2 @@ def fibonacci_generator(): | ||
| # 输出:[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] | ||
| # 输出:[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] |
+11
-6
@@ -1,3 +0,3 @@ | ||
| from queue_sqlite.core import core | ||
| from queue_sqlite.mounter import TaskMounter | ||
| import queue_sqlite_core as core | ||
| from queue_sqlite.mounter.task_mounter import TaskMounter | ||
| from queue_sqlite.model import MessageItem | ||
@@ -13,7 +13,12 @@ | ||
| task_mounter.get_task_list() | ||
| print(task_mounter.get_task_function("task")({"num": 1})(lambda x: x+1).meta["num"]) | ||
| print( | ||
| task_mounter.get_task_function("task")({"num": 1})(lambda x: x + 1).meta[ # type: ignore | ||
| "num" | ||
| ] | ||
| ) | ||
| from tasks import example | ||
| task_mounter.get_task_list() | ||
| print(task_mounter.get_task_function("<lambda>")) | ||
| @classmethod | ||
@@ -25,3 +30,3 @@ def test_queue_operation_init_db(cls): | ||
| def test_queue_operation_enqueue(cls): | ||
| message_item = MessageItem(content={"num": 1}, destination="test") | ||
| message_item = MessageItem(content={"num": 1}, destination="test") # type: ignore | ||
| cls.queue_operation.enqueue(message_item.to_dict_by_core()) | ||
@@ -33,2 +38,2 @@ | ||
| cls.queue_operation.enqueue(message_item.to_dict_by_core()) | ||
| print(cls.queue_operation.dequeue(1)) | ||
| print(cls.queue_operation.dequeue(1)) |
@@ -9,3 +9,3 @@ from listen import * | ||
| scheduler = QueueScheduler() | ||
| scheduler.start_queue_scheduler() | ||
| scheduler.start() | ||
| scheduler.update_listen_data("key_1", "value_1") | ||
@@ -19,4 +19,4 @@ time.sleep(0.001) | ||
| time.sleep(0.001) | ||
| scheduler.stop_queue_scheduler() | ||
| scheduler.stop() | ||
| print(scheduler.get_listen_datas()) | ||
| print(scheduler.get_listen_data("key_1")) |
+20
-13
@@ -28,2 +28,5 @@ from queue_sqlite.model import MessageItem | ||
| cls.callback_counter += 1 | ||
| # if cls.callback_counter % 100 == 0: # 每100个任务打印一次 | ||
| # print(f"callback: {cls.callback_counter}") | ||
| print(message_item.id) | ||
| # print(f"callback: {message_item}") | ||
@@ -53,8 +56,10 @@ # print(f"callback: {message_item.id}") | ||
| messages.append(message_item) | ||
| cls.is_monitoring = True | ||
| monitor_thread = threading.Thread(target=cls.monitor_resources, daemon=True) | ||
| monitor_thread.start() | ||
| queue_scheduler = QueueScheduler(receive_thread_num=4, task_thread_num=8, shard_num=12) | ||
| queue_scheduler = QueueScheduler( | ||
| receive_thread_num=4, task_thread_num=8, shard_num=12 | ||
| ) | ||
| # threads = [] | ||
@@ -67,22 +72,25 @@ # for message_item in messages: | ||
| start_time = time.perf_counter() | ||
| queue_scheduler.start_queue_scheduler() | ||
| queue_scheduler.start() | ||
| for message_item in messages: # 增加任务数量 | ||
| message_item: MessageItem | ||
| queue_scheduler.send_message(message_item, cls._callback) | ||
| # # 多线程发送任务 | ||
| # for t in threads: | ||
| # t.start() | ||
| # # 动态等待任务完成 | ||
| start_wait = time.time() | ||
| while (queue_scheduler.queue_operation.get_queue_length() > 0 or cls.callback_counter < TASK_NUM): # 30秒超时 | ||
| while ( | ||
| queue_scheduler.queue_operation.get_queue_length() > 0 | ||
| or cls.callback_counter < TASK_NUM | ||
| ): # 30秒超时 | ||
| time.sleep(0.5) | ||
| print(f"当前队列长度:{queue_scheduler.queue_operation.get_queue_length()}") | ||
| print(f"当前回调数量:{cls.callback_counter}") | ||
| queue_scheduler.stop_queue_scheduler() | ||
| queue_scheduler.stop() | ||
| print(f"当前队列长度:{queue_scheduler.queue_operation.get_queue_length()}") | ||
@@ -95,2 +103,1 @@ print(f"测试函数:斐波那契数列") | ||
| monitor_thread.join(timeout=1) | ||
| /target | ||
| # Byte-compiled / optimized / DLL files | ||
| __pycache__/ | ||
| .pytest_cache/ | ||
| *.py[cod] | ||
| # C extensions | ||
| *.so | ||
| # Distribution / packaging | ||
| .Python | ||
| .venv/ | ||
| env/ | ||
| bin/ | ||
| build/ | ||
| develop-eggs/ | ||
| dist/ | ||
| eggs/ | ||
| lib/ | ||
| lib64/ | ||
| parts/ | ||
| sdist/ | ||
| var/ | ||
| include/ | ||
| man/ | ||
| venv/ | ||
| *.egg-info/ | ||
| .installed.cfg | ||
| *.egg | ||
| # Installer logs | ||
| pip-log.txt | ||
| pip-delete-this-directory.txt | ||
| pip-selfcheck.json | ||
| # Unit test / coverage reports | ||
| htmlcov/ | ||
| .tox/ | ||
| .coverage | ||
| .cache | ||
| nosetests.xml | ||
| coverage.xml | ||
| # Translations | ||
| *.mo | ||
| # Mr Developer | ||
| .mr.developer.cfg | ||
| .project | ||
| .pydevproject | ||
| # Rope | ||
| .ropeproject | ||
| # Django stuff: | ||
| *.log | ||
| *.pot | ||
| .DS_Store | ||
| # Sphinx documentation | ||
| docs/_build/ | ||
| # PyCharm | ||
| .idea/ | ||
| # VSCode | ||
| .vscode/ | ||
| # Pyenv | ||
| .python-version |
| # This file is automatically @generated by Cargo. | ||
| # It is not intended for manual editing. | ||
| version = 4 | ||
| [[package]] | ||
| name = "ahash" | ||
| version = "0.8.12" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "once_cell", | ||
| "version_check", | ||
| "zerocopy", | ||
| ] | ||
| [[package]] | ||
| name = "android-tzdata" | ||
| version = "0.1.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" | ||
| [[package]] | ||
| name = "android_system_properties" | ||
| version = "0.1.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" | ||
| dependencies = [ | ||
| "libc", | ||
| ] | ||
| [[package]] | ||
| name = "autocfg" | ||
| version = "1.5.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" | ||
| [[package]] | ||
| name = "bitflags" | ||
| version = "2.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" | ||
| [[package]] | ||
| name = "bumpalo" | ||
| version = "3.19.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" | ||
| [[package]] | ||
| name = "cc" | ||
| version = "1.2.31" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" | ||
| dependencies = [ | ||
| "shlex", | ||
| ] | ||
| [[package]] | ||
| name = "cfg-if" | ||
| version = "1.0.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" | ||
| [[package]] | ||
| name = "chrono" | ||
| version = "0.4.41" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" | ||
| dependencies = [ | ||
| "android-tzdata", | ||
| "iana-time-zone", | ||
| "js-sys", | ||
| "num-traits", | ||
| "wasm-bindgen", | ||
| "windows-link", | ||
| ] | ||
| [[package]] | ||
| name = "core" | ||
| version = "0.1.0" | ||
| dependencies = [ | ||
| "chrono", | ||
| "pyo3", | ||
| "r2d2", | ||
| "r2d2_sqlite", | ||
| "rusqlite", | ||
| ] | ||
| [[package]] | ||
| name = "core-foundation-sys" | ||
| version = "0.8.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" | ||
| [[package]] | ||
| name = "fallible-iterator" | ||
| version = "0.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" | ||
| [[package]] | ||
| name = "fallible-streaming-iterator" | ||
| version = "0.1.9" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" | ||
| [[package]] | ||
| name = "getrandom" | ||
| version = "0.3.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "libc", | ||
| "r-efi", | ||
| "wasi", | ||
| ] | ||
| [[package]] | ||
| name = "hashbrown" | ||
| version = "0.14.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" | ||
| dependencies = [ | ||
| "ahash", | ||
| ] | ||
| [[package]] | ||
| name = "hashlink" | ||
| version = "0.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" | ||
| dependencies = [ | ||
| "hashbrown", | ||
| ] | ||
| [[package]] | ||
| name = "heck" | ||
| version = "0.5.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" | ||
| [[package]] | ||
| name = "iana-time-zone" | ||
| version = "0.1.63" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" | ||
| dependencies = [ | ||
| "android_system_properties", | ||
| "core-foundation-sys", | ||
| "iana-time-zone-haiku", | ||
| "js-sys", | ||
| "log", | ||
| "wasm-bindgen", | ||
| "windows-core", | ||
| ] | ||
| [[package]] | ||
| name = "iana-time-zone-haiku" | ||
| version = "0.1.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" | ||
| dependencies = [ | ||
| "cc", | ||
| ] | ||
| [[package]] | ||
| name = "indoc" | ||
| version = "2.0.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" | ||
| [[package]] | ||
| name = "js-sys" | ||
| version = "0.3.77" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" | ||
| dependencies = [ | ||
| "once_cell", | ||
| "wasm-bindgen", | ||
| ] | ||
| [[package]] | ||
| name = "libc" | ||
| version = "0.2.174" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" | ||
| [[package]] | ||
| name = "libsqlite3-sys" | ||
| version = "0.30.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" | ||
| dependencies = [ | ||
| "cc", | ||
| "pkg-config", | ||
| "vcpkg", | ||
| ] | ||
| [[package]] | ||
| name = "lock_api" | ||
| version = "0.4.13" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" | ||
| dependencies = [ | ||
| "autocfg", | ||
| "scopeguard", | ||
| ] | ||
| [[package]] | ||
| name = "log" | ||
| version = "0.4.27" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" | ||
| [[package]] | ||
| name = "memoffset" | ||
| version = "0.9.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" | ||
| dependencies = [ | ||
| "autocfg", | ||
| ] | ||
| [[package]] | ||
| name = "num-traits" | ||
| version = "0.2.19" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" | ||
| dependencies = [ | ||
| "autocfg", | ||
| ] | ||
| [[package]] | ||
| name = "once_cell" | ||
| version = "1.21.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" | ||
| [[package]] | ||
| name = "parking_lot" | ||
| version = "0.12.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" | ||
| dependencies = [ | ||
| "lock_api", | ||
| "parking_lot_core", | ||
| ] | ||
| [[package]] | ||
| name = "parking_lot_core" | ||
| version = "0.9.11" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "libc", | ||
| "redox_syscall", | ||
| "smallvec", | ||
| "windows-targets", | ||
| ] | ||
| [[package]] | ||
| name = "pkg-config" | ||
| version = "0.3.32" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" | ||
| [[package]] | ||
| name = "portable-atomic" | ||
| version = "1.11.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" | ||
| [[package]] | ||
| name = "ppv-lite86" | ||
| version = "0.2.21" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" | ||
| dependencies = [ | ||
| "zerocopy", | ||
| ] | ||
| [[package]] | ||
| name = "proc-macro2" | ||
| version = "1.0.95" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" | ||
| dependencies = [ | ||
| "unicode-ident", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a" | ||
| dependencies = [ | ||
| "indoc", | ||
| "libc", | ||
| "memoffset", | ||
| "once_cell", | ||
| "portable-atomic", | ||
| "pyo3-build-config", | ||
| "pyo3-ffi", | ||
| "pyo3-macros", | ||
| "unindent", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-build-config" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598" | ||
| dependencies = [ | ||
| "once_cell", | ||
| "target-lexicon", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-ffi" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c" | ||
| dependencies = [ | ||
| "libc", | ||
| "pyo3-build-config", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-macros" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "pyo3-macros-backend", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "pyo3-macros-backend" | ||
| version = "0.25.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc" | ||
| dependencies = [ | ||
| "heck", | ||
| "proc-macro2", | ||
| "pyo3-build-config", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "quote" | ||
| version = "1.0.40" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| ] | ||
| [[package]] | ||
| name = "r-efi" | ||
| version = "5.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" | ||
| [[package]] | ||
| name = "r2d2" | ||
| version = "0.8.10" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" | ||
| dependencies = [ | ||
| "log", | ||
| "parking_lot", | ||
| "scheduled-thread-pool", | ||
| ] | ||
| [[package]] | ||
| name = "r2d2_sqlite" | ||
| version = "0.25.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "eb14dba8247a6a15b7fdbc7d389e2e6f03ee9f184f87117706d509c092dfe846" | ||
| dependencies = [ | ||
| "r2d2", | ||
| "rusqlite", | ||
| "uuid", | ||
| ] | ||
| [[package]] | ||
| name = "rand" | ||
| version = "0.9.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" | ||
| dependencies = [ | ||
| "rand_chacha", | ||
| "rand_core", | ||
| ] | ||
| [[package]] | ||
| name = "rand_chacha" | ||
| version = "0.9.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" | ||
| dependencies = [ | ||
| "ppv-lite86", | ||
| "rand_core", | ||
| ] | ||
| [[package]] | ||
| name = "rand_core" | ||
| version = "0.9.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" | ||
| dependencies = [ | ||
| "getrandom", | ||
| ] | ||
| [[package]] | ||
| name = "redox_syscall" | ||
| version = "0.5.17" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" | ||
| dependencies = [ | ||
| "bitflags", | ||
| ] | ||
| [[package]] | ||
| name = "rusqlite" | ||
| version = "0.32.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" | ||
| dependencies = [ | ||
| "bitflags", | ||
| "fallible-iterator", | ||
| "fallible-streaming-iterator", | ||
| "hashlink", | ||
| "libsqlite3-sys", | ||
| "smallvec", | ||
| ] | ||
| [[package]] | ||
| name = "rustversion" | ||
| version = "1.0.21" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" | ||
| [[package]] | ||
| name = "scheduled-thread-pool" | ||
| version = "0.2.7" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" | ||
| dependencies = [ | ||
| "parking_lot", | ||
| ] | ||
| [[package]] | ||
| name = "scopeguard" | ||
| version = "1.2.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" | ||
| [[package]] | ||
| name = "shlex" | ||
| version = "1.3.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" | ||
| [[package]] | ||
| name = "smallvec" | ||
| version = "1.15.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | ||
| [[package]] | ||
| name = "syn" | ||
| version = "2.0.104" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "unicode-ident", | ||
| ] | ||
| [[package]] | ||
| name = "target-lexicon" | ||
| version = "0.13.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" | ||
| [[package]] | ||
| name = "unicode-ident" | ||
| version = "1.0.18" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" | ||
| [[package]] | ||
| name = "unindent" | ||
| version = "0.2.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" | ||
| [[package]] | ||
| name = "uuid" | ||
| version = "1.17.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" | ||
| dependencies = [ | ||
| "getrandom", | ||
| "js-sys", | ||
| "rand", | ||
| "wasm-bindgen", | ||
| ] | ||
| [[package]] | ||
| name = "vcpkg" | ||
| version = "0.2.15" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" | ||
| [[package]] | ||
| name = "version_check" | ||
| version = "0.9.5" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" | ||
| [[package]] | ||
| name = "wasi" | ||
| version = "0.14.2+wasi-0.2.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" | ||
| dependencies = [ | ||
| "wit-bindgen-rt", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" | ||
| dependencies = [ | ||
| "cfg-if", | ||
| "once_cell", | ||
| "rustversion", | ||
| "wasm-bindgen-macro", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-backend" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" | ||
| dependencies = [ | ||
| "bumpalo", | ||
| "log", | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| "wasm-bindgen-shared", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-macro" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" | ||
| dependencies = [ | ||
| "quote", | ||
| "wasm-bindgen-macro-support", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-macro-support" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| "wasm-bindgen-backend", | ||
| "wasm-bindgen-shared", | ||
| ] | ||
| [[package]] | ||
| name = "wasm-bindgen-shared" | ||
| version = "0.2.100" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" | ||
| dependencies = [ | ||
| "unicode-ident", | ||
| ] | ||
| [[package]] | ||
| name = "windows-core" | ||
| version = "0.61.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" | ||
| dependencies = [ | ||
| "windows-implement", | ||
| "windows-interface", | ||
| "windows-link", | ||
| "windows-result", | ||
| "windows-strings", | ||
| ] | ||
| [[package]] | ||
| name = "windows-implement" | ||
| version = "0.60.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "windows-interface" | ||
| version = "0.59.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] | ||
| [[package]] | ||
| name = "windows-link" | ||
| version = "0.1.3" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" | ||
| [[package]] | ||
| name = "windows-result" | ||
| version = "0.3.4" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" | ||
| dependencies = [ | ||
| "windows-link", | ||
| ] | ||
| [[package]] | ||
| name = "windows-strings" | ||
| version = "0.4.2" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" | ||
| dependencies = [ | ||
| "windows-link", | ||
| ] | ||
| [[package]] | ||
| name = "windows-targets" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" | ||
| dependencies = [ | ||
| "windows_aarch64_gnullvm", | ||
| "windows_aarch64_msvc", | ||
| "windows_i686_gnu", | ||
| "windows_i686_gnullvm", | ||
| "windows_i686_msvc", | ||
| "windows_x86_64_gnu", | ||
| "windows_x86_64_gnullvm", | ||
| "windows_x86_64_msvc", | ||
| ] | ||
| [[package]] | ||
| name = "windows_aarch64_gnullvm" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" | ||
| [[package]] | ||
| name = "windows_aarch64_msvc" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" | ||
| [[package]] | ||
| name = "windows_i686_gnu" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" | ||
| [[package]] | ||
| name = "windows_i686_gnullvm" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" | ||
| [[package]] | ||
| name = "windows_i686_msvc" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" | ||
| [[package]] | ||
| name = "windows_x86_64_gnu" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" | ||
| [[package]] | ||
| name = "windows_x86_64_gnullvm" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" | ||
| [[package]] | ||
| name = "windows_x86_64_msvc" | ||
| version = "0.52.6" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" | ||
| [[package]] | ||
| name = "wit-bindgen-rt" | ||
| version = "0.39.0" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" | ||
| dependencies = [ | ||
| "bitflags", | ||
| ] | ||
| [[package]] | ||
| name = "zerocopy" | ||
| version = "0.8.26" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" | ||
| dependencies = [ | ||
| "zerocopy-derive", | ||
| ] | ||
| [[package]] | ||
| name = "zerocopy-derive" | ||
| version = "0.8.26" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" | ||
| dependencies = [ | ||
| "proc-macro2", | ||
| "quote", | ||
| "syn", | ||
| ] |
| [package] | ||
| name = "core" | ||
| version = "0.1.0" | ||
| edition = "2021" | ||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
| [lib] | ||
| name = "core" | ||
| crate-type = ["cdylib"] | ||
| [dependencies] | ||
| chrono = "0.4.41" | ||
| pyo3 = "0.25.0" | ||
| r2d2 = "0.8" | ||
| r2d2_sqlite = "0.25" | ||
| rusqlite = { version = "0.32", features = ["bundled"] } |
| [build-system] | ||
| requires = ["maturin>=1.9,<2.0"] | ||
| build-backend = "maturin" | ||
| [project] | ||
| name = "core" | ||
| requires-python = ">=3.7" | ||
| classifiers = [ | ||
| "Programming Language :: Rust", | ||
| "Programming Language :: Python :: Implementation :: CPython", | ||
| "Programming Language :: Python :: Implementation :: PyPy", | ||
| ] | ||
| dynamic = ["version"] | ||
| [tool.maturin] | ||
| features = ["pyo3/extension-module"] |
| mod queue_operation; | ||
| mod task_mounter; | ||
| use pyo3::prelude::*; | ||
| use queue_operation::QueueOperation; | ||
| use task_mounter::TaskMounter; // 导入结构体 // 导入结构体 | ||
| #[pymodule] | ||
| fn core(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> { | ||
| m.add_class::<TaskMounter>()?; | ||
| m.add_class::<QueueOperation>()?; | ||
| Ok(()) | ||
| } |
| use chrono::{DateTime, Duration, Utc}; | ||
| use pyo3::prelude::*; | ||
| use pyo3::types::*; | ||
| use r2d2::Pool; | ||
| use r2d2_sqlite::SqliteConnectionManager; | ||
| use rusqlite::params; | ||
| #[pyclass] | ||
| pub struct QueueOperation { | ||
| pool: Pool<SqliteConnectionManager>, | ||
| } | ||
| #[pymethods] | ||
| impl QueueOperation { | ||
| #[new] | ||
| pub fn new(queue_path: String) -> Self { | ||
| let manager = SqliteConnectionManager::file(queue_path.as_str()); | ||
| let pool = Pool::new(manager).unwrap(); | ||
| QueueOperation { pool } | ||
| } | ||
| pub fn init_db(&self) -> PyResult<()> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| CREATE TABLE IF NOT EXISTS messages ( | ||
| id TEXT PRIMARY KEY, | ||
| type TEXT NOT NULL, | ||
| status INTEGER NOT NULL, | ||
| content TEXT NOT NULL, | ||
| createtime DATETIME NOT NULL, | ||
| updatetime DATETIME NOT NULL, | ||
| result TEXT DEFAULT NULL, | ||
| priority INTEGER NOT NULL, | ||
| source TEXT NOT NULL, | ||
| destination TEXT NOT NULL, | ||
| retry_count INTEGER NOT NULL, | ||
| expire_time DATETIME DEFAULT NULL, | ||
| tags TEXT DEFAULT NULL, | ||
| metadata TEXT DEFAULT NULL, | ||
| is_deleted INTEGER NOT NULL DEFAULT 0 | ||
| ); | ||
| CREATE INDEX IF NOT EXISTS idx_status ON messages(status); | ||
| CREATE INDEX IF NOT EXISTS idx_priority ON messages(priority); | ||
| CREATE INDEX IF NOT EXISTS idx_dequeue ON messages( | ||
| status, | ||
| priority DESC, | ||
| createtime ASC | ||
| ) WHERE is_deleted = 0 AND status = 0; | ||
| ", | ||
| params![], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let pragmas = [ | ||
| "PRAGMA journal_mode=WAL", | ||
| "PRAGMA synchronous=NORMAL", | ||
| "PRAGMA cache_size=-20000", | ||
| "PRAGMA mmap_size=1073741824", | ||
| "PRAGMA temp_store=MEMORY", | ||
| "PRAGMA busy_timeout=5000", | ||
| ]; | ||
| for pragma in pragmas.iter() { | ||
| let mut stmt = conn | ||
| .prepare(pragma) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut rows = stmt | ||
| .query([]) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| while let Some(_) = rows | ||
| .next() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))? | ||
| { | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
| pub fn enqueue<'py>( | ||
| &self, | ||
| py: Python<'py>, | ||
| message: &Bound<'py, PyDict>, | ||
| ) -> PyResult<Bound<'py, PyString>> { | ||
| let mut conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let get_field = |key: &str| -> PyResult<_> { | ||
| message.get_item(key)?.ok_or_else(|| { | ||
| PyErr::new::<pyo3::exceptions::PyKeyError, _>(format!("{} not found", key)) | ||
| }) | ||
| }; | ||
| let id = get_field("id")?.extract::<String>()?; | ||
| let type_ = get_field("type")?.extract::<String>()?; | ||
| let status = get_field("status")?.extract::<i32>()?; | ||
| let content = get_field("content")?.extract::<String>()?; | ||
| let createtime = get_field("createtime")?.extract::<String>()?; | ||
| let updatetime = get_field("updatetime")?.extract::<String>()?; | ||
| let result = get_field("result")?.extract::<String>()?; | ||
| let priority = get_field("priority")?.extract::<i32>()?; | ||
| let source = get_field("source")?.extract::<String>()?; | ||
| let destination = get_field("destination")?.extract::<String>()?; | ||
| let retry_count = get_field("retry_count")?.extract::<i32>()?; | ||
| let expire_time = get_field("expire_time")?.extract::<String>()?; | ||
| let tags = get_field("tags")?.extract::<String>()?; | ||
| let metadata = get_field("metadata")?.extract::<String>()?; | ||
| let tx = conn | ||
| .transaction() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| tx.execute( | ||
| " | ||
| INSERT INTO messages ( | ||
| id, type, status, content, createtime, | ||
| updatetime, result, priority, source, | ||
| destination, retry_count, expire_time, tags, metadata | ||
| ) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14) | ||
| ", | ||
| params![ | ||
| id, | ||
| type_, | ||
| status, | ||
| content, | ||
| createtime, | ||
| updatetime, | ||
| result, | ||
| priority, | ||
| source, | ||
| destination, | ||
| retry_count, | ||
| expire_time, | ||
| tags, | ||
| metadata | ||
| ], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| tx.commit() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(Bound::from(PyString::new(py, &id))) | ||
| } | ||
| pub fn dequeue<'py>(&self, py: Python<'py>, size: i32) -> PyResult<Bound<'py, PyList>> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let now: DateTime<Utc> = Utc::now(); | ||
| let iso_format = now.to_rfc3339(); | ||
| // Fixed SQL query with proper subquery alias | ||
| let mut stmt = conn | ||
| .prepare( | ||
| "UPDATE messages | ||
| SET status = 1 | ||
| WHERE id IN ( | ||
| SELECT id | ||
| FROM ( | ||
| SELECT id, ROW_NUMBER() OVER (ORDER BY priority DESC, createtime ASC) AS rn | ||
| FROM messages | ||
| WHERE is_deleted = 0 | ||
| AND status = 0 | ||
| AND (expire_time IS NULL OR expire_time > ?1) | ||
| ) AS sub | ||
| WHERE rn <= ?2 | ||
| ) | ||
| RETURNING *;", | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let rows = PyList::empty(py); | ||
| let mapped_rows = stmt | ||
| .query_map(params![iso_format, size], |row| { | ||
| let dict = PyDict::new(py); | ||
| // Helper to convert PyErr to rusqlite::Error | ||
| let to_rusqlite_error = | ||
| |e: PyErr| rusqlite::Error::ToSqlConversionFailure(Box::new(e)); | ||
| // Extract and set each field with proper error handling | ||
| dict.set_item("id", row.get::<_, String>("id")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("type", row.get::<_, String>("type")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("status", row.get::<_, i32>("status")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("content", row.get::<_, String>("content")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("createtime", row.get::<_, String>("createtime")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("updatetime", row.get::<_, String>("updatetime")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("result", row.get::<_, Option<String>>("result")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("priority", row.get::<_, i32>("priority")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("source", row.get::<_, Option<String>>("source")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("destination", row.get::<_, Option<String>>("destination")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("retry_count", row.get::<_, i32>("retry_count")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("expire_time", row.get::<_, Option<String>>("expire_time")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("tags", row.get::<_, Option<String>>("tags")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("metadata", row.get::<_, Option<String>>("metadata")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| // Return the dictionary as Py<PyDict> | ||
| Ok(dict) | ||
| }) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| for row in mapped_rows { | ||
| let dict = | ||
| row.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| rows.append(dict)?; | ||
| } | ||
| Ok(rows.into()) | ||
| } | ||
| pub fn get_queue_length(&self) -> PyResult<i32> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let now = Utc::now().to_rfc3339(); | ||
| // Using query_row for single result handling | ||
| let count: i32 = conn | ||
| .query_row( | ||
| "SELECT COUNT(*) FROM messages | ||
| WHERE is_deleted = 0 | ||
| AND status = ?1 | ||
| AND (expire_time IS NULL OR expire_time > ?2)", | ||
| params![0, now], | ||
| |row| row.get(0), | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(count) | ||
| } | ||
| pub fn get_completed_messages<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyList>> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut stmt = conn | ||
| .prepare( | ||
| "SELECT | ||
| * | ||
| FROM | ||
| messages | ||
| WHERE | ||
| is_deleted = 0 | ||
| AND (status = ?1 OR status = ?2)", | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let rows = PyList::empty(py); | ||
| let mapped_rows = stmt | ||
| .query_map(params![2, 3], |row| { | ||
| let dict = PyDict::new(py); | ||
| // Helper to convert PyErr to rusqlite::Error | ||
| let to_rusqlite_error = | ||
| |e: PyErr| rusqlite::Error::ToSqlConversionFailure(Box::new(e)); | ||
| // Extract and set each field with proper error handling | ||
| dict.set_item("id", row.get::<_, String>("id")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("type", row.get::<_, String>("type")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("status", row.get::<_, i32>("status")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("content", row.get::<_, String>("content")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("createtime", row.get::<_, String>("createtime")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("updatetime", row.get::<_, String>("updatetime")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("result", row.get::<_, Option<String>>("result")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("priority", row.get::<_, i32>("priority")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("source", row.get::<_, Option<String>>("source")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("destination", row.get::<_, Option<String>>("destination")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("retry_count", row.get::<_, i32>("retry_count")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("expire_time", row.get::<_, Option<String>>("expire_time")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("tags", row.get::<_, Option<String>>("tags")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("metadata", row.get::<_, Option<String>>("metadata")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| // Return the dictionary as Py<PyDict> | ||
| Ok(dict) | ||
| }) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| for row in mapped_rows { | ||
| let dict = | ||
| row.map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| rows.append(dict)?; | ||
| } | ||
| Ok(rows.into()) | ||
| } | ||
| pub fn get_result<'py>(&self, py: Python<'py>, id: String) -> PyResult<Bound<'py, PyDict>> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut stmt = conn | ||
| .prepare( | ||
| "SELECT result, status FROM messages WHERE id = ?1 AND (status = ?2 OR status = ?3)", | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let mut mapped_rows = stmt | ||
| .query_map(params![&id, 2, 3], |row| { | ||
| let dict = PyDict::new(py); | ||
| // Helper to convert PyErr to rusqlite::Error | ||
| let to_rusqlite_error = | ||
| |e: PyErr| rusqlite::Error::ToSqlConversionFailure(Box::new(e)); | ||
| // Extract and set each field with proper error handling | ||
| dict.set_item("id", row.get::<_, String>("id")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("type", row.get::<_, String>("type")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("status", row.get::<_, i32>("status")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("content", row.get::<_, String>("content")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("createtime", row.get::<_, String>("createtime")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("updatetime", row.get::<_, String>("updatetime")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("result", row.get::<_, Option<String>>("result")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("priority", row.get::<_, i32>("priority")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("source", row.get::<_, Option<String>>("source")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("destination", row.get::<_, Option<String>>("destination")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("retry_count", row.get::<_, i32>("retry_count")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("expire_time", row.get::<_, Option<String>>("expire_time")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("tags", row.get::<_, Option<String>>("tags")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| dict.set_item("metadata", row.get::<_, Option<String>>("metadata")?) | ||
| .map_err(to_rusqlite_error)?; | ||
| // Return the dictionary as Py<PyDict> | ||
| Ok(dict) | ||
| }) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| let dict = mapped_rows | ||
| .next() | ||
| .transpose() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(dict.unwrap().into()) | ||
| } | ||
| pub fn update_status(&self, id: String, status: i32) -> PyResult<()> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| UPDATE messages SET status = ?1 WHERE id = ?2 | ||
| ", | ||
| params![status, id], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| pub fn update_result(&self, id: String, result: String) -> PyResult<()> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| UPDATE messages SET result = ?1 WHERE id = ?2 | ||
| ", | ||
| params![result, id], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| pub fn delete_message(&self, id: String) -> PyResult<()> { | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| UPDATE messages SET is_deleted = 1 WHERE id = ?1 | ||
| ", | ||
| params![id], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| pub fn clean_expired_messages(&self) -> PyResult<()> { | ||
| let now: DateTime<Utc> = Utc::now(); | ||
| let iso_format = now.to_rfc3339(); | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| UPDATE messages | ||
| SET is_deleted = 1 | ||
| WHERE is_deleted = 0 | ||
| AND expire_time IS NOT NULL | ||
| AND expire_time < ?1 | ||
| ", | ||
| params![iso_format], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| pub fn clean_old_messages(&self, days: i64) -> PyResult<()> { | ||
| // 获取七天前的时间 | ||
| let now: DateTime<Utc> = Utc::now(); | ||
| let mut old_time = now - Duration::days(days); | ||
| let iso_format = old_time.to_rfc3339(); | ||
| let conn = self | ||
| .pool | ||
| .get() | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| conn.execute( | ||
| " | ||
| UPDATE messages | ||
| SET is_deleted = 1 | ||
| WHERE is_deleted = 0 | ||
| AND status IN (?1, ?2) | ||
| AND updatetime < ?3 | ||
| ", | ||
| params![2, 3, iso_format], | ||
| ) | ||
| .map_err(|e| PyErr::new::<pyo3::exceptions::PyRuntimeError, _>(e.to_string()))?; | ||
| Ok(()) | ||
| } | ||
| } |
| use pyo3::prelude::*; | ||
| #[pyclass] | ||
| pub struct TaskMounter { | ||
| obj: Py<PyAny>, | ||
| } | ||
| #[pymethods] | ||
| impl TaskMounter { | ||
| #[new] | ||
| fn new(obj: Py<PyAny>) -> Self { | ||
| TaskMounter { obj } | ||
| } | ||
| fn get_task_list(&self, py: Python<'_>) -> PyResult<()> { | ||
| let obj = self.obj.bind(py); | ||
| let result_obj = obj.call_method("get_task_list", (), None)?; | ||
| println!("Method result: {:?}", result_obj); | ||
| Ok(()) | ||
| } | ||
| fn get_task_function(&self, py: Python<'_>, task_name: &str) -> PyResult<PyObject> { | ||
| let obj = self.obj.bind(py); | ||
| let result = obj.call_method1("get_task_function", (task_name,))?; | ||
| Ok(result.into()) | ||
| } | ||
| } |
| {"rustc_fingerprint":16828809463305737152,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.85.0 (4d91de4e4 2025-02-17)\nbinary: rustc\ncommit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688\ncommit-date: 2025-02-17\nhost: x86_64-pc-windows-msvc\nrelease: 1.85.0\nLLVM version: 19.1.7\n","stderr":""},"13331785392996375709":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\chakcy\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"atomic-polyfill\", \"compile-time-rng\", \"const-random\", \"default\", \"getrandom\", \"nightly-arm-aes\", \"no-rng\", \"runtime-rng\", \"serde\", \"std\"]","target":17883862002600103897,"profile":1369601567987815722,"path":7187415306358235769,"deps":[[5398981501050481332,"version_check",false,5152529911640053841]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ahash-618bed490d9b176c\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[966925859616469517,"build_script_build",false,477776375443088751]],"local":[{"RerunIfChanged":{"output":"release\\build\\ahash-a64029572804b107\\output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"atomic-polyfill\", \"compile-time-rng\", \"const-random\", \"default\", \"getrandom\", \"nightly-arm-aes\", \"no-rng\", \"runtime-rng\", \"serde\", \"std\"]","target":8470944000320059508,"profile":2040997289075261528,"path":11058538058298686862,"deps":[[966925859616469517,"build_script_build",false,17187585555194121828],[2828590642173593838,"cfg_if",false,3529753655869530981],[3722963349756955755,"once_cell",false,14203488916802877105],[14131061446229887432,"zerocopy",false,10851525930956496799]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ahash-cdbd549697ed3c2b\\dep-lib-ahash","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":6962977057026645649,"profile":1369601567987815722,"path":1109273032424510304,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\autocfg-8f50209681064803\\dep-lib-autocfg","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"arbitrary\", \"bytemuck\", \"compiler_builtins\", \"core\", \"example_generated\", \"rustc-dep-of-std\", \"serde\", \"std\"]","target":7691312148208718491,"profile":2040997289075261528,"path":13161629348797759227,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\bitflags-08c3405087d6208f\\dep-lib-bitflags","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"jobserver\", \"parallel\"]","target":11042037588551934598,"profile":1369601567987815722,"path":17367059011886777038,"deps":[[8410525223747752176,"shlex",false,12348762316555851408]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\cc-7911f450bd2b3294\\dep-lib-cc","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"core\", \"rustc-dep-of-std\"]","target":13840298032947503755,"profile":2040997289075261528,"path":12840637216311260298,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\cfg-if-fddddf2a8a57c2af\\dep-lib-cfg_if","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"alloc\", \"android-tzdata\", \"clock\", \"default\", \"iana-time-zone\", \"js-sys\", \"now\", \"oldtime\", \"std\", \"wasm-bindgen\", \"wasmbind\", \"winapi\", \"windows-link\"]","declared_features":"[\"__internal_bench\", \"alloc\", \"android-tzdata\", \"arbitrary\", \"clock\", \"default\", \"iana-time-zone\", \"js-sys\", \"libc\", \"now\", \"oldtime\", \"pure-rust-locales\", \"rkyv\", \"rkyv-16\", \"rkyv-32\", \"rkyv-64\", \"rkyv-validation\", \"serde\", \"std\", \"unstable-locales\", \"wasm-bindgen\", \"wasmbind\", \"winapi\", \"windows-link\"]","target":15315924755136109342,"profile":2040997289075261528,"path":18242240443748505464,"deps":[[5157631553186200874,"num_traits",false,4472832703676574606],[11505586985402185701,"windows_link",false,16050127126512364089]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\chrono-cd956ae90a917c3a\\dep-lib-chrono","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":9481103799263360118,"profile":2040997289075261528,"path":10763286916239946207,"deps":[[192435385979317305,"rusqlite",false,16398314829797795095],[6722490998346977199,"r2d2",false,10621514956452897850],[9768805234657844767,"pyo3",false,14008540978274937561],[9897246384292347999,"chrono",false,15154050221431942546],[15603018939137051047,"r2d2_sqlite",false,3616463723475073391]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\core-187b7ead45a00b52\\dep-lib-core","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"alloc\", \"default\"]","declared_features":"[\"alloc\", \"default\", \"std\"]","target":15245709686714427328,"profile":2040997289075261528,"path":10075374889910060692,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\fallible-iterator-60cfbacb12397e6a\\dep-lib-fallible_iterator","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"std\"]","target":16001337131876932863,"profile":2040997289075261528,"path":472327145677387694,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\fallible-streaming-iterator-ee548347587e685b\\dep-lib-fallible_streaming_iterator","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"std\"]","declared_features":"[\"rustc-dep-of-std\", \"std\", \"wasm_js\"]","target":11669924403970522481,"profile":2896712256932847751,"path":7094784053576849647,"deps":[[2828590642173593838,"cfg_if",false,3529753655869530981],[3331586631144870129,"build_script_build",false,2609823101006913687]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\getrandom-201eddce882566b5\\dep-lib-getrandom","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[3331586631144870129,"build_script_build",false,6580641408514738487]],"local":[{"RerunIfChanged":{"output":"release\\build\\getrandom-496d26fcdcbc7147\\output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"std\"]","declared_features":"[\"rustc-dep-of-std\", \"std\", \"wasm_js\"]","target":5408242616063297496,"profile":7474683644146943920,"path":4034927775639244411,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\getrandom-aadbfd4ebcb030e9\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"ahash\", \"inline-more\"]","declared_features":"[\"ahash\", \"alloc\", \"allocator-api2\", \"compiler_builtins\", \"core\", \"default\", \"equivalent\", \"inline-more\", \"nightly\", \"raw\", \"rayon\", \"rkyv\", \"rustc-dep-of-std\", \"rustc-internal-api\", \"serde\"]","target":9101038166729729440,"profile":2040997289075261528,"path":6325068763524267641,"deps":[[966925859616469517,"ahash",false,3403621609760964756]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\hashbrown-2c631726c8d5eec3\\dep-lib-hashbrown","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"serde\", \"serde_impl\"]","target":3158588102652511467,"profile":2040997289075261528,"path":6313918777122170750,"deps":[[13018563866916002725,"hashbrown",false,7082741557864153614]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\hashlink-787cecac9ad7d879\\dep-lib-hashlink","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":17886154901722686619,"profile":1369601567987815722,"path":3799244107749432215,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\heck-91007429548817d2\\dep-lib-heck","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":8726396592336845528,"profile":1369601567987815722,"path":6050833074540040594,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\indoc-7ee1445ea314d386\\dep-lib-indoc","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"std\"]","declared_features":"[\"align\", \"const-extern-fn\", \"default\", \"extra_traits\", \"rustc-dep-of-std\", \"rustc-std-workspace-core\", \"std\", \"use_std\"]","target":5408242616063297496,"profile":8928907579149787682,"path":3274576605620797992,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\libc-57b162ef8a4b1bdf\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"std\"]","declared_features":"[\"align\", \"const-extern-fn\", \"default\", \"extra_traits\", \"rustc-dep-of-std\", \"rustc-std-workspace-core\", \"std\", \"use_std\"]","target":17682796336736096309,"profile":7322064999780386650,"path":2762566396684894566,"deps":[[4684437522915235464,"build_script_build",false,527656645942942820]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\libc-79f82e7af061abdf\\dep-lib-libc","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[4684437522915235464,"build_script_build",false,10892369269054245752]],"local":[{"RerunIfChanged":{"output":"release\\build\\libc-9a05721030041749\\output","paths":["build.rs"]}},{"RerunIfEnvChanged":{"var":"RUST_LIBC_UNSTABLE_FREEBSD_VERSION","val":null}},{"RerunIfEnvChanged":{"var":"RUST_LIBC_UNSTABLE_MUSL_V1_2_3","val":null}},{"RerunIfEnvChanged":{"var":"RUST_LIBC_UNSTABLE_LINUX_TIME_BITS64","val":null}},{"RerunIfEnvChanged":{"var":"RUST_LIBC_UNSTABLE_GNU_FILE_OFFSET_BITS","val":null}},{"RerunIfEnvChanged":{"var":"RUST_LIBC_UNSTABLE_GNU_TIME_BITS","val":null}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"bundled\", \"bundled_bindings\", \"cc\", \"default\", \"min_sqlite_version_3_14_0\", \"pkg-config\", \"vcpkg\"]","declared_features":"[\"bindgen\", \"buildtime_bindgen\", \"bundled\", \"bundled-sqlcipher\", \"bundled-sqlcipher-vendored-openssl\", \"bundled-windows\", \"bundled_bindings\", \"cc\", \"default\", \"in_gecko\", \"loadable_extension\", \"min_sqlite_version_3_14_0\", \"openssl-sys\", \"pkg-config\", \"prettyplease\", \"preupdate_hook\", \"quote\", \"session\", \"sqlcipher\", \"syn\", \"unlock_notify\", \"vcpkg\", \"wasm32-wasi-vfs\", \"with-asan\"]","target":14162657976132989036,"profile":2040997289075261528,"path":10530713483260882185,"deps":[[16675652872862304210,"build_script_build",false,9673119400128177155]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\libsqlite3-sys-0fd02b17c9f114a1\\dep-lib-libsqlite3_sys","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[16675652872862304210,"build_script_build",false,2120142010177750133]],"local":[{"RerunIfChanged":{"output":"release\\build\\libsqlite3-sys-c1baf407615f28b5\\output","paths":["sqlite3/sqlite3.c","sqlite3/wasm32-wasi-vfs.c"]}},{"RerunIfEnvChanged":{"var":"LIBSQLITE3_SYS_USE_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"SQLITE_MAX_VARIABLE_NUMBER","val":null}},{"RerunIfEnvChanged":{"var":"SQLITE_MAX_EXPR_DEPTH","val":null}},{"RerunIfEnvChanged":{"var":"SQLITE_MAX_COLUMN","val":null}},{"RerunIfEnvChanged":{"var":"LIBSQLITE3_FLAGS","val":null}},{"RerunIfEnvChanged":{"var":"VCINSTALLDIR","val":null}},{"RerunIfEnvChanged":{"var":"VSTEL_MSBuildProjectFullPath","val":null}},{"RerunIfEnvChanged":{"var":"VSCMD_ARG_VCVARS_SPECTRE","val":null}},{"RerunIfEnvChanged":{"var":"WindowsSdkDir","val":null}},{"RerunIfEnvChanged":{"var":"WindowsSDKVersion","val":null}},{"RerunIfEnvChanged":{"var":"LIB","val":null}},{"RerunIfEnvChanged":{"var":"INCLUDE","val":null}},{"RerunIfEnvChanged":{"var":"CC_x86_64-pc-windows-msvc","val":null}},{"RerunIfEnvChanged":{"var":"CC_x86_64_pc_windows_msvc","val":null}},{"RerunIfEnvChanged":{"var":"HOST_CC","val":null}},{"RerunIfEnvChanged":{"var":"CC","val":null}},{"RerunIfEnvChanged":{"var":"CRATE_CC_NO_DEFAULTS","val":null}},{"RerunIfEnvChanged":{"var":"CFLAGS","val":null}},{"RerunIfEnvChanged":{"var":"HOST_CFLAGS","val":null}},{"RerunIfEnvChanged":{"var":"CFLAGS_x86_64_pc_windows_msvc","val":null}},{"RerunIfEnvChanged":{"var":"CFLAGS_x86_64-pc-windows-msvc","val":null}},{"RerunIfEnvChanged":{"var":"CC_ENABLE_DEBUG_OUTPUT","val":null}},{"RerunIfEnvChanged":{"var":"AR_x86_64-pc-windows-msvc","val":null}},{"RerunIfEnvChanged":{"var":"AR_x86_64_pc_windows_msvc","val":null}},{"RerunIfEnvChanged":{"var":"HOST_AR","val":null}},{"RerunIfEnvChanged":{"var":"AR","val":null}},{"RerunIfEnvChanged":{"var":"ARFLAGS","val":null}},{"RerunIfEnvChanged":{"var":"HOST_ARFLAGS","val":null}},{"RerunIfEnvChanged":{"var":"ARFLAGS_x86_64_pc_windows_msvc","val":null}},{"RerunIfEnvChanged":{"var":"ARFLAGS_x86_64-pc-windows-msvc","val":null}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"bundled\", \"bundled_bindings\", \"cc\", \"default\", \"min_sqlite_version_3_14_0\", \"pkg-config\", \"vcpkg\"]","declared_features":"[\"bindgen\", \"buildtime_bindgen\", \"bundled\", \"bundled-sqlcipher\", \"bundled-sqlcipher-vendored-openssl\", \"bundled-windows\", \"bundled_bindings\", \"cc\", \"default\", \"in_gecko\", \"loadable_extension\", \"min_sqlite_version_3_14_0\", \"openssl-sys\", \"pkg-config\", \"prettyplease\", \"preupdate_hook\", \"quote\", \"session\", \"sqlcipher\", \"syn\", \"unlock_notify\", \"vcpkg\", \"wasm32-wasi-vfs\", \"with-asan\"]","target":5408242616063297496,"profile":1369601567987815722,"path":625912203354219688,"deps":[[3214373357989284387,"pkg_config",false,3746155248345363064],[12410631062411814511,"cc",false,10721797073743873174],[12933202132622624734,"vcpkg",false,9319435682794445159]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\libsqlite3-sys-d71c8f7cc848411d\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[8081351675046095464,"build_script_build",false,11220389140392644711]],"local":[{"RerunIfChanged":{"output":"release\\build\\lock_api-07e339981ee548a0\\output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"atomic_usize\", \"default\"]","declared_features":"[\"arc_lock\", \"atomic_usize\", \"default\", \"nightly\", \"owning_ref\", \"serde\"]","target":16157403318809843794,"profile":2040997289075261528,"path":17152997284959853979,"deps":[[8081351675046095464,"build_script_build",false,10622216818104965846],[15358414700195712381,"scopeguard",false,16641918902514700494]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\lock_api-9ea19cb4c895b60d\\dep-lib-lock_api","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"atomic_usize\", \"default\"]","declared_features":"[\"arc_lock\", \"atomic_usize\", \"default\", \"nightly\", \"owning_ref\", \"serde\"]","target":5408242616063297496,"profile":1369601567987815722,"path":8381630802460163874,"deps":[[13927012481677012980,"autocfg",false,16001986718668605667]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\lock_api-efea3916520fd3bd\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"kv\", \"kv_serde\", \"kv_std\", \"kv_sval\", \"kv_unstable\", \"kv_unstable_serde\", \"kv_unstable_std\", \"kv_unstable_sval\", \"max_level_debug\", \"max_level_error\", \"max_level_info\", \"max_level_off\", \"max_level_trace\", \"max_level_warn\", \"release_max_level_debug\", \"release_max_level_error\", \"release_max_level_info\", \"release_max_level_off\", \"release_max_level_trace\", \"release_max_level_warn\", \"serde\", \"std\", \"sval\", \"sval_ref\", \"value-bag\"]","target":6550155848337067049,"profile":2040997289075261528,"path":8533745218607109982,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\log-ca1e761a760515a9\\dep-lib-log","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\"]","declared_features":"[\"default\", \"unstable_const\", \"unstable_offset_of\"]","target":5262764120681397832,"profile":2040997289075261528,"path":12263493987707800701,"deps":[[14643204177830147187,"build_script_build",false,17202933915751391697]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\memoffset-5086ab237aa73712\\dep-lib-memoffset","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[14643204177830147187,"build_script_build",false,14140619502124977365]],"local":[{"Precalculated":"0.9.1"}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\"]","declared_features":"[\"default\", \"unstable_const\", \"unstable_offset_of\"]","target":12318548087768197662,"profile":1369601567987815722,"path":6667662306641456362,"deps":[[13927012481677012980,"autocfg",false,16001986718668605667]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\memoffset-80e4c9250cc27d00\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"default\", \"i128\", \"libm\", \"std\"]","target":4278088450330190724,"profile":2040997289075261528,"path":1307759943557664513,"deps":[[5157631553186200874,"build_script_build",false,542026996320701959]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\num-traits-13c0fcf8906940e0\\dep-lib-num_traits","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"default\", \"i128\", \"libm\", \"std\"]","target":5408242616063297496,"profile":1369601567987815722,"path":1209071406963241058,"deps":[[13927012481677012980,"autocfg",false,16001986718668605667]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\num-traits-5341d0b74bf9fde1\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[5157631553186200874,"build_script_build",false,9588493927211177312]],"local":[{"RerunIfChanged":{"output":"release\\build\\num-traits-e47b44e487ec8721\\output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"alloc\", \"default\", \"race\", \"std\"]","declared_features":"[\"alloc\", \"atomic-polyfill\", \"critical-section\", \"default\", \"parking_lot\", \"portable-atomic\", \"race\", \"std\", \"unstable\"]","target":17524666916136250164,"profile":2040997289075261528,"path":16840263027473211633,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\once_cell-07228f505a7fd006\\dep-lib-once_cell","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"alloc\", \"default\", \"race\", \"std\"]","declared_features":"[\"alloc\", \"atomic-polyfill\", \"critical-section\", \"default\", \"parking_lot\", \"portable-atomic\", \"race\", \"std\", \"unstable\"]","target":17524666916136250164,"profile":1369601567987815722,"path":16840263027473211633,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\once_cell-7379bc3ea4aafeab\\dep-lib-once_cell","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"backtrace\", \"deadlock_detection\", \"nightly\", \"petgraph\", \"thread-id\"]","target":5408242616063297496,"profile":1369601567987815722,"path":5168383813830834172,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\parking_lot_core-8f9908891ef587ba\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[4269498962362888130,"build_script_build",false,2399922120788209857]],"local":[{"RerunIfChanged":{"output":"release\\build\\parking_lot_core-bccc79614f04a422\\output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"backtrace\", \"deadlock_detection\", \"nightly\", \"petgraph\", \"thread-id\"]","target":12558056885032795287,"profile":2040997289075261528,"path":754501412176373145,"deps":[[2828590642173593838,"cfg_if",false,3529753655869530981],[3666196340704888985,"smallvec",false,15202448748883864493],[4269498962362888130,"build_script_build",false,14382775254161940221],[14322346790800707264,"windows_targets",false,4831157894195068346]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\parking_lot_core-eee7154c5e2470fc\\dep-lib-parking_lot_core","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\"]","declared_features":"[\"arc_lock\", \"deadlock_detection\", \"default\", \"hardware-lock-elision\", \"nightly\", \"owning_ref\", \"send_guard\", \"serde\"]","target":9887373948397848517,"profile":2040997289075261528,"path":4398465562472263497,"deps":[[4269498962362888130,"parking_lot_core",false,10777900627942538867],[8081351675046095464,"lock_api",false,272623154470769603]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\parking_lot-1e88aa5503e4a24c\\dep-lib-parking_lot","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":4588055084852603002,"profile":1369601567987815722,"path":2440322116967862848,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pkg-config-a49543740da30a14\\dep-lib-pkg_config","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"simd\", \"std\"]","declared_features":"[\"default\", \"no_simd\", \"simd\", \"std\"]","target":2607852365283500179,"profile":2040997289075261528,"path":17968823014529482847,"deps":[[14131061446229887432,"zerocopy",false,10851525930956496799]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ppv-lite86-43ee7e4b46061b7c\\dep-lib-ppv_lite86","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"proc-macro\"]","declared_features":"[\"default\", \"nightly\", \"proc-macro\", \"span-locations\"]","target":369203346396300798,"profile":1369601567987815722,"path":5241799387116779719,"deps":[[1988483478007900009,"unicode_ident",false,12502023975305169797],[3060637413840920116,"build_script_build",false,9476129797068399299]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\proc-macro2-68ff1a79ead5ec29\\dep-lib-proc_macro2","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[3060637413840920116,"build_script_build",false,3279482352611148958]],"local":[{"RerunIfChanged":{"output":"release\\build\\proc-macro2-a3b127353f5ab8eb\\output","paths":["build/probe.rs"]}},{"RerunIfEnvChanged":{"var":"RUSTC_BOOTSTRAP","val":null}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"proc-macro\"]","declared_features":"[\"default\", \"nightly\", \"proc-macro\", \"span-locations\"]","target":5408242616063297496,"profile":1369601567987815722,"path":4078808203560626792,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\proc-macro2-ac0f5fb69251a703\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[9768805234657844767,"build_script_build",false,2048076876145290014],[5099523288940447918,"build_script_build",false,13359973145528291754]],"local":[{"RerunIfEnvChanged":{"var":"PYO3_CROSS","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_CROSS_LIB_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_CROSS_PYTHON_VERSION","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_CROSS_PYTHON_IMPLEMENTATION","val":null}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"extension-module\", \"indoc\", \"macros\", \"pyo3-macros\", \"unindent\"]","declared_features":"[\"abi3\", \"abi3-py310\", \"abi3-py311\", \"abi3-py312\", \"abi3-py313\", \"abi3-py314\", \"abi3-py37\", \"abi3-py38\", \"abi3-py39\", \"anyhow\", \"arc_lock\", \"auto-initialize\", \"bigdecimal\", \"chrono\", \"chrono-local\", \"chrono-tz\", \"default\", \"either\", \"experimental-async\", \"experimental-inspect\", \"extension-module\", \"eyre\", \"full\", \"generate-import-lib\", \"hashbrown\", \"indexmap\", \"indoc\", \"inventory\", \"jiff-02\", \"lock_api\", \"macros\", \"multiple-pymethods\", \"nightly\", \"num-bigint\", \"num-complex\", \"num-rational\", \"ordered-float\", \"parking_lot\", \"py-clone\", \"pyo3-macros\", \"rust_decimal\", \"serde\", \"smallvec\", \"time\", \"unindent\", \"uuid\"]","target":5408242616063297496,"profile":17251378959361963653,"path":1649810187623250950,"deps":[[10288871127199797760,"pyo3_build_config",false,2674323004433707384]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-87d13c879bb07bfd\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"extension-module\", \"resolve-config\"]","declared_features":"[\"abi3\", \"abi3-py310\", \"abi3-py311\", \"abi3-py312\", \"abi3-py313\", \"abi3-py314\", \"abi3-py37\", \"abi3-py38\", \"abi3-py39\", \"default\", \"extension-module\", \"python3-dll-a\", \"resolve-config\"]","target":5408242616063297496,"profile":1369601567987815722,"path":11596988989115316493,"deps":[[3346669234123344896,"target_lexicon",false,3235129498885017616]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-build-config-352b92e60ead4e34\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"extension-module\", \"resolve-config\"]","declared_features":"[\"abi3\", \"abi3-py310\", \"abi3-py311\", \"abi3-py312\", \"abi3-py313\", \"abi3-py314\", \"abi3-py37\", \"abi3-py38\", \"abi3-py39\", \"default\", \"extension-module\", \"python3-dll-a\", \"resolve-config\"]","target":8254743344416261242,"profile":1369601567987815722,"path":2769507156638034175,"deps":[[3346669234123344896,"target_lexicon",false,3235129498885017616],[3722963349756955755,"once_cell",false,565428509745689332],[10288871127199797760,"build_script_build",false,4597791918667620256]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-build-config-c968b97f4116ebf9\\dep-lib-pyo3_build_config","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[10288871127199797760,"build_script_build",false,10163924845054448287]],"local":[{"RerunIfEnvChanged":{"var":"PYO3_CONFIG_FILE","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_NO_PYTHON","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_ENVIRONMENT_SIGNATURE","val":"cpython-3.12-64bit"}},{"RerunIfEnvChanged":{"var":"PYO3_PYTHON","val":"C:\\Users\\chakcy\\Desktop\\queue_sqlite\\.venv\\Scripts\\python.exe"}},{"RerunIfEnvChanged":{"var":"PYO3_USE_ABI3_FORWARD_COMPATIBILITY","val":null}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"extension-module\", \"indoc\", \"macros\", \"pyo3-macros\", \"unindent\"]","declared_features":"[\"abi3\", \"abi3-py310\", \"abi3-py311\", \"abi3-py312\", \"abi3-py313\", \"abi3-py314\", \"abi3-py37\", \"abi3-py38\", \"abi3-py39\", \"anyhow\", \"arc_lock\", \"auto-initialize\", \"bigdecimal\", \"chrono\", \"chrono-local\", \"chrono-tz\", \"default\", \"either\", \"experimental-async\", \"experimental-inspect\", \"extension-module\", \"eyre\", \"full\", \"generate-import-lib\", \"hashbrown\", \"indexmap\", \"indoc\", \"inventory\", \"jiff-02\", \"lock_api\", \"macros\", \"multiple-pymethods\", \"nightly\", \"num-bigint\", \"num-complex\", \"num-rational\", \"ordered-float\", \"parking_lot\", \"py-clone\", \"pyo3-macros\", \"rust_decimal\", \"serde\", \"smallvec\", \"time\", \"unindent\", \"uuid\"]","target":1859062398649441551,"profile":3090641468231581632,"path":18097575732206088062,"deps":[[629381703529241162,"indoc",false,10222147945785977365],[3722963349756955755,"once_cell",false,14203488916802877105],[4684437522915235464,"libc",false,3690385363039411855],[5099523288940447918,"pyo3_ffi",false,4988513813086426855],[5197680718850464868,"pyo3_macros",false,15778545967058107387],[9768805234657844767,"build_script_build",false,18313781752780777068],[14643204177830147187,"memoffset",false,5454162402715648132],[14748792705540276325,"unindent",false,11087532354683070974]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-ccad702a555945ef\\dep-lib-pyo3","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"extension-module\"]","declared_features":"[\"abi3\", \"abi3-py310\", \"abi3-py311\", \"abi3-py312\", \"abi3-py313\", \"abi3-py314\", \"abi3-py37\", \"abi3-py38\", \"abi3-py39\", \"default\", \"extension-module\", \"generate-import-lib\"]","target":5408242616063297496,"profile":17251378959361963653,"path":14535780848116250269,"deps":[[10288871127199797760,"pyo3_build_config",false,2674323004433707384]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-ffi-92fafec08a260e75\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[5099523288940447918,"build_script_build",false,11272688488096803995]],"local":[{"RerunIfEnvChanged":{"var":"PYO3_CROSS","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_CROSS_LIB_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_CROSS_PYTHON_VERSION","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_CROSS_PYTHON_IMPLEMENTATION","val":null}},{"RerunIfEnvChanged":{"var":"PYO3_PRINT_CONFIG","val":null}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"extension-module\"]","declared_features":"[\"abi3\", \"abi3-py310\", \"abi3-py311\", \"abi3-py312\", \"abi3-py313\", \"abi3-py314\", \"abi3-py37\", \"abi3-py38\", \"abi3-py39\", \"default\", \"extension-module\", \"generate-import-lib\"]","target":14506753996192664611,"profile":3090641468231581632,"path":17681210344408711756,"deps":[[4684437522915235464,"libc",false,3690385363039411855],[5099523288940447918,"build_script_build",false,13359973145528291754]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-ffi-ae9309aefb99fc5a\\dep-lib-pyo3_ffi","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[4342566878770968593,"build_script_build",false,3834675320176426004]],"local":[{"Precalculated":"0.25.1"}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"experimental-async\", \"experimental-inspect\"]","target":5408242616063297496,"profile":17251378959361963653,"path":17802904956838174714,"deps":[[10288871127199797760,"pyo3_build_config",false,2674323004433707384]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-macros-backend-9bbea0e02cc9f0dd\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"experimental-async\", \"experimental-inspect\"]","target":1500063600279316151,"profile":17251378959361963653,"path":16576233947071825936,"deps":[[3060637413840920116,"proc_macro2",false,4766645904778405251],[4342566878770968593,"build_script_build",false,18135458823276627212],[4974441333307933176,"syn",false,1767673609828797379],[10288871127199797760,"pyo3_build_config",false,2674323004433707384],[13077543566650298139,"heck",false,6669380849747886],[17990358020177143287,"quote",false,16896938825330447260]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-macros-backend-cf3ae0fcf9a2f820\\dep-lib-pyo3_macros_backend","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"experimental-async\", \"experimental-inspect\", \"multiple-pymethods\"]","target":13917622123232857288,"profile":17251378959361963653,"path":5284851714811173766,"deps":[[3060637413840920116,"proc_macro2",false,4766645904778405251],[4342566878770968593,"pyo3_macros_backend",false,5235803941198806865],[4974441333307933176,"syn",false,1767673609828797379],[17990358020177143287,"quote",false,16896938825330447260]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\pyo3-macros-dd3b8c11438e8701\\dep-lib-pyo3_macros","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"proc-macro\"]","declared_features":"[\"default\", \"proc-macro\"]","target":3570458776599611685,"profile":1369601567987815722,"path":17342412802485852785,"deps":[[3060637413840920116,"proc_macro2",false,4766645904778405251]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\quote-154914917bad8d2c\\dep-lib-quote","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"bundled\", \"bundled-sqlcipher\"]","target":6452129321492349119,"profile":2040997289075261528,"path":7661385335748744420,"deps":[[192435385979317305,"rusqlite",false,16398314829797795095],[6722490998346977199,"r2d2",false,10621514956452897850],[8319709847752024821,"uuid",false,1453095975880334574]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\r2d2_sqlite-7fd91004f3f3551b\\dep-lib-r2d2_sqlite","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":7974416832344299927,"profile":2040997289075261528,"path":1392823847235840310,"deps":[[4495526598637097934,"parking_lot",false,6439719128032313600],[5986029879202738730,"log",false,1352804051171957031],[12318498634224238561,"scheduled_thread_pool",false,4342319991613184863]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\r2d2-93df6035f79ec9d9\\dep-lib-r2d2","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"std\"]","declared_features":"[\"default\", \"os_rng\", \"serde\", \"std\"]","target":12152606625246618204,"profile":2040997289075261528,"path":4529323970913769600,"deps":[[12919011715531272606,"ppv_lite86",false,4236056542985528377],[13135315962794364551,"rand_core",false,16811026693593117703]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\rand_chacha-25f1e2669c7b18c1\\dep-lib-rand_chacha","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"os_rng\", \"std\"]","declared_features":"[\"os_rng\", \"serde\", \"std\"]","target":7103588737537114155,"profile":2040997289075261528,"path":18056747494721673097,"deps":[[3331586631144870129,"getrandom",false,4223657033335357958]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\rand_core-988d2910b06f7092\\dep-lib-rand_core","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"alloc\", \"default\", \"os_rng\", \"small_rng\", \"std\", \"std_rng\", \"thread_rng\"]","declared_features":"[\"alloc\", \"default\", \"log\", \"nightly\", \"os_rng\", \"serde\", \"simd_support\", \"small_rng\", \"std\", \"std_rng\", \"thread_rng\", \"unbiased\"]","target":4488736914369465202,"profile":2040997289075261528,"path":8207378344465267276,"deps":[[5652558058897858086,"rand_chacha",false,15785902116676629680],[13135315962794364551,"rand_core",false,16811026693593117703]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\rand-678236627f6f80bc\\dep-lib-rand","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"bundled\", \"modern_sqlite\"]","declared_features":"[\"array\", \"backup\", \"blob\", \"buildtime_bindgen\", \"bundled\", \"bundled-full\", \"bundled-sqlcipher\", \"bundled-sqlcipher-vendored-openssl\", \"bundled-windows\", \"chrono\", \"collation\", \"column_decltype\", \"csv\", \"csvtab\", \"extra_check\", \"functions\", \"hooks\", \"i128_blob\", \"in_gecko\", \"limits\", \"load_extension\", \"loadable_extension\", \"modern-full\", \"modern_sqlite\", \"preupdate_hook\", \"release_memory\", \"rusqlite-macros\", \"serde_json\", \"serialize\", \"series\", \"session\", \"sqlcipher\", \"time\", \"trace\", \"unlock_notify\", \"url\", \"uuid\", \"vtab\", \"wasm32-wasi-vfs\", \"window\", \"with-asan\"]","target":10662205063260755052,"profile":2040997289075261528,"path":8713614378765049877,"deps":[[3056352129074654578,"hashlink",false,1205671189650787708],[3666196340704888985,"smallvec",false,15202448748883864493],[5510864063823219921,"fallible_streaming_iterator",false,17211302762384991236],[7896293946984509699,"bitflags",false,14707906480895005465],[12860549049674006569,"fallible_iterator",false,13664285845613945792],[16675652872862304210,"libsqlite3_sys",false,3579168459202359888]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\rusqlite-3ea41771c56aa455\\dep-lib-rusqlite","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":1483978684523555203,"profile":2040997289075261528,"path":14674978390905755121,"deps":[[4495526598637097934,"parking_lot",false,6439719128032313600]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\scheduled-thread-pool-25e2bdd115e39094\\dep-lib-scheduled_thread_pool","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"default\", \"use_std\"]","target":3556356971060988614,"profile":2040997289075261528,"path":5636350220448400533,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\scopeguard-95a98862524d8015\\dep-lib-scopeguard","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"std\"]","target":929485496544747924,"profile":1369601567987815722,"path":5449551212038370859,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\shlex-ab01a0e35f651deb\\dep-lib-shlex","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[\"arbitrary\", \"bincode\", \"const_generics\", \"const_new\", \"debugger_visualizer\", \"drain_filter\", \"drain_keep_rest\", \"impl_bincode\", \"malloc_size_of\", \"may_dangle\", \"serde\", \"specialization\", \"union\", \"unty\", \"write\"]","target":9091769176333489034,"profile":2040997289075261528,"path":7578975667559371145,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\smallvec-22031a20ed39b1e1\\dep-lib-smallvec","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"clone-impls\", \"default\", \"derive\", \"extra-traits\", \"full\", \"parsing\", \"printing\", \"proc-macro\"]","declared_features":"[\"clone-impls\", \"default\", \"derive\", \"extra-traits\", \"fold\", \"full\", \"parsing\", \"printing\", \"proc-macro\", \"test\", \"visit\", \"visit-mut\"]","target":9442126953582868550,"profile":1369601567987815722,"path":9103715929877979346,"deps":[[1988483478007900009,"unicode_ident",false,12502023975305169797],[3060637413840920116,"proc_macro2",false,4766645904778405251],[17990358020177143287,"quote",false,16896938825330447260]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\syn-dcc8dbd15b548f63\\dep-lib-syn","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\"]","declared_features":"[\"arch_zkasm\", \"default\", \"serde\", \"serde_support\", \"std\"]","target":12703160134031456009,"profile":1369601567987815722,"path":16850927552934778827,"deps":[[3346669234123344896,"build_script_build",false,6619606441958142681]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\target-lexicon-052b4e810b2936e4\\dep-lib-target_lexicon","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[3346669234123344896,"build_script_build",false,4565448003524370620]],"local":[{"Precalculated":"0.13.2"}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\"]","declared_features":"[\"arch_zkasm\", \"default\", \"serde\", \"serde_support\", \"std\"]","target":17883862002600103897,"profile":1369601567987815722,"path":13132915812802927071,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\target-lexicon-a7dc9c2fed21ec5f\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":5438535436255082082,"profile":1369601567987815722,"path":11454069733524763581,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\unicode-ident-ebb679d917e3a862\\dep-lib-unicode_ident","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":15796751668680979503,"profile":2040997289075261528,"path":14695497435455390920,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\unindent-5e5091b4149cfdd7\\dep-lib-unindent","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"default\", \"fast-rng\", \"rng\", \"std\", \"v4\"]","declared_features":"[\"arbitrary\", \"atomic\", \"borsh\", \"bytemuck\", \"default\", \"fast-rng\", \"js\", \"macro-diagnostics\", \"md5\", \"rng\", \"rng-getrandom\", \"rng-rand\", \"serde\", \"sha1\", \"slog\", \"std\", \"uuid-rng-internal-lib\", \"v1\", \"v3\", \"v4\", \"v5\", \"v6\", \"v7\", \"v8\", \"zerocopy\"]","target":10485754080552990909,"profile":761789833876511999,"path":12239564885782907672,"deps":[[3331586631144870129,"getrandom",false,4223657033335357958],[11916940916964035392,"rand",false,1757186709270924158]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\uuid-456ad130a4d6e142\\dep-lib-uuid","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":3860171895115171228,"profile":1369601567987815722,"path":10774807644426544333,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\vcpkg-26e6d8da24cd92e3\\dep-lib-vcpkg","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":18099224280402537651,"profile":1369601567987815722,"path":3991868636303472625,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\version_check-551b1ded92f39411\\dep-lib-version_check","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[6520462792382062950,"build_script_build",false,4107658563283854278]],"local":[{"Precalculated":"0.52.6"}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":3306771437825829530,"profile":2040997289075261528,"path":847967504024714307,"deps":[[6520462792382062950,"build_script_build",false,1968863350789577828]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\windows_x86_64_msvc-58adaf465a2ec997\\dep-lib-windows_x86_64_msvc","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":5408242616063297496,"profile":1369601567987815722,"path":3005598861278728804,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\windows_x86_64_msvc-98e85a3eb727a787\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":2558631941022679061,"profile":2544543907377151103,"path":5647306714056893248,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\windows-link-cccd9bffd63aa929\\dep-lib-windows_link","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[]","declared_features":"[]","target":12110220207092481134,"profile":1263639915129602509,"path":12455905127975248019,"deps":[[6520462792382062950,"windows_x86_64_msvc",false,13729075174588570314]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\windows-targets-37dea605cc03ec98\\dep-lib-windows_targets","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[14131061446229887432,"build_script_build",false,6970181904722980160]],"local":[{"RerunIfChanged":{"output":"release\\build\\zerocopy-002db567c9afd588\\output","paths":["build.rs","Cargo.toml"]}}],"rustflags":[],"config":0,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"simd\"]","declared_features":"[\"__internal_use_only_features_that_work_on_stable\", \"alloc\", \"derive\", \"float-nightly\", \"simd\", \"simd-nightly\", \"std\", \"zerocopy-derive\"]","target":5408242616063297496,"profile":1369601567987815722,"path":334889221332062195,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\zerocopy-7ae7e4c6c4f2adf7\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| {"rustc":13800692020808712694,"features":"[\"simd\"]","declared_features":"[\"__internal_use_only_features_that_work_on_stable\", \"alloc\", \"derive\", \"float-nightly\", \"simd\", \"simd-nightly\", \"std\", \"zerocopy-derive\"]","target":3084901215544504908,"profile":2040997289075261528,"path":10900471008086817828,"deps":[[14131061446229887432,"build_script_build",false,10204952581994946853]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\zerocopy-80a10467cd7db62e\\dep-lib-zerocopy","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| from ..mounter import TaskMounter | ||
| from typing import Callable, List | ||
| from ..constant import MessageStatus | ||
| class core: | ||
| class QueueOperation: | ||
| def __init__(self, db_path: str): | ||
| ... | ||
| def init_db(self): | ||
| ... | ||
| def enqueue(self, message_dict: dict) -> str: | ||
| ... | ||
| def dequeue(self, size: int = 1) -> List[dict]: | ||
| ... | ||
| def get_queue_length(self) -> int: | ||
| ... | ||
| def get_completed_messages(self) -> List[dict]: | ||
| ... | ||
| def get_result(self, message_id: str): | ||
| ... | ||
| def update_status(self, message_id: str, status: MessageStatus): | ||
| ... | ||
| def update_result(self, message_id: str, result: str): | ||
| ... | ||
| def delete_message(self, message_id: str): | ||
| ... | ||
| def clean_old_messages(self, days: int): | ||
| ... | ||
| def clean_expired_messages(self): | ||
| ... | ||
| class TaskMounter: | ||
| def __init__(self, task_class: type[TaskMounter]): | ||
| ... | ||
| def get_task_list(self) -> List[str]: | ||
| ... | ||
| def get_task_function(self, name: str) -> Callable: | ||
| ... | ||
| import os | ||
| import json | ||
| import hashlib | ||
| from typing import Tuple, Union, List | ||
| import threading | ||
| import random | ||
| from ..core import core | ||
| from ..constant import MessageStatus | ||
| class QueueOperation: | ||
| def __init__(self, shard_num: int = 4, queue_name: str = "default"): | ||
| self.shard_num = shard_num | ||
| self.db_dir = os.path.join("cache", queue_name) | ||
| self.shard_connections = threading.local() | ||
| if not os.path.exists(self.db_dir): | ||
| os.makedirs(self.db_dir) | ||
| self.init_shards() | ||
| def _get_shard_index(self, message_id: str) -> int: | ||
| """计算消息的分片索引""" | ||
| hash_obj = hashlib.sha256(message_id.encode()) | ||
| return int(hash_obj.hexdigest(), 16) % self.shard_num | ||
| def _get_shard_path(self, shard_index: int) -> str: | ||
| """获取分片数据库路径""" | ||
| return os.path.join(self.db_dir, f"queue_shard_{shard_index}.db") | ||
| def _get_shard_conn(self, shard_index: int) -> core.QueueOperation: | ||
| """获取分片数据库连接(线程安全)""" | ||
| if not hasattr(self.shard_connections, "shards"): | ||
| self.shard_connections.shards = {} | ||
| if shard_index not in self.shard_connections.shards: | ||
| db_path = self._get_shard_path(shard_index) | ||
| conn = core.QueueOperation(db_path) | ||
| self.shard_connections.shards[shard_index] = conn | ||
| return self.shard_connections.shards[shard_index] | ||
| def init_shards(self): | ||
| """初始化分片数据库""" | ||
| for i in range(self.shard_num): | ||
| conn = self._get_shard_conn(i) | ||
| conn.init_db() | ||
| # 入队 | ||
| def enqueue(self, message: dict) -> str: | ||
| shard_index = self._get_shard_index(message["id"]) | ||
| conn = self._get_shard_conn(shard_index) | ||
| conn.enqueue(message) | ||
| return message["id"] | ||
| def dequeue(self, size: int = 1) -> List[dict]: | ||
| messages = [] | ||
| collected = 0 | ||
| # 随机轮询分片顺序 | ||
| shard_order = list(range(self.shard_num)) | ||
| random.shuffle(shard_order) | ||
| for shard_index in shard_order: | ||
| if collected >= size: | ||
| break | ||
| conn = self._get_shard_conn(shard_index) | ||
| shard_messages = conn.dequeue(size - collected) | ||
| messages.extend(shard_messages) | ||
| collected += len(shard_messages) | ||
| return messages | ||
| # 获取队列长度 | ||
| def get_queue_length(self) -> int: | ||
| """获取队列中待处理消息的数量 | ||
| Returns: | ||
| int: 待处理消息数量 | ||
| """ | ||
| total = 0 | ||
| for i in range(self.shard_num): | ||
| conn = self._get_shard_conn(i) | ||
| total += conn.get_queue_length() | ||
| return total | ||
| # 获取完成/失败的消息 | ||
| def get_completed_messages(self) -> List[dict]: | ||
| messages = [] | ||
| for i in range(self.shard_num): | ||
| conn = self._get_shard_conn(i) | ||
| messages.extend(conn.get_completed_messages()) | ||
| return messages | ||
| # 获取消息结果 | ||
| def get_result(self, message_id: str) -> Tuple[bool, Union[str, dict]]: | ||
| conn = self._get_shard_conn(self._get_shard_index(message_id)) | ||
| return conn.get_result(message_id) | ||
| # 更新消息状态 | ||
| def update_status(self, message_id: str, status: MessageStatus): | ||
| conn = self._get_shard_conn(self._get_shard_index(message_id)) | ||
| conn.update_status(message_id, status) | ||
| # 更新消息结果 | ||
| def update_result(self, message_id: str, result: str): | ||
| conn = self._get_shard_conn(self._get_shard_index(message_id)) | ||
| conn.update_result(message_id, result) | ||
| # 删除消息 | ||
| def delete_message(self, message_id: str): | ||
| conn = self._get_shard_conn(self._get_shard_index(message_id)) | ||
| conn.delete_message(message_id) | ||
| # 清理7天前的已完成/失败消息 | ||
| def clean_old_messages(self, shard_index: int, days: int = 7): | ||
| conn = self._get_shard_conn(shard_index) | ||
| conn.clean_old_messages(days) | ||
| # 清理过期但未处理的消息 | ||
| def clean_expired_messages(self, shard_index: int): | ||
| conn = self._get_shard_conn(shard_index) | ||
| conn.clean_expired_messages() |
| from ..queue_operation.listen_operation import ListenOperation | ||
| from concurrent.futures import ThreadPoolExecutor | ||
| from ..mounter.listen_mounter import ListenMounter | ||
| import threading | ||
| class ListenDataScheduler: | ||
| def __init__(self, listen_operation: ListenOperation): | ||
| self.listen_operation = listen_operation | ||
| self.is_running = False | ||
| self.executor = ThreadPoolExecutor(max_workers=1) | ||
| self.listen_thread = None | ||
| def _process_listen_data(self, key, value, delete_id): | ||
| listen_function = ListenMounter.get_Listener_function(key) | ||
| if listen_function: | ||
| try: | ||
| listen_function(value) | ||
| except Exception as e: | ||
| ValueError(f"Error in {key} listener function: {e}") | ||
| finally: | ||
| self.listen_operation.delete_change_log(delete_id=delete_id) | ||
| def listen(self): | ||
| while self.is_running: | ||
| status, change_data_items = self.listen_operation.listen_data() | ||
| if status: | ||
| for data in change_data_items: | ||
| key = data[6] | ||
| new_value = data[7] | ||
| delete_id = data[0] | ||
| self.executor.submit(self._process_listen_data, key, new_value, delete_id) | ||
| def start_listen_data(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| self.listen_thread = threading.Thread(target=self.listen) | ||
| self.listen_thread.start() | ||
| def stop_listen_data(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| if self.listen_thread and self.listen_thread.is_alive(): | ||
| self.listen_thread.join(timeout=2) | ||
| self.executor.shutdown(wait=True) | ||
| from ..queue_operation import QueueOperation | ||
| from ..model import MessageItem | ||
| from typing import Callable | ||
| from concurrent.futures import ThreadPoolExecutor | ||
| import threading | ||
| import time | ||
| class ReceiveScheduler: | ||
| def __init__(self, queue_operation: QueueOperation, receive_thread_num: int = 1): | ||
| self.callbacks = dict() | ||
| self.receive_thread_num = receive_thread_num | ||
| self.is_running = False | ||
| self.executor = ThreadPoolExecutor(max_workers=receive_thread_num) # 并行执行回调 | ||
| self.lock = threading.Lock() | ||
| self.queue_operation = queue_operation | ||
| self.receive_thread = None # 单一轮询线程 | ||
| def send_message(self, message: MessageItem, callback: Callable = None): # type: ignore | ||
| if callback is None: | ||
| callback = lambda message: print(message) | ||
| # self.queue_operation.enqueue(message.to_dict()) | ||
| self.queue_operation.enqueue(message.to_dict_by_core()) | ||
| with self.lock: | ||
| self.callbacks[message.id] = callback | ||
| def receive_message(self): | ||
| """单一轮询线程,并行执行回调""" | ||
| while self.is_running: | ||
| message_list = self.queue_operation.get_completed_messages() | ||
| if message_list: | ||
| for message in message_list: | ||
| message = MessageItem.from_dict(message) | ||
| callback_default = lambda message: message | ||
| with self.lock: | ||
| callback = self.callbacks.pop(message.id, None) | ||
| if callback is None: | ||
| callback = callback_default | ||
| # 使用线程池并行执行回调 | ||
| self.executor.submit(self._safe_callback, callback, message) | ||
| else: | ||
| time.sleep(0.1) # 适当休眠避免CPU空转 | ||
| def _safe_callback(self, callback, message): | ||
| """安全执行回调函数""" | ||
| try: | ||
| callback(message) | ||
| # with ThreadPoolExecutor(max_workers=1) as executor: | ||
| # future = executor.submit(callback, message) | ||
| # future.result(timeout=5.0) | ||
| # except TimeoutError: | ||
| # print(f"回调执行超时: {message.id}") | ||
| except Exception as e: | ||
| print(f"回调执行错误: {str(e)}") | ||
| finally: | ||
| self.queue_operation.delete_message(message.id) | ||
| def start_receive_thread(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| # 创建单一轮询线程 | ||
| self.receive_thread = threading.Thread(target=self.receive_message, daemon=True) | ||
| self.receive_thread.start() | ||
| def stop_receive_thread(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| # 等待轮询线程结束 | ||
| if self.receive_thread and self.receive_thread.is_alive(): | ||
| self.receive_thread.join(timeout=2.0) | ||
| # 关闭线程池 | ||
| self.executor.shutdown(wait=True) | ||
| from ..queue_operation import QueueOperation | ||
| from ..model import MessageItem | ||
| from ..constant import MessageStatus | ||
| from ..cycle.task_cycle import TaskCycle | ||
| from ..mounter.task_mounter import TaskMounter | ||
| from concurrent.futures import ThreadPoolExecutor | ||
| from datetime import datetime | ||
| import time | ||
| import threading | ||
| class TaskScheduler: | ||
| def __init__(self, queue_operation: QueueOperation, task_thread_num: int = 2): | ||
| self.task_thread_num = task_thread_num | ||
| self.is_running = False | ||
| self.executor = ThreadPoolExecutor(max_workers=task_thread_num) # 并行执行任务 | ||
| self.queue_operation = queue_operation | ||
| self.task_thread = None # 单一轮询线程 | ||
| def _process_message(self, message: MessageItem): | ||
| """处理单个消息""" | ||
| try: | ||
| if message.destination == "client": | ||
| message.status = MessageStatus.COMPLETED | ||
| message.result = {"result": "success"} | ||
| message.updatetime = datetime.now() | ||
| return message | ||
| task_function = TaskMounter.get_task_function(message.destination) | ||
| task_cycle = TaskCycle(message, task_function) | ||
| task_cycle.run() | ||
| message.status = task_cycle.get_task_status() # type: ignore | ||
| if message.status == MessageStatus.FAILED: | ||
| message.result = {"error": task_cycle.get_task_error()} | ||
| else: | ||
| message.result = task_cycle.get_task_result() # type: ignore | ||
| message.updatetime = datetime.now() | ||
| except Exception as e: | ||
| message.status = MessageStatus.FAILED | ||
| message.result = {"error": str(e)} | ||
| message.updatetime = datetime.now() | ||
| return message | ||
| def _update_result(self, message): | ||
| """更新任务结果到数据库""" | ||
| try: | ||
| self.queue_operation.update_result(message.id, message.result) | ||
| self.queue_operation.update_status(message.id, message.status) | ||
| except Exception as e: | ||
| print(f"任务结果更新失败: {str(e)}") | ||
| def task_callback(self): | ||
| """单一轮询线程,并行执行任务""" | ||
| while self.is_running: | ||
| try: | ||
| message_list = self.queue_operation.dequeue( | ||
| size=self.task_thread_num * 2 | ||
| ) | ||
| if message_list: | ||
| # 并行处理所有获取到的消息 | ||
| for message in message_list: | ||
| self.executor.submit( | ||
| lambda m: self._update_result(self._process_message(m)), | ||
| MessageItem.from_dict(message), | ||
| ) | ||
| else: | ||
| time.sleep(0.1) # 适当休眠 | ||
| except Exception as e: | ||
| print(f"任务调度错误: {str(e)}") | ||
| time.sleep(1) | ||
| def start_task_thread(self): | ||
| if self.is_running: | ||
| return | ||
| self.is_running = True | ||
| # 创建单一轮询线程 | ||
| self.task_thread = threading.Thread(target=self.task_callback, daemon=True) | ||
| self.task_thread.start() | ||
| def stop_task_thread(self): | ||
| if not self.is_running: | ||
| return | ||
| self.is_running = False | ||
| # 等待轮询线程结束 | ||
| if self.task_thread and self.task_thread.is_alive(): | ||
| self.task_thread.join(timeout=2.0) | ||
| # 关闭线程池 | ||
| self.executor.shutdown(wait=True) |
Sorry, the diff of this file is not supported yet
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
2114
95.2%157249
-99.87%60
-88.72%