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 { formatSql } from './formatSql';
import { isObject } from './isObject';
import {
date,
stderr as sherr,
@ -140,52 +139,16 @@ class Access extends EventEmitter {
const access = new Access();
const asyncAnvilAccessModule = (
args: string[],
{
onClose,
onError,
stdio = 'pipe',
timeout = 60000,
...restSpawnOptions
}: AsyncAnvilAccessModuleOptions = {},
) => {
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 query = <T extends (number | null | string)[][]>(script: string) =>
access.interact<T>('r', formatSql(script));
const write = async (script: string) => {
const { write_code: wcode } = await access.interact<{ write_code: number }>(
'w',
formatSql(script),
);
return wcode;
};
const execAnvilAccessModule = (
@ -304,9 +267,6 @@ const dbJobAnvilSyncShared = (
return dbInsertOrUpdateJob(subParams);
};
const query = <T extends (number | null | string)[][]>(sqlscript: string) =>
access.interact<T>('r', formatSql(sqlscript));
const dbSubRefreshTimestamp = () => {
let result: string;
@ -321,39 +281,6 @@ const dbSubRefreshTimestamp = () => {
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>(
dataStruct: AnvilDataStruct,
{ predata, ...spawnSyncOptions }: GetAnvilDataOptions = {},
@ -430,16 +357,15 @@ const getPeerData: GetPeerDataFunction = (
};
export {
awrite,
dbInsertOrUpdateJob as job,
dbInsertOrUpdateVariable as variable,
dbJobAnvilSyncShared,
dbSubRefreshTimestamp as timestamp,
dbWrite,
execModuleSubroutine as sub,
getAnvilData,
getLocalHostName,
getLocalHostUUID,
getPeerData,
query,
write,
};

@ -3,7 +3,7 @@ import { RequestHandler } from 'express';
import { DELETED, REP_UUID } from '../../consts';
import { awrite } from '../../accessModule';
import { write } from '../../accessModule';
import join from '../../join';
import { sanitize } from '../../sanitize';
import { stderr, stdoutVar } from '../../shell';
@ -12,7 +12,7 @@ export const deleteUser: RequestHandler<
DeleteUserParamsDictionary,
undefined,
DeleteUserRequestBody
> = (request, response) => {
> = async (request, response) => {
const {
body: { uuids: rawUserUuidList } = {},
params: { userUuid },
@ -42,23 +42,13 @@ export const deleteUser: RequestHandler<
}
try {
awrite(
const wcode = await write(
`UPDATE users
SET user_algorithm = '${DELETED}'
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) {
stderr(`Failed to delete user(s); CAUSE: ${error}`);

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

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

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

Loading…
Cancel
Save