Loading IVOA.js +11 −9 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ export { IVOA_syncEndpoint }; * @returns {function(Symbol): Promise<string>} - A CPS IO action that returns a VOTable XML response. */ const IVOA_datalinkEndpoint = (req) => async (IO) => { // Extracts id and clientId from the request query string const id = req.query?.id; const clientId = req.query?.clientId; Loading @@ -181,6 +182,8 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { } const redis = await connRedis()(IO); // Searches for the row in Redis using multiple fallback keys let result; const possibleKeys = [ `client:${clientId}:query:${id}`, Loading @@ -188,14 +191,10 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { `client:${clientId}:merge:transits:${id}`, ]; let matchedKey = null; for (const key of possibleKeys) { const attempt = await getRedis(redis, key)(IO); if (attempt.tag === "just") { result = attempt; matchedKey = key; console.log("🔍 Redis result per", key, "=>", result); break; } } Loading @@ -205,8 +204,9 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { } const rowData = JSON.parse(result.value); const type = rowData.transit_id ? "transits" : "sources"; // Determines the data type (transits or sources) and stores the row const type = rowData.transit_id ? "transits" : "sources"; const uuid = uuidv4(); const storeKey = `client:${clientId}:merge:${type}:${uuid}`; Loading @@ -215,12 +215,14 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { value: JSON.stringify(rowData), })(IO); // Constructs the URLs for DataLink services: merge, progenitor, and counterpart const didName = rowData.did_name; const baseUrl = URLs.serverHost; const transitsUrl = `${baseUrl}/datalink/transits?id=${id}&clientId=${clientId}`; const gaiamergerUrl = `${baseUrl}/datalink/gaiamerger?id=${uuid}&clientId=${clientId}`; const progenitorUrl = `${baseUrl}/api/files?name=${encodeURIComponent(didName)}`; const transitsUrl = `${baseUrl}/datalink/transits?id=${id}&clientId=${clientId}`; // Creates a standard DataLink VOTable with access_url, description, content_type, and semantics const votable = xmlbuilder .create("VOTABLE", { encoding: "UTF-8" }) .att("version", "1.3") Loading Loading @@ -383,7 +385,7 @@ export const datalinkTransitsEndpoint = (req) => async (IO) => { * Functional signature: Request -> IO -> IO String * * @param {Request} req - HTTP request with 'id' and 'clientId' * @returns {(IO) => Promise<string>} - A CPS IO action returning a redirect or error * @returns {Promise<string>} - A CPS IO action that takes an IO token and returns a redirect or error string */ export const datalinkGaiamergerEndpoint = (req) => async (IO) => { const id = req.query?.id; Loading Loading @@ -450,7 +452,7 @@ export const datalinkGaiamergerEndpoint = (req) => async (IO) => { * Functional signature: Request -> IO -> IO String * * @param {Request} req - HTTP request with 'id' and 'clientId' * @returns {(IO) => Promise<string>} - A CPS IO action returning a VOTable with progenitor link * @returns {Promise<string>} - A CPS IO action that takes an IO token and returns a VOTable with progenitor link */ export const datalinkProgenitorEndpoint = (req) => async (IO) => { const id = req.query?.id; Loading Loading @@ -551,7 +553,7 @@ const IVOA_main = () => async (IO) => { * * Functional signature: () -> IO () * * @returns {(IO) => Promise<void>} - A CPS IO action that launches the server logic * @returns {Promise<void>} - A CPS IO action that takes an IO token and launches the server logic */ const mainExpression = () => IVOA_main(); Loading IVOA.py +9 −1 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: """ async def inner(io): # Extracts TAP parameters from the request method = req.method Loading Loading @@ -201,6 +202,7 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: """ async def inner(io): # Extracts id and clientId from the request query string id_ = req.query.get("id") client_id = req.query.get("clientId") Loading @@ -208,6 +210,8 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: return make_datalink_error("Missing id or clientId") redis = await conn_redis()(io) # Searches for the row in Redis using multiple fallback keys possible_keys = [ f"client:{client_id}:query:{id_}", f"client:{client_id}:merge:sources:{id_}", Loading @@ -225,13 +229,15 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: return make_datalink_error("Row not found or expired") row_data = json.loads(result["value"]) type_ = "transits" if "transit_id" in row_data else "sources" # Determines the data type (transits or sources) and stores the row type_ = "transits" if "transit_id" in row_data else "sources" uuid_str = str(uuid.uuid4()) store_key = f"client:{client_id}:merge:{type_}:{uuid_str}" await set_redis(redis)({"key": store_key, "value": json.dumps(row_data)})(io) # Constructs the URLs for DataLink services: merge, progenitor, and counterpart did_name = row_data.get("did_name") gaiamerger_url = f"{URLS['serverHost']}/datalink/gaiamerger?id={uuid_str}&clientId={client_id}" progenitor_url = f"{URLS['serverHost']}/api/files?name={did_name}" Loading @@ -239,10 +245,12 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: f"{URLS['serverHost']}/datalink/transits?id={id_}&clientId={client_id}" ) # Creates a standard DataLink VOTable with access_url, description, content_type, and semantics votable = ET.Element( "VOTABLE", {"version": "1.3", "xmlns": "http://www.ivoa.net/xml/VOTable/v1.3"}, ) resource = ET.SubElement(votable, "RESOURCE", {"type": "results"}) table = ET.SubElement(resource, "TABLE") Loading Loading
IVOA.js +11 −9 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ export { IVOA_syncEndpoint }; * @returns {function(Symbol): Promise<string>} - A CPS IO action that returns a VOTable XML response. */ const IVOA_datalinkEndpoint = (req) => async (IO) => { // Extracts id and clientId from the request query string const id = req.query?.id; const clientId = req.query?.clientId; Loading @@ -181,6 +182,8 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { } const redis = await connRedis()(IO); // Searches for the row in Redis using multiple fallback keys let result; const possibleKeys = [ `client:${clientId}:query:${id}`, Loading @@ -188,14 +191,10 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { `client:${clientId}:merge:transits:${id}`, ]; let matchedKey = null; for (const key of possibleKeys) { const attempt = await getRedis(redis, key)(IO); if (attempt.tag === "just") { result = attempt; matchedKey = key; console.log("🔍 Redis result per", key, "=>", result); break; } } Loading @@ -205,8 +204,9 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { } const rowData = JSON.parse(result.value); const type = rowData.transit_id ? "transits" : "sources"; // Determines the data type (transits or sources) and stores the row const type = rowData.transit_id ? "transits" : "sources"; const uuid = uuidv4(); const storeKey = `client:${clientId}:merge:${type}:${uuid}`; Loading @@ -215,12 +215,14 @@ const IVOA_datalinkEndpoint = (req) => async (IO) => { value: JSON.stringify(rowData), })(IO); // Constructs the URLs for DataLink services: merge, progenitor, and counterpart const didName = rowData.did_name; const baseUrl = URLs.serverHost; const transitsUrl = `${baseUrl}/datalink/transits?id=${id}&clientId=${clientId}`; const gaiamergerUrl = `${baseUrl}/datalink/gaiamerger?id=${uuid}&clientId=${clientId}`; const progenitorUrl = `${baseUrl}/api/files?name=${encodeURIComponent(didName)}`; const transitsUrl = `${baseUrl}/datalink/transits?id=${id}&clientId=${clientId}`; // Creates a standard DataLink VOTable with access_url, description, content_type, and semantics const votable = xmlbuilder .create("VOTABLE", { encoding: "UTF-8" }) .att("version", "1.3") Loading Loading @@ -383,7 +385,7 @@ export const datalinkTransitsEndpoint = (req) => async (IO) => { * Functional signature: Request -> IO -> IO String * * @param {Request} req - HTTP request with 'id' and 'clientId' * @returns {(IO) => Promise<string>} - A CPS IO action returning a redirect or error * @returns {Promise<string>} - A CPS IO action that takes an IO token and returns a redirect or error string */ export const datalinkGaiamergerEndpoint = (req) => async (IO) => { const id = req.query?.id; Loading Loading @@ -450,7 +452,7 @@ export const datalinkGaiamergerEndpoint = (req) => async (IO) => { * Functional signature: Request -> IO -> IO String * * @param {Request} req - HTTP request with 'id' and 'clientId' * @returns {(IO) => Promise<string>} - A CPS IO action returning a VOTable with progenitor link * @returns {Promise<string>} - A CPS IO action that takes an IO token and returns a VOTable with progenitor link */ export const datalinkProgenitorEndpoint = (req) => async (IO) => { const id = req.query?.id; Loading Loading @@ -551,7 +553,7 @@ const IVOA_main = () => async (IO) => { * * Functional signature: () -> IO () * * @returns {(IO) => Promise<void>} - A CPS IO action that launches the server logic * @returns {Promise<void>} - A CPS IO action that takes an IO token and launches the server logic */ const mainExpression = () => IVOA_main(); Loading
IVOA.py +9 −1 Original line number Diff line number Diff line Loading @@ -97,6 +97,7 @@ def ivoa_sync_endpoint(req) -> Callable[[object], Awaitable[str]]: """ async def inner(io): # Extracts TAP parameters from the request method = req.method Loading Loading @@ -201,6 +202,7 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: """ async def inner(io): # Extracts id and clientId from the request query string id_ = req.query.get("id") client_id = req.query.get("clientId") Loading @@ -208,6 +210,8 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: return make_datalink_error("Missing id or clientId") redis = await conn_redis()(io) # Searches for the row in Redis using multiple fallback keys possible_keys = [ f"client:{client_id}:query:{id_}", f"client:{client_id}:merge:sources:{id_}", Loading @@ -225,13 +229,15 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: return make_datalink_error("Row not found or expired") row_data = json.loads(result["value"]) type_ = "transits" if "transit_id" in row_data else "sources" # Determines the data type (transits or sources) and stores the row type_ = "transits" if "transit_id" in row_data else "sources" uuid_str = str(uuid.uuid4()) store_key = f"client:{client_id}:merge:{type_}:{uuid_str}" await set_redis(redis)({"key": store_key, "value": json.dumps(row_data)})(io) # Constructs the URLs for DataLink services: merge, progenitor, and counterpart did_name = row_data.get("did_name") gaiamerger_url = f"{URLS['serverHost']}/datalink/gaiamerger?id={uuid_str}&clientId={client_id}" progenitor_url = f"{URLS['serverHost']}/api/files?name={did_name}" Loading @@ -239,10 +245,12 @@ def ivoa_datalink_endpoint(req) -> Callable[[object], Awaitable[str]]: f"{URLS['serverHost']}/datalink/transits?id={id_}&clientId={client_id}" ) # Creates a standard DataLink VOTable with access_url, description, content_type, and semantics votable = ET.Element( "VOTABLE", {"version": "1.3", "xmlns": "http://www.ivoa.net/xml/VOTable/v1.3"}, ) resource = ET.SubElement(votable, "RESOURCE", {"type": "results"}) table = ET.SubElement(resource, "TABLE") Loading