@sjcrh/proteinpaint-server 2.71.0 → 2.72.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjcrh/proteinpaint-server",
3
- "version": "2.71.0",
3
+ "version": "2.72.0",
4
4
  "type": "module",
5
5
  "description": "a genomics visualization tool for exploring a cohort's genotype and phenotype data",
6
6
  "main": "src/app.js",
@@ -44,6 +44,7 @@
44
44
  "@babel/preset-typescript": "^7.21.4",
45
45
  "@babel/register": "^7.14.5",
46
46
  "@types/node": "^20.11.24",
47
+ "@types/tough-cookie": "^4.0.5",
47
48
  "@typescript-eslint/eslint-plugin": "^5.60.0",
48
49
  "babel-loader": "^8.2.2",
49
50
  "esbuild": "^0.19.12",
@@ -82,6 +83,7 @@
82
83
  "node-fetch": "^2.6.1",
83
84
  "partjson": "^0.58.2",
84
85
  "tiny-async-pool": "^1.2.0",
86
+ "tough-cookie": "^4.1.4",
85
87
  "typedoc-plugin-missing-exports": "^2.0.1"
86
88
  },
87
89
  "repository": {
@@ -0,0 +1,50 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import serverconfig from "#src/serverconfig.js";
4
+ const api = {
5
+ endpoint: "samplewsimages",
6
+ methods: {
7
+ get: {
8
+ init,
9
+ request: {
10
+ typeId: "GetSampleWSImagesRequest"
11
+ },
12
+ response: {
13
+ typeId: "GetSampleWSImagesResponse"
14
+ }
15
+ },
16
+ post: {
17
+ alternativeFor: "get",
18
+ init
19
+ }
20
+ }
21
+ };
22
+ function init({ genomes }) {
23
+ return async (req, res) => {
24
+ try {
25
+ const g = genomes[req.query.genome];
26
+ if (!g)
27
+ throw "invalid genome name";
28
+ const ds = g.datasets[req.query.dslabel];
29
+ if (!ds)
30
+ throw "invalid dataset name";
31
+ const sampleId = req.query.sample_id;
32
+ const sampleWSImagesPath = path.join(
33
+ `${serverconfig.tpmasterdir}/${ds.queries.WSImages.imageBySampleFolder}`,
34
+ sampleId
35
+ );
36
+ const sampleWSImages = await getWSImages(sampleWSImagesPath);
37
+ res.send({ sampleWSImages });
38
+ } catch (e) {
39
+ console.log(e);
40
+ res.status(404).send("Sample images not found");
41
+ }
42
+ };
43
+ }
44
+ async function getWSImages(sampleImagesPath) {
45
+ const files = await fs.promises.readdir(sampleImagesPath);
46
+ return files.filter((file) => [".svs", ".mrxs", ".scn", ".ndpi", ".tiff"].includes(path.extname(file)));
47
+ }
48
+ export {
49
+ api
50
+ };
@@ -177,11 +177,16 @@ function addNonDictionaryQueries(c, ds, genome) {
177
177
  q2.NIdata[k] = JSON.parse(JSON.stringify(q.NIdata[k]));
178
178
  }
179
179
  }
180
- if (q.DZImages) {
180
+ if (q.DZImages && serverconfig.features.showDZImages) {
181
181
  q2.DZImages = {
182
182
  type: q.DZImages.type
183
183
  };
184
184
  }
185
+ if (q.WSImages && serverconfig.features.showWSImages) {
186
+ q2.WSImages = {
187
+ type: q.WSImages.type
188
+ };
189
+ }
185
190
  if (q.singleSampleGbtk) {
186
191
  q2.singleSampleGbtk = {};
187
192
  for (const k in q.singleSampleGbtk) {
@@ -1,9 +1,9 @@
1
1
  import path from "path";
2
2
  import { run_rust } from "@sjcrh/proteinpaint-rust";
3
- import got from "got";
4
3
  import serverconfig from "#src/serverconfig.js";
5
4
  import { get_samples } from "#src/termdb.sql.js";
6
5
  import { makeFilter } from "#src/mds3.gdc.js";
6
+ import { cachedFetch } from "#src/utils.js";
7
7
  const api = {
8
8
  endpoint: "termdb/topVariablyExpressedGenes",
9
9
  methods: {
@@ -120,11 +120,12 @@ function gdcValidateQuery(ds, genome) {
120
120
  const { host, headers } = ds.getHostHeaders(q);
121
121
  const url = path.join(host.geneExp, "/gene_expression/gene_selection");
122
122
  try {
123
- const response = await got.post(url, {
123
+ const response = await cachedFetch(url, {
124
+ method: "POST",
124
125
  headers,
125
- body: JSON.stringify(getGeneSelectionArg(q))
126
+ body: getGeneSelectionArg(q)
126
127
  });
127
- const re = JSON.parse(response.body);
128
+ const re = response.body;
128
129
  const genes = [];
129
130
  if (!Array.isArray(re.gene_selection))
130
131
  throw "re.gene_selection[] is not array";
@@ -0,0 +1,42 @@
1
+ import ky from "ky";
2
+ import serverconfig from "#src/serverconfig.js";
3
+ const routePath = "tileserver";
4
+ const api = {
5
+ endpoint: `${routePath}/layer/slide/:sampleId/zoomify/:TileGroup/:z-:x-:y@1x.jpg`,
6
+ methods: {
7
+ get: {
8
+ init,
9
+ request: {
10
+ typeId: "any"
11
+ },
12
+ response: {
13
+ typeId: "any"
14
+ }
15
+ },
16
+ post: {
17
+ alternativeFor: "get",
18
+ init
19
+ }
20
+ }
21
+ };
22
+ function init() {
23
+ return async (req, res) => {
24
+ try {
25
+ const { sampleId, TileGroup, z, x, y } = req.params;
26
+ const url = `${serverconfig.tileServerURL}/tileserver/layer/slide/${sampleId}/zoomify/${TileGroup}/${z}-${x}-${y}@1x.jpg`;
27
+ const response = await ky.get(url);
28
+ const buffer = await response.arrayBuffer();
29
+ res.status(response.status).send(Buffer.from(buffer));
30
+ } catch (error) {
31
+ if (error.response) {
32
+ const errorBody = await error.response.arrayBuffer();
33
+ res.status(error.response.status).send(Buffer.from(errorBody));
34
+ } else {
35
+ res.status(500).send("Internal Server Error");
36
+ }
37
+ }
38
+ };
39
+ }
40
+ export {
41
+ api
42
+ };
@@ -0,0 +1,115 @@
1
+ import ky from "ky";
2
+ import qs from "qs";
3
+ import path from "path";
4
+ import serverconfig from "#src/serverconfig.js";
5
+ import { CookieJar } from "tough-cookie";
6
+ import { promisify } from "util";
7
+ const routePath = "wsimages";
8
+ const api = {
9
+ endpoint: `${routePath}`,
10
+ methods: {
11
+ get: {
12
+ init,
13
+ request: {
14
+ typeId: "any"
15
+ },
16
+ response: {
17
+ typeId: "any"
18
+ }
19
+ },
20
+ post: {
21
+ alternativeFor: "get",
22
+ init
23
+ }
24
+ }
25
+ };
26
+ function init({ genomes }) {
27
+ return async (req, res) => {
28
+ try {
29
+ const g = genomes[req.query.genome];
30
+ if (!g)
31
+ throw "invalid genome name";
32
+ const ds = g.datasets[req.query.dslabel];
33
+ if (!ds)
34
+ throw "invalid dataset name";
35
+ const sampleId = req.query.sampleId;
36
+ if (!sampleId)
37
+ throw "invalid sampleId";
38
+ const wsimage = req.query.wsimage;
39
+ if (!wsimage)
40
+ throw "invalid wsimage";
41
+ const cookieJar = new CookieJar();
42
+ const setCookie = promisify(cookieJar.setCookie.bind(cookieJar));
43
+ const getCookieString = promisify(cookieJar.getCookieString.bind(cookieJar));
44
+ await ky.get(`${serverconfig.tileServerURL}/tileserver/session_id`, {
45
+ hooks: {
46
+ beforeRequest: [
47
+ async (request) => {
48
+ const cookie = await getCookieString(request.url);
49
+ request.headers.set("Cookie", cookie);
50
+ }
51
+ ],
52
+ afterResponse: [
53
+ async (request, options, response) => {
54
+ const setCookieHeader = response.headers.get("set-cookie");
55
+ if (setCookieHeader) {
56
+ await setCookie(setCookieHeader, request.url);
57
+ }
58
+ }
59
+ ]
60
+ }
61
+ });
62
+ const cookieString = await getCookieString(`${serverconfig.tileServerURL}/tileserver/session_id`);
63
+ const sessionId = cookieString.match(/session_id=([^;]*)/)?.[1];
64
+ const sampleWsiTileServer = path.join(
65
+ `${serverconfig.tileServerMount}/${ds.queries.WSImages.imageBySampleFolder}/${sampleId}`,
66
+ wsimage
67
+ );
68
+ const data = qs.stringify({ slide_path: sampleWsiTileServer });
69
+ await ky.put(`${serverconfig.tileServerURL}/tileserver/slide`, {
70
+ body: data,
71
+ headers: {
72
+ "Content-Type": "application/x-www-form-urlencoded",
73
+ Cookie: `session_id=${sessionId}`
74
+ // Include the session_id in the headers
75
+ },
76
+ hooks: {
77
+ beforeRequest: [
78
+ async (request) => {
79
+ const cookie = await getCookieString(request.url);
80
+ request.headers.set("Cookie", cookie);
81
+ }
82
+ ],
83
+ afterResponse: [
84
+ async (request, options, response) => {
85
+ const setCookieHeader = response.headers.get("set-cookie");
86
+ if (setCookieHeader) {
87
+ await setCookie(setCookieHeader, request.url);
88
+ }
89
+ }
90
+ ]
91
+ }
92
+ });
93
+ const getWsiImageResponse = await ky.get(`${serverconfig.tileServerURL}/tileserver/slide`, {
94
+ hooks: {
95
+ beforeRequest: [
96
+ async (request) => {
97
+ const cookie = await getCookieString(request.url);
98
+ request.headers.set("Cookie", cookie);
99
+ }
100
+ ]
101
+ }
102
+ }).json();
103
+ res.status(200).json({ sessionId, slide_dimensions: getWsiImageResponse.slide_dimensions });
104
+ } catch (e) {
105
+ console.log(e);
106
+ res.send({
107
+ status: "error",
108
+ error: e.error || e
109
+ });
110
+ }
111
+ };
112
+ }
113
+ export {
114
+ api
115
+ };