diff --git a/docs/api/admin.md b/docs/api/admin.md index dfc8f11..62d9c12 100644 --- a/docs/api/admin.md +++ b/docs/api/admin.md @@ -14,8 +14,8 @@ Use this to get the server status. ## Response This returns a JSON object with ``websocketClients`` (of the type number, -the number of clients connected using the websocket) and the map ``counters`` -which maps values to numbers. You should not make any assumptions about the counter names +the number of clients connected using the websocket) and the maps ``counters`` and ``maxValues`` +which map values to numbers. You should not make any assumptions about the key names and their availability. ### example response @@ -25,13 +25,16 @@ and their availability. "websocketClients": 3, "counters": { "testCounter": 1 + }, + "maxValues": { + "testMax": 3 } } ``` ## POST /admin/reset-counters -Use this to reset the counters included in the server status. +Use this to reset the counters and maxValues included in the server status. Although this uses POST, it does not take any request body diff --git a/src/api/admin.ts b/src/api/admin.ts index 67e9adc..5a869ec 100644 --- a/src/api/admin.ts +++ b/src/api/admin.ts @@ -34,9 +34,12 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: { router.get('/status', async (_, res, next) => { try { + const { counters, maxValues } = await eventHandler.getValues() + res.json({ websocketClients: websocket.countConnections(), - counters: await eventHandler.getCounters() + counters, + maxValues }) } catch (ex) { next(ex) @@ -45,7 +48,7 @@ export const createAdminRouter = ({ database, websocket, eventHandler }: { router.post('/reset-counters', async (_, res, next) => { try { - await eventHandler.resetCounters() + await eventHandler.reset() res.json({ ok: true }) } catch (ex) { diff --git a/src/function/sync/apply-actions/dispatch-helper/app-logic-action.ts b/src/function/sync/apply-actions/dispatch-helper/app-logic-action.ts index 1d81747..39d2ccb 100644 --- a/src/function/sync/apply-actions/dispatch-helper/app-logic-action.ts +++ b/src/function/sync/apply-actions/dispatch-helper/app-logic-action.ts @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +import { max } from 'lodash' +import { AddInstalledAppsAction, AppLogicAction, UpdateAppActivitiesAction } from '../../../../action' import { parseAppLogicAction } from '../../../../action/serialization' import { ClientPushChangesRequestAction } from '../../../../api/schema' import { isSerializedAppLogicAction } from '../../../../api/validator' @@ -23,6 +25,30 @@ import { Cache } from '../cache' import { dispatchAppLogicAction as dispatchAppLogicActionInternal } from '../dispatch-app-logic-action' import { dispatch } from './helper' +function getAppRelatedMaxValues (action: AppLogicAction): { + packageNameLength: number | null + activityNameLength: number | null +} { + if (action instanceof AddInstalledAppsAction) { + const packageNameLength = max(action.apps.map((item) => item.packageName.length)) || null + + return { packageNameLength, activityNameLength: null } + } else if (action instanceof UpdateAppActivitiesAction) { + const packageNameLength = max(action.updatedOrAdded.map((item) => item.packageName.length)) || null + const activityNameLength = max(action.updatedOrAdded.map((item) => item.activityName.length)) || null + + return { packageNameLength, activityNameLength } + } else return { packageNameLength: null, activityNameLength: null } +} + +function roundCounterUp (input: number, factor: number) { + if (input % factor === 0) { + return input + } else { + return input - (input % factor) + factor + } +} + export async function dispatchAppLogicAction ({ action, eventHandler, deviceId, cache }: { action: ClientPushChangesRequestAction deviceId: string @@ -36,6 +62,11 @@ export async function dispatchAppLogicAction ({ action, eventHandler, deviceId, validator: isSerializedAppLogicAction, parser: parseAppLogicAction, applier: async (action) => { + const maxValues = getAppRelatedMaxValues(action) + + if (maxValues.packageNameLength) eventHandler.reportMax('packageNameLength', roundCounterUp(maxValues.packageNameLength, 10)) + if (maxValues.activityNameLength) eventHandler.reportMax('activityNameLength', roundCounterUp(maxValues.activityNameLength, 10)) + await dispatchAppLogicActionInternal({ action, cache, eventHandler, deviceId }) } }) diff --git a/src/monitoring/eventhandler.ts b/src/monitoring/eventhandler.ts index 80b1acd..09ae523 100644 --- a/src/monitoring/eventhandler.ts +++ b/src/monitoring/eventhandler.ts @@ -17,6 +17,10 @@ export interface EventHandler { countEvent (name: string): void - getCounters (): Promise<{[key: string]: number}> - resetCounters (): Promise + reportMax (name: string, value: number): void + getValues (): Promise<{ + counters: {[key: string]: number} + maxValues: {[key: string]: number} + }> + reset (): Promise } diff --git a/src/monitoring/inmemoryeventhandler.ts b/src/monitoring/inmemoryeventhandler.ts index 86d3edc..98d602e 100644 --- a/src/monitoring/inmemoryeventhandler.ts +++ b/src/monitoring/inmemoryeventhandler.ts @@ -19,6 +19,7 @@ import { EventHandler } from './eventhandler' export class InMemoryEventHandler implements EventHandler { private counters = new Map() + private maxValues = new Map() countEvent (name: string) { this.counters.set( @@ -27,17 +28,39 @@ export class InMemoryEventHandler implements EventHandler { ) } - async getCounters () { - const result: {[key: string]: number} = {} + reportMax (name: string, value: number) { + this.maxValues.set( + name, + Math.max((this.maxValues.get(name) || 0), value) + ) + } - this.counters.forEach((value, key) => { - result[key] = value + async getValues () { + return { + counters: this.buildObject(this.counters), + maxValues: this.buildObject(this.maxValues) + } + } + + async reset () { + this.counters.clear() + this.maxValues.clear() + } + + private buildObject (map: Map): {[key: string]: T} { + const result: {[key: string]: T} = {} + + const keys: Array = [] + map.forEach((_, key) => keys.push(key)) + + keys.sort().forEach((key) => { + const value = map.get(key) + + if (value !== undefined) { + result[key] = value + } }) return result } - - async resetCounters () { - this.counters.clear() - } }