summary refs log tree commit diff
path: root/api
diff options
context:
space:
mode:
authorAlTech98 <altech123159@gmail.com>2021-08-30 21:12:13 +0200
committerAlTech98 <altech123159@gmail.com>2021-08-30 21:12:13 +0200
commitb59cbdb081da601cb7c19cb6010474def1bdcffb (patch)
tree0acfe5d47cc277b3bac5e91056ed4db0ad6ec3f9 /api
parentadded first unittests for api endpoints (diff)
downloadserver-b59cbdb081da601cb7c19cb6010474def1bdcffb.tar.xz
Implemented voice apis #127 and #78
Diffstat (limited to 'api')
-rw-r--r--api/src/routes/guilds/#guild_id/regions.ts9
-rw-r--r--api/src/routes/voice/regions.ts11
-rw-r--r--api/src/util/Voice.ts32
-rw-r--r--api/src/util/ipAddress.ts17
4 files changed, 67 insertions, 2 deletions
diff --git a/api/src/routes/guilds/#guild_id/regions.ts b/api/src/routes/guilds/#guild_id/regions.ts
index 5ec649ee..212c9bcd 100644
--- a/api/src/routes/guilds/#guild_id/regions.ts
+++ b/api/src/routes/guilds/#guild_id/regions.ts
@@ -1,10 +1,15 @@
-import { Config } from "@fosscord/util";
+import {Config, Guild, Member} from "@fosscord/util";
 import { Request, Response, Router } from "express";
+import {getVoiceRegions} from "../../../util/Voice";
+import {getIpAdress} from "../../../util/ipAddress";
 
 const router = Router();
 
 router.get("/", async (req: Request, res: Response) => {
-	return res.json(Config.get().regions.available);
+	const { guild_id } = req.params;
+	const guild = await Guild.findOneOrFail({ id: guild_id });
+	//TODO we should use an enum for guild's features and not hardcoded strings
+	return res.json(await getVoiceRegions(getIpAdress(req), guild.features.includes("VIP_REGIONS")));
 });
 
 export default router;
diff --git a/api/src/routes/voice/regions.ts b/api/src/routes/voice/regions.ts
new file mode 100644
index 00000000..812aa8f6
--- /dev/null
+++ b/api/src/routes/voice/regions.ts
@@ -0,0 +1,11 @@
+import { Router, Request, Response } from "express";
+import {getIpAdress} from "../../util/ipAddress";
+import {getVoiceRegions} from "../../util/Voice";
+
+const router: Router = Router();
+
+router.get("/", async (req: Request, res: Response) => {
+    res.json(await getVoiceRegions(getIpAdress(req), true))//vip true?
+});
+
+export default router;
diff --git a/api/src/util/Voice.ts b/api/src/util/Voice.ts
new file mode 100644
index 00000000..087bdfa8
--- /dev/null
+++ b/api/src/util/Voice.ts
@@ -0,0 +1,32 @@
+import {Config} from "@fosscord/util";
+import {distanceBetweenLocations, IPAnalysis} from "./ipAddress";
+
+export async function getVoiceRegions(ipAddress: string, vip: boolean) {
+    const regions = Config.get().regions;
+    const availableRegions = regions.available.filter(ar => vip ? true : !ar.vip);
+    let optimalId = regions.default
+
+    if(!regions.useDefaultAsOptimal) {
+        const clientIpAnalysis = await IPAnalysis(ipAddress)
+
+        let min = Number.POSITIVE_INFINITY
+
+        for (let ar of availableRegions) {
+            //TODO the endpoint location should be saved in the database if not already present to prevent IPAnalysis call
+            const dist = distanceBetweenLocations(clientIpAnalysis, ar.location || (await IPAnalysis(ar.endpoint)))
+
+            if(dist < min) {
+                min = dist
+                optimalId = ar.id
+            }
+        }
+    }
+
+    return availableRegions.map(ar => ({
+        id: ar.id,
+        name: ar.name,
+        custom: ar.custom,
+        deprecated: ar.deprecated,
+        optimal: ar.id === optimalId
+    }))
+}
\ No newline at end of file
diff --git a/api/src/util/ipAddress.ts b/api/src/util/ipAddress.ts
index 0a724daa..c6239426 100644
--- a/api/src/util/ipAddress.ts
+++ b/api/src/util/ipAddress.ts
@@ -60,6 +60,7 @@ const exampleData = {
 	status: 200
 };
 
+//TODO add function that support both ip and domain names
 export async function IPAnalysis(ip: string): Promise<typeof exampleData> {
 	const { ipdataApiKey } = Config.get().security;
 	if (!ipdataApiKey) return { ...exampleData, ip };
@@ -79,3 +80,19 @@ export function getIpAdress(req: Request): string {
 	// @ts-ignore
 	return req.headers[Config.get().security.forwadedFor] || req.socket.remoteAddress;
 }
+
+
+export function distanceBetweenLocations(loc1: any, loc2: any): number {
+	return distanceBetweenCoords(loc1.latitude, loc1.longitude, loc2.latitude, loc2.longitude);
+}
+
+//Haversine function
+function distanceBetweenCoords(lat1: number, lon1: number, lat2: number, lon2: number) {
+	const p = 0.017453292519943295;    // Math.PI / 180
+	const c = Math.cos;
+	const a = 0.5 - c((lat2 - lat1) * p) / 2 +
+		c(lat1 * p) * c(lat2 * p) *
+		(1 - c((lon2 - lon1) * p)) / 2;
+
+	return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
+}
\ No newline at end of file