mirror of
https://github.com/alexgo-io/redstone-cache-layer.git
synced 2026-01-12 08:34:36 +08:00
feat: route for historical packages fetching implemented
This commit is contained in:
@@ -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);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user