1.添加多线程支持

2.优化代码结构
3.升级依赖
This commit is contained in:
Lkhsss
2024-08-17 22:05:34 +08:00
parent 7245260604
commit 4af4ce7405
9 changed files with 996 additions and 164 deletions

View File

@ -1,19 +1,26 @@
use env_logger::Builder;
use hex::decode;
use log::{error, info, warn};
use ncmmiao::{dump, Key, Ncmfile};
use std::env;
use std::path::Path;
// use std::time::SystemTime;
use walkdir::WalkDir;
#[warn(unreachable_code)]
use walkdir::WalkDir; //遍历目录
mod ncmdump;
mod threadpool;
use ncmdump::{dump, Key, Ncmfile};
mod test;
fn main() {
// 最大线程数
let max_workers = 4;
let mut builder = Builder::new();
builder.filter(None, log::LevelFilter::Info);
builder.init(); //初始化logger
let keys = Key {
let keys: Key = Key {
core: decode("687A4852416D736F356B496E62617857").unwrap(),
meta: decode("2331346C6A6B5F215C5D2630553C2728").unwrap(),
};
@ -21,6 +28,7 @@ fn main() {
let args: Vec<String> = env::args().collect();
let args = if args.len() == 1 {
warn!("未指定文件夹,将使用默认文件夹。");
let mut args_temp = Vec::new();
if Path::new("CloudMusic").exists() {
warn!("CloudMusic文件夹存在将自动使用。");
@ -39,7 +47,6 @@ fn main() {
} else {
args[1..].to_vec()
};
// let args = &args[1..];
let mut undumpfile = Vec::new(); // 该列表将存入文件的路径
@ -78,8 +85,14 @@ fn main() {
// let filepaths = undumpfile;
// let count = undumpfile.len();
// let mut time = 0usize;
// 初始化线程池
let pool = threadpool::Pool::new(max_workers);
for filepath in undumpfile {
let mut ncmfile = Ncmfile::new(&filepath).unwrap();
dump(&mut ncmfile, &keys, Path::new("output")).unwrap();
let tkey = keys.clone();
pool.execute(move || {
let mut ncmfile = Ncmfile::new(filepath.as_str()).unwrap();
dump(&mut ncmfile, &tkey, Path::new("output")).unwrap();
});
}
}

View File

@ -16,9 +16,9 @@ use std::str::from_utf8;
pub struct Ncmfile {
/// 文件对象
pub file: File,
/// 只是名称,不带后缀
/// 歌曲名称,不带文件后缀
pub name: String,
/// 带后缀名
/// 文件名称,带后缀名
pub filename: String,
/// 文件大小
pub size: u64,
@ -182,6 +182,7 @@ struct Metadata {
}
// 存储各种密钥的结构体
#[derive(Clone)]
pub struct Key {
pub core: Vec<u8>,
pub meta: Vec<u8>,
@ -257,7 +258,7 @@ pub fn dump(ncmfile: &mut Ncmfile, keys: &Key, outputdir: &Path) -> Result<(), M
};
// 跳过4个字节的校验码
trace!("跳过4个字节的校验码");
trace!("读取校验码");
let crc32 = u32::from_le_bytes(ncmfile.seekread(4).unwrap().try_into().unwrap()) as u64;
// 跳过5个字节
@ -278,7 +279,7 @@ pub fn dump(ncmfile: &mut Ncmfile, keys: &Key, outputdir: &Path) -> Result<(), M
// trace!("保存图片");
// let mut file = File::create(format!("TEST.jpg",)).unwrap();
// file.write_all(&image_data).unwrap();
trace!("组成密码盒");
let key_box = {
let key_length = key_data.len();
let key_data = Vec::from(key_data);
@ -430,6 +431,7 @@ pub fn dump(ncmfile: &mut Ncmfile, keys: &Key, outputdir: &Path) -> Result<(), M
}
// fn read_meta(file: &mut File, meta_length: u32) -> Result<Vec<u8>, Error> {}
fn convert_to_generic_arrays(input: &[u8]) -> Vec<GenericArray<u8, U16>> {
// 确保输入的长度是16的倍数
assert!(
@ -470,6 +472,8 @@ fn aes128(key: &[u8], blocks: &[u8]) -> String {
x.to_string()
}
/// ## AES128解密
fn aes128_to_slice(key: &[u8], blocks: &[u8]) -> Vec<u8> {
trace!("进行AES128解密");
let key = GenericArray::from_slice(key);
@ -481,6 +485,8 @@ fn aes128_to_slice(key: &[u8], blocks: &[u8]) -> Vec<u8> {
// 开始解密
cipher.decrypt_blocks(&mut blocks);
//取出解密后的值
let mut x: Vec<u8> = Vec::new();
for block in blocks.iter() {
for i in block {
@ -496,8 +502,9 @@ fn aes128_to_slice(key: &[u8], blocks: &[u8]) -> Vec<u8> {
/// - \ / * ? " : < > |
/// - _ _ ⟨ ⟩ _
fn standardize_filename(old_filename: String) -> String {
trace!("格式化文件名");
let mut new_filename = String::from(old_filename);
debug!("规范文件名:{}", new_filename);
// debug!("规范文件名:{}", new_filename);
let standard = ["\\", "/", "*", "?", "\"", ":", "<", ">", "|"];
let resolution = ["_", "_", "", "", "", "", "", "", "_"];
for i in 0..standard.len() {

14
src/test.rs Normal file
View File

@ -0,0 +1,14 @@
#[cfg(test)]
mod tests {
use crate::*;
#[test]
#[ignore = "测验成功"]
fn it_works() {
let p = threadpool::Pool::new(4);
p.execute(|| println!("do new job1"));
p.execute(|| println!("do new job2"));
p.execute(|| println!("do new job3"));
p.execute(|| println!("do new job4"));
}
}

90
src/threadpool.rs Normal file
View File

@ -0,0 +1,90 @@
use std::sync::{mpsc, Arc, Mutex};
use std::thread::{self, JoinHandle};
use log::{info,debug};
use serde::de;
type Job = Box<dyn FnOnce() + 'static + Send>;
enum Message {
ByeBye,
NewJob(Job),
}
struct Worker {
_id: usize,
t: Option<JoinHandle<()>>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
let t = thread::spawn(move || loop {
let message = receiver.lock().unwrap().recv().unwrap();
match message {
Message::NewJob(job) => {
debug!("线程[{}]获得任务", id);
job();
}
Message::ByeBye => {
debug!("线程[{}]结束任务", id);
break;
}
}
});
Worker {
_id: id,
t: Some(t),
}
}
}
pub struct Pool {
workers: Vec<Worker>,
max_workers: usize,
sender: mpsc::Sender<Message>,
}
impl Pool {
pub fn new(max_workers: usize) -> Pool {
if max_workers == 0 {
panic!("最大线程数不能小于零!")
}else {
debug!("将开启{}线程",max_workers);
}
let (tx, rx) = mpsc::channel();
let mut workers = Vec::with_capacity(max_workers);
let receiver = Arc::new(Mutex::new(rx));
for i in 0..max_workers {
workers.push(Worker::new(i, Arc::clone(&receiver)));
}
Pool {
workers: workers,
max_workers: max_workers,
sender: tx,
}
}
pub fn execute<F>(&self, f: F)
where
F: FnOnce() + 'static + Send,
{
let job = Message::NewJob(Box::new(f));
self.sender.send(job).unwrap();
}
}
impl Drop for Pool {
fn drop(&mut self) {
for _ in 0..self.max_workers {
self.sender.send(Message::ByeBye).unwrap();
}
for w in self.workers.iter_mut() {
if let Some(t) = w.t.take() {
t.join().unwrap();
}
}
}
}