Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
df96d74
Update package.json
ReuschelCGN Aug 28, 2025
3b80cfb
Add files via upload
ReuschelCGN Aug 28, 2025
fcf4fbb
Add files via upload
ReuschelCGN Aug 28, 2025
51b347f
Update dts.json
ReuschelCGN Aug 28, 2025
7784e07
Update testdata.json
ReuschelCGN Aug 28, 2025
eb3b8c5
Update default.json
ReuschelCGN Aug 28, 2025
ba3b38b
Update de.json
ReuschelCGN Aug 28, 2025
6bcc682
Update de.json
ReuschelCGN Aug 28, 2025
372ba56
Update app.js
ReuschelCGN Aug 28, 2025
0b44c51
Update app.js
ReuschelCGN Aug 28, 2025
e36187c
Update controllerWorker.js
ReuschelCGN Aug 28, 2025
ad67d7d
Update upgradeDts.js
ReuschelCGN Aug 28, 2025
86a5ffe
Update util.json
ReuschelCGN Aug 28, 2025
6e7f1ff
Update apiConfig.js
ReuschelCGN Aug 28, 2025
b3f9a0f
Update apiTracking.js
ReuschelCGN Aug 28, 2025
9e17d6e
Add files via upload
ReuschelCGN Aug 28, 2025
fda4114
Add files via upload
ReuschelCGN Aug 28, 2025
cfe4927
Update telegramReconciliation.js
ReuschelCGN Aug 28, 2025
1842d9c
Add files via upload
ReuschelCGN Aug 28, 2025
a7d3657
Add files via upload
ReuschelCGN Aug 28, 2025
7930d91
Update discordReconciliation.js
ReuschelCGN Aug 28, 2025
4d254b8
Update channelDelete.js
ReuschelCGN Aug 28, 2025
de85e27
Add files via upload
ReuschelCGN Aug 28, 2025
a6c46f1
Update backup.js
ReuschelCGN Aug 28, 2025
f8fcdb5
Add files via upload
ReuschelCGN Aug 28, 2025
7352f2b
Update poracle-test.js
ReuschelCGN Aug 28, 2025
ac7a6ff
Update profile.js
ReuschelCGN Aug 28, 2025
68e9b96
Update script.js
ReuschelCGN Aug 28, 2025
3b5e63d
Update tracked.js
ReuschelCGN Aug 28, 2025
4b43cfe
Update unregister.js
ReuschelCGN Aug 28, 2025
5fe4eb1
Update uicons.js
ReuschelCGN Aug 28, 2025
c5ed218
Update maxbattle.js
ReuschelCGN Aug 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"disableNest": false,
"disableGym": false,
"disableFortUpdate": false,
"disableMaxBattle": false,
// invasion hook processing for Golbat systems
"processConfirmedInvasionLineups": false,
"disableUnconfirmedInvasion": false,
Expand Down
38 changes: 38 additions & 0 deletions config/defaults/dts.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,44 @@
"webpage_preview": true
}
},
{
"id": 1,
"language": "en",
"type": "maxbattle",
"default": true,
"platform": "discord",
"template": {
"embed": {
"title": "{{levelName}} against {{fullName}} has started at Powerstation {{{stationName}}}!",
"description": "quick: {{quickMoveName}}, charge: {{chargeMoveName}} \n Maps: [Google]({{{googleMapUrl}}}) | [Apple]({{{appleMapUrl}}})",
"color": "{{color}}",
"thumbnail": {
"url": "{{{imgUrl}}}"
},
"author": {
"name": "{{fullName}} {{levelName}} maxbattle. End: {{time}} in {{tthm}}m {{tths}}s",
"icon_url": "{{{imgUrl}}}"
},
"image": {
"url": "{{{staticMap}}}"
}
}
}
},
{
"id": 1,
"language": "en",
"type": "maxbattle",
"default": true,
"platform": "telegram",
"template": {
"content": "{{levelName}} against {{fullName}} has started at Powerstation {{{stationName}}}! \nquick: {{quickMoveName}}, charge: {{chargeMoveName}} \nEnd: {{time}} in {{tthm}}m {{tths}}s\nMaps: [Google]({{{googleMapUrl}}}) | [Apple]({{{appleMapUrl}}})",
"parse_mode": "Markdown",
"sticker": "{{{stickerUrl}}}",
"location": true,
"webpage_preview": true
}
},
{
"id": 1,
"language": "en",
Expand Down
18 changes: 18 additions & 0 deletions config/defaults/testdata.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,5 +208,23 @@
"test": "remove",
"location": "current",
"webhook": {"change_type": "removal", "old": {"id": "f7430347f5c34facb838be376f16adea.16", "type": "pokestop", "name": "Journey Through Trees And Time", "description": null, "image_url": "http://lh3.googleusercontent.com/VSBh5Q5W6z5LHBLDFQqBNtCTBxqe0HAy4H9W_Um2_AVUg8Rh40u1tYteSc2TVLtPAd4v7c83umdTh6RUVNpOkACjt9saHNj6a_2XYRsGYg", "location": {"lat": 50.975598, "lon": 6.942527}}}
},
{
"type": "max_battle",
"test": "level3",
"location": "current",
"webhook": {"battle_end": 1745982000, "battle_level": 3, "battle_pokemon_alignment": 0, "battle_pokemon_bread_mode": 1, "battle_pokemon_costume": 0, "battle_pokemon_form": 0, "battle_pokemon_gender": 3, "battle_pokemon_id": 615, "battle_pokemon_move_1": 217, "battle_pokemon_move_2": 116, "battle_start": 1745780400, "end_time": 1745982000, "is_battle_available": true, "latitude": 50.942951, "longitude": 6.871009, "name": "Stahlwand", "start_time": 1745722800, "id": "f0797fd357ff4122ab935b5b154fedf0.16", "total_stationed_gmax": 0, "total_stationed_pokemon": 0, "updated": 1745850039}
},
{
"type": "max_battle",
"test": "level1",
"location": "current",
"webhook": {"battle_end": 1745895600, "battle_level": 1, "battle_pokemon_alignment": 0, "battle_pokemon_bread_mode": 1, "battle_pokemon_costume": 0, "battle_pokemon_form": 0, "battle_pokemon_gender": 2, "battle_pokemon_id": 831, "battle_pokemon_move_1": 221, "battle_pokemon_move_2": 333, "battle_start": 1745778600, "end_time": 1745895600, "is_battle_available": true, "latitude": 50.998899, "longitude": 6.939451, "name": "Parkour Movement", "start_time": 1745636400, "id": "bb161a9eff2a47c291df2906a02f11de.23", "total_stationed_gmax": 0, "total_stationed_pokemon": 0, "updated": 1745850055}
},
{
"type": "max_battle",
"test":"gmax",
"location":"keep",
"webhook":{"battle_end": 1745859600, "battle_level": 7, "battle_pokemon_alignment": 0, "battle_pokemon_bread_mode": 2, "battle_pokemon_costume": 0, "battle_pokemon_form": 815, "battle_pokemon_gender": 1, "battle_pokemon_id": 68, "battle_pokemon_move_1": 243, "battle_pokemon_move_2": 64, "battle_start": 1745856000, "end_time": 1746068400, "is_battle_available": true, "latitude": 50.964694, "longitude": 6.953887, "name": "Taqsim Patisserie", "start_time": 1745809200, "station_id": "4f949bb0bc9244e6b46e9e665c050970.23", "total_stationed_gmax": 3, "total_stationed_pokemon": 8, "updated": 1745857449}
}
]
6 changes: 6 additions & 0 deletions locale/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@
"Max Potion":"Top-Trank",
"Max Revive":"Top-Beleber",
"maxatk":"maxatk",
"maxbattle":"dynamax",
"maxbattles":"dynamax Kämpfe",
"maxcp":"maxwp",
"maxdef":"maxdef",
"maxiv":"maxiv",
Expand Down Expand Up @@ -390,6 +392,7 @@
"Valid commands are e.g. `{0}incident giovanni`, `{0}incident dragon`, `{0}incident remove everything`":"Gültige Befehle sind z.B. `{0}ereignis giovanni`, `{0}ereignis drache`, `{0}ereignis entfernen alle` (oder z.B. `{0}invasion drache`)",
"Valid commands are e.g. `{0}location <lat>,<lon>`, `{0}location <your address>`":"Gültige Befehle sind z.B. `{0}standort <lat>,<lon>`, `{0}standort <adresse>`",
"Valid commands are e.g. `{0}lure mossy`, `{0}lure remove everything`":"Gültige Befehle sind z.B. `{0}lockmodul moos`, `{0}lockmodul entfernen alle`",
"Valid commands are e.g. `{0}maxbattle level5`, `{0}maxbattle relaxo gmax`, `{0}maxbattle remove everything`":"Gültige Befehle sind z.B. `{0}dynamax level5`, `{0}dynamax relaxo gmax`, `{0}dynamax entfernen alle`",
"Valid commands are e.g. `{0}quest spinda`, `{0}quest energycharizard`, `{0}quest remove everything`":"Gültige Befehle sind z.B. `{0}quest pandir`, `{0}quest energieglurak`, `{0}quest entfernen alle`",
"Valid commands are e.g. `{0}raid level5`, `{0}raid articuno`, `{0}raid remove everything`":"Gültige Befehle sind z.B. `{0}raid level5`, `{0}raid arktos`, `{0}raid entfernen alle`",
"Valid commands are e.g. `{0}script everything`, `{0}script pokemon raids eggs quest lures invasion nests gym`, `{0}script everything allprofiles`, `{0}script everything link`":"Gültige Befehle sind z.B. `{0}script alle`, `{0}script pokemon raids quest eier lockmodule invasion nester arena`, `{0}script alle alleprofile`, `{0}script alle link`",
Expand Down Expand Up @@ -433,6 +436,7 @@
"You do not have permission to track nests":"keine Berechtigung Nester zu tracken",
"You do not have permission to track gyms":"keine Berechtigung Arenen zu tracken",
"You do not have permission to track fort changes":"keine Berechtigung Gym und Stop Änderungen zu tracken",
"You do not have permission to track maxbattles":"keine Berechtigung dynamax Kämpfe zu tracken",
"You don't have a profile set":"Kein Profil gewählt",
"You have been granted the role {0}":"Folgende Rolle wurde hinzugefügt: {0}",
"You have breached the rate limit too many times in the last 24 hours. Your messages are now stopped, use {0}start to resume":"24 Std. Nachrichtenlimit wurde überschritten. Benachrichtigungen sind nun deaktiviert, nutze {0}start um diese wieder zu aktivieren",
Expand All @@ -456,6 +460,7 @@
"You're not tracking any quests":"Es werden keine Quests beobachtet.",
"You're not tracking any raids":"Es werden keine Raids beobachtet.",
"You're not tracking any fort changes":"Es werden keine Gym und Stop Änderungen beobachtet.",
"You're not tracking any maxbattles":"Es werden keine dynamax Kämpfe beobachtet.",
"You're tracking the following gyms:":"Folgende Arenen werden beobachtet:",
"You're tracking the following invasions:":"Folgende Team-GO-Rocket-Invasionen werden beobachtet:",
"You're tracking the following lures:":"Folgende Lockmodule werden beobachtet:",
Expand All @@ -464,5 +469,6 @@
"You're tracking the following quests:":"Folgende Quests werden beobachtet:",
"You're tracking the following raids:":"Folgende Raids werden beobachtet:",
"You're tracking the following fort changes:":"Folgende Gym und Stop Änderungen werden beobachtet:",
"You're tracking the following maxbattles:":"Folgende dynamax Kämpfe werden beobachtet:",
"Zen":"Trance-Modus"
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "poracle",
"version": "4.8.4",
"version": "4.8.5",
"description": "Webhook processing and personalised discord|telegram alarms",
"keywords": [
"poracle",
Expand Down
21 changes: 20 additions & 1 deletion src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,6 @@ async function processOne(hook) {
await processHook(hook)
break
}

case 'nest': {
if (config.general.disableNest) {
fastify.controllerLog.debug(`${hook.message.nest_id}: Nest was received but set to be ignored in config`)
Expand All @@ -797,7 +796,27 @@ async function processOne(hook) {
await processHook(hook)
break
}
case 'max_battle': {
if (config.general.disableMaxBattle) {
fastify.controllerLog.debug(`${hook.message.id}: MaxBattle was received but set to be ignored in config`)

break
}
if (!hook.message.poracleTest) {
fastify.webhooks.info(`max_battle ${JSON.stringify(hook.message)}`)
const cacheKey = `${hook.message.id}${hook.message.battle_end}${hook.message.battle_pokemon_id}`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache will expire well ahead of the max battle most probably, so this may not provide any value whatsoever.
What causes golbat to resend a station webhook and do we care that this will generate a new alert?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hook.message.id -> Station ID
hook.message.battle_end -> is eqal to end_time in golbat DB
hook.message.battle_pokemon_id -> if this change we get a new alert on same station

Why the cache should expire in normal use ahead of the max battle end?
But on Maxmondays or Events, it should gen. a new alert.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jabes meant that you put an element into cache, but the cache itself lasts for x minutes?! Maybe an hour? So cache lookup will almost never happen

Golbat is not sending any duplicate hooks, it only sends if there something changes, like battle end, or Pokémon etc.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the cache lasts an hour (I think). And the max battle has a duration much longer than that, so updates within the period will not be eliminated by the cache

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok so the cache could look like that:

const cacheKey = ${hook.message.id}${hook.message.battle_pokemon_id}``

Copy link
Copy Markdown
Contributor Author

@ReuschelCGN ReuschelCGN Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rephrasing my question - are there any duplicate webhook messages that you are trying to avoid passing into the alerting engine?

Maxbattles have rotating moves and there are stationed mons which change, so i wanted to be sure, not to gen unnecessary alterts. But maybe im wrong with my thought.

Copy link
Copy Markdown
Contributor

@Fabio1988 Fabio1988 Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Max Monday would be such a case... For one hour there is a certain mon deployed... After that hour it changes back to the old one.... Golbat might send another hook
But the old mon can be already available for days, a one hour cache won't belp on that duplicate

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we increase the cache for max battles to 2h? So we would safely not send a duplicate webhook on the 7PM change? :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const cache = new NodeCache({ stdTTL: 5400, useClones: false }) // 90 minutes

looks like its gen. 90min cache

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... As the first webhook could be sent the day before, we might still send another hook at 7PM... If I think about it, that's not that bad I guess

Do you have some notification examples for max monday or e.g. this event with Toxtricity?! :)


if (fastify.cache.get(cacheKey)) {
fastify.controllerLog.debug(`${hook.message.id}: MaxBattle was sent again too soon, ignoring`)
break
}

fastify.cache.set(cacheKey, 'x')
}

await processHook(hook)
break
}
case 'weather': {
if (config.general.disableWeather) break
fastify.webhooks.info(`weather ${JSON.stringify(hook.message)}`)
Expand Down
14 changes: 14 additions & 0 deletions src/controllerWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const FortUpdateController = require('./controllers/fortupdate')
const GymController = require('./controllers/gym')
const PokestopLureController = require('./controllers/pokestop_lure')
const NestController = require('./controllers/nest')
const MaxbattleController = require('./controllers/maxbattle')
const ControllerWeatherManager = require('./controllers/weatherData')
const StatsData = require('./controllers/statsData')
const CachingGeocoder = require('./lib/cachingGeocoder')
Expand Down Expand Up @@ -62,6 +63,7 @@ const nestController = new NestController(logs.controller, knex, cachingGeocoder
const pokestopLureController = new PokestopLureController(logs.controller, knex, cachingGeocoder, scannerQuery, config, dts, geofence, GameData, rateLimitedUserCache, translatorFactory, mustache, controllerWeatherManager, statsData, eventParsers)
const fortUpdateController = new FortUpdateController(logs.controller, knex, cachingGeocoder, scannerQuery, config, dts, geofence, GameData, rateLimitedUserCache, translatorFactory, mustache, controllerWeatherManager, statsData, eventParsers)
const gymController = new GymController(logs.controller, knex, cachingGeocoder, scannerQuery, config, dts, geofence, GameData, rateLimitedUserCache, translatorFactory, mustache, controllerWeatherManager, statsData, eventParsers)
const maxbattleController = new MaxbattleController(logs.controller, knex, cachingGeocoder, scannerQuery, config, dts, geofence, GameData, rateLimitedUserCache, translatorFactory, mustache, controllerWeatherManager, statsData, eventParsers)

const monsterAlarmMatch = new MonsterAlarmMatch(logs.controller, knex, config)

Expand Down Expand Up @@ -143,6 +145,15 @@ async function processOne(hook) {
}
break
}
case 'max_battle': {
const result = await maxbattleController.handle(hook.message)
if (result) {
queueAddition = result
} else {
log.error(`Worker ${workerId}: Missing result from ${hook.type} processor`, { data: hook.message })
}
break
}
case 'nest': {
const result = await nestController.handle(hook.message)
if (result) {
Expand Down Expand Up @@ -199,6 +210,7 @@ function reloadDts() {
pokestopLureController.setDts(newDts)
gymController.setDts(newDts)
fortUpdateController.setDts(newDts)
maxbattleController.setDts(newDts)
log.info('DTS reloaded')
} catch (err) {
log.error('Error reloading dts', err)
Expand All @@ -216,6 +228,7 @@ function reloadGeofence() {
pokestopLureController.setGeofence(newGeofence)
gymController.setGeofence(newGeofence)
fortUpdateController.setGeofence(newGeofence)
maxbattleController.setGeofence(newGeofence)
log.info('Geofence reloaded')
} catch (err) {
log.error('Error reloading geofence', err)
Expand Down Expand Up @@ -326,6 +339,7 @@ if (!isMainThread) {
pokestopController.on('postMessage', (jobs) => queuePort.postMessage({ queue: jobs }))
pokestopLureController.on('postMessage', (jobs) => queuePort.postMessage({ queue: jobs }))
gymController.on('postMessage', (jobs) => queuePort.postMessage({ queue: jobs }))
maxbattleController.on('postMessage', (jobs) => queuePort.postMessage({ queue: jobs }))

monsterAlarmMatch.loadData().catch(() => {})
setInterval(currentStatus, 60000)
Expand Down
Loading