dev: add monthly usage to new call method

This commit is contained in:
KernelDeimos 2024-07-25 22:09:24 -04:00 committed by Eric Dubé
parent 8be7a7d219
commit af3180a57f
2 changed files with 108 additions and 40 deletions

View File

@ -278,6 +278,8 @@ class DriverService extends BaseService {
console.log('EFFECTIVE', console.log('EFFECTIVE',
JSON.stringify(effective_policy, undefined, ' ')); JSON.stringify(effective_policy, undefined, ' '));
const method_key = `V1:${service_name}:${iface}:${method}`;
const invoker = Invoker.create({ const invoker = Invoker.create({
decorators: [ decorators: [
{ {
@ -296,6 +298,35 @@ class DriverService extends BaseService {
return args; return args;
}, },
}, },
{
name: 'enforce monthly usage limit',
on_call: async args => {
if ( ! effective_policy['monthly-limit'] ) return args;
const svc_monthlyUsage = services.get('monthly-usage');
const count = await svc_monthlyUsage.check_2(
actor, method_key
);
if ( count >= effective_policy['monthly-limit'] ) {
throw APIError.create('monthly_limit_exceeded', null, {
method_key,
limit: effective_policy['monthly-limit'],
});
}
return args;
},
on_return: async result => {
console.log('monthly usage is returning');
const svc_monthlyUsage = services.get('monthly-usage');
const extra = {
'driver.interface': iface,
'driver.implementation': service_name,
'driver.method': method,
};
console.log('calling the increment method')
await svc_monthlyUsage.increment(actor, method_key, extra);
return result;
},
},
{ {
name: 'add metadata', name: 'add metadata',
on_return: async result => { on_return: async result => {

View File

@ -34,47 +34,21 @@ class MonthlyUsageService extends BaseService {
const maybe_app_id = actor.type.app?.id; const maybe_app_id = actor.type.app?.id;
if ( this.db.case({ sqlite: true, otherwise: false }) ) {
return;
}
const vals =
[
year, month, key, actor.type.user.id, maybe_app_id, JSON.stringify(extra),
...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [] }),
]
// UPSERT increment count // UPSERT increment count
try { await this.db.write(
await this.db.write( 'INSERT INTO `service_usage_monthly` (`year`, `month`, `key`, `count`, `user_id`, `app_id`, `extra`) ' +
'INSERT INTO `service_usage_monthly` (`year`, `month`, `key`, `count`, `user_id`, `app_id`, `extra`) ' + 'VALUES (?, ?, ?, 1, ?, ?, ?) ' +
'VALUES (?, ?, ?, 1, ?, ?, ?) ' + this.db.case({
this.db.case({ mysql: 'ON DUPLICATE KEY UPDATE `count` = `count` + 1, `extra` = ?',
mysql: 'ON DUPLICATE KEY UPDATE `count` = `count` + 1, `extra` = ?', // sqlite: ' ',
sqlite: ' ', otherwise: 'ON CONFLICT(`year`, `month`, `key`) ' +
// sqlite: 'ON CONFLICT(`year`, `month`, `key`, `user_id`, `app_id`) ' + 'DO UPDATE SET `count` = `count` + 1, `extra` = ?',
// 'DO UPDATE SET `count` = `count` + 1 AND `extra` = ?', }),
}), [
[ year, month, key, actor.type.user.id, maybe_app_id ?? null, JSON.stringify(extra),
year, month, key, actor.type.user.id, maybe_app_id ?? null, JSON.stringify(extra), ...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [JSON.stringify({ a: 1 })] }),
...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [] }), ]
] );
);
} catch (e) {
// if ( e.code !== 'SQLITE_ERROR' && e.code !== 'SQLITE_CONSTRAINT_PRIMARYKEY' ) throw e;
// The "ON CONFLICT" clause isn't currently working.
await this.db.write(
'UPDATE `service_usage_monthly` ' +
'SET `count` = `count` + 1, `extra` = ? ' +
'WHERE `year` = ? AND `month` = ? AND `key` = ? ' +
'AND `user_id` = ? AND `app_id` = ?',
[
JSON.stringify(extra),
year, month, key, actor.type.user.id, maybe_app_id,
]
);
}
} }
async check (actor, specifiers) { async check (actor, specifiers) {
@ -88,6 +62,18 @@ class MonthlyUsageService extends BaseService {
} }
async check_2 (actor, key) {
key = `${actor.uid}:${key}`;
if ( actor.type instanceof UserActorType ) {
return await this._user_check_2(actor, key);
}
if ( actor.type instanceof AppUnderUserActorType ) {
return await this._app_under_user_check_2(actor, key);
}
}
async _user_check (actor, specifiers) { async _user_check (actor, specifiers) {
const year = new Date().getUTCFullYear(); const year = new Date().getUTCFullYear();
// months are zero-indexed by getUTCMonth, which could be confusing // months are zero-indexed by getUTCMonth, which could be confusing
@ -106,6 +92,36 @@ class MonthlyUsageService extends BaseService {
return rows[0]?.sum || 0; return rows[0]?.sum || 0;
} }
async _user_check_2 (actor, key) {
const year = new Date().getUTCFullYear();
// months are zero-indexed by getUTCMonth, which could be confusing
const month = new Date().getUTCMonth() + 1;
console.log(
'what check query?',
'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' +
'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' +
'AND `key` = ?',
[
year, month, actor.type.user.id,
key,
]
);
const rows = await this.db.read(
'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' +
'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' +
'AND `key` = ?',
[
year, month, actor.type.user.id,
key,
]
);
console.log('what rows?', rows);
return rows[0]?.sum || 0;
}
async _app_under_user_check (actor, specifiers) { async _app_under_user_check (actor, specifiers) {
const year = new Date().getUTCFullYear(); const year = new Date().getUTCFullYear();
// months are zero-indexed by getUTCMonth, which could be confusing // months are zero-indexed by getUTCMonth, which could be confusing
@ -128,6 +144,27 @@ class MonthlyUsageService extends BaseService {
return rows[0]?.count || 0; return rows[0]?.count || 0;
} }
async _app_under_user_check_2 (actor, key) {
const year = new Date().getUTCFullYear();
// months are zero-indexed by getUTCMonth, which could be confusing
const month = new Date().getUTCMonth() + 1;
// SELECT count
const rows = await this.db.read(
'SELECT `count` FROM `service_usage_monthly` ' +
'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' +
'AND `app_id` = ? ' +
'AND `key` = ?',
[
year, month, actor.type.user.id,
actor.type.app.id,
key,
]
);
return rows[0]?.count || 0;
}
} }
module.exports = { module.exports = {