feat: route for historical packages fetching implemented

This commit is contained in:
hatskier
2022-07-17 21:55:38 +02:00
parent 5cf66c98cc
commit 6c2de9fbad
2 changed files with 149 additions and 69 deletions

View File

@@ -10,79 +10,110 @@ import { Document } from "mongoose";
const dbItemToObj = (item: Document<unknown, any, Package> & Package) => {
return _.omit(item.toObject(), ["_id", "__v"]);
}
};
const findPackage = async (req, res, initialMongoQuery) => {
const provider = await getProviderFromParams(
req.query as { provider: string }
);
if (!provider.address) {
throw new Error("Provider address is required");
}
const symbol = req.query.symbol as string;
if (symbol) {
// Fetching latest price for symbol from DB
const price = await Price.findOne({
...initialMongoQuery,
provider: provider.address,
symbol,
}).sort({ timestamp: -1 });
if (!price) {
throw new Error(`Requested package not found for symbol: ${symbol}`);
}
const responseObj = {
..._.pick(price, ["timestamp", "provider"]),
signature: price.evmSignature?.toString("base64"),
liteSignature: price.liteEvmSignature.toString("base64"),
prices: [{ symbol, value: price.value }],
signer: provider.evmAddress, // TODO: we don't really need signer, as it must be fetched from a trusted source or hardcoded in the redstone-evm-connector
};
return res.json(responseObj);
} else {
// Fetching latest package from DB
const packageFromDB = await Package.findOne({
...initialMongoQuery,
provider: provider.address,
}).sort({ timestamp: -1 });
if (!packageFromDB) {
throw new Error(`Requested package not found`);
}
const responseObj = dbItemToObj(packageFromDB);
return res.json(responseObj);
}
};
export const packages = (router: Router) => {
/**
* This endpoint is used for publishing a new price package
*/
router.post("/packages", asyncHandler(async (req, res) => {
// Saving package in DB
const newPackage = new Package(req.body);
await newPackage.save();
*/
router.post(
"/packages",
asyncHandler(async (req, res) => {
// Saving package in DB
const newPackage = new Package(req.body);
await newPackage.save();
// Cleaning older packages of the same provider before in the lite mode
if (enableLiteMode) {
await tryCleanCollection(Package, {
signer: req.body.signer,
timestamp: { $lt: newPackage.timestamp - cacheTTLMilliseconds },
// Cleaning older packages of the same provider before in the lite mode
if (enableLiteMode) {
await tryCleanCollection(Package, {
signer: req.body.signer,
timestamp: { $lt: newPackage.timestamp - cacheTTLMilliseconds },
});
}
// Returning package id in response
return res.json({
msg: "Package saved",
id: newPackage._id,
});
}
// Returning package id in response
return res.json({
msg: "Package saved",
id: newPackage._id,
});
}));
})
);
/**
* This endpoint is used for fetching the latest
* packages for the specified provider
*/
router.get("/packages/latest", asyncHandler(async (req, res) => {
const provider = await getProviderFromParams(req.query as { provider: string; });
*/
router.get(
"/packages/latest",
asyncHandler(async (req, res) => {
const initialMongoQuery = {};
return await findPackage(req, res, initialMongoQuery);
})
);
if (!provider.address) {
throw new Error("Provider address is required");
}
const symbol = req.query.symbol as string;
if (symbol) {
// Fetching latest price for symbol from DB
const price = await Price.findOne({
provider: provider.address,
symbol,
})
.sort({ timestamp: -1 });
if (!price) {
throw new Error(`Value not found for symbol: ${symbol}`);
/**
* This endpoint is used for fetching historical
* packages for the specified provider and timestamp
*/
router.get(
"/packages",
asyncHandler(async (req, res) => {
if (!req.query.toTimestamp) {
throw new Error("toTimestamp query param is required");
}
const responseObj = {
..._.pick(price, ["timestamp", "provider"]),
signature: price.evmSignature?.toString("base64"),
liteSignature: price.liteEvmSignature.toString("base64"),
prices: [{ symbol, value: price.value }],
signer: provider.evmAddress, // TODO: we don't really need signer, as it must be fetched from a trusted source or hardcoded in the redstone-evm-connector
const initialMongoQuery = {
timestamp: { $lte: req.query.toTimestamp },
};
return res.json(responseObj);
} else {
// Fetching latest package from DB
const packageFromDB = await Package.findOne({
provider: provider.address,
})
.sort({ timestamp: -1 });
if (!packageFromDB) {
throw new Error(`Latest package not found`);
}
const responseObj = dbItemToObj(packageFromDB);
return res.json(responseObj);
}
}));
return await findPackage(req, res, initialMongoQuery);
})
);
};

View File

@@ -33,15 +33,12 @@ describe("Testing packages route", () => {
evmSignature: Buffer.from(evmSignature, "base64"),
liteEvmSignature: Buffer.from(liteEvmSignature, "base64"),
version: "0.4",
source: {"test": 123},
source: { test: 123 },
timestamp: testTimestamp,
};
test("Should post a package and fetch it", async () => {
await request(app)
.post("/packages")
.send(testPackage)
.expect(200);
await request(app).post("/packages").send(testPackage).expect(200);
const response = await request(app)
.get(`/packages/latest?provider=${provider.name}`)
@@ -58,19 +55,71 @@ describe("Testing packages route", () => {
await new Price({
...testPrice,
}).save();
// await new Package(testPackage).save();
// When
const response = await request(app).get("/packages/latest").query({
provider: provider.name,
symbol: testPrice.symbol,
});
// Then
expect(response.body).toEqual({
...testPackage,
signer: "0x926E370fD53c23f8B71ad2B3217b227E41A92b12",
signature: evmSignature,
liteSignature: liteEvmSignature,
prices: [_.pick(testPrice, ["value", "symbol"])],
});
});
test("Should get a historical package", async () => {
const olderPackage = {
...testPackage,
timestamp: testPackage.timestamp - 50 * 1000,
};
await request(app).post("/packages").send(testPackage).expect(200);
await request(app).post("/packages").send(olderPackage).expect(200);
const response = await request(app)
.get(
`/packages/?provider=${provider.name}&toTimestamp=${
olderPackage.timestamp + 1
}`
)
.expect(200);
expect(response.body).toEqual({
...olderPackage,
prices: [],
});
});
test("Should get a historical package by symbol", async () => {
// Given
const olderPrice = {
...testPrice,
timestamp: testPrice.timestamp - 50 * 1000,
};
await new Price({
...testPrice,
}).save();
await new Price({
...olderPrice,
}).save();
// When
const response = await request(app)
.get("/packages/latest")
.get("/packages")
.query({
provider: provider.name,
symbol: testPrice.symbol,
toTimestamp: olderPrice.timestamp + 1,
});
// Then
expect(response.body).toEqual({
...testPackage,
timestamp: olderPrice.timestamp,
signer: "0x926E370fD53c23f8B71ad2B3217b227E41A92b12",
signature: evmSignature,
liteSignature: liteEvmSignature,