fix(striker-ui-api): migrate a/dbWrite to daemon write

main
Tsu-ba-me 2 years ago
parent dc4a49a94c
commit da785218ec
  1. 96
      striker-ui-api/src/lib/accessModule.ts
  2. 20
      striker-ui-api/src/lib/request_handlers/user/deleteUser.ts
  3. 18
      striker-ui-api/src/passport.ts
  4. 16
      striker-ui-api/src/routes/file.ts
  5. 141
      striker-ui-api/src/session.ts

@ -11,7 +11,6 @@ import { readFileSync } from 'fs';
import { SERVER_PATHS, PGID, PUID } from './consts'; import { SERVER_PATHS, PGID, PUID } from './consts';
import { formatSql } from './formatSql'; import { formatSql } from './formatSql';
import { isObject } from './isObject';
import { import {
date, date,
stderr as sherr, stderr as sherr,
@ -140,52 +139,16 @@ class Access extends EventEmitter {
const access = new Access(); const access = new Access();
const asyncAnvilAccessModule = ( const query = <T extends (number | null | string)[][]>(script: string) =>
args: string[], access.interact<T>('r', formatSql(script));
{
onClose, const write = async (script: string) => {
onError, const { write_code: wcode } = await access.interact<{ write_code: number }>(
stdio = 'pipe', 'w',
timeout = 60000, formatSql(script),
...restSpawnOptions );
}: AsyncAnvilAccessModuleOptions = {},
) => { return wcode;
const ps = spawn(SERVER_PATHS.usr.sbin['anvil-access-module'].self, args, {
stdio,
timeout,
...restSpawnOptions,
});
let stderr = '';
let stdout = '';
ps.once('close', (ecode, signal) => {
let output;
try {
output = JSON.parse(stdout);
} catch (stdoutParseError) {
output = stdout;
sherr(
`Failed to parse async anvil-access-module stdout; CAUSE: ${stdoutParseError}`,
);
}
onClose?.call(null, { ecode, signal, stderr, stdout: output });
});
ps.once('error', (...args) => {
onError?.call(null, ...args);
});
ps.stderr?.setEncoding('utf-8').on('data', (data) => {
stderr += data;
});
ps.stdout?.setEncoding('utf-8').on('data', (data) => {
stdout += data;
});
}; };
const execAnvilAccessModule = ( const execAnvilAccessModule = (
@ -304,9 +267,6 @@ const dbJobAnvilSyncShared = (
return dbInsertOrUpdateJob(subParams); return dbInsertOrUpdateJob(subParams);
}; };
const query = <T extends (number | null | string)[][]>(sqlscript: string) =>
access.interact<T>('r', formatSql(sqlscript));
const dbSubRefreshTimestamp = () => { const dbSubRefreshTimestamp = () => {
let result: string; let result: string;
@ -321,39 +281,6 @@ const dbSubRefreshTimestamp = () => {
return result; return result;
}; };
const awrite = (
script: string,
{ onClose: initOnClose, ...restOptions }: AsyncDatabaseWriteOptions = {},
) => {
shout(formatSql(script));
const onClose: AsyncAnvilAccessModuleCloseHandler = (args, ...rest) => {
const { stdout } = args;
const { obj: output } = isObject(stdout);
let wcode: number | null = null;
if ('write_code' in output) {
({ write_code: wcode } = output as { write_code: number });
shout(`Async write completed with write_code=${wcode}`);
}
initOnClose?.call(null, { wcode, ...args }, ...rest);
};
return asyncAnvilAccessModule(['--query', script, '--mode', 'write'], {
onClose,
...restOptions,
});
};
const dbWrite = (script: string, options?: SpawnSyncOptions) => {
shout(formatSql(script));
return execAnvilAccessModule(['--query', script, '--mode', 'write'], options);
};
const getAnvilData = <HashType>( const getAnvilData = <HashType>(
dataStruct: AnvilDataStruct, dataStruct: AnvilDataStruct,
{ predata, ...spawnSyncOptions }: GetAnvilDataOptions = {}, { predata, ...spawnSyncOptions }: GetAnvilDataOptions = {},
@ -430,16 +357,15 @@ const getPeerData: GetPeerDataFunction = (
}; };
export { export {
awrite,
dbInsertOrUpdateJob as job, dbInsertOrUpdateJob as job,
dbInsertOrUpdateVariable as variable, dbInsertOrUpdateVariable as variable,
dbJobAnvilSyncShared, dbJobAnvilSyncShared,
dbSubRefreshTimestamp as timestamp, dbSubRefreshTimestamp as timestamp,
dbWrite,
execModuleSubroutine as sub, execModuleSubroutine as sub,
getAnvilData, getAnvilData,
getLocalHostName, getLocalHostName,
getLocalHostUUID, getLocalHostUUID,
getPeerData, getPeerData,
query, query,
write,
}; };

@ -3,7 +3,7 @@ import { RequestHandler } from 'express';
import { DELETED, REP_UUID } from '../../consts'; import { DELETED, REP_UUID } from '../../consts';
import { awrite } from '../../accessModule'; import { write } from '../../accessModule';
import join from '../../join'; import join from '../../join';
import { sanitize } from '../../sanitize'; import { sanitize } from '../../sanitize';
import { stderr, stdoutVar } from '../../shell'; import { stderr, stdoutVar } from '../../shell';
@ -12,7 +12,7 @@ export const deleteUser: RequestHandler<
DeleteUserParamsDictionary, DeleteUserParamsDictionary,
undefined, undefined,
DeleteUserRequestBody DeleteUserRequestBody
> = (request, response) => { > = async (request, response) => {
const { const {
body: { uuids: rawUserUuidList } = {}, body: { uuids: rawUserUuidList } = {},
params: { userUuid }, params: { userUuid },
@ -42,23 +42,13 @@ export const deleteUser: RequestHandler<
} }
try { try {
awrite( const wcode = await write(
`UPDATE users `UPDATE users
SET user_algorithm = '${DELETED}' SET user_algorithm = '${DELETED}'
WHERE user_uuid IN (${join(ulist)});`, WHERE user_uuid IN (${join(ulist)});`,
{
onClose: ({ ecode, wcode }) => {
if (ecode !== 0 || wcode !== 0) {
stderr(
`SQL script failed in delete user(s); ecode=${ecode}, wcode=${wcode}`,
);
}
},
onError: (error) => {
stderr(`Delete user subprocess error; CAUSE: ${error}`);
},
},
); );
assert(wcode === 0, `Write exited with code ${wcode}`);
} catch (error) { } catch (error) {
stderr(`Failed to delete user(s); CAUSE: ${error}`); stderr(`Failed to delete user(s); CAUSE: ${error}`);

@ -1,13 +1,15 @@
import passport from 'passport'; import passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local'; import { Strategy as LocalStrategy } from 'passport-local';
import { dbQuery, sub } from './lib/accessModule'; import { DELETED } from './lib/consts';
import { query, sub } from './lib/accessModule';
import { sanitize } from './lib/sanitize'; import { sanitize } from './lib/sanitize';
import { stdout } from './lib/shell'; import { stdout } from './lib/shell';
passport.use( passport.use(
'login', 'login',
new LocalStrategy((username, password, done) => { new LocalStrategy(async (username, password, done) => {
stdout(`Attempting passport local strategy "login" for user [${username}]`); stdout(`Attempting passport local strategy "login" for user [${username}]`);
let rows: [ let rows: [
@ -20,7 +22,7 @@ passport.use(
][]; ][];
try { try {
rows = dbQuery( rows = await query(
`SELECT `SELECT
user_uuid, user_uuid,
user_name, user_name,
@ -32,7 +34,7 @@ passport.use(
WHERE user_algorithm != 'DELETED' WHERE user_algorithm != 'DELETED'
AND user_name = '${username}' AND user_name = '${username}'
LIMIT 1;`, LIMIT 1;`,
).stdout; );
} catch (queryError) { } catch (queryError) {
return done(queryError); return done(queryError);
} }
@ -89,7 +91,7 @@ passport.serializeUser((user, done) => {
return done(null, uuid); return done(null, uuid);
}); });
passport.deserializeUser((id, done) => { passport.deserializeUser(async (id, done) => {
const uuid = sanitize(id, 'string', { modifierType: 'sql' }); const uuid = sanitize(id, 'string', { modifierType: 'sql' });
stdout(`Deserialize user identified by ${uuid}`); stdout(`Deserialize user identified by ${uuid}`);
@ -97,12 +99,12 @@ passport.deserializeUser((id, done) => {
let rows: [userName: string][]; let rows: [userName: string][];
try { try {
rows = dbQuery( rows = await query(
`SELECT user_name `SELECT user_name
FROM users FROM users
WHERE user_algorithm != 'DELETED' WHERE user_algorithm != '${DELETED}'
AND user_uuid = '${uuid}';`, AND user_uuid = '${uuid}';`,
).stdout; );
} catch (error) { } catch (error) {
return done(error); return done(error);
} }

@ -5,8 +5,8 @@ import { DELETED } from '../lib/consts';
import { import {
dbJobAnvilSyncShared, dbJobAnvilSyncShared,
timestamp, timestamp,
dbWrite,
query, query,
write,
} from '../lib/accessModule'; } from '../lib/accessModule';
import getFile from '../lib/request_handlers/file/getFile'; import getFile from '../lib/request_handlers/file/getFile';
import getFileDetail from '../lib/request_handlers/file/getFileDetail'; import getFileDetail from '../lib/request_handlers/file/getFileDetail';
@ -24,13 +24,13 @@ router
); );
if (oldFileType !== DELETED) { if (oldFileType !== DELETED) {
dbWrite( await write(
`UPDATE files `UPDATE files
SET SET
file_type = '${DELETED}', file_type = '${DELETED}',
modified_date = '${timestamp()}' modified_date = '${timestamp()}'
WHERE file_uuid = '${fileUUID}';`, WHERE file_uuid = '${fileUUID}';`,
).stdout; );
dbJobAnvilSyncShared('purge', `file_uuid=${fileUUID}`, '0136', '0137', { dbJobAnvilSyncShared('purge', `file_uuid=${fileUUID}`, '0136', '0137', {
jobHostUUID: 'all', jobHostUUID: 'all',
@ -174,25 +174,21 @@ router
); );
} }
stdout(`Query (type=[${typeof sqlscript}]): [${sqlscript}]`); let wcode: number;
let queryStdout;
try { try {
({ stdout: queryStdout } = dbWrite(sqlscript)); wcode = await write(sqlscript);
} catch (queryError) { } catch (queryError) {
stderr(`Failed to execute query; CAUSE: ${queryError}`); stderr(`Failed to execute query; CAUSE: ${queryError}`);
return response.status(500).send(); return response.status(500).send();
} }
stdoutVar(queryStdout, `Query stdout (type=[${typeof queryStdout}]): `);
anvilSyncSharedFunctions.forEach((fn, index) => anvilSyncSharedFunctions.forEach((fn, index) =>
stdoutVar(fn(), `Anvil sync shared [${index}] output: `), stdoutVar(fn(), `Anvil sync shared [${index}] output: `),
); );
response.status(200).send(queryStdout); response.status(200).send(wcode);
}); });
export default router; export default router;

@ -1,16 +1,14 @@
import assert from 'assert';
import expressSession, { import expressSession, {
SessionData, SessionData,
Store as BaseSessionStore, Store as BaseSessionStore,
} from 'express-session'; } from 'express-session';
import { import { DELETED } from './lib/consts';
awrite,
dbQuery, import { getLocalHostUUID, query, timestamp, write } from './lib/accessModule';
getLocalHostUUID,
timestamp,
} from './lib/accessModule';
import { getSessionSecret } from './lib/getSessionSecret'; import { getSessionSecret } from './lib/getSessionSecret';
import { stderr, stdout, stdoutVar, uuidgen } from './lib/shell'; import { stderr, stdout, stdoutVar, uuid } from './lib/shell';
const DEFAULT_COOKIE_ORIGINAL_MAX_AGE = 3600000; const DEFAULT_COOKIE_ORIGINAL_MAX_AGE = 3600000;
@ -19,38 +17,33 @@ export class SessionStore extends BaseSessionStore {
super(options); super(options);
} }
public destroy( public async destroy(
sid: string, sid: string,
done?: ((err?: unknown) => void) | undefined, done?: ((err?: unknown) => void) | undefined,
): void { ): Promise<void> {
stdout(`Destroy session ${sid}`); stdout(`Destroy session ${sid}`);
try { try {
awrite(`DELETE FROM sessions WHERE session_uuid = '${sid}';`, { const wcode = await write(
onClose({ wcode }) { `UPDATE sessions SET session_salt = '${DELETED}' WHERE session_uuid = '${sid}';`,
if (wcode !== 0) { );
stderr(
`SQL script failed during destroy session ${sid}; code: ${wcode}`, assert(wcode === 0, `Write exited with code ${wcode}`);
);
}
},
onError(error) {
stderr(
`Failed to complete DB write in destroy session ${sid}; CAUSE: ${error}`,
);
},
});
} catch (error) { } catch (error) {
stderr(
`Failed to complete DB write in destroy session ${sid}; CAUSE: ${error}`,
);
return done?.call(null, error); return done?.call(null, error);
} }
return done?.call(null); return done?.call(null);
} }
public get( public async get(
sid: string, sid: string,
done: (err: unknown, session?: SessionData | null | undefined) => void, done: (err: unknown, session?: SessionData | null | undefined) => void,
): void { ): Promise<void> {
stdout(`Get session ${sid}`); stdout(`Get session ${sid}`);
let rows: [ let rows: [
@ -60,7 +53,7 @@ export class SessionStore extends BaseSessionStore {
][]; ][];
try { try {
rows = dbQuery( rows = await query(
`SELECT `SELECT
s.session_uuid, s.session_uuid,
u.user_uuid, u.user_uuid,
@ -69,7 +62,7 @@ export class SessionStore extends BaseSessionStore {
JOIN users AS u JOIN users AS u
ON s.session_user_uuid = u.user_uuid ON s.session_user_uuid = u.user_uuid
WHERE s.session_uuid = '${sid}';`, WHERE s.session_uuid = '${sid}';`,
).stdout; );
} catch (queryError) { } catch (queryError) {
return done(queryError); return done(queryError);
} }
@ -90,20 +83,18 @@ export class SessionStore extends BaseSessionStore {
maxAge: cookieMaxAge, maxAge: cookieMaxAge,
originalMaxAge: DEFAULT_COOKIE_ORIGINAL_MAX_AGE, originalMaxAge: DEFAULT_COOKIE_ORIGINAL_MAX_AGE,
}, },
passport: { passport: { user: userUuid },
user: userUuid,
},
}; };
return done(null, data); return done(null, data);
} }
public set( public async set(
sid: string, sid: string,
session: SessionData, session: SessionData,
done?: ((err?: unknown) => void) | undefined, done?: ((err?: unknown) => void) | undefined,
): void { ): Promise<void> {
stdout(`Set session ${sid}`); stdoutVar({ session }, `Set session ${sid}`);
const { const {
passport: { user: userUuid }, passport: { user: userUuid },
@ -113,7 +104,7 @@ export class SessionStore extends BaseSessionStore {
const localHostUuid = getLocalHostUUID(); const localHostUuid = getLocalHostUUID();
const modifiedDate = timestamp(); const modifiedDate = timestamp();
awrite( const wcode = await write(
`INSERT INTO `INSERT INTO
sessions ( sessions (
session_uuid, session_uuid,
@ -131,56 +122,39 @@ export class SessionStore extends BaseSessionStore {
'${modifiedDate}' '${modifiedDate}'
) )
ON CONFLICT (session_uuid) ON CONFLICT (session_uuid)
DO UPDATE SET session_host_uuid = '${localHostUuid}', DO UPDATE SET modified_date = '${modifiedDate}';`,
modified_date = '${modifiedDate}';`,
{
onClose: ({ wcode }) => {
if (wcode !== 0) {
stderr(
`SQL script failed during set session ${sid}; code: ${wcode}`,
);
}
},
onError: (error) => {
stderr(
`Failed to complete DB write in set session ${sid}; CAUSE: ${error}`,
);
},
},
); );
assert(wcode === 0, `Write exited with code ${wcode}`);
} catch (error) { } catch (error) {
stderr(
`Failed to complete DB write in set session ${sid}; CAUSE: ${error}`,
);
return done?.call(null, error); return done?.call(null, error);
} }
return done?.call(null); return done?.call(null);
} }
public touch( public async touch(
sid: string, sid: string,
session: SessionData, session: SessionData,
done?: ((err?: unknown) => void) | undefined, done?: ((err?: unknown) => void) | undefined,
): void { ): Promise<void> {
stdout(`Touch session ${sid}`); stdoutVar({ session }, `Touch session ${sid}`);
try { try {
awrite( const wcode = await write(
`UPDATE sessions SET modified_date = '${timestamp()}' WHERE session_uuid = '${sid}';`, `UPDATE sessions SET modified_date = '${timestamp()}' WHERE session_uuid = '${sid}';`,
{
onClose: ({ wcode }) => {
if (wcode !== 0) {
stderr(
`SQL script failed during touch session ${sid}; code: ${wcode}`,
);
}
},
onError: (error) => {
stderr(
`Failed to complete DB write in touch session ${sid}; CAUSE: ${error}`,
);
},
},
); );
assert(wcode === 0, `Write exited with code ${wcode}`);
} catch (error) { } catch (error) {
stderr(
`Failed to complete DB write in touch session ${sid}; CAUSE: ${error}`,
);
return done?.call(null, error); return done?.call(null, error);
} }
@ -201,19 +175,18 @@ export class SessionStore extends BaseSessionStore {
} }
} }
const session = expressSession({ export default (async () =>
cookie: { maxAge: DEFAULT_COOKIE_ORIGINAL_MAX_AGE }, expressSession({
genid: ({ path }) => { cookie: { maxAge: DEFAULT_COOKIE_ORIGINAL_MAX_AGE },
const sid = uuidgen('--random').trim(); genid: ({ path }) => {
const sid = uuid();
stdout(`Generated session identifier ${sid}; request.path=${path}`);
stdout(`Generated session identifier ${sid}; request.path=${path}`);
return sid;
}, return sid;
resave: false, },
saveUninitialized: false, resave: false,
secret: getSessionSecret(), saveUninitialized: false,
store: new SessionStore(), secret: await getSessionSecret(),
}); store: new SessionStore(),
}))();
export default session;

Loading…
Cancel
Save