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 net from 'net';
|
||||
|
||||
import express, {Express} from 'express';
|
||||
import http, {ServerResponse} from 'http';
|
||||
import path from 'path';
|
||||
@@ -16,7 +16,8 @@ import fs from 'fs-extra';
|
||||
import {VerifyClientCallbackSync, WebSocketServer} from 'ws';
|
||||
import {WEBSOCKET_MAX_MESSAGE_SIZE} from 'flipper-server-core';
|
||||
import {parse} from 'url';
|
||||
import xdgBasedir from 'xdg-basedir';
|
||||
import {makeSocketPath, checkSocketInUse} from './utilities';
|
||||
|
||||
import proxy from 'http-proxy';
|
||||
import exitHook from 'exit-hook';
|
||||
|
||||
@@ -78,66 +79,6 @@ async function startHTTPServer(
|
||||
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.
|
||||
* @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