fix: Improvements; Add prettier; Improve timeouts

This commit is contained in:
Myzel394 2024-11-06 14:15:10 +01:00
parent c60913b796
commit cb34b81209
No known key found for this signature in database
GPG Key ID: ED20A1D1D423AF3F
10 changed files with 139 additions and 101 deletions

2
.gitignore vendored
View File

@ -1,2 +1,4 @@
# deps # deps
node_modules/ node_modules/
debug.log

7
.prettierrc.json Normal file
View File

@ -0,0 +1,7 @@
{
"tabWidth": 4,
"useTabs": true,
"singleQuote": false,
"trailingComma": "all",
"arrowParens": "avoid"
}

View File

@ -1,9 +1,11 @@
To install dependencies: To install dependencies:
```sh ```sh
bun install bun install
``` ```
To run: To run:
```sh ```sh
bun run dev bun run dev
``` ```

BIN
bun.lockb

Binary file not shown.

View File

@ -1,7 +1,8 @@
{ {
"name": "amiopen", "name": "amiopen",
"scripts": { "scripts": {
"dev": "bun run --hot src/index.ts" "dev": "bun run --hot src/index.ts",
"prettier": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"hono": "^4.6.9", "hono": "^4.6.9",
@ -10,6 +11,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "latest", "@types/bun": "latest",
"@types/ip": "^1.1.3" "@types/ip": "^1.1.3",
"prettier": "^3.3.3"
} }
} }

View File

@ -1,11 +1,8 @@
import { Hono } from 'hono' import { Hono } from "hono";
import { portRoute } from './routes/port' import { portRoute } from "./routes/port";
const app = new Hono() const app = new Hono();
app.route( app.route("/", portRoute);
"/",
portRoute,
)
export default app export default app;

View File

@ -2,34 +2,55 @@ import { Hono } from "hono";
import { getConnInfo } from "hono/bun"; import { getConnInfo } from "hono/bun";
import connectToAddress from "../utils/connect-to-address"; import connectToAddress from "../utils/connect-to-address";
import { z } from "zod"; import { z } from "zod";
import * as IP from "ip" import * as IP from "ip";
export const portRoute = new Hono(); export const portRoute = new Hono();
const schema = z.object({ const schema = z.object({
ip: z.string().refine(ip => IP.isPublic(ip), "This IP address is not valid"), ip: z
port: z.string().transform(Number).pipe(z.number().min(1).max(2**16 - 1)), .string()
.refine(ip => IP.isPublic(ip), "This IP address is not valid"),
port: z
.string()
.transform(Number)
.pipe(
z
.number()
.min(1)
.max(2 ** 16 - 1),
),
timeout: z
.string()
.optional()
.transform(val => (val === undefined ? 5_000 : Number(val)))
.pipe(z.number().min(1_000).max(60_000)),
}); });
portRoute.get("/:port", async context => { portRoute.get("/:port", async context => {
const info = getConnInfo(context) const info = getConnInfo(context);
const rawData = { const rawData = {
ip: info.remote.address || "", ip: info.remote.address || "",
port: context.req.param("port"), port: context.req.param("port"),
timeout: context.req.query("timeout") || "",
}; };
const parsedData = schema.safeParse(rawData); const parsedData = schema.safeParse(rawData);
if (!parsedData.success) { if (!parsedData.success) {
return context.json({ error: parsedData.error }, 401); return context.json(
{
error: parsedData.error,
},
401,
);
} }
const { ip, port } = parsedData.data; const { ip, port } = parsedData.data;
const result = await connectToAddress(ip, port) const result = await connectToAddress(ip, port);
return context.json({ return context.json({
isOpen: result.isOpen isOpen: result.isOpen,
}) });
}); });
portRoute.get("/:ip/:port", async context => { portRoute.get("/:ip/:port", async context => {
@ -40,14 +61,19 @@ portRoute.get("/:ip/:port", async context => {
const parsedData = schema.safeParse(rawData); const parsedData = schema.safeParse(rawData);
if (!parsedData.success) { if (!parsedData.success) {
return context.json({ error: parsedData.error }, 401); return context.json(
{
error: parsedData.error,
},
401,
);
} }
const { ip, port } = parsedData.data; const { ip, port } = parsedData.data;
const result = await connectToAddress(ip, port) const result = await connectToAddress(ip, port);
return context.json({ return context.json({
isOpen: result.isOpen isOpen: result.isOpen,
}) });
}) });

View File

@ -1,54 +1,57 @@
import * as net from "net" import * as net from "net";
export interface ConnectionResult { export interface ConnectionResult {
isOpen: boolean isOpen: boolean;
} }
const TIMEOUT = 5_000 const TIMEOUT = 5_000;
export default function connectToAddress(address: string, port: number): Promise<ConnectionResult> { export default function connectToAddress(
return new Promise<ConnectionResult>(async (resolve) => { address: string,
port: number,
): Promise<ConnectionResult> {
return new Promise<ConnectionResult>(async resolve => {
const onIsOpen = () => { const onIsOpen = () => {
if (!socket.destroyed) { if (!socket.destroyed) {
socket.end() socket.end();
socket.destroy() socket.destroy();
} }
resolve({ resolve({
isOpen: true isOpen: true,
}) });
} };
const onIsClosed = () => { const onIsClosed = () => {
if (!socket.destroyed) { if (!socket.destroyed) {
socket.end() socket.end();
socket.destroy() socket.destroy();
} }
resolve({ resolve({
isOpen: false isOpen: false,
}) });
} };
const socket = new net.Socket() const socket = new net.Socket();
// The `setTimeout` function from a socket does not work when connecting, // The `setTimeout` function from a socket does not work when connecting,
// so we need to use a custom timeout function ourselves. // so we need to use a custom timeout function ourselves.
setTimeout(() => { setTimeout(() => {
if (!socket.destroyed) { if (!socket.destroyed) {
socket.end() socket.end();
socket.destroy() socket.destroy();
} }
resolve({ resolve({
isOpen: false isOpen: false,
}) });
}, TIMEOUT) }, TIMEOUT);
socket.on("ready", onIsOpen) socket.on("ready", onIsOpen);
socket.on("close", onIsClosed) socket.on("close", onIsClosed);
socket.on("error", onIsClosed) socket.on("error", onIsClosed);
socket.on("timeout", onIsClosed) socket.on("timeout", onIsClosed);
socket.connect(port, address) socket.connect(port, address);
}) });
} }

View File

@ -1,4 +1,3 @@
export default function timeout(ms: number): Promise<void> { export default function timeout(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms)) return new Promise(resolve => setTimeout(resolve, ms));
} }