@sjcrh/proteinpaint-rust 2.99.0 → 2.108.3-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.
Files changed (3) hide show
  1. package/index.js +26 -7
  2. package/package.json +2 -2
  3. package/src/gdcmaf.rs +114 -30
package/index.js CHANGED
@@ -43,16 +43,22 @@ exports.run_rust = function (binfile, input_data) {
43
43
  })
44
44
  }
45
45
 
46
- exports.run_rust_stream = function (binfile, input_data) {
46
+ exports.stream_rust = function (binfile, input_data, emitJson) {
47
47
  const binpath = path.join(__dirname, '/target/release/', binfile)
48
48
  const ps = spawn(binpath)
49
+ const stderr = []
49
50
  try {
51
+ // from GDC API -> ps.stdin -> ps.stdout -> transformed stream
50
52
  Readable.from(input_data).pipe(ps.stdin)
53
+ //reader.on('data', ps.stdout.pipe)
54
+ //reader.on('error', ps.stderr.pipe)
55
+ //return reader
51
56
  } catch (error) {
52
57
  ps.kill()
53
58
  let errmsg = error
54
- if (stderr.length) errmsg += `killed run_rust('${binfile}'), stderr: ${stderr.join('').trim()}`
55
- reject(errmsg)
59
+ //if (stderr.length) errmsg += `killed run_rust('${binfile}'), stderr: ${stderr.join('').trim()}`
60
+ //reject(errmsg)
61
+ console.log(59, error)
56
62
  }
57
63
 
58
64
  const childStream = new Transform({
@@ -62,11 +68,24 @@ exports.run_rust_stream = function (binfile, input_data) {
62
68
  }
63
69
  })
64
70
  ps.stdout.pipe(childStream)
65
- childStream.on('error', err => {
66
- reject(err)
71
+ ps.stderr.on('data', data => stderr.push(data))
72
+ ps.on('close', code => { //console.log(72, stderr.length)
73
+ if (stderr.length) {
74
+ // handle rust stderr
75
+ const errors = stderr.join('').trim().split('\n').map(JSON.parse)
76
+ //const errmsg = `!!! stream_rust('${binfile}') stderr: !!!`
77
+ //console.log(errmsg, errors)
78
+ emitJson({errors})
79
+ } else {
80
+ emitJson({ ok: true, status: 'ok', message: 'Processing complete' })
81
+ }
67
82
  })
68
- childStream.on('close', code => {
69
- childStream.end()
83
+ ps.on('error', err => {
84
+ //console.log(74, `stream_rust().on('error')`, err)
85
+ const errors = stderr.join('').trim().split('\n').map(JSON.parse)
86
+ emitJson({errors})
70
87
  })
88
+ // below will duplicate ps.on('close') event above
89
+ // childStream.on('end', () => console.log(`-- childStream done --`))
71
90
  return childStream
72
91
  }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.99.0",
2
+ "version": "2.108.3-0",
3
3
  "name": "@sjcrh/proteinpaint-rust",
4
4
  "description": "Rust-based utilities for proteinpaint",
5
5
  "main": "index.js",
@@ -38,5 +38,5 @@
38
38
  "devDependencies": {
39
39
  "tape": "^5.2.2"
40
40
  },
41
- "pp_release_tag": "v2.99.0"
41
+ "pp_release_tag": "v2.108.3-0"
42
42
  }
package/src/gdcmaf.rs CHANGED
@@ -19,21 +19,32 @@ use futures::StreamExt;
19
19
  use std::io::{self,Read,Write};
20
20
 
21
21
 
22
+ // Struct to hold error information
23
+ #[derive(serde::Serialize)]
24
+ struct ErrorEntry {
25
+ url: String,
26
+ error: String,
27
+ }
22
28
 
23
- fn select_maf_col(d:String,columns:&Vec<String>) -> Vec<u8> {
29
+ fn select_maf_col(d:String,columns:&Vec<String>,url:&str) -> Result<(Vec<u8>,i32), (String, String)> {
24
30
  let mut maf_str: String = String::new();
25
31
  let mut header_indices: Vec<usize> = Vec::new();
26
32
  let lines = d.trim_end().split("\n");
33
+ let mut mafrows = 0;
27
34
  for line in lines {
28
35
  if line.starts_with("#") {
29
36
  continue
30
37
  } else if line.contains("Hugo_Symbol") {
31
38
  let header: Vec<String> = line.split("\t").map(|s| s.to_string()).collect();
32
39
  for col in columns {
33
- if let Some(index) = header.iter().position(|x| x == col) {
34
- header_indices.push(index);
35
- } else {
36
- panic!("{} was not found!",col);
40
+ match header.iter().position(|x| x == col) {
41
+ Some(index) => {
42
+ header_indices.push(index);
43
+ }
44
+ None => {
45
+ let error_msg = format!("Column {} was not found", col);
46
+ return Err((url.to_string(), error_msg));
47
+ }
37
48
  }
38
49
  }
39
50
  } else {
@@ -44,12 +55,14 @@ fn select_maf_col(d:String,columns:&Vec<String>) -> Vec<u8> {
44
55
  };
45
56
  maf_str.push_str(maf_out_lst.join("\t").as_str());
46
57
  maf_str.push_str("\n");
58
+ mafrows += 1;
47
59
  }
48
60
  };
49
- maf_str.as_bytes().to_vec()
61
+ Ok((maf_str.as_bytes().to_vec(),mafrows))
50
62
  }
51
63
 
52
64
 
65
+
53
66
  #[tokio::main]
54
67
  async fn main() -> Result<(),Box<dyn std::error::Error>> {
55
68
  // Accepting the piped input json from jodejs and assign to the variable
@@ -57,6 +70,8 @@ async fn main() -> Result<(),Box<dyn std::error::Error>> {
57
70
  // url: urls to download single maf files
58
71
  let mut buffer = String::new();
59
72
  io::stdin().read_line(&mut buffer)?;
73
+
74
+ // reading the input from PP
60
75
  let file_id_lst_js = serde_json::from_str::<Value>(&buffer).expect("Error reading input and serializing to JSON");
61
76
  let host = file_id_lst_js.get("host").expect("Host was not provided").as_str().expect("Host is not a string");
62
77
  let mut url: Vec<String> = Vec::new();
@@ -75,49 +90,118 @@ async fn main() -> Result<(),Box<dyn std::error::Error>> {
75
90
  .map(|v| v.to_string().replace("\"",""))
76
91
  .collect::<Vec<String>>();
77
92
  } else {
78
- panic!("Columns is not an array");
93
+ let column_error = ErrorEntry {
94
+ url: String::new(),
95
+ error: "The columns in arg is not an array".to_string(),
96
+ };
97
+ let column_error_js = serde_json::to_string(&column_error).unwrap();
98
+ writeln!(io::stderr(), "{}", column_error_js).expect("Failed to output stderr!");
99
+ return Err(Box::new(std::io::Error::new(
100
+ std::io::ErrorKind::InvalidInput,
101
+ "The columns in arg is not an array",
102
+ )) as Box<dyn std::error::Error>);
79
103
  }
80
104
  } else {
81
- panic!("Columns was not selected");
105
+ let column_error = ErrorEntry {
106
+ url: String::new(),
107
+ error: "Columns was not selected".to_string(),
108
+ };
109
+ let column_error_js = serde_json::to_string(&column_error).unwrap();
110
+ writeln!(io::stderr(), "{}", column_error_js).expect("Failed to output stderr!");
111
+ return Err(Box::new(std::io::Error::new(
112
+ std::io::ErrorKind::InvalidInput,
113
+ "Columns was not selected",
114
+ )) as Box<dyn std::error::Error>);
82
115
  };
83
116
 
84
117
  //downloading maf files parallelly and merge them into single maf file
85
118
  let download_futures = futures::stream::iter(
86
119
  url.into_iter().map(|url|{
87
120
  async move {
88
- let result = reqwest::get(&url).await;
89
- if let Ok(resp) = result {
90
- let content = resp.bytes().await.unwrap();
91
- let mut decoder = GzDecoder::new(&content[..]);
92
- let mut decompressed_content = Vec::new();
93
- let read_content = decoder.read_to_end(&mut decompressed_content);
94
- if let Ok(_) = read_content {
95
- let text = String::from_utf8_lossy(&decompressed_content).to_string();
96
- text
97
- } else {
98
- let error_msg = "Failed to read content downloaded from: ".to_string() + &url;
99
- error_msg
121
+ match reqwest::get(&url).await {
122
+ Ok(resp) if resp.status().is_success() => {
123
+ match resp.bytes().await {
124
+ Ok(content) => {
125
+ let mut decoder = GzDecoder::new(&content[..]);
126
+ let mut decompressed_content = Vec::new();
127
+ match decoder.read_to_end(&mut decompressed_content) {
128
+ Ok(_) => {
129
+ let text = String::from_utf8_lossy(&decompressed_content).to_string();
130
+ return Ok((url.clone(),text))
131
+ }
132
+ Err(e) => {
133
+ let error_msg = format!("Failed to decompress downloaded maf file: {}", e);
134
+ Err((url.clone(), error_msg))
135
+ }
136
+ }
137
+ }
138
+ Err(e) => {
139
+ let error_msg = format!("Failed to decompress downloaded maf file: {}", e);
140
+ Err((url.clone(), error_msg))
141
+ }
142
+ }
143
+ }
144
+ Ok(resp) => {
145
+ let error_msg = format!("HTTP error: {}", resp.status());
146
+ Err((url.clone(), error_msg))
147
+ }
148
+ Err(e) => {
149
+ let error_msg = format!("Server request failed: {}", e);
150
+ Err((url.clone(), error_msg))
100
151
  }
101
- } else {
102
- let error_msg = "Failed to download: ".to_string() + &url;
103
- error_msg
104
152
  }
105
153
  }
106
154
  })
107
155
  );
108
156
 
109
- // output
157
+ // binary output
110
158
  let mut encoder = GzEncoder::new(io::stdout(), Compression::default());
111
159
  let _ = encoder.write_all(&maf_col.join("\t").as_bytes().to_vec()).expect("Failed to write header");
112
160
  let _ = encoder.write_all(b"\n").expect("Failed to write newline");
113
- download_futures.buffer_unordered(20).for_each(|item| {
114
- if item.starts_with("Failed") {
115
- eprintln!("{}",item);
116
- } else {
117
- let maf_bit = select_maf_col(item,&maf_col);
118
- let _ = encoder.write_all(&maf_bit).expect("Failed to write file");
161
+
162
+ download_futures.buffer_unordered(20).for_each(|result| {
163
+ match result {
164
+ Ok((url, content)) => {
165
+ match select_maf_col(content, &maf_col, &url) {
166
+ Ok((maf_bit,mafrows)) => {
167
+ if mafrows > 0 {
168
+ encoder.write_all(&maf_bit).expect("Failed to write file");
169
+ } else {
170
+ let error = ErrorEntry {
171
+ url: url.clone(),
172
+ error: "Empty maf file".to_string(),
173
+ };
174
+ let error_js = serde_json::to_string(&error).unwrap();
175
+ writeln!(io::stderr(), "{}", error_js).expect("Failed to output stderr!");
176
+ }
177
+ }
178
+ Err((url,error)) => {
179
+ let error = ErrorEntry {
180
+ url,
181
+ error,
182
+ };
183
+ let error_js = serde_json::to_string(&error).unwrap();
184
+ writeln!(io::stderr(), "{}", error_js).expect("Failed to output stderr!");
185
+ }
186
+ }
187
+ }
188
+ Err((url, error)) => {
189
+ let error = ErrorEntry {
190
+ url,
191
+ error,
192
+ };
193
+ let error_js = serde_json::to_string(&error).unwrap();
194
+ writeln!(io::stderr(), "{}", error_js).expect("Failed to output stderr!");
195
+ }
119
196
  };
120
197
  async {}
121
198
  }).await;
199
+
200
+ // Finalize output and printing errors
201
+ encoder.finish().expect("Maf file output error!");
202
+ // Manually flush stdout and stderr
203
+ io::stdout().flush().expect("Failed to flush stdout");
204
+ io::stderr().flush().expect("Failed to flush stderr");
205
+
122
206
  Ok(())
123
207
  }