Commit 28f9053b authored by Massimo Costantini's avatar Massimo Costantini
Browse files

First version

parent a9fdb5a0
Loading
Loading
Loading
Loading

Conf/PostgreSQL.json

0 → 100644
+7 −0
Original line number Diff line number Diff line
{
  "user": "postgres",
  "host": "131.154.98.131",
  "database": "spoke3",
  "password": "postgres",
  "port": 5432
}

Conf/REST.json

0 → 100644
+3 −0
Original line number Diff line number Diff line
{
  "port": 3000
}

Conf/Redis.json

0 → 100644
+4 −0
Original line number Diff line number Diff line
{
  "host": "127.0.0.1",
  "port": 6379
}

IVOA.js

0 → 100644
+101 −0
Original line number Diff line number Diff line
// IVOA
// IVOA implementation

import { InternalError, IO, performIO } from "./Lib/IO.js";
import { putStr, readFile } from "./Lib/IO.js";

import { connPostgreSQL, fetchRows, quitPostgreSQL } from "./Lib/PostgreSQL.js";

import { startRESTServer, readRESTPort } from "./Lib/REST.js";

import { buildVOTablesFromRows } from "./Lib/VOTable.js";

/**
 * Serves the static /tap HTML landing page (functional signature: Request -> IO -> IO String).
 *
 * @param {Request} req - Incoming HTTP request
 * @param {Symbol} IO - IO token
 * @returns {Promise<string>} - HTML content
 */
async function IVOA_tapEndpoint(req, IO) {
  return await readFile("Stat/tap.html")(IO);
}

/**
 * Serves the static /availability XML response (functional signature: Request -> IO -> IO String).
 *
 * @param {Request} req - Incoming HTTP request
 * @param {Symbol} IO - IO token
 * @returns {Promise<string>} - XML content
 */
async function IVOA_availabilityEndpoint(req, IO) {
  return await readFile("Stat/availability.xml")(IO);
}

/**
 * Serves the static /capabilities XML response (functional signature: Request -> IO -> IO String).
 *
 * @param {Request} req - Incoming HTTP request
 * @param {Symbol} IO - IO token
 * @returns {Promise<string>} - XML content
 */
async function IVOA_capabilitiesEndpoint(req, IO) {
  return await readFile("Stat/capabilities.xml")(IO);
}

/**
 * IVOA_tablesEndpoint : Request -> IO -> IO String
 * Executes an SQL query from file and returns a VOTable representation (functional signature: Request -> IO -> IO String).
 *
 * @param {Request} req - Incoming HTTP request
 * @param {Symbol} IO - IO token
 * @returns {Promise<string>} - XML content in VOTable format or error message
 */
async function IVOA_tablesEndpoint(req, IO) {
  const query = await readFile("Query/tables.sql")(IO);
  const conn = await connPostgreSQL()(IO);
  const result = await fetchRows(conn, query, [])(IO);
  await quitPostgreSQL(conn)(IO);

  if (result.tag === "nothing") {
    return '<?xml version="1.0" encoding="UTF-8"?><error>No tables found</error>';
  }

  return buildVOTablesFromRows(result.value);
}

/**
 * Main entry point for the IVOA TAP and DataLink server (functional signature: IO -> IO ()).
 *
 * @param {Symbol} IO - IO token
 * @returns {Promise<void>} - Starts the server and binds all routes
 */
async function IVOA_main(IO) {
  await putStr("IVOA server started")(IO);
  const port = await readRESTPort(IO);
  startRESTServer(port, [
    { path: "/tap", endpoint: IVOA_tapEndpoint },
    { path: "/tap/availability", endpoint: IVOA_availabilityEndpoint },
    { path: "/tap/capabilities", endpoint: IVOA_capabilitiesEndpoint },
    { path: "/tap/tables", endpoint: IVOA_tablesEndpoint },
  ])(IO);
}

/**
 * Wraps the program execution in a safe IO environment (functional signature: () -> IO ()).
 *
 * @returns {IO} - The IO token after the execution
 */
function mainExpression() {
  return performIO((IO) => IVOA_main(IO));
}

try {
  await mainExpression();
} catch (e) {
  if (e instanceof InternalError) {
    await putStr("ERROR: " + e.message)(IO);
  } else {
    throw e;
  }
}

IVOA.py

0 → 100644
+103 −0
Original line number Diff line number Diff line
# IVOA
# IVOA implementation

from Lib.IO import InternalError, IO, performIO
from Lib.IO import putStr, readFile

from Lib.PostgreSQL import connPostgreSQL, fetchRows, quitPostgreSQL

from Lib.REST import startRESTServer, readRESTPort

from Lib.VOTable import buildVOTablesFromRows


async def IVOA_tapEndpoint(req, IO):
    """
    Serves the static /tap HTML landing page (functional signature: Request -> IO -> IO String).

    @param req: Incoming HTTP request
    @param IO: IO token
    @returns: Coroutine[str] - HTML content
    """
    return await readFile("Stat/tap.html")(IO)


async def IVOA_availabilityEndpoint(req, IO):
    """
    Serves the static /availability XML response (functional signature: Request -> IO -> IO String).

    @param req: Incoming HTTP request
    @param IO: IO token
    @returns: Coroutine[str] - XML content
    """
    return await readFile("Stat/availability.xml")(IO)


async def IVOA_capabilitiesEndpoint(req, IO):
    """
    Serves the static /capabilities XML response (functional signature: Request -> IO -> IO String).

    @param req: Incoming HTTP request
    @param IO: IO token
    @returns: Coroutine[str] - XML content
    """
    return await readFile("Stat/capabilities.xml")(IO)


async def IVOA_tablesEndpoint(req, IO):
    """
    Executes an SQL query from file and returns a VOTable representation (functional signature: Request -> IO -> IO String).

    @param req: Incoming HTTP request
    @param IO: IO token
    @returns: Coroutine[str] - XML content in VOTable format or error message
    """
    query = await readFile("Query/tables.sql")(IO)
    conn = await connPostgreSQL()(IO)
    result = await fetchRows(conn, query, [])(IO)
    await quitPostgreSQL(conn)(IO)

    if result["tag"] == "nothing":
        return '<?xml version="1.0" encoding="UTF-8"?><error>No tables found</error>'
    return buildVOTablesFromRows(result["value"])


async def IVOA_main(IO):
    """
    Main entry point for the IVOA TAP and DataLink server (functional signature: IO -> IO ()).

    @param IO: IO token
    @returns: Coroutine[None] - Starts the server and binds all routes
    """
    await putStr("IVOA server started")(IO)
    port = readRESTPort(IO)
    await startRESTServer(
        port,
        [
            {"path": "/tap", "endpoint": IVOA_tapEndpoint},
            {"path": "/tap/availability", "endpoint": IVOA_availabilityEndpoint},
            {"path": "/tap/capabilities", "endpoint": IVOA_capabilitiesEndpoint},
            {"path": "/tap/tables", "endpoint": IVOA_tablesEndpoint},
        ],
    )(IO)
    await asyncio.Event().wait()


def mainExpression():
    """
    Wraps the program execution in a safe IO environment (functional signature: () -> IO ()).

    @returns: IO () - The IO token after the execution
    """
    return performIO(lambda IO: IVOA_main(IO))


if __name__ == "__main__":
    import asyncio

    try:
        asyncio.run(mainExpression())
    except InternalError as e:
        asyncio.run(putStr("ERROR: " + str(e))(IO))
    except Exception as e:
        raise
Loading