
投稿日:
今まで普通のファイルで処理済みパスを管理していたんですが、完成間近になってデータベースを使うことに決めて、アプリ全体を作り直すことになりました・・・。せっかく書いたし消すのがもったいないと思いブログに残すことにしました!一応セキュリティアプリなので、載せても平気なものだけ載せます。
複数ファイル登録関数
fn filter_new_paths(&self, mut paths: Vec<String>) -> Result<Vec<String>, FPError> {
let mut enc = FPEncrypt::new_with_mode(&CFG_PATH, false, false)?;
enc.decrypt_file()?;
let file = try_open()?;
let reader = BufReader::new(file);
let mut new_list = String::new();
let mut throw_list = Vec::<String>::new(); // 登録済みファイルの二重登録防止
for line in reader.lines() {
let path = unwrap_line(line);
let (num_part, path_part) = split_line(&path);
if paths.iter().any(|p| p == path_part) {
throw_list.push(path_part.to_string());
let new_num = self.match_number_add(num_part)?;
// 既に処理済みのパス
if new_num == num_part {
new_list.push_str(&path);
new_list.push_str("\n");
continue
}
// マジックナンバー更新
new_list.push_str(new_num);
new_list.push_str(path_part);
new_list.push_str("\n");
continue
}
new_list.push_str(&path);
new_list.push_str("\n");
}
// 新しいパスをフィルター
if !throw_list.is_empty() {
paths.retain(|p| {
!throw_list.iter().any(|t| t == p)
});
for p in paths.iter() {
new_list.push_str(self.num);
new_list.push_str(p);
new_list.push_str("\n");
}
}
enc.save_text(&CFG_PATH, new_list.as_bytes())?;
enc.encrypt_file()?;
update_cfg!();
Ok(paths)
}
これはユーザーがフォルダ単位で処理を指定した場合に使う関数です。再帰関数でパスを集めたものを引数に受け取ります。途中で呼んでいる関数たちははエラーハンドリングするために送っています。num_partの部分はマジックナンバーの部分で、self.num(実行する処理のマジックナンバー)との組み合わせによってマジックナンバーを変更したりしています。この組み合わせ結果は、マジックナンバーが複数あるのでかなり頭使いました。あと、配列ではなくIndexSet使っても良かったかな?と思いました。
データベースなら重複確認もいらなくなるということでこの関数は消えます・・・
リスト表示パスソート関数
fn sort_paths(&mut self, mut path_list: Vec<String>)
-> Result<<IndexMap<String, Vec<String>>, FPError> {
let path_map = IndexMap::<String, Vec<String>>::new();
loop {
let to_path: Vec<_> = path_list
.iter()
.map(|v| {
let (_, p) = split_line(v);
Path::new(p)
})
.collect();
// 一番短いパスを探す
let root = to_path
.iter()
.min_by_key(|x| x.components().count())
.unwrap();
let search = find_parent(root)?;
let with_num = self.num + search;
// 共通パスとそれ以外で分ける
let (sorted, left): (Vec<String>, Vec<String>) = path_list
.into_iter()
.partition(|n| n.starts_with(&with_num));
let total_files = count_files(); // 対象フォルダのルート下のファイル数
// ルート下ファイルが全て登録されてる、または20ファイル以上だったらフォルダだけ表示
if total_files == sorted.len() || (!self.change && total_files > 20) {
path_map.insert(search, sorted);
path_map.entry(TOTAL.to_string())
.or_insert_with(Vec::new)
.push(total_files.to_string());
} else {
// 単体で表示する用(ファイル)
path_map.entry(FILE.to_string())
.or_default()
.extend(sorted);
}
if left.is_empty() {
break
}
path_list = left;
}
Ok(path_map)
}
この関数は最近作ったもので、リスト一覧でパス表記する際に使おうかなと思って書いていましたが、未完成の状態で消えることになりました(泣)
最初のパス表記に使うための関数で、フォルダ展開した時の表示関数は別にあります。20個以上ファイルがあればフォルダ表示というのは、今までは、ルート下全て登録されてた場合のみフォルダだけ表示して、ユーザーが展開を選択した時に中身を表示する。それ以外はファイルで単体で表示って感じでやっていたのですが、ファイル数が多い場合大量に表示されることを防ぐために、全て登録されてなくても20個以上ならフォルダで表示させるようにしました。TOTALは対象フォルダ内の登録ファイル数です。残念ながら消えますが、一部のコードは使うかも?
とりあえず載せれるのはこれくらいで、あとはパスワード設定処理とかも完全に変えてすでに完成しています!ちなみに使ったのはkeyringで、OSの認証ストアにパスワードを保存するためのライブラリです。そしてそれに必要な引数を、セキュリティ対策で直接コードに書かないで外部から取得するようにしました。ローカルだとかなり方法が限られるのですが、独自の方法で設計しました。ランダム要素があるので私自身もわかりませんが同じ引数が取れるようにしています。
最後まで読んでいただきありがとうございました!

コメント