refactoed backend code to split team and admin messagin logic

This commit is contained in:
2024-04-18 17:21:53 +00:00
parent ae84c552f1
commit f384878964
6 changed files with 324 additions and 269 deletions

186
traque-back/zone_manager.js Normal file
View File

@@ -0,0 +1,186 @@
import randomLocation, { randomCirclePoint } from 'random-location'
import { getDistanceFromLatLon, isInCircle } from './map_utils.js';
import { map } from './util.js';
export class ZoneManager {
constructor(onZoneUpdate, onNextZoneUpdate) {
//Setings storing where the zone will start, end and how it should evolve
//The zone will start by staying at its mzx value for reductionInterval minutes
//and then reduce during reductionDuration minutes, then wait again...
//The reduction factor is such that after reductionCount the zone will be the min zone
//a call to onZoneUpdate will be made every updateIntervalSeconds when the zone is changing
//a call to onNextZoneUpdate will be made when the zone reduction ends and a new next zone is announced
this.zoneSettings = {
min: { center: null, radius: null },
max: { center: null, radius: null },
reductionCount: 2,
reductionDuration: 1,
reductionInterval: 1,
updateIntervalSeconds: 1,
}
this.shrinkFactor = null;
//Live location of the zone
this.currentZone = { center: null, radius: null };
//If the zone is shrinking, this is the target of the current shrinking
//If the zone is not shrinking, this will be the target of the next shrinking
this.nextZone = { center: null, radius: null };
//Zone at the begining of the shrinking
this.currentStartZone = { center: null, radius: null };
this.startDate = null;
this.started = false;
this.updateIntervalId = null;
this.nextZoneTimeoutId = null;
this.onZoneUpdate = onZoneUpdate;
this.onNextZoneUpdate = onNextZoneUpdate
}
/**
* Test if a given configuration object is valid, i.e if all needed values are well defined
* @param {Object} settings Settings object describing a config of a zone manager
* @returns if the config is correct
*/
validateSettings(settings) {
if (settings.reductionCount && (typeof settings.reductionCount != "number" || settings.reductionCount <= 0)) { return false }
if (settings.reductionDuration && (typeof settings.reductionDuration != "number" || settings.reductionDuration < 0)) { return false }
if (settings.reductionInterval && (typeof settings.reductionInterval != "number" || settings.reductionInterval < 0)) { return false }
if (settings.updateIntervalSeconds && (typeof settings.updateIntervalSeconds != "number" || settings.updateIntervalSeconds <= 0)) { return false }
if (settings.max && (typeof settings.max.radius != "number" || typeof settings.max.center.lat != "number" || typeof settings.max.center.lng != "number")) { return false }
if (settings.min && (typeof settings.min.radius != "number" || typeof settings.min.center.lat != "number" || typeof settings.min.center.lng != "number")) { return false }
return true;
}
/**
* Test if the zone manager is ready to start
* @returns true if the zone manager is ready to be started, false otherwise
*/
ready() {
return this.validateSettings(this.zoneSettings);
}
/**
* Update the settings of the zone, this can be done by passing an object containing the settings to change.
* Unless specified, the durations are in minutes
* Default config :
* `this.zoneSettings = {
* min: {center: null, radius: null},
* max: {center: null, radius: null},
* reductionCount: 2,
* reductionDuration: 10,
* reductionInterval: 10,
* updateIntervalSeconds: 10,
* }`
* @param {Object} newSettings The fields of the settings to udpate
* @returns
*/
udpateSettings(newSettings) {
//validate settings
this.zoneSettings = { ...this.zoneSettings, ...newSettings };
this.shrinkFactor = Math.pow(this.zoneSettings.min.radius / this.zoneSettings.max.radius, 1 / this.zoneSettings.reductionCount)
return true;
}
/**
* Reinitialize the object and stop all the tasks
*/
reset() {
this.currentZoneCount = 0;
this.started = false;
if (this.updateIntervalId != null) {
clearInterval(this.updateIntervalId);
this.updateIntervalId = null;
}
if (this.nextZoneTimeoutId != null) {
clearTimeout(this.nextZoneTimeoutId);
this.nextZoneTimeoutId = null;
}
}
/**
* Start the zone reduction sequence
*/
start() {
this.started = true;
this.startDate = new Date();
//initialize the zone to its max value
this.nextZone = JSON.parse(JSON.stringify(this.zoneSettings.max));
this.currentStartZone = JSON.parse(JSON.stringify(this.zoneSettings.max));
this.currentZone = JSON.parse(JSON.stringify(this.zoneSettings.max));
this.setNextZone();
}
/**
* Get the center of the next zone, this center need to satisfy two properties
* - it needs to be included in the current zone, this means that this new point should lie in the circle of center currentZone.center and radius currentZone.radius - newRadius
* - it needs to include the last zone, which means that the center must lie in the center of center min.center and of radius newRadius - min.radius
* @param newRadius the radius that the new zone will have
* @returns the coordinates of the new center as an object with lat and long fields
*/
getRandomNextCenter(newRadius) {
let ok = false;
let res = null
//take a random point satisfying both conditions
while (!ok) {
res = randomCirclePoint({ latitude: this.currentZone.center.lat, longitude: this.currentZone.center.lng }, this.currentZone.radius - newRadius);
ok = (isInCircle({ lat: res.latitude, lng: res.longitude }, this.zoneSettings.min.center, newRadius - this.zoneSettings.min.radius))
}
return {
lat: res.latitude,
lng: res.longitude
}
}
/**
* Compute the next zone satifying the given settings, update the nextZone and currentStartZone
* Wait for the appropriate duration before starting a new zone reduction if needed
*/
setNextZone() {
//At this point, nextZone == currentZone, we need to update the next zone, the raidus decrement, and start a timer before the next shrink
//last zone
if (this.currentZoneCount == this.zoneSettings.reductionCount) {
this.nextZone = JSON.parse(JSON.stringify(this.zoneSettings.min))
this.currentStartZone = JSON.parse(JSON.stringify(this.zoneSettings.min))
} else if (this.currentZoneCount == this.zoneSettings.reductionCount - 1) {
this.currentStartZone = JSON.parse(JSON.stringify(this.currentZone))
this.nextZone = JSON.parse(JSON.stringify(this.zoneSettings.min))
this.nextZoneTimeoutId = setTimeout(() => this.startShrinking(), 1000 * 60 * this.zoneSettings.reductionInterval)
this.currentZoneCount++;
} else if (this.currentZoneCount < this.zoneSettings.reductionCount) {
this.nextZone.center = this.getRandomNextCenter(this.nextZone.radius * this.shrinkFactor)
this.nextZone.radius *= this.shrinkFactor;
this.currentStartZone = JSON.parse(JSON.stringify(this.currentZone))
this.nextZoneTimeoutId = setTimeout(() => this.startShrinking(), 1000 * 60 * this.zoneSettings.reductionInterval)
this.currentZoneCount++;
}
this.onNextZoneUpdate({
begin: JSON.parse(JSON.stringify(this.currentStartZone)),
end: JSON.parse(JSON.stringify(this.nextZone))
})
}
/*
* Start a task that will run periodically updatinng the zone size, and calling the onZoneUpdate callback
* This will also periodically check if the reduction is over or not
* If the reduction is over this function will call setNextZone
*/
startShrinking() {
const startTime = new Date();
this.updateIntervalId = setInterval(() => {
const completed = ((new Date() - startTime) / (1000 * 60)) / this.zoneSettings.reductionDuration;
this.currentZone.radius = map(completed, 0, 1, this.currentStartZone.radius, this.nextZone.radius)
this.currentZone.center.lat = map(completed,0,1, this.currentStartZone.center.lat, this.nextZone.center.lat)
this.currentZone.center.lng = map(completed,0,1, this.currentStartZone.center.lng, this.nextZone.center.lng)
this.onZoneUpdate(JSON.parse(JSON.stringify(this.currentZone)))
//Zone shrinking is over
if (completed >= 1) {
clearInterval(this.updateIntervalId);
this.updateIntervalId = null;
this.setNextZone();
return;
}
}, this.zoneSettings.updateIntervalSeconds * 1000);
}
}