Skip to content

Commit

Permalink
refactor(core-api): sort peers by height, latency (#3078)
Browse files Browse the repository at this point in the history
  • Loading branch information
dated authored and faustbrian committed Oct 21, 2019
1 parent 13808e0 commit 03fdf01
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 24 deletions.
3 changes: 3 additions & 0 deletions __tests__/integration/core-api/__support__/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Utils } from "@arkecosystem/crypto";
import delay from "delay";
import { defaults } from "../../../../packages/core-api/src/defaults";
import { plugin } from "../../../../packages/core-api/src/plugin";
import { defaults as defaultsPeer } from "../../../../packages/core-p2p/src/defaults";
import { registerWithContainer, setUpContainer } from "../../../utils/helpers/container";

import { delegates } from "../../../utils/fixtures";
Expand Down Expand Up @@ -36,6 +37,8 @@ const setUp = async () => {
],
});

app.register("pkg.p2p.opts", asValue(defaultsPeer));

const databaseService = app.resolvePlugin<Database.IDatabaseService>("database");
await databaseService.buildWallets();
await databaseService.saveRound(round);
Expand Down
66 changes: 55 additions & 11 deletions __tests__/integration/core-api/handlers/peers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,37 @@ import { utils } from "../utils";
const peers = [
{
ip: "1.0.0.99",
port: 4000,
port: 4002,
version: "2.4.0-next.3",
state: {
height: 2,
},
latency: 2,
},
{
ip: "1.0.0.98",
port: 4000,
port: 4002,
version: "2.4.0-next.1",
state: {
height: 1,
},
latency: 1,
},
];

beforeAll(async () => {
await setUp();

const peerMocks = peers
.map(mock => {
const peerMock = new Peer(mock.ip);
(peerMock as any).port = mock.port;
peerMock.version = mock.version;
return peerMock;
})
.reduce((result, mock) => ({ ...result, [mock.ip]: mock }), {});
const peerMocks = JSON.parse(JSON.stringify(peers)).map(mock => {
const peer = new Peer(mock.ip);
(peer as any).port = mock.port;

for (const peerMock of Object.values(peerMocks)) {
delete mock.port;

return Object.assign(peer, mock);
});

for (const peerMock of peerMocks) {
app.resolvePlugin("p2p")
.getStorage()
.setPeer(peerMock);
Expand Down Expand Up @@ -65,6 +73,42 @@ describe("API 2.0 - Peers", () => {
expect(response.data.data[0].ip).toBe(peers[0].ip);
expect(response.data.data[1].ip).toBe(peers[1].ip);
});

it("should GET all the peers sorted by height,asc", async () => {
const response = await utils.request("GET", "peers", { orderBy: "height:asc" });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArrayOfSize(peers.length);
expect(response.data.data[0]).toBeObject();
expect(response.data.data[0].ip).toBe(peers[1].ip);
expect(response.data.data[1].ip).toBe(peers[0].ip);
});

it("should GET all the peers sorted by height,desc", async () => {
const response = await utils.request("GET", "peers", { orderBy: "height:desc" });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArrayOfSize(peers.length);
expect(response.data.data[0]).toBeObject();
expect(response.data.data[0].ip).toBe(peers[0].ip);
expect(response.data.data[1].ip).toBe(peers[1].ip);
});

it("should GET all the peers sorted by latency,asc", async () => {
const response = await utils.request("GET", "peers", { orderBy: "latency:asc" });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArrayOfSize(peers.length);
expect(response.data.data[0]).toBeObject();
expect(response.data.data[0].ip).toBe(peers[1].ip);
expect(response.data.data[1].ip).toBe(peers[0].ip);
});

it("should GET all the peers sorted by latency,desc", async () => {
const response = await utils.request("GET", "peers", { orderBy: "latency:desc" });
expect(response).toBeSuccessfulResponse();
expect(response.data.data).toBeArrayOfSize(peers.length);
expect(response.data.data[0]).toBeObject();
expect(response.data.data[0].ip).toBe(peers[0].ip);
expect(response.data.data[1].ip).toBe(peers[1].ip);
});
});

describe("GET /peers/:ip", () => {
Expand Down
47 changes: 34 additions & 13 deletions packages/core-api/src/handlers/peers/controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { P2P } from "@arkecosystem/core-interfaces";
import { orderBy } from "@arkecosystem/utils";
import Boom from "@hapi/boom";
import Hapi from "@hapi/hapi";
import { get } from "dottie";
Expand All @@ -7,12 +8,11 @@ import { Controller } from "../shared/controller";

export class PeersController extends Controller {
public async index(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const allPeers: P2P.IPeer[] = this.blockchain.p2p.getStorage().getPeers();
const allPeers: P2P.IPeer[] = [...this.blockchain.p2p.getStorage().getPeers()];

let result = allPeers.sort((a, b) => a.latency - b.latency);
result = request.query.version
? result.filter(peer => peer.version === (request.query as any).version)
: result;
let result = request.query.version
? allPeers.filter(peer => peer.version === (request.query as any).version)
: allPeers;

const count: number = result.length;

Expand All @@ -28,16 +28,37 @@ export class PeersController extends Controller {
offset = 0;
}

const orderBy: string = request.query.orderBy as string;
if (orderBy) {
const order = orderBy.split(":");
const order: string = request.query.orderBy as string;
if (order) {
const orderByMapped = order.split(":").map(p => p.toLowerCase());

if (order[0] === "version") {
result =
order[1].toUpperCase() === "ASC"
? result.sort((a, b) => semver.compare(a[order[0]], b[order[0]]))
: result.sort((a, b) => semver.rcompare(a[order[0]], b[order[0]]));
switch (orderByMapped[0]) {
case "version": {
result =
orderByMapped[1] === "asc"
? result.sort((a, b) => semver.compare(a[orderByMapped[0]], b[orderByMapped[0]]))
: result.sort((a, b) => semver.rcompare(a[orderByMapped[0]], b[orderByMapped[0]]));
break;
}
case "height": {
result = orderBy(
result,
el => el.state[orderByMapped[0]],
orderByMapped[1] === "asc" ? "asc" : "desc",
);
break;
}
case "latency": {
result = orderBy(result, orderByMapped[0], orderByMapped[1] === "asc" ? "asc" : "desc");
break;
}
default: {
result = result.sort((a, b) => a.latency - b.latency);
break;
}
}
} else {
result = result.sort((a, b) => a.latency - b.latency);
}

result = result.slice(offset, offset + limit);
Expand Down

0 comments on commit 03fdf01

Please sign in to comment.