Skip to content

Commit 19a5297

Browse files
gamcilmilot-mirdita
authored andcommitted
add support for gzipped input files
1 parent 41a3135 commit 19a5297

7 files changed

Lines changed: 101 additions & 59 deletions

File tree

backend/foldmasonmsa.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ func (r FoldMasonMSAJob) WritePDB(path string) error {
3535
os.Mkdir(pdbDir, os.ModePerm)
3636
for idx, query := range r.Queries {
3737
name := cleanPathComponent.ReplaceAllString(r.FileNames[idx], "")
38-
ext := filepath.Ext(r.FileNames[idx])
38+
if strings.EqualFold(filepath.Ext(name), ".gz") {
39+
name = strings.TrimSuffix(name, filepath.Ext(name))
40+
}
41+
ext := filepath.Ext(name)
3942
if ext == ".cif" || ext == ".mmcif" {
4043
name = strings.TrimSuffix(name, ext) + ".cif"
4144
}

backend/server.go

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"bufio"
55
"bytes"
6+
"compress/gzip"
67
"encoding/json"
78
"io"
89
"log"
@@ -23,6 +24,34 @@ import (
2324
"github.com/rs/cors"
2425
)
2526

27+
func readUploadedText(r io.Reader) (string, error) {
28+
data, err := io.ReadAll(r)
29+
if err != nil {
30+
return "", err
31+
}
32+
33+
if !isGzipPayload(data) {
34+
return string(data), nil
35+
}
36+
37+
gr, err := gzip.NewReader(bytes.NewReader(data))
38+
if err != nil {
39+
return "", err
40+
}
41+
defer gr.Close()
42+
43+
decoded, err := io.ReadAll(gr)
44+
if err != nil {
45+
return "", err
46+
}
47+
48+
return string(decoded), nil
49+
}
50+
51+
func isGzipPayload(data []byte) bool {
52+
return len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b
53+
}
54+
2655
type DatabaseResponse struct {
2756
Databases []Params `json:"databases"`
2857
}
@@ -148,10 +177,13 @@ func server(jobsystem JobSystem, config ConfigRoot) {
148177
http.Error(w, err.Error(), http.StatusBadRequest)
149178
return
150179
}
180+
defer f.Close()
151181

152-
buf := new(bytes.Buffer)
153-
buf.ReadFrom(f)
154-
data = buf.String()
182+
data, err = readUploadedText(f)
183+
if err != nil {
184+
http.Error(w, err.Error(), http.StatusBadRequest)
185+
return
186+
}
155187
} else {
156188
err := req.ParseForm()
157189
if err != nil {
@@ -292,10 +324,13 @@ func server(jobsystem JobSystem, config ConfigRoot) {
292324
http.Error(w, err.Error(), http.StatusBadRequest)
293325
return
294326
}
327+
defer f.Close()
295328

296-
buf := new(bytes.Buffer)
297-
buf.ReadFrom(f)
298-
query = buf.String()
329+
query, err = readUploadedText(f)
330+
if err != nil {
331+
http.Error(w, err.Error(), http.StatusBadRequest)
332+
return
333+
}
299334
dbs = req.Form["database[]"]
300335
mode = req.FormValue("mode")
301336
email = req.FormValue("email")
@@ -378,10 +413,13 @@ func server(jobsystem JobSystem, config ConfigRoot) {
378413
http.Error(w, err.Error(), http.StatusBadRequest)
379414
return
380415
}
416+
defer f.Close()
381417

382-
buf := new(bytes.Buffer)
383-
buf.ReadFrom(f)
384-
query = buf.String()
418+
query, err = readUploadedText(f)
419+
if err != nil {
420+
http.Error(w, err.Error(), http.StatusBadRequest)
421+
return
422+
}
385423
dbs = req.Form["database[]"]
386424
mode = req.FormValue("mode")
387425
email = req.FormValue("email")
@@ -440,10 +478,13 @@ func server(jobsystem JobSystem, config ConfigRoot) {
440478
http.Error(w, err.Error(), http.StatusBadRequest)
441479
return
442480
}
481+
defer f.Close()
443482

444-
buf := new(bytes.Buffer)
445-
buf.ReadFrom(f)
446-
query = buf.String()
483+
query, err = readUploadedText(f)
484+
if err != nil {
485+
http.Error(w, err.Error(), http.StatusBadRequest)
486+
return
487+
}
447488
mode = req.FormValue("mode")
448489
email = req.FormValue("email")
449490
} else {
@@ -502,14 +543,11 @@ func server(jobsystem JobSystem, config ConfigRoot) {
502543
}
503544
defer file.Close()
504545

505-
buf := new(bytes.Buffer)
506-
_, err = io.Copy(buf, file)
546+
query, err := readUploadedText(file)
507547
if err != nil {
508-
http.Error(w, err.Error(), http.StatusInternalServerError)
548+
http.Error(w, err.Error(), http.StatusBadRequest)
509549
return
510550
}
511-
512-
query := buf.String()
513551
queries = append(queries, query)
514552
}
515553
} else {
@@ -561,10 +599,13 @@ func server(jobsystem JobSystem, config ConfigRoot) {
561599
http.Error(w, err.Error(), http.StatusBadRequest)
562600
return
563601
}
602+
defer f.Close()
564603

565-
buf := new(bytes.Buffer)
566-
buf.ReadFrom(f)
567-
query = buf.String()
604+
query, err = readUploadedText(f)
605+
if err != nil {
606+
http.Error(w, err.Error(), http.StatusBadRequest)
607+
return
608+
}
568609
dbs = req.Form["database[]"]
569610
//mode = req.FormValue("mode")
570611
email = req.FormValue("email")

frontend/FoldDiscoSearch.vue

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ import Panel from "./Panel.vue";
174174
import FileButton from "./FileButton.vue";
175175
import LoadAcessionButton from './LoadAcessionButton.vue';
176176
import Reference from "./Reference.vue";
177+
import { readUploadedText } from './Utilities.js';
177178
import { AxiosCompressRequest } from './lib/AxiosCompressRequest.js';
178179
import { convertToQueryUrl } from './lib/convertToQueryUrl';
179180
import TaxonomyAutocomplete from './TaxonomyAutocomplete.vue';
@@ -413,12 +414,13 @@ export default {
413414
this.inSearch = false;
414415
}
415416
},
416-
upload(files) {
417-
var reader = new FileReader();
418-
reader.onload = async e => {
419-
this.query = e.target.result;
420-
};
421-
reader.readAsText(files[0]);
417+
async upload(files) {
418+
try {
419+
this.query = await readUploadedText(files[0]);
420+
} catch (error) {
421+
this.errorMessage = "Error reading uploaded file";
422+
throw error;
423+
}
422424
},
423425
async goToFoldseek() {
424426
await db.setItem('query', this.query);

frontend/FoldMasonSearch.vue

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export default {
227227
const params = new FormData();
228228
this.queries.forEach((v) => {
229229
params.append('fileNames[]', v.name);
230-
params.append('queries[]', new Blob([v.text], { type: 'text/plain' }), v.name);
230+
params.append('queries[]', v.file || new Blob([v.text], { type: 'text/plain' }), v.name);
231231
});
232232
233233
try {
@@ -285,21 +285,7 @@ export default {
285285
* @param {*} files - FileList from upload event
286286
*/
287287
async upload(files) {
288-
const readFile = async (file) => {
289-
return new Promise((resolve, reject) => {
290-
const reader = new FileReader();
291-
reader.onload = e => resolve({ name: file.name, text: e.target.result });
292-
reader.onerror = err => reject(err);
293-
reader.readAsText(file);
294-
});
295-
}
296-
try {
297-
const fileReadPromises = Array.from(files).map(readFile);
298-
const fileContents = await Promise.all(fileReadPromises);
299-
this.addFiles(fileContents);
300-
} catch(error) {
301-
console.log("Error reading files", error);
302-
}
288+
this.addFiles(Array.from(files).map(file => ({ name: file.name, file })));
303289
},
304290
uploadJSON(files) {
305291
let file = files[0];

frontend/MultimerSearch.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,13 @@ import LoadAcessionButton from './LoadAcessionButton.vue';
138138
import Reference from "./Reference.vue";
139139
import { convertToQueryUrl } from './lib/convertToQueryUrl';
140140
import TaxonomyAutocomplete from './TaxonomyAutocomplete.vue';
141-
import { djb2, parseResultsList, checkMultimer } from './Utilities.js';
141+
import { djb2, parseResultsList, checkMultimer, readUploadedText } from './Utilities.js';
142142
import { AxiosCompressRequest } from './lib/AxiosCompressRequest.js';
143143
import ApiDialog from './ApiDialog.vue';
144144
import { StorageWrapper, HistoryMixin } from './lib/HistoryMixin.js';
145145
import { BlobDatabase } from './lib/BlobDatabase.js';
146146
import Databases from './Databases.vue';
147147
import QueryTextarea from "./QueryTextarea.vue";
148-
149148
const db = BlobDatabase();
150149
const storage = new StorageWrapper("complex");
151150
@@ -286,12 +285,13 @@ export default {
286285
this.inSearch = false;
287286
}
288287
},
289-
upload(files) {
290-
var reader = new FileReader();
291-
reader.onload = e => {
292-
this.query = e.target.result;
293-
};
294-
reader.readAsText(files[0]);
288+
async upload(files) {
289+
try {
290+
this.query = await readUploadedText(files[0]);
291+
} catch (error) {
292+
this.errorMessage = "Error reading uploaded file";
293+
throw error;
294+
}
295295
},
296296
uploadJSON(files) {
297297
let file = files[0];

frontend/Search.vue

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,13 @@ import LoadAcessionButton from './LoadAcessionButton.vue';
155155
import Reference from "./Reference.vue";
156156
import { convertToQueryUrl } from './lib/convertToQueryUrl';
157157
import TaxonomyAutocomplete from './TaxonomyAutocomplete.vue';
158-
import { djb2, parseResultsList, checkMultimer } from './Utilities.js';
158+
import { djb2, parseResultsList, checkMultimer, readUploadedText } from './Utilities.js';
159159
import { AxiosCompressRequest } from './lib/AxiosCompressRequest.js';
160160
import ApiDialog from './ApiDialog.vue';
161161
import { storage, HistoryMixin } from './lib/HistoryMixin.js';
162162
import { BlobDatabase } from './lib/BlobDatabase.js';
163163
import Databases from './Databases.vue';
164164
import QueryTextarea from "./QueryTextarea.vue";
165-
166165
const db = BlobDatabase();
167166
168167
export default {
@@ -325,12 +324,13 @@ export default {
325324
this.inSearch = false;
326325
}
327326
},
328-
upload(files) {
329-
var reader = new FileReader();
330-
reader.onload = e => {
331-
this.query = e.target.result;
332-
};
333-
reader.readAsText(files[0]);
327+
async upload(files) {
328+
try {
329+
this.query = await readUploadedText(files[0]);
330+
} catch (error) {
331+
this.errorMessage = "Error reading uploaded file";
332+
throw error;
333+
}
334334
},
335335
uploadJSON(files) {
336336
let file = files[0];

frontend/Utilities.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Selection, Matrix4, PdbWriter } from "ngl";
2+
import { ungzip } from "pako";
23

34
function tryLinkTargetToDB(target, db) {
45
try {
@@ -174,6 +175,15 @@ export function tryFixName(name) {
174175
return name.replaceAll(/\.(cif|pdb|gz)/g, "");
175176
}
176177

178+
export async function readUploadedText(file) {
179+
const bytes = new Uint8Array(await file.arrayBuffer());
180+
const data =
181+
bytes.length >= 2 && bytes[0] === 0x1f && bytes[1] === 0x8b
182+
? ungzip(bytes)
183+
: bytes;
184+
return new TextDecoder().decode(data);
185+
}
186+
177187
export function parseResults(data) {
178188
let empty = 0;
179189
let total = 0;

0 commit comments

Comments
 (0)