@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.
- package/index.js +26 -7
- package/package.json +2 -2
- 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.
|
|
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
|
-
|
|
66
|
-
|
|
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
|
-
|
|
69
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
}
|