Commit 46d16760 authored by 神楽坂玲奈's avatar 神楽坂玲奈

test

parent 83cd16fc
{
"port": 500,
"timeout": 10,
"interval": 1000
}
[
{ "id": 1, "inbound_cost": 0, "outbound_cost": 1 },
{ "id": 3, "inbound_cost": 0, "outbound_cost": 1 },
{ "id": 7, "inbound_cost": 0, "outbound_cost": 1 },
{ "id": 9, "inbound_cost": 0, "outbound_cost": 1 }
]
This diff is collapsed.
{ {
"name": "application-name", "name": "railgun-routing-server",
"version": "0.0.1", "version": "0.0.1",
"devDependencies": { "author": "zh99998 <zh99998@gmail.com>",
"@types/node": "^14.14.19"
},
"dependencies": { "dependencies": {
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/lodash": "^4.14.172", "@types/lodash": "^4.14.172",
"lodash": "^4.17.21", "@types/node": "^16.6.1",
"ts-node": "^9.1.1", "ts-node": "^10.2.0",
"typescript": "^4.1.3" "typescript": "^4.3.5"
} }
} }
// 这个文件两端共用
export interface PeerQuality {
delay: number;
jitter: number;
reliability: number;
}
// 路由器向中心服务器发送的消息
export interface UploadMessage {
id: number; // router id
ack: number;
peers?: Record<number, PeerQuality>;
}
// 中心服务器向路由器发送的消息
export interface DownloadMessage {
seq: number,
to: number,
via: number;
}
// 路由器向路由器发送的消息
export interface PeerMessage {
id: number;
seq: number;
time: number;
}
[
{ "id": 2, "inbound_cost": 0, "outbound_cost": 0.8 },
{ "id": 3, "inbound_cost": 0, "outbound_cost": 0.05 },
{ "id": 4, "inbound_cost": 0, "outbound_cost": 0.03 },
{ "id": 6, "inbound_cost": 0, "outbound_cost": 0.8 },
{ "id": 7, "inbound_cost": 0, "outbound_cost": 1 }
]
import { RemoteInfo } from 'dgram'; import { RemoteInfo } from 'dgram';
import { PeerQuality } from './protocol'; import { PeerQuality } from '../protocol';
import servers from '../servers.json'; import routers from '../config/routers.json';
import assert from 'assert'; import assert from 'assert';
import { Quality } from './Quality'; import { Quality } from './Quality';
export class Router { export class Router {
static all: Router[] = servers.map(s => Object.assign(new Router(), s)); static all: Router[] = routers.map(s => Object.assign(new Router(), s));
// config // config
id!: number; id!: number;
inbound_cost!: number; inbound_cost!: number;
outbound_cost!: number; outbound_cost!: number;
//report seq = 0;
peers: Record<number, PeerQuality> = {}; peers: Record<number, PeerQuality> = {};
via: Map<Router, Router> = new Map();
// routing
next_hop: Map<Router, Router> = new Map();
rinfo?: RemoteInfo; rinfo?: RemoteInfo;
reset() { reset() {
this.seq = 0;
this.peers = {}; this.peers = {};
for (const router of Router.all) { for (const router of Router.all) {
this.next_hop.set(router, router); this.via.set(router, router);
} }
} }
lost() { lost() {
this.seq = 0;
this.rinfo = undefined; this.rinfo = undefined;
return console.log(`router ${this.id} lost connection.`); return console.log(`router ${this.id} lost connection.`);
} }
route_quality(to: Router, next_hop = this.next_hop.get(to)!) { route_quality(to: Router, via = this.via.get(to)!) {
assert(next_hop != null); assert(via != null);
assert(this !== next_hop); assert(this !== via);
assert(this !== to); assert(this !== to);
const result = new Quality(); const result = new Quality();
let current: Router = this; let current: Router = this;
let next = next_hop; let next = via;
const route = [current, next]; const route = [current, next];
while (true) { while (true) {
...@@ -50,7 +51,7 @@ export class Router { ...@@ -50,7 +51,7 @@ export class Router {
// 寻找下一跳 // 寻找下一跳
current = next; current = next;
next = current.next_hop.get(to)!; next = current.via.get(to)!;
assert(next); //to server_id 型路由,由于 server 两两相连,下一跳一定是存在的,至少能直达 assert(next); //to server_id 型路由,由于 server 两两相连,下一跳一定是存在的,至少能直达
if (route.includes(next)) { if (route.includes(next)) {
// 环路 // 环路
......
import dgram from 'dgram'; import dgram from 'dgram';
import http from 'http'; import http from 'http';
import peers from '../servers.json';
import { ServerMessage } from './protocol'; import { DownloadMessage, UploadMessage } from '../protocol';
import assert from 'assert'; import assert from 'assert';
import { Router } from './Router'; import { Router } from './Router';
import _ from 'lodash'; import _ from 'lodash';
const server_port = 495; import config from '../config/config.json';
const timeout = 10;
let sequence = 0;
let updating: any = null; let updating: any = null;
let timeout_timer: any = null; let timeout_timer: any = null;
export function send_route(router: Router, to: Router, next_hop: Router) { export function send_route(from: Router, to: Router, via: Router) {
const message = { sequence, to: to.id, next_hop: next_hop.id }; const message: DownloadMessage = { seq: from.seq, to: to.id, via: via.id };
return socket.send(JSON.stringify(message), router.rinfo!.port, router.rinfo!.address); return socket.send(JSON.stringify(message), from.rinfo!.port, from.rinfo!.address);
} }
const socket = dgram const socket = dgram
.createSocket('udp4') .createSocket('udp4')
.on('message', function(message, rinfo) { .on('message', function(message, rinfo) {
try { try {
const hello: ServerMessage = JSON.parse(message.toString()); const hello: UploadMessage = JSON.parse(message.toString());
assert(hello.id); assert(hello.id);
const router: Router = Router.all.find(r => r.id === hello.id)!; const router: Router = Router.all.find(r => r.id === hello.id)!;
assert(router); assert(router);
if (_.isEqual(rinfo, router.rinfo)) { router.rinfo = rinfo;
router.rinfo = rinfo;
if (hello.ack === 0) {
router.reset(); router.reset();
} }
router.peers = hello.peers; if (hello.peers) router.peers = hello.peers;
if (updating) { if (updating) {
if (hello.ack === sequence) { if (hello.ack === router.seq + 1) {
clearInterval(updating); clearInterval(updating);
clearTimeout(timeout_timer); clearTimeout(timeout_timer);
updating = null; updating = null;
sequence++; router.seq++;
} }
return; return;
} }
...@@ -55,28 +53,27 @@ const socket = dgram ...@@ -55,28 +53,27 @@ const socket = dgram
const best_route = _.minBy(Router.all.filter(router => router.id !== from.id), (router) => from.route_quality(to, router).metric())!; const best_route = _.minBy(Router.all.filter(router => router.id !== from.id), (router) => from.route_quality(to, router).metric())!;
// 变更 // 变更
if (from.next_hop.get(to) !== best_route) { if (from.via.get(to) !== best_route) {
from.next_hop.set(to, best_route); from.via.set(to, best_route);
updating = setInterval(() => send_route(from, to, best_route), 1000); updating = setInterval(() => send_route(from, to, best_route), config.interval);
send_route(from, to, best_route); send_route(from, to, best_route);
timeout_timer = setTimeout(function() { timeout_timer = setTimeout(function() {
from.lost(); from.lost();
clearInterval(updating); clearInterval(updating);
updating = null; updating = null;
}, timeout * 1000); }, config.timeout * config.interval);
return; return;
} }
} }
} }
}); });
socket.bind(server_port); socket.bind(config.port);
//web management api //web management api
http http
.createServer(function(req, res) { .createServer(function(req, res) {
res.writeHead(200, { 'Content-Type': 'application/json' }); res.writeHead(200, { 'Content-Type': 'application/json' });
return res.end(JSON.stringify(peers)); const result: Record<number, Record<number, number>> = Object.fromEntries(Router.all.map(from => [from.id, Object.fromEntries([...from.via.entries()].map(([to, via]) => [to.id, via.id]))]));
return res.end(JSON.stringify(result));
}) })
.listen(server_port); .listen(config.port);
// setInterval(refresh(socket, routers), 1000)
export interface PeerQuality {
delay: number;
jitter: number;
reliability: number;
}
export interface ServerMessage {
id: number;
ack: number;
peers: PeerQuality[];
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment