Refactor checks to see if socket is in use
Summary: These are utility methods that are not specific to startServer. They will be reused by other components needing to check if something is listening to a port. Make socket path is also extracted. Reviewed By: passy Differential Revision: D36473641 fbshipit-source-id: 73ed67912052896696b59670cb757d22761eeaa1
This commit is contained in:
committed by
Facebook GitHub Bot
parent
4f7dd3b5eb
commit
2fe7e73175
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import net from 'net';
|
|
||||||
import express, {Express} from 'express';
|
import express, {Express} from 'express';
|
||||||
import http, {ServerResponse} from 'http';
|
import http, {ServerResponse} from 'http';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
@@ -16,7 +16,8 @@ import fs from 'fs-extra';
|
|||||||
import {VerifyClientCallbackSync, WebSocketServer} from 'ws';
|
import {VerifyClientCallbackSync, WebSocketServer} from 'ws';
|
||||||
import {WEBSOCKET_MAX_MESSAGE_SIZE} from 'flipper-server-core';
|
import {WEBSOCKET_MAX_MESSAGE_SIZE} from 'flipper-server-core';
|
||||||
import {parse} from 'url';
|
import {parse} from 'url';
|
||||||
import xdgBasedir from 'xdg-basedir';
|
import {makeSocketPath, checkSocketInUse} from './utilities';
|
||||||
|
|
||||||
import proxy from 'http-proxy';
|
import proxy from 'http-proxy';
|
||||||
import exitHook from 'exit-hook';
|
import exitHook from 'exit-hook';
|
||||||
|
|
||||||
@@ -78,66 +79,6 @@ async function startHTTPServer(
|
|||||||
return startProxyServer(config, app);
|
return startProxyServer(config, app);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a socket is in used for given path.
|
|
||||||
* If the path doesn't exist then is not in use. If it does,
|
|
||||||
* create a socket client and attempt to connect to it.
|
|
||||||
* If the connection is established, then there's a process
|
|
||||||
* already listening. Otherwise, it kind of indicates the
|
|
||||||
* contrary.
|
|
||||||
* @param path Path used instead of port number.
|
|
||||||
* @returns True or false dependning on whether the socket is in
|
|
||||||
* use or not.
|
|
||||||
*/
|
|
||||||
async function checkSocketInUse(path: string): Promise<boolean> {
|
|
||||||
if (!(await fs.pathExists(path))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return new Promise((resolve, _reject) => {
|
|
||||||
const client = net
|
|
||||||
.createConnection(path, () => {
|
|
||||||
resolve(true);
|
|
||||||
client.destroy();
|
|
||||||
})
|
|
||||||
.on('error', (e) => {
|
|
||||||
if (e.message.includes('ECONNREFUSED')) {
|
|
||||||
resolve(false);
|
|
||||||
} else {
|
|
||||||
console.warn(
|
|
||||||
`[conn] Socket ${path} is in use, but we don't know why.`,
|
|
||||||
e,
|
|
||||||
);
|
|
||||||
resolve(false);
|
|
||||||
}
|
|
||||||
client.destroy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a socket path. Used to open the socket at location.
|
|
||||||
* Format: flipper-server-${userInfo}.sock
|
|
||||||
* @returns The created socket path.
|
|
||||||
*/
|
|
||||||
async function makeSocketPath(): Promise<string> {
|
|
||||||
const runtimeDir = xdgBasedir.runtime || '/tmp';
|
|
||||||
await fs.mkdirp(runtimeDir);
|
|
||||||
const filename = `flipper-server-${os.userInfo().uid}.sock`;
|
|
||||||
const path = `${runtimeDir}/${filename}`;
|
|
||||||
|
|
||||||
// Depending on the OS this is between 104 and 108:
|
|
||||||
// https://unix.stackexchange.com/a/367012/10198
|
|
||||||
if (path.length >= 104) {
|
|
||||||
console.warn(
|
|
||||||
'Ignoring XDG_RUNTIME_DIR as it would exceed the total limit for domain socket paths. See man 7 unix.',
|
|
||||||
);
|
|
||||||
// Even with the INT32_MAX userid, we should have plenty of room.
|
|
||||||
return `/tmp/${filename}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and starts the HTTP and proxy servers.
|
* Creates and starts the HTTP and proxy servers.
|
||||||
* @param config Server configuration.
|
* @param config Server configuration.
|
||||||
|
|||||||
73
desktop/flipper-server/src/utilities.tsx
Normal file
73
desktop/flipper-server/src/utilities.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
|
||||||
|
import os from 'os';
|
||||||
|
import xdgBasedir from 'xdg-basedir';
|
||||||
|
import net from 'net';
|
||||||
|
import fs from 'fs-extra';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a socket is in used for given path.
|
||||||
|
* If the path doesn't exist then is not in use. If it does,
|
||||||
|
* create a socket client and attempt to connect to it.
|
||||||
|
* If the connection is established, then there's a process
|
||||||
|
* already listening. Otherwise, it kind of indicates the
|
||||||
|
* contrary.
|
||||||
|
* @param path Path used instead of port number.
|
||||||
|
* @returns True or false dependning on whether the socket is in
|
||||||
|
* use or not.
|
||||||
|
*/
|
||||||
|
export async function checkSocketInUse(path: string): Promise<boolean> {
|
||||||
|
if (!(await fs.pathExists(path))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return new Promise((resolve, _reject) => {
|
||||||
|
const client = net
|
||||||
|
.createConnection(path, () => {
|
||||||
|
resolve(true);
|
||||||
|
client.destroy();
|
||||||
|
})
|
||||||
|
.on('error', (e) => {
|
||||||
|
if (e.message.includes('ECONNREFUSED')) {
|
||||||
|
resolve(false);
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
`[conn] Socket ${path} is in use, but we don't know why.`,
|
||||||
|
e,
|
||||||
|
);
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
client.destroy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a socket path. Used to open the socket at location.
|
||||||
|
* Format: flipper-server-${userInfo}.sock
|
||||||
|
* @returns The created socket path.
|
||||||
|
*/
|
||||||
|
export async function makeSocketPath(): Promise<string> {
|
||||||
|
const runtimeDir = xdgBasedir.runtime || '/tmp';
|
||||||
|
await fs.mkdirp(runtimeDir);
|
||||||
|
const filename = `flipper-server-${os.userInfo().uid}.sock`;
|
||||||
|
const path = `${runtimeDir}/${filename}`;
|
||||||
|
|
||||||
|
// Depending on the OS this is between 104 and 108:
|
||||||
|
// https://unix.stackexchange.com/a/367012/10198
|
||||||
|
if (path.length >= 104) {
|
||||||
|
console.warn(
|
||||||
|
'Ignoring XDG_RUNTIME_DIR as it would exceed the total limit for domain socket paths. See man 7 unix.',
|
||||||
|
);
|
||||||
|
// Even with the INT32_MAX userid, we should have plenty of room.
|
||||||
|
return `/tmp/${filename}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user