mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2025-10-03 09:49:32 +02:00
Compare commits
24 commits
2023-06-13
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6189601459 | ||
![]() |
569e5ce62d | ||
![]() |
6220cc6bb9 | ||
![]() |
33d9fd732f | ||
![]() |
764f240707 | ||
![]() |
b392ca295a | ||
![]() |
f5fc8e6cd6 | ||
![]() |
9c2048af64 | ||
![]() |
b69271f7df | ||
![]() |
97d2730b20 | ||
![]() |
0346197c23 | ||
![]() |
a7ed01af74 | ||
![]() |
f77d91ff56 | ||
![]() |
2d035da0da | ||
![]() |
2d73cba90e | ||
![]() |
1918c74277 | ||
![]() |
e55d1fd1a9 | ||
![]() |
f10b79a023 | ||
![]() |
2c401288a3 | ||
![]() |
89f3325a18 | ||
![]() |
7aaad00881 | ||
![]() |
c7e4cfc9f9 | ||
![]() |
12ed5d73cd | ||
![]() |
4df809a306 |
7 changed files with 1879 additions and 1362 deletions
3124
package-lock.json
generated
3124
package-lock.json
generated
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -38,12 +38,11 @@
|
|||
"@types/lodash": "^4.14.166",
|
||||
"@types/node": "^16.11.59",
|
||||
"@types/nodemailer": "^6.4.4",
|
||||
"@types/umzug": "^2.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"eslint": "^8.7.0",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.4.4",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-json-schema": "^0.52.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -63,8 +62,7 @@
|
|||
"rate-limiter-flexible": "^2.1.15",
|
||||
"sequelize": "^6.25.5",
|
||||
"socket.io": "^4.0.1",
|
||||
"sqlite3": "^4.0.0",
|
||||
"umzug": "^2.3.0"
|
||||
"umzug": "^3.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"sqlite3": "^5.0.0"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2023 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2024 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
|
@ -58,7 +58,9 @@ const allTypes = [
|
|||
|
||||
const settings = {
|
||||
required: true,
|
||||
noExtraProps: true
|
||||
noExtraProps: true,
|
||||
// otherwise it finds errors in dependencies that we don't care about
|
||||
ignoreErrors: true
|
||||
};
|
||||
|
||||
const compilerOptions = {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2022 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2024 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
|
@ -26,7 +26,7 @@ export const config = {
|
|||
expireTimeRounding: 1000 * 60 * 15
|
||||
}
|
||||
|
||||
export function calculateExpireTime(now: bigint): BigInt {
|
||||
export function calculateExpireTime(now: bigint): bigint {
|
||||
const expireBaseTime = now + BigInt(config.expireDelay)
|
||||
const expireTime = expireBaseTime - expireBaseTime % BigInt(config.expireTimeRounding) + BigInt(config.expireTimeRounding)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2024 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
|
@ -17,18 +17,26 @@
|
|||
|
||||
import { resolve } from 'path'
|
||||
import { Sequelize } from 'sequelize'
|
||||
import * as Umzug from 'umzug'
|
||||
import { Umzug, SequelizeStorage } from 'umzug'
|
||||
|
||||
export const createUmzug = (sequelize: Sequelize) => (
|
||||
new Umzug({
|
||||
storage: 'sequelize',
|
||||
storageOptions: {
|
||||
sequelize
|
||||
},
|
||||
storage: new SequelizeStorage({ sequelize }),
|
||||
migrations: {
|
||||
params: [sequelize.getQueryInterface(), sequelize],
|
||||
path: resolve(__dirname, '../../../build/database/migration/migrations'),
|
||||
pattern: /^\d+[\w-]+\.js$/
|
||||
}
|
||||
glob: resolve(__dirname, '../../../build/database/migration/migrations/*.js'),
|
||||
resolve: ({ name, path }) => {
|
||||
if (!path) throw new Error()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const migration = require(path)
|
||||
|
||||
return {
|
||||
name,
|
||||
up: async () => migration.up(sequelize.getQueryInterface(), sequelize),
|
||||
down: async () => migration.down(sequelize.getQueryInterface(), sequelize),
|
||||
}
|
||||
},
|
||||
},
|
||||
logger: console
|
||||
})
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2022 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2023 Jonas Lochmann
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
|
@ -15,6 +15,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { AddUsedTimeActionVersion2 } from '../../../../action'
|
||||
import { EventHandler } from '../../../../monitoring/eventhandler'
|
||||
import { MinuteOfDay } from '../../../../util/minuteofday'
|
||||
|
@ -22,6 +23,8 @@ import { Cache } from '../cache'
|
|||
import { IllegalStateException, SourceDeviceNotFoundException } from '../exception/illegal-state'
|
||||
import { getRoundedTimestamp as getRoundedTimestampForUsedTime } from './addusedtime'
|
||||
|
||||
const tolerance = 5 * 1000 // 5 seconds
|
||||
|
||||
export const getRoundedTimestampForSessionDuration = () => {
|
||||
const now = Date.now()
|
||||
|
||||
|
@ -129,11 +132,32 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
|
|||
}
|
||||
}
|
||||
} else {
|
||||
const oldTime: number | null = await cache.database.usedTime.aggregate(
|
||||
'usedTime',
|
||||
'MAX',
|
||||
{
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: item.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
startMinuteOfDay: {
|
||||
[Sequelize.Op.gte]: start
|
||||
},
|
||||
endMinuteOfDay: {
|
||||
[Sequelize.Op.lte]: end
|
||||
}
|
||||
},
|
||||
transaction: cache.transaction
|
||||
}
|
||||
) || 0
|
||||
|
||||
if (oldTime !== null && typeof oldTime !== 'number') throw new Error()
|
||||
|
||||
await cache.database.usedTime.create({
|
||||
familyId: cache.familyId,
|
||||
categoryId: item.categoryId,
|
||||
dayOfEpoch: action.dayOfEpoch,
|
||||
usedTime: Math.max(0, Math.min(item.timeToAdd, lengthInMs)),
|
||||
usedTime: Math.max(0, Math.min(oldTime + item.timeToAdd, lengthInMs)),
|
||||
lastUpdate: roundedTimestampForUsedTime,
|
||||
startMinuteOfDay: start,
|
||||
endMinuteOfDay: end
|
||||
|
@ -168,6 +192,39 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
|
|||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
const oldDuration: () => Promise<number> = async () => {
|
||||
const fittingDurationItems = await cache.database.sessionDuration.findAll({
|
||||
where: {
|
||||
familyId: cache.familyId,
|
||||
categoryId: item.categoryId,
|
||||
startMinuteOfDay: {
|
||||
[Sequelize.Op.gte]: limit.start
|
||||
},
|
||||
endMinuteOfDay: {
|
||||
[Sequelize.Op.lte]: limit.end
|
||||
},
|
||||
maxSessionDuration: {
|
||||
[Sequelize.Op.gte]: limit.duration
|
||||
},
|
||||
sessionPauseDuration: {
|
||||
[Sequelize.Op.lte]: limit.pause
|
||||
}
|
||||
},
|
||||
transaction: cache.transaction
|
||||
})
|
||||
|
||||
const fittingDurationItemsLastUsageFiltered =
|
||||
hasTrustedTimestamp ?
|
||||
fittingDurationItems.filter((it) => {
|
||||
action.trustedTimestamp - item.timeToAdd <=
|
||||
parseInt(it.lastUsage, 10) + it.sessionPauseDuration - tolerance
|
||||
}) : fittingDurationItems
|
||||
|
||||
return fittingDurationItemsLastUsageFiltered
|
||||
.map((it) => it.lastSessionDuration)
|
||||
.reduce((a, b) => Math.max(a, b), 0)
|
||||
}
|
||||
|
||||
if (oldItem) {
|
||||
let extendSession: boolean
|
||||
|
||||
|
@ -188,14 +245,13 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
|
|||
* Due to this, a session is reset if it would be over in a few seconds, too.
|
||||
*/
|
||||
|
||||
const tolerance = 5 * 1000 // 5 seconds
|
||||
const timeWhenStartingCurrentUsage = action.trustedTimestamp - item.timeToAdd
|
||||
const nextSessionStart = parseInt(oldItem.lastUsage, 10) + oldItem.sessionPauseDuration - tolerance
|
||||
|
||||
extendSession = timeWhenStartingCurrentUsage <= nextSessionStart
|
||||
}
|
||||
|
||||
oldItem.lastSessionDuration = extendSession ? oldItem.lastSessionDuration + item.timeToAdd : item.timeToAdd
|
||||
oldItem.lastSessionDuration = extendSession ? oldItem.lastSessionDuration + item.timeToAdd : await oldDuration() + item.timeToAdd
|
||||
oldItem.roundedLastUpdate = roundedTimestampForSessionDuration
|
||||
|
||||
if (hasTrustedTimestamp) {
|
||||
|
@ -215,7 +271,7 @@ export async function dispatchAddUsedTimeVersion2 ({ deviceId, action, cache, ev
|
|||
endMinuteOfDay: limit.end,
|
||||
// end of primary key
|
||||
lastUsage: action.trustedTimestamp.toString(10),
|
||||
lastSessionDuration: item.timeToAdd,
|
||||
lastSessionDuration: await oldDuration() + item.timeToAdd,
|
||||
roundedLastUpdate: roundedTimestampForSessionDuration
|
||||
}, { transaction: cache.transaction })
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
"noUnusedParameters": false,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"sourceMap": true
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue