tons of cursor-shit cleaning, finished implementing cnxId in observer

This commit is contained in:
STEINNI
2026-06-27 17:24:41 +00:00
parent 4c9e989bda
commit a1dba5060a
28 changed files with 213 additions and 224 deletions
+18 -42
View File
@@ -14,10 +14,11 @@ export class gpsServer {
constructor(configHelper, allRediscnx, debug) { constructor(configHelper, allRediscnx, debug) {
this.configHelper = configHelper this.configHelper = configHelper
this.gpsConfig = configHelper.config this.rootConfig = configHelper.config
this.gpsConfig = configHelper.config.gps ?? {}
this.allRediscnx = allRediscnx this.allRediscnx = allRediscnx
this.debug = debug this.debug = debug
this.accessRights = new AccesRights(this.gpsConfig, debug) this.accessRights = new AccesRights(this.rootConfig, debug)
this.agents = new Map() this.agents = new Map()
this.registry = new CollisionRegistry() this.registry = new CollisionRegistry()
this.arenaCnx = null this.arenaCnx = null
@@ -33,33 +34,6 @@ export class gpsServer {
this.ignoredChangeCount = 0 this.ignoredChangeCount = 0
} }
getGpsSettings() {
const gps = this.gpsConfig.gps ?? {}
return({
nearMissDistance: gps.nearMissDistance ?? 1,
prismTimeHeight: gps.prismTimeHeight ?? 60,
collisionTickMs: gps.collisionTickMs ?? 100,
prismRefreshLeadSeconds: gps.prismRefreshLeadSeconds ?? 1,
})
}
getLifecycleSettings() {
const gps = this.gpsConfig.gps ?? {}
return({
arenaChannel: gps.lifecycle?.arenaChannel ?? 'arena:lifecycle',
godsReadyChannel: gps.lifecycle?.godsReadyChannel ?? 'arena:gods:ready',
senderId: gps.senderId ?? 'gps',
})
}
getArenaStorageSettings() {
const gps = this.gpsConfig.gps ?? {}
return({
agentHashKey: gps.arenaStorage?.agentHashKey ?? 'arena:agents:[UID]',
agentsIndexKey: gps.arenaStorage?.agentsIndexKey ?? 'arena:agents',
})
}
isLive() { isLive() {
return(this.state === SimState.LIVE) return(this.state === SimState.LIVE)
} }
@@ -103,7 +77,7 @@ export class gpsServer {
} }
initAgentStore() { initAgentStore() {
const gpsStorage = this.gpsConfig.gps?.GPSstorage const gpsStorage = this.gpsConfig.GPSstorage
if(gpsStorage && this.systemCnx) { if(gpsStorage && this.systemCnx) {
this.agentStore = new AgentStore(this.systemCnx, gpsStorage, this.debug) this.agentStore = new AgentStore(this.systemCnx, gpsStorage, this.debug)
} }
@@ -114,7 +88,10 @@ export class gpsServer {
this.arenaCnxs.push(cnx) this.arenaCnxs.push(cnx)
if(!this.arenaCnx || cnx.redisConfig.role === 'primary') { if(!this.arenaCnx || cnx.redisConfig.role === 'primary') {
this.arenaCnx = cnx this.arenaCnx = cnx
this.arenaLoader = new ArenaAgentLoader(cnx, this.getArenaStorageSettings(), this.debug) const arenaStorage = this.gpsConfig.arenaStorage
if(arenaStorage) {
this.arenaLoader = new ArenaAgentLoader(cnx, arenaStorage, this.debug)
}
} }
} }
@@ -194,7 +171,7 @@ export class gpsServer {
} }
runInitialPairScan() { runInitialPairScan() {
const { nearMissDistance, prismTimeHeight } = this.getGpsSettings() const { nearMissDistance, prismTimeHeight } = this.gpsConfig
const ids = [...this.agents.keys()] const ids = [...this.agents.keys()]
for(let i = 0; i < ids.length; i++) { for(let i = 0; i < ids.length; i++) {
for(let j = i + 1; j < ids.length; j++) { for(let j = i + 1; j < ids.length; j++) {
@@ -213,10 +190,9 @@ export class gpsServer {
async publishReadyToStart(result) { async publishReadyToStart(result) {
if(!this.arenaCnx) return if(!this.arenaCnx) return
const { godsReadyChannel, senderId } = this.getLifecycleSettings() await this.arenaCnx.redisPublish(this.gpsConfig.lifecycle.godsReadyChannel, {
await this.arenaCnx.redisPublish(godsReadyChannel, {
eventType: 'readyToStart', eventType: 'readyToStart',
sender: senderId, sender: this.gpsConfig.senderId,
payload: { payload: {
success: result.success, success: result.success,
simulationId: this.simulationId, simulationId: this.simulationId,
@@ -370,7 +346,7 @@ export class gpsServer {
const agent = this.agents.get(agentId) const agent = this.agents.get(agentId)
if(!agent) return(false) if(!agent) return(false)
const { prismTimeHeight, prismRefreshLeadSeconds } = this.getGpsSettings() const { prismTimeHeight, prismRefreshLeadSeconds } = this.gpsConfig
const now = this.now() const now = this.now()
if(!needsPrismRefresh(agent, now, prismTimeHeight, prismRefreshLeadSeconds)) return(false) if(!needsPrismRefresh(agent, now, prismTimeHeight, prismRefreshLeadSeconds)) return(false)
@@ -390,7 +366,7 @@ export class gpsServer {
const changed = this.agents.get(changedAgentId) const changed = this.agents.get(changedAgentId)
if(!changed) return([]) if(!changed) return([])
const { nearMissDistance, prismTimeHeight } = this.getGpsSettings() const { nearMissDistance, prismTimeHeight } = this.gpsConfig
const now = this.now() const now = this.now()
const hits = [] const hits = []
for(const [otherId, other] of this.agents) { for(const [otherId, other] of this.agents) {
@@ -459,14 +435,14 @@ export class gpsServer {
async publishProximityBatch(targetAgentId, pairs) { async publishProximityBatch(targetAgentId, pairs) {
if(!this.arenaCnx || !pairs.length) return if(!this.arenaCnx || !pairs.length) return
const chan = this.arenaCnx.config.gps.collisionsChannel.replace(/\[UID\]/g, targetAgentId) const chan = this.gpsConfig.collisionsChannel.replace(/\[UID\]/g, targetAgentId)
await this.arenaCnx.redisPublish(chan, { await this.arenaCnx.redisPublish(chan, {
eventType: 'proximity', eventType: 'proximity',
payload: { payload: {
pairs, pairs,
simulationId: this.simulationId, simulationId: this.simulationId,
}, },
sender: this.getLifecycleSettings().senderId, sender: this.gpsConfig.senderId,
}) })
} }
@@ -491,12 +467,12 @@ export class gpsServer {
async reloadAccessRights() { async reloadAccessRights() {
await this.configHelper.refreshAccessRights() await this.configHelper.refreshAccessRights()
this.gpsConfig.accessRights = this.configHelper.config.accessRights this.rootConfig.accessRights = this.configHelper.config.accessRights
this.accessRights.refreshAccessRights(this.gpsConfig) this.accessRights.refreshAccessRights(this.rootConfig)
} }
getAccessRights() { getAccessRights() {
return(this.gpsConfig.accessRights) return(this.rootConfig.accessRights)
} }
} }
+2 -2
View File
@@ -1,7 +1,7 @@
export const eventHandlers = { export const eventHandlers = {
'arena:agents:*': { 'arena:agents:*': {
change(msg, chan) { change(msg, chan, sender, cnxId) {
const agentId = msg.sender const agentId = msg.sender
if(!agentId || typeof(agentId) !== 'string') { if(!agentId || typeof(agentId) !== 'string') {
console.warn(`[${this.redisId}] Agent event without sender`) console.warn(`[${this.redisId}] Agent event without sender`)
@@ -15,7 +15,7 @@ export const eventHandlers = {
const newPosition = msg.payload?.newPosition ?? null const newPosition = msg.payload?.newPosition ?? null
this.gpsSrv?.onVectorChange(agentId, newVector, newPosition) this.gpsSrv?.onVectorChange(agentId, newVector, newPosition)
}, },
remove(msg, chan) { remove(msg, chan, sender, cnxId) {
const agentId = msg.sender const agentId = msg.sender
if(!agentId || typeof(agentId) !== 'string') { if(!agentId || typeof(agentId) !== 'string') {
console.warn(`[${this.redisId}] Agent event without sender`) console.warn(`[${this.redisId}] Agent event without sender`)
+1 -1
View File
@@ -10,7 +10,7 @@ export const dispatchMessage = createDispatchMessage({
eventHandlers, eventHandlers,
actionRules(redisCnx) { actionRules(redisCnx) {
const gps = redisCnx.config.gps ?? {} const gps = redisCnx.config.gps ?? {}
const arenaChannel = gps.bus?.arena?.actionsChannel const arenaChannel = gps.arenaActionsChannel
return({ return({
channels: arenaChannel ? [arenaChannel] : [], channels: arenaChannel ? [arenaChannel] : [],
}) })
+6 -6
View File
@@ -1,6 +1,6 @@
export function construct(redisCnx) { export function construct(redisCnx) {
const tickMs = redisCnx.gpsSrv?.getGpsSettings().collisionTickMs ?? 100 const tickMs = redisCnx.gpsSrv?.gpsConfig.collisionTickMs ?? 100
setInterval(() => { setInterval(() => {
redisCnx.gpsSrv?.tickArena() redisCnx.gpsSrv?.tickArena()
}, tickMs) }, tickMs)
@@ -8,7 +8,7 @@ export function construct(redisCnx) {
export const eventHandlers = { export const eventHandlers = {
'arena:lifecycle': { 'arena:lifecycle': {
onYourMarks(msg, chan) { onYourMarks(msg, chan, sender, cnxId) {
const srv = this.gpsSrv const srv = this.gpsSrv
if(!srv) return if(!srv) return
srv.onYourMarks(msg.payload ?? {}).catch(err => { srv.onYourMarks(msg.payload ?? {}).catch(err => {
@@ -16,16 +16,16 @@ export const eventHandlers = {
srv.publishReadyToStart({ success: false, err: err.message ?? 'onYourMarks failed' }) srv.publishReadyToStart({ success: false, err: err.message ?? 'onYourMarks failed' })
}) })
}, },
bigBang(msg, chan) { bigBang(msg, chan, sender, cnxId) {
this.gpsSrv?.onBigBang(msg.payload ?? {}) this.gpsSrv?.onBigBang(msg.payload ?? {})
}, },
simulationPaused(msg, chan) { simulationPaused(msg, chan, sender, cnxId) {
this.gpsSrv?.onSimulationPaused(msg.payload ?? {}) this.gpsSrv?.onSimulationPaused(msg.payload ?? {})
}, },
simulationResumed(msg, chan) { simulationResumed(msg, chan, sender, cnxId) {
this.gpsSrv?.onSimulationResumed(msg.payload ?? {}) this.gpsSrv?.onSimulationResumed(msg.payload ?? {})
}, },
simulationStopped(msg, chan) { simulationStopped(msg, chan, sender, cnxId) {
const srv = this.gpsSrv const srv = this.gpsSrv
if(!srv) return if(!srv) return
srv.onSimulationStopped(msg.payload ?? {}).catch(err => { srv.onSimulationStopped(msg.payload ?? {}).catch(err => {
+1 -1
View File
@@ -10,7 +10,7 @@ export const dispatchMessage = createDispatchMessage({
actionRules(redisCnx) { actionRules(redisCnx) {
const gps = redisCnx.config.gps ?? {} const gps = redisCnx.config.gps ?? {}
return({ return({
channels: [gps.gpsActionsChannel].filter(Boolean), channels: [gps.ActionsChannel].filter(Boolean),
}) })
}, },
}) })
+6 -4
View File
@@ -2,11 +2,12 @@ import { replyToAction } from '../../../bus/publishActionReply.js'
export const actions = { export const actions = {
async action_TIME(action, payload, reqid, sender, roles) { async action_TIME(action, payload, reqid, sender, cnxId, roles) {
replyToAction(this, { replyToAction(this, {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: { payload: {
gpsTime: new Date().toISOString(), gpsTime: new Date().toISOString(),
@@ -15,16 +16,17 @@ export const actions = {
}) })
}, },
async action_RELOADCONFIG(action, payload, reqid, sender, roles) { async action_RELOADCONFIG(action, payload, reqid, sender, cnxId, roles) {
this.reloadAccessRights() this.reloadAccessRights()
replyToAction(this, { action, reqid, sender, success: true }) replyToAction(this, { action, reqid, sender, cnxId, success: true })
}, },
async action_GETCONFIG(action, payload, reqid, sender, roles) { async action_GETCONFIG(action, payload, reqid, sender, cnxId, roles) {
replyToAction(this, { replyToAction(this, {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: this.getAccessRights(), payload: this.getAccessRights(),
}) })
+1 -1
View File
@@ -9,7 +9,7 @@ export const dispatchMessage = createDispatchMessage({
eventHandlers, eventHandlers,
actionRules(redisCnx) { actionRules(redisCnx) {
const maestro = redisCnx.config.maestro ?? {} const maestro = redisCnx.config.maestro ?? {}
const arenaChannel = maestro.bus?.arena?.actionsChannel const arenaChannel = maestro.arenaActionsChannel
return({ return({
channels: arenaChannel ? [arenaChannel] : [], channels: arenaChannel ? [arenaChannel] : [],
}) })
+1 -1
View File
@@ -1,7 +1,7 @@
export const eventHandlers = { export const eventHandlers = {
'arena:gods:ready': { 'arena:gods:ready': {
readyToStart(msg, chan) { readyToStart(msg, chan, sender, cnxId) {
if(!this.maestroSrv) return if(!this.maestroSrv) return
this.maestroSrv.handlePrepareAck(msg, chan) this.maestroSrv.handlePrepareAck(msg, chan)
}, },
+1 -1
View File
@@ -11,7 +11,7 @@ export const dispatchMessage = createDispatchMessage({
actionRules(redisCnx) { actionRules(redisCnx) {
const maestro = redisCnx.config.maestro ?? {} const maestro = redisCnx.config.maestro ?? {}
return({ return({
channels: [maestro.maestroActionsChannel].filter(Boolean), channels: [maestro.ActionsChannel].filter(Boolean),
}) })
}, },
}) })
+19 -15
View File
@@ -3,20 +3,20 @@ import { isValidUuid } from '../../simRepository.js'
export const actions = { export const actions = {
async action_STARTSIMULATION(action, payload, reqid, sender, roles) { async action_STARTSIMULATION(action, payload, reqid, sender, cnxId, roles) {
if(!isValidUuid(sender)) { if(!isValidUuid(sender)) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing or invalid sender (user UUID)' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid sender (user UUID)' })
return return
} }
if(!payload?.simulationUuid) { if(!payload?.simulationUuid) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing simulationUuid' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing simulationUuid' })
return return
} }
const result = await this.maestroSrv.startSimulation(sender, payload) const result = await this.maestroSrv.startSimulation(sender, payload)
if(!result.ok) { if(!result.ok) {
replyToAction(this, { action, reqid, sender, success: false, err: result.err }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: result.err })
return return
} }
@@ -24,6 +24,7 @@ export const actions = {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: { payload: {
simulationId: result.simulationId, simulationId: result.simulationId,
@@ -36,20 +37,20 @@ export const actions = {
}) })
}, },
async action_PAUSESIMULATION(action, payload, reqid, sender, roles) { async action_PAUSESIMULATION(action, payload, reqid, sender, cnxId, roles) {
if(!isValidUuid(sender)) { if(!isValidUuid(sender)) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing or invalid sender (user UUID)' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid sender (user UUID)' })
return return
} }
if(!payload?.simulationUuid) { if(!payload?.simulationUuid) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing simulationUuid' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing simulationUuid' })
return return
} }
const result = await this.maestroSrv.pauseSimulation(sender, payload) const result = await this.maestroSrv.pauseSimulation(sender, payload)
if(!result.ok) { if(!result.ok) {
replyToAction(this, { action, reqid, sender, success: false, err: result.err }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: result.err })
return return
} }
@@ -57,6 +58,7 @@ export const actions = {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: { payload: {
simulationId: result.simulationId, simulationId: result.simulationId,
@@ -65,20 +67,20 @@ export const actions = {
}) })
}, },
async action_STOPSIMULATION(action, payload, reqid, sender, roles) { async action_STOPSIMULATION(action, payload, reqid, sender, cnxId, roles) {
if(!isValidUuid(sender)) { if(!isValidUuid(sender)) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing or invalid sender (user UUID)' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid sender (user UUID)' })
return return
} }
if(!payload?.simulationUuid) { if(!payload?.simulationUuid) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing simulationUuid' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing simulationUuid' })
return return
} }
const result = await this.maestroSrv.stopSimulation(sender, payload) const result = await this.maestroSrv.stopSimulation(sender, payload)
if(!result.ok) { if(!result.ok) {
replyToAction(this, { action, reqid, sender, success: false, err: result.err }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: result.err })
return return
} }
@@ -86,20 +88,21 @@ export const actions = {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: { simulationId: result.simulationId }, payload: { simulationId: result.simulationId },
}) })
}, },
async action_GETSIMULATIONSSTATUS(action, payload, reqid, sender, roles) { async action_GETSIMULATIONSSTATUS(action, payload, reqid, sender, cnxId, roles) {
if(!isValidUuid(sender)) { if(!isValidUuid(sender)) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing or invalid sender (user UUID)' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid sender (user UUID)' })
return return
} }
const result = await this.maestroSrv.getSimulationsStatus(sender) const result = await this.maestroSrv.getSimulationsStatus(sender)
if(!result.ok) { if(!result.ok) {
replyToAction(this, { action, reqid, sender, success: false, err: result.err }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: result.err })
return return
} }
@@ -107,6 +110,7 @@ export const actions = {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: result.simulations, payload: result.simulations,
}) })
+4 -3
View File
@@ -2,16 +2,17 @@ import { replyToAction } from '../../../bus/publishActionReply.js'
export const actions = { export const actions = {
async action_RELOADCONFIG(action, payload, reqid, sender, roles) { async action_RELOADCONFIG(action, payload, reqid, sender, cnxId, roles) {
this.reloadAccessRights() this.reloadAccessRights()
replyToAction(this, { action, reqid, sender, success: true }) replyToAction(this, { action, reqid, sender, cnxId, success: true })
}, },
async action_GETCONFIG(action, payload, reqid, sender, roles) { async action_GETCONFIG(action, payload, reqid, sender, cnxId, roles) {
replyToAction(this, { replyToAction(this, {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: this.getAccessRights(), payload: this.getAccessRights(),
}) })
+18 -38
View File
@@ -10,10 +10,12 @@ export class maestroServer {
constructor(configHelper, allRediscnx, debug) { constructor(configHelper, allRediscnx, debug) {
this.configHelper = configHelper this.configHelper = configHelper
this.maestroConfig = configHelper.config this.rootConfig = configHelper.config
this.maestroConfig = configHelper.config.maestro ?? {}
this.gpsConfig = configHelper.config.gps ?? {}
this.allRediscnx = allRediscnx this.allRediscnx = allRediscnx
this.debug = debug this.debug = debug
this.accessRights = new AccesRights(this.maestroConfig, debug) this.accessRights = new AccesRights(this.rootConfig, debug)
this.arenaCnx = null this.arenaCnx = null
this.arenaCnxs = [] this.arenaCnxs = []
this.systemCnx = null this.systemCnx = null
@@ -31,26 +33,6 @@ export class maestroServer {
this.pausedAt = null this.pausedAt = null
} }
getMaestroSettings() {
const maestro = this.maestroConfig.maestro ?? {}
return({
senderId: maestro.senderId ?? 'maestro',
lifecycle: {
arenaChannel: maestro.lifecycle?.arenaChannel ?? 'arena:lifecycle',
prepareAckChannel: maestro.lifecycle?.godsReadyChannel ?? 'arena:gods:ready',
},
readyTimeoutMs: maestro.readyTimeoutMs ?? 30000,
})
}
getArenaStorageSettings() {
const gps = this.maestroConfig.gps ?? {}
return({
agentHashKey: gps.arenaStorage?.agentHashKey ?? 'arena:agents:[UID]',
agentsIndexKey: gps.arenaStorage?.agentsIndexKey ?? 'arena:agents',
})
}
isIdle() { isIdle() {
return(this.orchestrationState === MaestroState.IDLE) return(this.orchestrationState === MaestroState.IDLE)
} }
@@ -72,7 +54,7 @@ export class maestroServer {
} }
async init() { async init() {
const mysqlCfg = this.maestroConfig.mysql const mysqlCfg = this.rootConfig.mysql
if(!mysqlCfg) { if(!mysqlCfg) {
console.error('[Maestro] Missing mysql config') console.error('[Maestro] Missing mysql config')
return(false) return(false)
@@ -84,10 +66,11 @@ export class maestroServer {
} }
refreshArenaGroom() { refreshArenaGroom() {
if(this.arenaCnx) { const arenaStorage = this.gpsConfig.arenaStorage
if(this.arenaCnx && arenaStorage) {
this.arenaGroom = new ArenaGroom( this.arenaGroom = new ArenaGroom(
this.arenaCnx, this.arenaCnx,
this.getArenaStorageSettings(), arenaStorage,
this.debug this.debug
) )
} }
@@ -95,10 +78,9 @@ export class maestroServer {
refreshPrepareQuorum() { refreshPrepareQuorum() {
if(!this.arenaCnx) return if(!this.arenaCnx) return
const { lifecycle, readyTimeoutMs } = this.getMaestroSettings()
this.prepareQuorum = new PrepareQuorum({ this.prepareQuorum = new PrepareQuorum({
ackChannel: lifecycle.prepareAckChannel, ackChannel: this.maestroConfig.lifecycle.godsReadyChannel,
timeoutMs: readyTimeoutMs, timeoutMs: this.maestroConfig.readyTimeoutMs,
matchesChan: this.arenaCnx.matchesChan.bind(this.arenaCnx), matchesChan: this.arenaCnx.matchesChan.bind(this.arenaCnx),
debug: this.debug, debug: this.debug,
}) })
@@ -144,11 +126,10 @@ export class maestroServer {
async publishLifecycle(eventType, payload, state = null) { async publishLifecycle(eventType, payload, state = null) {
if(!this.arenaCnx) throw(new Error('No arena Redis connection')) if(!this.arenaCnx) throw(new Error('No arena Redis connection'))
const { arenaChannel, senderId } = this.getMaestroSettings().lifecycle
const resolvedState = state ?? this.orchestrationStateFor(payload?.simulationId ?? this.simulationId) const resolvedState = state ?? this.orchestrationStateFor(payload?.simulationId ?? this.simulationId)
await this.arenaCnx.redisPublish(arenaChannel, { await this.arenaCnx.redisPublish(this.maestroConfig.lifecycle.arenaChannel, {
eventType, eventType,
sender: senderId, sender: this.maestroConfig.senderId,
payload, payload,
}) })
await this.publishSystemLifecycle(eventType, payload, resolvedState) await this.publishSystemLifecycle(eventType, payload, resolvedState)
@@ -164,9 +145,8 @@ export class maestroServer {
const ownersResult = await this.simRepo.listSimulationOwnerUuids(simulationId) const ownersResult = await this.simRepo.listSimulationOwnerUuids(simulationId)
if(!ownersResult.ok || !ownersResult.ownerUuids.length) return if(!ownersResult.ok || !ownersResult.ownerUuids.length) return
const maestro = this.maestroConfig.maestro ?? {} const channelTemplate = this.maestroConfig.systemLifecycleChannel
const channelTemplate = maestro.systemLifecycleChannel ?? 'system:maestro:lifecycle:[UID]' const senderId = this.maestroConfig.senderId
const senderId = maestro.senderId ?? 'maestro'
const msg = { const msg = {
eventType, eventType,
sender: senderId, sender: senderId,
@@ -219,7 +199,7 @@ export class maestroServer {
infraId, infraId,
} }
const expectedParticipants = buildPrepareQuorum(this.agentIds, this.maestroConfig) const expectedParticipants = buildPrepareQuorum(this.agentIds, this.rootConfig)
const readyWait = this.prepareQuorum.begin(expectedParticipants, this.simulationId) const readyWait = this.prepareQuorum.begin(expectedParticipants, this.simulationId)
await this.publishLifecycle('onYourMarks', lifecyclePayload) await this.publishLifecycle('onYourMarks', lifecyclePayload)
@@ -410,12 +390,12 @@ export class maestroServer {
async reloadAccessRights() { async reloadAccessRights() {
await this.configHelper.refreshAccessRights() await this.configHelper.refreshAccessRights()
this.maestroConfig.accessRights = this.configHelper.config.accessRights this.rootConfig.accessRights = this.configHelper.config.accessRights
this.accessRights.refreshAccessRights(this.maestroConfig) this.accessRights.refreshAccessRights(this.rootConfig)
} }
getAccessRights() { getAccessRights() {
return(this.maestroConfig.accessRights) return(this.rootConfig.accessRights)
} }
} }
+1 -1
View File
@@ -9,7 +9,7 @@ export const dispatchMessage = createDispatchMessage({
eventHandlers, eventHandlers,
actionRules(redisCnx) { actionRules(redisCnx) {
const observer = redisCnx.config.observer ?? {} const observer = redisCnx.config.observer ?? {}
const arenaChannel = observer.bus?.arena?.actionsChannel const arenaChannel = observer.arenaActionsChannel
return({ return({
channels: arenaChannel ? [arenaChannel] : [], channels: arenaChannel ? [arenaChannel] : [],
}) })
+3 -3
View File
@@ -1,13 +1,13 @@
export const eventHandlers = { export const eventHandlers = {
'arena:lifecycle': { 'arena:lifecycle': {
onYourMarks(msg, chan) { onYourMarks(msg, chan, sender, cnxId) {
this.observerSrv?.onYourMarks() this.observerSrv?.onYourMarks()
}, },
bigBang(msg, chan) { bigBang(msg, chan, sender, cnxId) {
this.observerSrv?.onBigBang() this.observerSrv?.onBigBang()
}, },
simulationStopped(msg, chan) { simulationStopped(msg, chan, sender, cnxId) {
this.observerSrv?.onSimulationStopped(msg.payload ?? {}) this.observerSrv?.onSimulationStopped(msg.payload ?? {})
}, },
}, },
+1 -1
View File
@@ -11,7 +11,7 @@ export const dispatchMessage = createDispatchMessage({
actionRules(redisCnx) { actionRules(redisCnx) {
const observer = redisCnx.config.observer ?? {} const observer = redisCnx.config.observer ?? {}
return({ return({
channels: [observer.observerActionsChannel].filter(Boolean), channels: [observer.ActionsChannel].filter(Boolean),
}) })
}, },
}) })
+25 -18
View File
@@ -4,66 +4,66 @@ import { Frustum } from '../../frustum.js'
export const actions = { export const actions = {
async action_GETAGENTPOSITION(action, payload, reqid, sender, roles) { async action_GETAGENTPOSITION(action, payload, reqid, sender, cnxId, roles) {
const reader = this.observerSrv.gpsStorageReader const reader = this.observerSrv.gpsStorageReader
if(!reader) { if(!reader) {
replyToAction(this, { action, reqid, sender, success: false, err: 'GPS storage reader not ready' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'GPS storage reader not ready' })
return return
} }
if(!this.observerSrv.isLive()) { if(!this.observerSrv.isLive()) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Simulation not live' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Simulation not live' })
return return
} }
const agentId = payload?.agentId const agentId = payload?.agentId
if(!agentId || typeof(agentId) !== 'string') { if(!agentId || typeof(agentId) !== 'string') {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing or invalid agentId' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid agentId' })
return return
} }
const at = parseSimTime(payload, () => this.observerSrv.now()) const at = parseSimTime(payload, () => this.observerSrv.now())
if(at === null) { if(at === null) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Invalid simulation time' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Invalid simulation time' })
return return
} }
const agent = await reader.getAgentPosition(agentId, at) const agent = await reader.getAgentPosition(agentId, at)
if(!agent) { if(!agent) {
replyToAction(this, { action, reqid, sender, success: false, err: `Unknown agent: ${agentId}` }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: `Unknown agent: ${agentId}` })
return return
} }
replyToAction(this, { action, reqid, sender, success: true, payload: { agent } }) replyToAction(this, { action, reqid, sender, cnxId, success: true, payload: { agent } })
}, },
async action_GETAGENTSINFRUSTUM(action, payload, reqid, sender, roles) { async action_GETAGENTSINFRUSTUM(action, payload, reqid, sender, cnxId, roles) {
const registry = this.observerSrv.requestorRegistry const registry = this.observerSrv.requestorRegistry
if(!registry) { if(!registry) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Requestor registry not ready' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Requestor registry not ready' })
return return
} }
if(!this.observerSrv.isLive()) { if(!this.observerSrv.isLive()) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Simulation not live' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Simulation not live' })
return return
} }
const frustum = Frustum.fromPlanes(payload?.planes) const frustum = Frustum.fromPlanes(payload?.planes)
if(!frustum) { if(!frustum) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Missing or invalid frustum planes (expected 6)' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid frustum planes (expected 6)' })
return return
} }
const at = parseSimTime(payload, () => this.observerSrv.now()) const at = parseSimTime(payload, () => this.observerSrv.now())
if(at === null) { if(at === null) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Invalid simulation time' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Invalid simulation time' })
return return
} }
const result = await registry.evaluateOnce({ frustum, t: at }) const result = await registry.evaluateOnce({ frustum, t: at })
if(!result.ok) { if(!result.ok) {
replyToAction(this, { action, reqid, sender, success: false, err: result.err }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: result.err })
return return
} }
@@ -71,6 +71,7 @@ export const actions = {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: { payload: {
agents: result.agents, agents: result.agents,
@@ -79,24 +80,29 @@ export const actions = {
}) })
}, },
async action_SUBSCRIBEFRUSTUM(action, payload, reqid, sender, roles) { async action_SUBSCRIBEFRUSTUM(action, payload, reqid, sender, cnxId, roles) {
const registry = this.observerSrv.requestorRegistry const registry = this.observerSrv.requestorRegistry
if(!registry) { if(!registry) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Requestor registry not ready' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Requestor registry not ready' })
return return
} }
if(!this.observerSrv.isLive()) { if(!this.observerSrv.isLive()) {
replyToAction(this, { action, reqid, sender, success: false, err: 'Simulation not live' }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Simulation not live' })
return return
} }
const result = await registry.subscribeFrustum(sender, { if(!cnxId || typeof(cnxId) !== 'string') {
replyToAction(this, { action, reqid, sender, cnxId, success: false, err: 'Missing or invalid cnxId' })
return
}
const result = await registry.subscribeFrustum(cnxId, {
planes: payload?.planes, planes: payload?.planes,
frequency: payload?.frequency, frequency: payload?.frequency,
}) })
if(!result.ok) { if(!result.ok) {
replyToAction(this, { action, reqid, sender, success: false, err: result.err }) replyToAction(this, { action, reqid, sender, cnxId, success: false, err: result.err })
return return
} }
@@ -104,6 +110,7 @@ export const actions = {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: { payload: {
frequency: result.frequency, frequency: result.frequency,
+4 -3
View File
@@ -2,16 +2,17 @@ import { replyToAction } from '../../../bus/publishActionReply.js'
export const actions = { export const actions = {
async action_RELOADCONFIG(action, payload, reqid, sender, roles) { async action_RELOADCONFIG(action, payload, reqid, sender, cnxId, roles) {
this.reloadAccessRights() this.reloadAccessRights()
replyToAction(this, { action, reqid, sender, success: true }) replyToAction(this, { action, reqid, sender, cnxId, success: true })
}, },
async action_GETCONFIG(action, payload, reqid, sender, roles) { async action_GETCONFIG(action, payload, reqid, sender, cnxId, roles) {
replyToAction(this, { replyToAction(this, {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: true, success: true,
payload: this.getAccessRights(), payload: this.getAccessRights(),
}) })
+13 -29
View File
@@ -7,10 +7,12 @@ export class observerServer {
constructor(configHelper, allRediscnx, debug) { constructor(configHelper, allRediscnx, debug) {
this.configHelper = configHelper this.configHelper = configHelper
this.observerConfig = configHelper.config this.rootConfig = configHelper.config
this.observerConfig = configHelper.config.observer ?? {}
this.gpsConfig = configHelper.config.gps ?? {}
this.allRediscnx = allRediscnx this.allRediscnx = allRediscnx
this.debug = debug this.debug = debug
this.accessRights = new AccesRights(this.observerConfig, debug) this.accessRights = new AccesRights(this.rootConfig, debug)
this.arenaCnx = null this.arenaCnx = null
this.arenaCnxs = [] this.arenaCnxs = []
this.systemCnx = null this.systemCnx = null
@@ -20,27 +22,8 @@ export class observerServer {
this.bigBangEpoch = null this.bigBangEpoch = null
} }
getObserverSettings() {
const observer = this.observerConfig.observer ?? {}
return({
senderId: observer.senderId ?? 'observer',
scanIntervalMs: observer.scanIntervalMs ?? 300,
frustumEventsChannel: observer.observerFrustumEventsChannel
?? 'system:observer:subscribed[UID]:agents',
lifecycle: {
arenaChannel: observer.lifecycle?.arenaChannel ?? 'arena:lifecycle',
godsReadyChannel: observer.lifecycle?.godsReadyChannel ?? 'arena:gods:ready',
},
})
}
getGpsStorageSettings() {
const gps = this.observerConfig.gps ?? {}
return(gps.GPSstorage ?? null)
}
initGpsStorageReader() { initGpsStorageReader() {
const gpsStorage = this.getGpsStorageSettings() const gpsStorage = this.gpsConfig.GPSstorage
if(gpsStorage && this.systemCnx) { if(gpsStorage && this.systemCnx) {
this.gpsStorageReader = new GpsStorageReader(this.systemCnx, gpsStorage, this.debug) this.gpsStorageReader = new GpsStorageReader(this.systemCnx, gpsStorage, this.debug)
this.initRequestorRegistry() this.initRequestorRegistry()
@@ -49,7 +32,7 @@ export class observerServer {
initRequestorRegistry() { initRequestorRegistry() {
if(!this.gpsStorageReader || this.requestorRegistry) return if(!this.gpsStorageReader || this.requestorRegistry) return
const { scanIntervalMs } = this.getObserverSettings() const { scanIntervalMs } = this.observerConfig
this.requestorRegistry = new RequestorRegistry( this.requestorRegistry = new RequestorRegistry(
this.gpsStorageReader, this.gpsStorageReader,
() => this.now(), () => this.now(),
@@ -67,9 +50,9 @@ export class observerServer {
if(!this.systemCnx || !subscriberId) return if(!this.systemCnx || !subscriberId) return
if(!Array.isArray(agents) || !agents.length) return if(!Array.isArray(agents) || !agents.length) return
const { frustumEventsChannel } = this.getObserverSettings() const chan = this.observerConfig.FrustumEventsChannel
const chan = frustumEventsChannel.replace(/\[UID\]/g, subscriberId) .replace(/\[CUID\]/g, subscriberId)
const senderId = this.getObserverSettings().senderId const senderId = this.observerConfig.senderId
for(const agent of agents) { for(const agent of agents) {
if(!agent?.id || !agent?.position) continue if(!agent?.id || !agent?.position) continue
@@ -77,6 +60,7 @@ export class observerServer {
await this.systemCnx.redisPublish(chan, { await this.systemCnx.redisPublish(chan, {
eventType: 'move', eventType: 'move',
sender: senderId, sender: senderId,
cnxId: this.systemCnx.cnxId,
payload: { payload: {
aid: agent.id, aid: agent.id,
coords: { coords: {
@@ -147,12 +131,12 @@ export class observerServer {
async reloadAccessRights() { async reloadAccessRights() {
await this.configHelper.refreshAccessRights() await this.configHelper.refreshAccessRights()
this.observerConfig.accessRights = this.configHelper.config.accessRights this.rootConfig.accessRights = this.configHelper.config.accessRights
this.accessRights.refreshAccessRights(this.observerConfig) this.accessRights.refreshAccessRights(this.rootConfig)
} }
getAccessRights() { getAccessRights() {
return(this.observerConfig.accessRights) return(this.rootConfig.accessRights)
} }
} }
+1
View File
@@ -0,0 +1 @@
t
+5 -2
View File
@@ -27,14 +27,17 @@ export function assembleHandlers(modules) {
}) })
} }
export function createDispatchMessage({ eventHandlers, actionRules }) { export function createDispatchMessage({ eventHandlers, eventRules, actionRules }) {
return(async function dispatchMessage(redisCnx, msg, chan) { return(async function dispatchMessage(redisCnx, msg, chan) {
if(msg.action && msg.eventType) { if(msg.action && msg.eventType) {
console.warn(`[${redisCnx.redisId}] Message has both action and eventType on ${chan}`) console.warn(`[${redisCnx.redisId}] Message has both action and eventType on ${chan}`)
return(false) return(false)
} }
if(msg.action) return(dispatchActions(redisCnx, msg, chan, actionRules(redisCnx))) if(msg.action) return(dispatchActions(redisCnx, msg, chan, actionRules(redisCnx)))
if(msg.eventType) return(dispatchEvents(redisCnx, msg, chan, eventHandlers)) if(msg.eventType) {
const handlers = eventRules ? eventRules(redisCnx) : eventHandlers
return(dispatchEvents(redisCnx, msg, chan, handlers))
}
return(false) return(false)
}) })
} }
+7 -2
View File
@@ -14,6 +14,7 @@ export async function dispatchActions(redisCnx, msg, chan, rules) {
const action = msg.action const action = msg.action
const sender = msg.sender ?? null const sender = msg.sender ?? null
const cnxId = msg.cnxId ?? null
const reqid = ('reqid' in msg) ? msg.reqid.substr(0, 50) : null const reqid = ('reqid' in msg) ? msg.reqid.substr(0, 50) : null
const roles = Array.isArray(msg.roles) ? msg.roles : ['*'] const roles = Array.isArray(msg.roles) ? msg.roles : ['*']
@@ -21,8 +22,9 @@ export async function dispatchActions(redisCnx, msg, chan, rules) {
if(!sender) return(true) if(!sender) return(true)
replyToAction(redisCnx, { replyToAction(redisCnx, {
action, action,
reqid,
sender, sender,
reqid,
cnxId,
success: false, success: false,
err: 'Missing or invalid action', err: 'Missing or invalid action',
}) })
@@ -39,6 +41,7 @@ export async function dispatchActions(redisCnx, msg, chan, rules) {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: false, success: false,
err: 'Unauthorized action !', err: 'Unauthorized action !',
}) })
@@ -51,6 +54,7 @@ export async function dispatchActions(redisCnx, msg, chan, rules) {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: false, success: false,
err: `Unknown action: ${action}`, err: `Unknown action: ${action}`,
}) })
@@ -62,13 +66,14 @@ export async function dispatchActions(redisCnx, msg, chan, rules) {
} }
try { try {
await handler.call(redisCnx, action, ('payload' in msg) ? msg.payload : null, reqid, sender, roles) await handler.call(redisCnx, action, ('payload' in msg) ? msg.payload : null, reqid, sender, cnxId, roles)
} catch(err) { } catch(err) {
console.error(`[${redisCnx.redisId}] Action ${action} failed:`, err) console.error(`[${redisCnx.redisId}] Action ${action} failed:`, err)
replyToAction(redisCnx, { replyToAction(redisCnx, {
action, action,
reqid, reqid,
sender, sender,
cnxId,
success: false, success: false,
err: err.message ?? `${action} failed`, err: err.message ?? `${action} failed`,
}) })
+3 -1
View File
@@ -1,6 +1,8 @@
export function dispatchEvents(redisCnx, msg, chan, eventHandlers) { export function dispatchEvents(redisCnx, msg, chan, eventHandlers) {
const eventType = msg.eventType const eventType = msg.eventType
const sender = msg.sender ?? null
const cnxId = msg.cnxId ?? null
if(!eventType || typeof(eventType) !== 'string') return(false) if(!eventType || typeof(eventType) !== 'string') return(false)
let handled = false let handled = false
@@ -13,7 +15,7 @@ export function dispatchEvents(redisCnx, msg, chan, eventHandlers) {
for(const handle of handlers) { for(const handle of handlers) {
try { try {
handle.call(redisCnx, msg, chan) handle.call(redisCnx, msg, chan, sender, cnxId)
} catch(err) { } catch(err) {
console.error( console.error(
`[${redisCnx.redisId}] Event ${eventType} on ${chan} failed:`, `[${redisCnx.redisId}] Event ${eventType} on ${chan} failed:`,
+6 -11
View File
@@ -3,12 +3,9 @@ export function busReplyRoute(daemonBlock, meshName) {
if(!daemonBlock?.senderId) return(null) if(!daemonBlock?.senderId) return(null)
const onArena = meshName === 'arena' const onArena = meshName === 'arena'
const systemReply = daemonBlock.maestroActionsReply
?? daemonBlock.gpsActionsReply
?? daemonBlock.observerActionsReply
const actionsReply = onArena const actionsReply = onArena
? (daemonBlock.bus?.arena?.actionsReply ?? systemReply) ? (daemonBlock.bus?.arena?.actionsReply ?? daemonBlock.ActionsReply)
: systemReply : daemonBlock.ActionsReply
if(!actionsReply) return(null) if(!actionsReply) return(null)
@@ -25,12 +22,13 @@ export function publishActionReply(redisCnx, options) {
sender, sender,
reply, reply,
replyChannel, replyChannel,
senderId,
} = options } = options
reply.action = action reply.action = action
reply.sender = senderId reply.sender = redisCnx.senderId
reply.cnxId = redisCnx.cnxId
if(reqid) reply.reqid = reqid if(reqid) reply.reqid = reqid
const chan = replyChannel.replace(/\[UID\]/g, sender) const chan = replyChannel.replace(/\[UID\]/g, sender)
.replace(/\[CUID\]/g, redisCnx.cnxId)
redisCnx.redisPublish(chan, reply) redisCnx.redisPublish(chan, reply)
} }
@@ -43,13 +41,11 @@ export function replyToAction(redisCnx, options) {
payload, payload,
err, err,
replyChannel, replyChannel,
senderId,
} = options } = options
const routeReplyChannel = replyChannel ?? redisCnx.actionsReply const routeReplyChannel = replyChannel ?? redisCnx.actionsReply
const routeSenderId = senderId ?? redisCnx.senderId
if(!routeReplyChannel || !routeSenderId) { if(!routeReplyChannel) {
console.error(`[${redisCnx.redisId}] Cannot resolve action reply route`) console.error(`[${redisCnx.redisId}] Cannot resolve action reply route`)
return return
} }
@@ -63,7 +59,6 @@ export function replyToAction(redisCnx, options) {
reqid, reqid,
sender, sender,
replyChannel: routeReplyChannel, replyChannel: routeReplyChannel,
senderId: routeSenderId,
reply, reply,
}) })
} }
+18 -12
View File
@@ -29,8 +29,10 @@
], ],
"gps": { "gps": {
"primordialDaemon": true, "primordialDaemon": true,
"gpsActionsChannel": "system:requests:gps", "ActionsChannel": "system:requests:gps",
"gpsActionsReply": "system:replies:[UID]", "ActionsReply": "system:replies:[UID]",
"arenaActionsChannel": "arena:requests:[UID]",
"arenaActionsReply": "arena:replies:[UID]",
"GPSstorage": { "GPSstorage": {
"agentHashKey": "system:gps:agent:[UID]", "agentHashKey": "system:gps:agent:[UID]",
"agentsIndexKey": "system:gps:agents", "agentsIndexKey": "system:gps:agents",
@@ -54,8 +56,10 @@
"prismRefreshLeadSeconds": 1 "prismRefreshLeadSeconds": 1
}, },
"maestro": { "maestro": {
"maestroActionsChannel": "system:requests:maestro", "ActionsChannel": "system:requests:maestro",
"maestroActionsReply": "system:replies:[UID]", "ActionsReply": "system:replies:[UID]",
"arenaActionsChannel": "arena:requests:[UID]",
"arenaActionsReply": "arena:replies:[UID]",
"senderId": "maestro", "senderId": "maestro",
"lifecycle": { "lifecycle": {
"arenaChannel": "arena:lifecycle", "arenaChannel": "arena:lifecycle",
@@ -64,16 +68,13 @@
"systemLifecycleChannel": "system:maestro:lifecycle:[UID]", "systemLifecycleChannel": "system:maestro:lifecycle:[UID]",
"readyTimeoutMs": 30000 "readyTimeoutMs": 30000
}, },
"mysql": {
"socketPath": "/var/run/mysqld/mysqld.sock",
"guiDatabase": "p42GUI",
"simDatabase": "p42SIM"
},
"observer": { "observer": {
"primordialDaemon": false, "primordialDaemon": false,
"observerActionsChannel": "system:requests:observer", "ActionsChannel": "system:requests:observer",
"observerActionsReply": "system:replies:[UID]", "ActionsReply": "system:replies:[UID]",
"observerFrustumEventsChannel": "system:observer:subscribed[UID]:agents", "arenaActionsChannel": "arena:requests:[UID]",
"arenaActionsReply": "arena:replies:[UID]",
"FrustumEventsChannel": "system:observer:subscribed[CUID]:agents",
"senderId": "observer", "senderId": "observer",
"scanIntervalMs": 300, "scanIntervalMs": 300,
"lifecycle": { "lifecycle": {
@@ -110,5 +111,10 @@
"basePrefix": "messageBus:" "basePrefix": "messageBus:"
} }
] ]
},
"mysql": {
"socketPath": "/var/run/mysqld/mysqld.sock",
"guiDatabase": "p42GUI",
"simDatabase": "p42SIM"
} }
} }
+26 -13
View File
@@ -61,8 +61,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"primordialDaemon": { "type": "boolean" }, "primordialDaemon": { "type": "boolean" },
"gpsActionsChannel": { "type": "string" }, "ActionsChannel": { "type": "string" },
"gpsActionsReply": { "type": "string" }, "ActionsReply": { "type": "string" },
"arenaActionsChannel": { "type": "string" },
"arenaActionsReply": { "type": "string" },
"GPSstorage": { "GPSstorage": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -108,8 +110,10 @@
"prismRefreshLeadSeconds": { "type": "number", "minimum": 0 } "prismRefreshLeadSeconds": { "type": "number", "minimum": 0 }
}, },
"required": [ "required": [
"gpsActionsChannel", "ActionsChannel",
"gpsActionsReply", "ActionsReply",
"arenaActionsChannel",
"arenaActionsReply",
"GPSstorage", "GPSstorage",
"agentVectorChangeChannel", "agentVectorChangeChannel",
"collisionsChannel" "collisionsChannel"
@@ -118,8 +122,10 @@
"maestro": { "maestro": {
"type": "object", "type": "object",
"properties": { "properties": {
"maestroActionsChannel": { "type": "string" }, "ActionsChannel": { "type": "string" },
"maestroActionsReply": { "type": "string" }, "ActionsReply": { "type": "string" },
"arenaActionsChannel": { "type": "string" },
"arenaActionsReply": { "type": "string" },
"senderId": { "type": "string" }, "senderId": { "type": "string" },
"lifecycle": { "lifecycle": {
"type": "object", "type": "object",
@@ -135,8 +141,10 @@
"readyTimeoutMs": { "type": "integer", "minimum": 1000 } "readyTimeoutMs": { "type": "integer", "minimum": 1000 }
}, },
"required": [ "required": [
"maestroActionsChannel", "ActionsChannel",
"maestroActionsReply" "ActionsReply",
"arenaActionsChannel",
"arenaActionsReply"
] ]
}, },
"mysql": { "mysql": {
@@ -155,9 +163,11 @@
"type": "object", "type": "object",
"properties": { "properties": {
"primordialDaemon": { "type": "boolean" }, "primordialDaemon": { "type": "boolean" },
"observerActionsChannel": { "type": "string" }, "ActionsChannel": { "type": "string" },
"observerActionsReply": { "type": "string" }, "ActionsReply": { "type": "string" },
"observerFrustumEventsChannel": { "type": "string" }, "arenaActionsChannel": { "type": "string" },
"arenaActionsReply": { "type": "string" },
"FrustumEventsChannel": { "type": "string" },
"senderId": { "type": "string" }, "senderId": { "type": "string" },
"scanIntervalMs": { "type": "integer", "minimum": 50 }, "scanIntervalMs": { "type": "integer", "minimum": 50 },
"lifecycle": { "lifecycle": {
@@ -173,8 +183,11 @@
} }
}, },
"required": [ "required": [
"observerActionsChannel", "ActionsChannel",
"observerActionsReply" "ActionsReply",
"FrustumEventsChannel",
"arenaActionsChannel",
"arenaActionsReply"
] ]
}, },
"systemMesh": { "systemMesh": {
+18 -12
View File
@@ -29,8 +29,10 @@
], ],
"gps": { "gps": {
"primordialDaemon": true, "primordialDaemon": true,
"gpsActionsChannel": "system:requests:gps", "ActionsChannel": "system:requests:gps",
"gpsActionsReply": "system:replies:[UID]", "ActionsReply": "system:replies:[UID]",
"arenaActionsChannel": "arena:requests:[UID]",
"arenaActionsReply": "arena:replies:[UID]",
"GPSstorage": { "GPSstorage": {
"agentHashKey": "system:gps:agent:[UID]", "agentHashKey": "system:gps:agent:[UID]",
"agentsIndexKey": "system:gps:agents", "agentsIndexKey": "system:gps:agents",
@@ -54,8 +56,10 @@
"prismRefreshLeadSeconds": 1 "prismRefreshLeadSeconds": 1
}, },
"maestro": { "maestro": {
"maestroActionsChannel": "system:requests:maestro", "ActionsChannel": "system:requests:maestro",
"maestroActionsReply": "system:replies:[UID]", "ActionsReply": "system:replies:[UID]",
"arenaActionsChannel": "arena:requests:[UID]",
"arenaActionsReply": "arena:replies:[UID]",
"senderId": "maestro", "senderId": "maestro",
"lifecycle": { "lifecycle": {
"arenaChannel": "arena:lifecycle", "arenaChannel": "arena:lifecycle",
@@ -64,16 +68,13 @@
"systemLifecycleChannel": "system:maestro:lifecycle:[UID]", "systemLifecycleChannel": "system:maestro:lifecycle:[UID]",
"readyTimeoutMs": 30000 "readyTimeoutMs": 30000
}, },
"mysql": {
"socketPath": "/var/run/mysqld/mysqld.sock",
"guiDatabase": "test_p42GUI",
"simDatabase": "test_p42SIM"
},
"observer": { "observer": {
"primordialDaemon": false, "primordialDaemon": false,
"observerActionsChannel": "system:requests:observer", "ActionsChannel": "system:requests:observer",
"observerActionsReply": "system:replies:[UID]", "ActionsReply": "system:replies:[UID]",
"observerFrustumEventsChannel": "system:observer:subscribed[UID]:agents", "FrustumEventsChannel": "system:observer:subscribed[CUID]:agents",
"arenaActionsChannel": "arena:requests:[UID]",
"arenaActionsReply": "arena:replies:[UID]",
"senderId": "observer", "senderId": "observer",
"scanIntervalMs": 300, "scanIntervalMs": 300,
"lifecycle": { "lifecycle": {
@@ -110,5 +111,10 @@
"basePrefix": "messageBus:" "basePrefix": "messageBus:"
} }
] ]
},
"mysql": {
"socketPath": "/var/run/mysqld/mysqld.sock",
"guiDatabase": "test_p42GUI",
"simDatabase": "test_p42SIM"
} }
} }
+3
View File
@@ -1,4 +1,5 @@
import redis from 'redis' import redis from 'redis'
import os from 'node:os'
export class RedisConnexion { export class RedisConnexion {
@@ -12,6 +13,8 @@ export class RedisConnexion {
this.senderId = options.senderId ?? null this.senderId = options.senderId ?? null
this.actionsReply = options.actionsReply ?? null this.actionsReply = options.actionsReply ?? null
this.cnxId = os.hostname() + ':' + process.pid + ':' + Date.now() + ':' + Math.random().toString(36).substring(2, 15)
if(this.meshModule?.actionHandlers) Object.assign(this, this.meshModule.actionHandlers) if(this.meshModule?.actionHandlers) Object.assign(this, this.meshModule.actionHandlers)
this.afterLogin = this.meshModule?.afterLogin ?? [] this.afterLogin = this.meshModule?.afterLogin ?? []
+1 -1
View File
@@ -197,7 +197,7 @@ export async function run(ctx) {
const lifecycleWait = waitForLifecycleEvent(ctx, 'onYourMarks', argv.timeout) const lifecycleWait = waitForLifecycleEvent(ctx, 'onYourMarks', argv.timeout)
const reqid = `maestro1-${Date.now()}` const reqid = `maestro1-${Date.now()}`
const actionsChan = config.maestro.maestroActionsChannel const actionsChan = config.maestro.ActionsChannel
log('action', `Publishing STARTSIMULATION on ${actionsChan} (reqid=${reqid})...`) log('action', `Publishing STARTSIMULATION on ${actionsChan} (reqid=${reqid})...`)
await systemCnx.redisPublish(actionsChan, { await systemCnx.redisPublish(actionsChan, {