Save worktree changes
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
const crypto = require('crypto');
|
||||
|
||||
function normalizeClientName(value) {
|
||||
return String(value || '').trim();
|
||||
}
|
||||
|
||||
function normalizeDeviceId(value) {
|
||||
return String(value || '').trim().replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 128);
|
||||
}
|
||||
|
||||
function collectLiveConnections(liveConnections) {
|
||||
return Array.isArray(liveConnections) ? liveConnections : [];
|
||||
}
|
||||
|
||||
async function isClientNameAvailable(pool, clientName, excludeDeviceId, liveConnections) {
|
||||
const normalizedName = normalizeClientName(clientName);
|
||||
if (!normalizedName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalizedDeviceId = normalizeDeviceId(excludeDeviceId);
|
||||
const live = collectLiveConnections(liveConnections);
|
||||
const lowerName = normalizedName.toLowerCase();
|
||||
|
||||
try {
|
||||
if (pool) {
|
||||
const [deviceRows] = await pool.query(
|
||||
`SELECT device_id
|
||||
FROM player_onboarding_devices
|
||||
WHERE client_name IS NOT NULL
|
||||
AND TRIM(client_name) <> ''
|
||||
AND LOWER(TRIM(client_name)) = LOWER(TRIM(?))
|
||||
AND device_id <> ?
|
||||
LIMIT 1`,
|
||||
[normalizedName, normalizedDeviceId]
|
||||
);
|
||||
|
||||
if (deviceRows.length) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const connection of live) {
|
||||
const existingName = normalizeClientName(connection && connection.clientName ? connection.clientName : '');
|
||||
if (!existingName || existingName.toLowerCase() !== lowerName) {
|
||||
continue;
|
||||
}
|
||||
const existingDeviceId = normalizeDeviceId(connection && (connection.deviceId || connection.clientId) ? (connection.deviceId || connection.clientId) : '');
|
||||
if (normalizedDeviceId && existingDeviceId && existingDeviceId === normalizedDeviceId) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (_error) {
|
||||
for (const connection of live) {
|
||||
const existingName = normalizeClientName(connection && connection.clientName ? connection.clientName : '');
|
||||
if (!existingName || existingName.toLowerCase() !== lowerName) {
|
||||
continue;
|
||||
}
|
||||
const existingDeviceId = normalizeDeviceId(connection && (connection.deviceId || connection.clientId) ? (connection.deviceId || connection.clientId) : '');
|
||||
if (normalizedDeviceId && existingDeviceId && existingDeviceId === normalizedDeviceId) {
|
||||
continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function buildClientNameLockName(clientName) {
|
||||
return `ps_client_name_${crypto.createHash('sha1').update(String(clientName || '').trim().toLowerCase()).digest('hex')}`;
|
||||
}
|
||||
|
||||
async function withClientNameReservation(pool, clientName, handler) {
|
||||
if (!pool || typeof pool.getConnection !== 'function') {
|
||||
return handler();
|
||||
}
|
||||
|
||||
const normalizedName = normalizeClientName(clientName);
|
||||
if (!normalizedName) {
|
||||
return handler();
|
||||
}
|
||||
|
||||
const connection = await pool.getConnection();
|
||||
const lockName = buildClientNameLockName(normalizedName);
|
||||
let lockAcquired = false;
|
||||
|
||||
try {
|
||||
const [lockRows] = await connection.query('SELECT GET_LOCK(?, 5) AS lock_result', [lockName]);
|
||||
const lockResult = lockRows && lockRows[0] ? Number(lockRows[0].lock_result) : 0;
|
||||
if (lockResult !== 1) {
|
||||
const error = new Error('Client name is busy. Please try again.');
|
||||
error.statusCode = 409;
|
||||
throw error;
|
||||
}
|
||||
|
||||
lockAcquired = true;
|
||||
return await handler();
|
||||
} finally {
|
||||
if (lockAcquired) {
|
||||
try {
|
||||
await connection.query('SELECT RELEASE_LOCK(?)', [lockName]);
|
||||
} catch (_error) {}
|
||||
}
|
||||
connection.release();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
normalizeClientName: normalizeClientName,
|
||||
normalizeDeviceId: normalizeDeviceId,
|
||||
collectLiveConnections: collectLiveConnections,
|
||||
isClientNameAvailable: isClientNameAvailable,
|
||||
withClientNameReservation: withClientNameReservation
|
||||
};
|
||||
Reference in New Issue
Block a user