Browse Source

compression working + reference

Thomas 1 năm trước cách đây
mục cha
commit
e7fd5d0f20
3 tập tin đã thay đổi với 293 bổ sung12 xóa
  1. 205 0
      Cargo.lock
  2. 4 0
      Cargo.toml
  3. 84 12
      src/lib.rs

+ 205 - 0
Cargo.lock

@@ -8,6 +8,36 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "adler32"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "allocator-api2"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
 [[package]]
 name = "base64"
 version = "0.22.1"
@@ -20,6 +50,15 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "core2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "crc32fast"
 version = "1.4.2"
@@ -29,6 +68,12 @@ dependencies = [
  "cfg-if",
 ]
 
+[[package]]
+name = "dary_heap"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca"
+
 [[package]]
 name = "flate2"
 version = "1.0.30"
@@ -39,6 +84,52 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "libflate"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45d9dfdc14ea4ef0900c1cddbc8dcd553fbaacd8a4a282cf4018ae9dd04fb21e"
+dependencies = [
+ "adler32",
+ "core2",
+ "crc32fast",
+ "dary_heap",
+ "libflate_lz77",
+]
+
+[[package]]
+name = "libflate_lz77"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e0d73b369f386f1c44abd9c570d5318f55ccde816ff4b562fa452e5182863d"
+dependencies = [
+ "core2",
+ "hashbrown",
+ "rle-decode-fast",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
 [[package]]
 name = "miniz_oxide"
 version = "0.7.4"
@@ -48,10 +139,124 @@ dependencies = [
  "adler",
 ]
 
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
 [[package]]
 name = "pandora_lib_igv"
 version = "0.1.0"
 dependencies = [
+ "anyhow",
  "base64",
  "flate2",
+ "libflate",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rle-decode-fast"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "serde"
+version = "1.0.204"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.204"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
 ]

+ 4 - 0
Cargo.toml

@@ -4,5 +4,9 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
+anyhow = "1.0.86"
 base64 = "0.22.1"
 flate2 = "1.0.30"
+libflate = "2.1.0"
+serde = { version = "^1.0.188", features = ["derive"] }
+serde_json = "1.0.120"

+ 84 - 12
src/lib.rs

@@ -1,21 +1,92 @@
-use base64::engine::general_purpose::URL_SAFE_NO_PAD;
+use anyhow::Context;
+use base64::engine::general_purpose::STANDARD;
 use base64::Engine;
 use flate2::write::DeflateEncoder;
 use flate2::Compression;
+
+use serde::Serialize;
+use serde_json::{json, Value};
 use std::io::prelude::*;
 
-/// Compress string and encode in a URL safe form
-pub fn compress_string(s: &str) -> String {
+/// Compress string according to compressString from: https://github.com/igvteam/igv-utils/blob/master/src/bgzf.js#L125
+fn compress_string(input: &str) -> anyhow::Result<String> {
     // Convert string to bytes
-    let bytes = s.as_bytes();
+    let bytes = input.as_bytes();
 
-    // Compress the bytes using deflate
+    // Compress bytes
     let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
-    encoder.write_all(bytes).expect("Failed to write bytes");
-    let compressed_bytes = encoder.finish().expect("Failed to compress bytes");
+    encoder
+        .write_all(bytes)
+        .context("Failed to write data to encoder")?;
+    let compressed_bytes = encoder.finish().context("Failed to finish encoding")?;
+
+    // Base64 encode
+    let encoded = STANDARD.encode(compressed_bytes);
+
+    // URL-safe replacements
+    Ok(encoded
+        .replace('+', ".")
+        .replace('/', "_")
+        .replace('=', "-"))
+}
+
+#[derive(Debug, Serialize)]
+pub struct ReferenceValues {
+    pub id: String,
+    pub name: String,
+    #[serde(rename = "fastaURL")]
+    pub fasta_url: String,
+    #[serde(rename = "indexURL")]
+    pub index_url: String,
+    #[serde(rename = "cytobandURL")]
+    pub cytoband_url: String,
+    #[serde(rename = "aliasURL")]
+    pub alias_url: String,
+}
+
+impl Default for ReferenceValues {
+    fn default() -> Self {
+        Self {
+            id: "chm13v2.0".to_string(),
+            name: "Human (T2T/hs1 CHM13-v2.0)".to_string(),
+            fasta_url: "/data/ref/hs1/chm13v2.0.fa".to_string(),
+            index_url: "/data/ref/hs1/chm13v2.0.fa.fai".to_string(),
+            cytoband_url: "/data/ref/hs1/chm13v2.0_cytobands_allchrs.bed".to_string(),
+            alias_url: "/data/ref/hs1/GCA_009914755.4.chromAlias.txt".to_string(),
+        }
+    }
+}
 
-    // Encode the compressed bytes to base64
-    URL_SAFE_NO_PAD.encode(compressed_bytes)
+#[derive(Debug)]
+pub struct Session {
+    value: Value,
+}
+
+impl Default for Session {
+    fn default() -> Self {
+        let value = json!({
+            "version": "2.16.0",
+            "showSampleNames": false,
+            "reference": {},
+            "locus": [],
+            "tracks": [],
+        });
+
+        Self { value }
+    }
+}
+
+impl Session {
+    pub fn with_reference(mut self, reference_values: ReferenceValues) -> Self {
+        if let Some(reference) = self.value.get_mut("reference") {
+            *reference = json!(reference_values);
+        }
+        self
+    }
+    pub fn link(&self, base_url: &str) -> anyhow::Result<String> {
+        let blob = compress_string(&self.value.to_string())?;
+        Ok(format!("{base_url}?sessionURL=blob:{blob}"))
+    }
 }
 
 #[cfg(test)]
@@ -23,9 +94,10 @@ mod tests {
     use super::*;
 
     #[test]
-    fn it_works() {
-        let input_str = "your_string_here";
-        let compressed_str = compress_string(input_str);
+    fn it_works() -> anyhow::Result<()> {
+        let sess = Session::default().with_reference(ReferenceValues::default());
+        let compressed_str = sess.link("http://store-desktop.local/igv/")?;
         println!("Compressed and URL-safe encoded string: {}", compressed_str);
+        Ok(())
     }
 }