@tutao/node-mimimi 271.250224.0 → 271.250227.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +3 -0
- package/Cargo.toml +1 -0
- package/package.json +5 -5
- package/src/importer.rs +181 -6
package/Cargo.lock
CHANGED
|
@@ -516,6 +516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
516
516
|
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
|
517
517
|
dependencies = [
|
|
518
518
|
"powerfmt",
|
|
519
|
+
"serde",
|
|
519
520
|
]
|
|
520
521
|
|
|
521
522
|
[[package]]
|
|
@@ -2172,6 +2173,7 @@ dependencies = [
|
|
|
2172
2173
|
"pqcrypto-mlkem",
|
|
2173
2174
|
"pqcrypto-traits",
|
|
2174
2175
|
"rand_core",
|
|
2176
|
+
"regex",
|
|
2175
2177
|
"rsa",
|
|
2176
2178
|
"rustls",
|
|
2177
2179
|
"serde",
|
|
@@ -2181,6 +2183,7 @@ dependencies = [
|
|
|
2181
2183
|
"sha3",
|
|
2182
2184
|
"simple_logger",
|
|
2183
2185
|
"thiserror 2.0.11",
|
|
2186
|
+
"time",
|
|
2184
2187
|
"tokio",
|
|
2185
2188
|
"uniffi",
|
|
2186
2189
|
"zeroize",
|
package/Cargo.toml
CHANGED
|
@@ -13,6 +13,7 @@ crate-type = ["cdylib"]
|
|
|
13
13
|
default = ["javascript"]
|
|
14
14
|
# needed to turn off the autogenerated ffi when using the tests
|
|
15
15
|
javascript = ["dep:napi-derive"]
|
|
16
|
+
test-with-local-http-server = []
|
|
16
17
|
|
|
17
18
|
[dependencies]
|
|
18
19
|
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tutao/node-mimimi",
|
|
3
|
-
"version": "271.
|
|
3
|
+
"version": "271.250227.0",
|
|
4
4
|
"main": "./dist/binding.js",
|
|
5
5
|
"types": "./dist/binding.d.ts",
|
|
6
6
|
"napi": {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@tutao/otest": "271.
|
|
16
|
+
"@tutao/otest": "271.250227.0",
|
|
17
17
|
"@napi-rs/cli": "3.0.0-alpha.68",
|
|
18
18
|
"typescript": "5.3.3",
|
|
19
19
|
"zx": "8.1.5"
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"version": "napi version"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
|
-
"@tutao/node-mimimi-win32-x64-msvc": "271.
|
|
34
|
-
"@tutao/node-mimimi-linux-x64-gnu": "271.
|
|
35
|
-
"@tutao/node-mimimi-darwin-universal": "271.
|
|
33
|
+
"@tutao/node-mimimi-win32-x64-msvc": "271.250227.0",
|
|
34
|
+
"@tutao/node-mimimi-linux-x64-gnu": "271.250227.0",
|
|
35
|
+
"@tutao/node-mimimi-darwin-universal": "271.250227.0"
|
|
36
36
|
}
|
|
37
37
|
}
|
package/src/importer.rs
CHANGED
|
@@ -627,10 +627,10 @@ impl Importer {
|
|
|
627
627
|
Ok(())
|
|
628
628
|
}
|
|
629
629
|
|
|
630
|
-
/// Decide weather this error should abort the import process, or it should move to import next chunk
|
|
631
|
-
/// -
|
|
632
|
-
/// be propagated to the node process to maybe be displayed and
|
|
633
|
-
/// -
|
|
630
|
+
/// Decide weather this error should abort the import process, or it should move to import the next chunk.
|
|
631
|
+
/// - If it returns `Ok`, we should continue with the next chunk, if it returns `Err`, the error should
|
|
632
|
+
/// be propagated to the node process to maybe be displayed, and the import should stop for now.
|
|
633
|
+
/// - If mails involved in this error should not be picked when user retry, move them to FAILED_MAILS_SUB_DIR
|
|
634
634
|
async fn handle_err_while_importing_chunk(
|
|
635
635
|
&self,
|
|
636
636
|
import_error: MailImportErrorMessage,
|
|
@@ -640,8 +640,8 @@ impl Importer {
|
|
|
640
640
|
// if the import is (temporary) disabled, we should give up and let user try again later
|
|
641
641
|
ImportErrorKind::ImportFeatureDisabled => Err(ImportErrorKind::ImportFeatureDisabled)?,
|
|
642
642
|
|
|
643
|
-
// If server
|
|
644
|
-
// nothing we can do about
|
|
643
|
+
// If a server does not give any available blob storage client (which we also use to make service call),
|
|
644
|
+
// nothing we can do about should error out in a client
|
|
645
645
|
ImportErrorKind::EmptyBlobServerList => Err(ImportErrorKind::SdkError)?,
|
|
646
646
|
|
|
647
647
|
ImportErrorKind::SdkError => Err(import_error)?,
|
|
@@ -739,3 +739,178 @@ impl From<ImportMailStateId> for IdTupleGenerated {
|
|
|
739
739
|
}
|
|
740
740
|
}
|
|
741
741
|
}
|
|
742
|
+
|
|
743
|
+
#[cfg(test)]
|
|
744
|
+
pub mod tests {
|
|
745
|
+
use super::*;
|
|
746
|
+
use crate::test_utils::{init_file_importer, write_big_sample_email, CleanDir};
|
|
747
|
+
|
|
748
|
+
#[cfg_attr(
|
|
749
|
+
not(feature = "test-with-local-http-server"),
|
|
750
|
+
ignore = "require local http server."
|
|
751
|
+
)]
|
|
752
|
+
#[tokio::test]
|
|
753
|
+
async fn can_import_single_eml_file_without_attachment() {
|
|
754
|
+
let importer = init_file_importer(vec!["sample.eml"]).await;
|
|
755
|
+
importer.start_stateful_import().await.unwrap();
|
|
756
|
+
|
|
757
|
+
let remote_state = importer.essentials.load_remote_state().await.unwrap();
|
|
758
|
+
assert_eq!(remote_state.status, ImportStatus::Finished as i64);
|
|
759
|
+
assert_eq!(remote_state.failedMails, 0);
|
|
760
|
+
assert_eq!(remote_state.successfulMails, 1);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
#[cfg_attr(
|
|
764
|
+
not(feature = "test-with-local-http-server"),
|
|
765
|
+
ignore = "require local https server."
|
|
766
|
+
)]
|
|
767
|
+
#[tokio::test]
|
|
768
|
+
async fn can_import_single_eml_file_with_attachment() {
|
|
769
|
+
let importer = init_file_importer(vec!["attachment_sample.eml"]).await;
|
|
770
|
+
importer.start_stateful_import().await.unwrap();
|
|
771
|
+
|
|
772
|
+
let remote_state = importer.essentials.load_remote_state().await.unwrap();
|
|
773
|
+
assert_eq!(remote_state.status, ImportStatus::Finished as i64);
|
|
774
|
+
assert_eq!(remote_state.failedMails, 0);
|
|
775
|
+
assert_eq!(remote_state.successfulMails, 1);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
#[test]
|
|
779
|
+
fn max_request_size_in_test_is_different() {
|
|
780
|
+
assert_eq!(1024 * 5, MAX_REQUEST_SIZE);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
#[tokio::test]
|
|
784
|
+
async fn existing_import_should_be_none_if_no_state_file() {
|
|
785
|
+
let config_dir_string = "/tmp/existing_import_should_be_none_if_no_state_file";
|
|
786
|
+
let mailbox_id = "some_mailbox_id";
|
|
787
|
+
let import_dir: PathBuf = [
|
|
788
|
+
config_dir_string.to_string(),
|
|
789
|
+
"current_imports".to_string(),
|
|
790
|
+
mailbox_id.to_string(),
|
|
791
|
+
]
|
|
792
|
+
.iter()
|
|
793
|
+
.collect();
|
|
794
|
+
|
|
795
|
+
let result = Importer::get_existing_import_id(&import_dir);
|
|
796
|
+
assert!(matches!(result, Ok(None)));
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
#[cfg_attr(
|
|
800
|
+
not(feature = "test-with-local-http-server"),
|
|
801
|
+
ignore = "require local http server."
|
|
802
|
+
)]
|
|
803
|
+
#[tokio::test]
|
|
804
|
+
async fn importing_too_big_eml_should_fail() {
|
|
805
|
+
let whither = "/tmp/toobig.eml";
|
|
806
|
+
write_big_sample_email(whither);
|
|
807
|
+
|
|
808
|
+
let importer = init_file_importer(vec![whither]).await;
|
|
809
|
+
let import_res = importer.start_stateful_import().await;
|
|
810
|
+
assert!(importer
|
|
811
|
+
.essentials
|
|
812
|
+
.import_directory
|
|
813
|
+
.join(FAILED_MAILS_SUB_DIR)
|
|
814
|
+
.join("toobig-0.eml")
|
|
815
|
+
.try_exists()
|
|
816
|
+
.unwrap());
|
|
817
|
+
|
|
818
|
+
assert_eq!(
|
|
819
|
+
ImportErrorKind::SourceExhaustedSomeError,
|
|
820
|
+
import_res.unwrap_err().kind
|
|
821
|
+
);
|
|
822
|
+
|
|
823
|
+
let remote_state = importer.essentials.load_remote_state().await.unwrap();
|
|
824
|
+
assert_eq!(remote_state.status, ImportStatus::Finished as i64);
|
|
825
|
+
assert_eq!(remote_state.failedMails, 1);
|
|
826
|
+
assert_eq!(remote_state.successfulMails, 0);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
#[test]
|
|
830
|
+
fn get_resumable_state_id_invalid_content() {
|
|
831
|
+
let config_dir_string = "/tmp/get_resumable_state_id_invalid_content";
|
|
832
|
+
let mailbox_id = "some_mailbox_id";
|
|
833
|
+
let import_dir: PathBuf = [
|
|
834
|
+
config_dir_string.to_string(),
|
|
835
|
+
"current_imports".to_string(),
|
|
836
|
+
mailbox_id.to_string(),
|
|
837
|
+
]
|
|
838
|
+
.iter()
|
|
839
|
+
.collect();
|
|
840
|
+
let config_dir = PathBuf::from(config_dir_string);
|
|
841
|
+
|
|
842
|
+
let _tear_down = CleanDir {
|
|
843
|
+
dir: config_dir.clone(),
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
if !import_dir.exists() {
|
|
847
|
+
fs::create_dir_all(&import_dir).unwrap();
|
|
848
|
+
}
|
|
849
|
+
let mut state_id_file_path = import_dir.clone();
|
|
850
|
+
state_id_file_path.push(STATE_ID_FILE_NAME);
|
|
851
|
+
let invalid_id = "blah";
|
|
852
|
+
fs::write(&state_id_file_path, invalid_id).unwrap();
|
|
853
|
+
|
|
854
|
+
let result = Importer::get_existing_import_id(&import_dir)
|
|
855
|
+
.unwrap_err()
|
|
856
|
+
.kind();
|
|
857
|
+
assert_eq!(result, std::io::ErrorKind::InvalidData);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
#[cfg_attr(
|
|
861
|
+
not(feature = "test-with-local-http-server"),
|
|
862
|
+
ignore = "require local https server."
|
|
863
|
+
)]
|
|
864
|
+
#[tokio::test]
|
|
865
|
+
async fn should_stop_if_on_stop_action() {
|
|
866
|
+
let importer = init_file_importer(vec!["sample.eml"; 1]).await;
|
|
867
|
+
importer
|
|
868
|
+
.set_next_progress_action(ImportProgressAction::Stop)
|
|
869
|
+
.await;
|
|
870
|
+
importer.start_stateful_import().await.unwrap();
|
|
871
|
+
|
|
872
|
+
let mut iterator = importer.chunked_import_source.lock().await;
|
|
873
|
+
|
|
874
|
+
// if we set progress action to stop, it should not have consumed any iterator
|
|
875
|
+
assert!(iterator.next().is_some());
|
|
876
|
+
assert!(iterator.next().is_none());
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
#[cfg_attr(
|
|
880
|
+
not(feature = "test-with-local-http-server"),
|
|
881
|
+
ignore = "require local http server."
|
|
882
|
+
)]
|
|
883
|
+
#[tokio::test]
|
|
884
|
+
async fn should_pause_if_on_pause_action() {
|
|
885
|
+
let importer = init_file_importer(vec!["sample.eml"; 2]).await;
|
|
886
|
+
importer
|
|
887
|
+
.set_next_progress_action(ImportProgressAction::Pause)
|
|
888
|
+
.await;
|
|
889
|
+
importer.start_stateful_import().await.unwrap();
|
|
890
|
+
|
|
891
|
+
let mut iterator = importer.chunked_import_source.lock().await;
|
|
892
|
+
|
|
893
|
+
// if we set progress action to pause, it should not have consumed any iterator
|
|
894
|
+
assert!(iterator.next().is_some());
|
|
895
|
+
assert!(iterator.next().is_some());
|
|
896
|
+
assert!(iterator.next().is_none());
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
#[cfg_attr(
|
|
900
|
+
not(feature = "test-with-local-http-server"),
|
|
901
|
+
ignore = "require local http server."
|
|
902
|
+
)]
|
|
903
|
+
#[tokio::test]
|
|
904
|
+
async fn should_continue_if_on_continue_action() {
|
|
905
|
+
let importer = init_file_importer(vec!["sample.eml"; 1]).await;
|
|
906
|
+
importer
|
|
907
|
+
.set_next_progress_action(ImportProgressAction::Continue)
|
|
908
|
+
.await;
|
|
909
|
+
importer.start_stateful_import().await.unwrap();
|
|
910
|
+
|
|
911
|
+
let mut iterator = importer.chunked_import_source.lock().await;
|
|
912
|
+
|
|
913
|
+
// if we set progress action to continue, it should have consumed all the chunks
|
|
914
|
+
assert!(iterator.next().is_none());
|
|
915
|
+
}
|
|
916
|
+
}
|