-
Notifications
You must be signed in to change notification settings - Fork 138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve migration to eosIDs #354
Changes from 6 commits
f68f8f3
0a8332f
ad1f9e4
8a2849e
cc3fce9
b506205
7b298a7
a78036b
cbe29e5
07be06f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
const ID_MATCHER = /\s*(?<name>[^:]+): (?<id>[^\s]+)/g; | ||
|
||
// PARSING AND ITERATION | ||
|
||
// main function intended for parsing `Online IDs:` body. Returns an | ||
// iterator that yields `{platform: id}` pairs. | ||
export const iterate = (idsStr) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be renamed to a more descriptive name such as |
||
return new IdsIterator(idsStr.matchAll(ID_MATCHER)); | ||
}; | ||
|
||
class IdsIterator { | ||
constructor(matchIterator) { | ||
this.inner = matchIterator; | ||
} | ||
|
||
[Symbol.iterator]() { | ||
return this; | ||
} | ||
|
||
next() { | ||
const match = this.inner.next(); | ||
if (match.done) return { value: undefined, done: true }; | ||
return { value: { key: match.value[1], value: match.value[2] }, done: false }; | ||
} | ||
|
||
forEach(callbackFn) { | ||
for (const { key, value } of this) callbackFn(key, value); | ||
} | ||
} | ||
|
||
// FORMATTING | ||
|
||
// `steam => SteamID` | ||
export const capitalID = (str) => { | ||
return str.charAt(0).toUpperCase() + str.slice(1) + 'ID'; | ||
}; | ||
|
||
// `EOS => eosID` | ||
export const lowerID = (str) => { | ||
return str.toLowerCase() + 'ID'; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import Rcon from './rcon.js'; | |
import { SQUADJS_VERSION } from './utils/constants.js'; | ||
|
||
import fetchAdminLists from './utils/admin-lists.js'; | ||
import { anyIDToPlayer, anyIDsToPlayers } from './utils/any-id.js'; | ||
|
||
export default class SquadServer extends EventEmitter { | ||
constructor(options = {}) { | ||
|
@@ -98,7 +99,7 @@ export default class SquadServer extends EventEmitter { | |
}); | ||
|
||
this.rcon.on('CHAT_MESSAGE', async (data) => { | ||
data.player = await this.getPlayerBySteamID(data.steamID); | ||
data.player = await this.getPlayerByEOSID(data.eosID); | ||
this.emit('CHAT_MESSAGE', data); | ||
|
||
const command = data.message.match(/!([^ ]+) ?(.*)/); | ||
|
@@ -110,22 +111,22 @@ export default class SquadServer extends EventEmitter { | |
}); | ||
|
||
this.rcon.on('POSSESSED_ADMIN_CAMERA', async (data) => { | ||
data.player = await this.getPlayerBySteamID(data.steamID); | ||
data.player = await this.getPlayerByEOSID(data.eosID); | ||
|
||
this.adminsInAdminCam[data.steamID] = data.time; | ||
this.adminsInAdminCam[data.eosID] = data.time; | ||
|
||
this.emit('POSSESSED_ADMIN_CAMERA', data); | ||
}); | ||
|
||
this.rcon.on('UNPOSSESSED_ADMIN_CAMERA', async (data) => { | ||
data.player = await this.getPlayerBySteamID(data.steamID); | ||
if (this.adminsInAdminCam[data.steamID]) { | ||
data.duration = data.time.getTime() - this.adminsInAdminCam[data.steamID].getTime(); | ||
data.player = await this.getPlayerByEOSID(data.eosID); | ||
if (this.adminsInAdminCam[data.eosID]) { | ||
data.duration = data.time.getTime() - this.adminsInAdminCam[data.eosID].getTime(); | ||
} else { | ||
data.duration = 0; | ||
} | ||
|
||
delete this.adminsInAdminCam[data.steamID]; | ||
delete this.adminsInAdminCam[data.eosID]; | ||
|
||
this.emit('UNPOSSESSED_ADMIN_CAMERA', data); | ||
}); | ||
|
@@ -141,13 +142,13 @@ export default class SquadServer extends EventEmitter { | |
}); | ||
|
||
this.rcon.on('PLAYER_KICKED', async (data) => { | ||
data.player = await this.getPlayerBySteamID(data.steamID); | ||
data.player = await this.getPlayerByEOSID(data.eosID); | ||
|
||
this.emit('PLAYER_KICKED', data); | ||
}); | ||
|
||
this.rcon.on('PLAYER_BANNED', async (data) => { | ||
data.player = await this.getPlayerBySteamID(data.steamID); | ||
data.player = await this.getPlayerByEOSID(data.eosID); | ||
|
||
this.emit('PLAYER_BANNED', data); | ||
}); | ||
|
@@ -157,8 +158,7 @@ export default class SquadServer extends EventEmitter { | |
data.player.squadID = data.squadID; | ||
|
||
delete data.playerName; | ||
delete data.playerSteamID; | ||
delete data.playerEOSID; | ||
for (const k in data) if (k.startsWith('player') && k.endsWith('ID')) delete data[k]; | ||
|
||
this.emit('SQUAD_CREATED', data); | ||
}); | ||
|
@@ -208,7 +208,7 @@ export default class SquadServer extends EventEmitter { | |
this.emit('NEW_GAME', data); | ||
}); | ||
|
||
this.logParser.on('PLAYER_CONNECTED', async (data) => { | ||
this.logParser.on('JOIN_SUCCEEDED', async (data) => { | ||
Logger.verbose( | ||
'SquadServer', | ||
1, | ||
|
@@ -218,7 +218,7 @@ export default class SquadServer extends EventEmitter { | |
data.player = await this.getPlayerByEOSID(data.eosID); | ||
if (data.player) data.player.suffix = data.playerSuffix; | ||
|
||
delete data.steamID; | ||
for (const k in data) if (k.endsWith('ID')) delete data[k]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be more specific: for (const k in data) if (["steamID", "eosID"].includes(k)) delete data[k]; |
||
delete data.playerSuffix; | ||
|
||
this.emit('PLAYER_CONNECTED', data); | ||
|
@@ -227,7 +227,7 @@ export default class SquadServer extends EventEmitter { | |
this.logParser.on('PLAYER_DISCONNECTED', async (data) => { | ||
data.player = await this.getPlayerByEOSID(data.eosID); | ||
|
||
delete data.steamID; | ||
for (const k in data) if (k.endsWith('ID')) delete data[k]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be more specific: for (const k in data) if (["steamID", "eosID"].includes(k)) delete data[k]; |
||
|
||
this.emit('PLAYER_DISCONNECTED', data); | ||
}); | ||
|
@@ -242,7 +242,7 @@ export default class SquadServer extends EventEmitter { | |
if (data.victim && data.attacker) { | ||
data.teamkill = | ||
data.victim.teamID === data.attacker.teamID && | ||
data.victim.steamID !== data.attacker.steamID; | ||
data.victim.eosID !== data.attacker.eosID; | ||
} | ||
|
||
delete data.victimName; | ||
|
@@ -260,7 +260,7 @@ export default class SquadServer extends EventEmitter { | |
if (data.victim && data.attacker) | ||
data.teamkill = | ||
data.victim.teamID === data.attacker.teamID && | ||
data.victim.steamID !== data.attacker.steamID; | ||
data.victim.eosID !== data.attacker.eosID; | ||
|
||
delete data.victimName; | ||
delete data.attackerName; | ||
|
@@ -278,7 +278,7 @@ export default class SquadServer extends EventEmitter { | |
if (data.victim && data.attacker) | ||
data.teamkill = | ||
data.victim.teamID === data.attacker.teamID && | ||
data.victim.steamID !== data.attacker.steamID; | ||
data.victim.eosID !== data.attacker.eosID; | ||
|
||
delete data.victimName; | ||
delete data.attackerName; | ||
|
@@ -322,23 +322,6 @@ export default class SquadServer extends EventEmitter { | |
this.logParser.on('TICK_RATE', (data) => { | ||
this.emit('TICK_RATE', data); | ||
}); | ||
|
||
this.logParser.on('CLIENT_EXTERNAL_ACCOUNT_INFO', (data) => { | ||
this.rcon.addIds(data.steamID, data.eosID); | ||
}); | ||
// this.logParser.on('CLIENT_CONNECTED', (data) => { | ||
// Logger.verbose("SquadServer", 1, `Client connected. Connection: ${data.connection} - SteamID: ${data.steamID}`) | ||
// }) | ||
// this.logParser.on('CLIENT_LOGIN_REQUEST', (data) => { | ||
// Logger.verbose("SquadServer", 1, `Login request. ChainID: ${data.chainID} - Suffix: ${data.suffix} - EOSID: ${data.eosID}`) | ||
|
||
// }) | ||
// this.logParser.on('RESOLVED_EOS_ID', (data) => { | ||
// Logger.verbose("SquadServer", 1, `Resolved EOSID. ChainID: ${data.chainID} - Suffix: ${data.suffix} - EOSID: ${data.eosID}`) | ||
// }) | ||
// this.logParser.on('ADDING_CLIENT_CONNECTION', (data) => { | ||
// Logger.verbose("SquadServer", 1, `Adding client connection`, data) | ||
// }) | ||
} | ||
|
||
async restartLogParser() { | ||
|
@@ -353,16 +336,26 @@ export default class SquadServer extends EventEmitter { | |
await this.logParser.watch(); | ||
} | ||
|
||
// DEPRECATED FUNCTION | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be replaced with a more suitable jsdoc
|
||
getAdminPermsBySteamID(steamID) { | ||
return this.admins[steamID]; | ||
return this.getAdminPermsByAnyID(steamID); | ||
} | ||
|
||
getAdminPermsByAnyID(anyID) { | ||
// using this.players directly to keep the function sync | ||
const player = anyIDToPlayer(anyID, this.players); | ||
if (player === undefined) return; | ||
for (const parm in player) | ||
if (parm.endsWith("ID") && player[parm] in this.admins) | ||
return this.admins[player[parm]]; | ||
} | ||
|
||
getAdminsWithPermission(perm) { | ||
const ret = []; | ||
for (const [steamID, perms] of Object.entries(this.admins)) { | ||
if (perm in perms) ret.push(steamID); | ||
for (const [anyID, perms] of Object.entries(this.admins)) { | ||
if (perm in perms) ret.push(anyID); | ||
} | ||
return ret; | ||
return anyIDsToPlayers(ret, this.players).map(player => player.eosID); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. considering that this is a breaking change, and it also limits the functionality from getting ALL the admins to ONLY THE ONLINE admins, I would prefer this to be converted to returning an array of objects with both eosID and steamID optional parameters. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed on Discord with @Ulibos, the best choice appears to be a method that accepts an extra parameter to tune the output based on the needs. A jsdoc would be a good fit for defining all the possible values for the extra parameter that I will just refer to as "output format parameter". The output format parameter could be defined with the following jsdoc:
|
||
} | ||
|
||
async updateAdmins() { | ||
|
@@ -377,34 +370,35 @@ export default class SquadServer extends EventEmitter { | |
try { | ||
const oldPlayerInfo = {}; | ||
for (const player of this.players) { | ||
oldPlayerInfo[player.steamID] = player; | ||
oldPlayerInfo[player.eosID] = player; | ||
} | ||
|
||
const players = []; | ||
for (const player of await this.rcon.getListPlayers(this)) | ||
players.push({ | ||
...oldPlayerInfo[player.steamID], | ||
...oldPlayerInfo[player.eosID], | ||
...player, | ||
playercontroller: this.logParser.eventStore.players[player.steamID] | ||
? this.logParser.eventStore.players[player.steamID].controller | ||
playercontroller: this.logParser.eventStore.players[player.eosID] | ||
? this.logParser.eventStore.players[player.eosID].controller | ||
: null, | ||
squad: await this.getSquadByID(player.teamID, player.squadID) | ||
}); | ||
|
||
this.players = players; | ||
|
||
for (const player of this.players) { | ||
if (typeof oldPlayerInfo[player.steamID] === 'undefined') continue; | ||
if (player.teamID !== oldPlayerInfo[player.steamID].teamID) | ||
const oldInfo = oldPlayerInfo[player.eosID]; | ||
if (oldInfo === undefined) continue; | ||
if (player.teamID !== oldInfo.teamID) | ||
this.emit('PLAYER_TEAM_CHANGE', { | ||
player: player, | ||
oldTeamID: oldPlayerInfo[player.steamID].teamID, | ||
oldTeamID: oldInfo.teamID, | ||
newTeamID: player.teamID | ||
}); | ||
if (player.squadID !== oldPlayerInfo[player.steamID].squadID) | ||
if (player.squadID !== oldInfo.squadID) | ||
this.emit('PLAYER_SQUAD_CHANGE', { | ||
player: player, | ||
oldSquadID: oldPlayerInfo[player.steamID].squadID, | ||
oldSquadID: oldInfo.squadID, | ||
newSquadID: player.squadID | ||
}); | ||
} | ||
|
@@ -591,6 +585,7 @@ export default class SquadServer extends EventEmitter { | |
); | ||
} | ||
|
||
// DEPRECATED | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be replaced with a more suitable jsdoc
|
||
async getPlayerBySteamID(steamID, forceUpdate) { | ||
return this.getPlayerByCondition((player) => player.steamID === steamID, forceUpdate); | ||
} | ||
|
@@ -599,6 +594,14 @@ export default class SquadServer extends EventEmitter { | |
return this.getPlayerByCondition((player) => player.eosID === eosID, forceUpdate); | ||
} | ||
|
||
async getPlayerByAnyID(anyID, forceUpdate) { | ||
return this.getPlayerByCondition( | ||
(player) => | ||
Object.entries(player).filter(([parm, val]) => parm.endsWith('ID') && val === anyID).length, | ||
forceUpdate | ||
); | ||
} | ||
|
||
async getPlayerByName(name, forceUpdate) { | ||
return this.getPlayerByCondition((player) => player.name === name, forceUpdate); | ||
} | ||
|
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally don't like the approach of having a "unified" regex to match the IDs because it depends only on the hope of OWI not breaking things with typos or non-standard formats, which has already happened, an example is a log line which has
Contoller
instead ofController
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All suggestions are implemented apart from one: changing
getAdminsWithPermission(perm)
to return players instead of IDs is not yet implemented. I'm all for implementing it, just want to make sure it is greenlit. Or, as a compromise, we could extend it togetAdminsWithPermission(perm, returnPlayers=false)
, that would allow for the new feature without potentially breaking custom plugins.As for unified regex, I kindly disagree.
master
implementation is prone to: changing ordering, extra spacing, lack of steamID (some regexes inmaster
were fixed to have steam as an optional but not all), renaming a key. This implementation will break only if delimiters are broken. Swapping, cloning, removing arbitrary k:v pairs, introducing new IDs, surrounding colons with spaces won't break it. Renaming a key will break things down the line but not the parser itself. And when OWI eventually breaks some output again - we can patch that specific item within it's parser, while everything else follows the same logic and is easy to remember.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm good with the new changes after my first review, and with keeping your implementation of the ID parser since you proved to have went through an analysis of all the side effects of both your implementation and the one currently on the
master
branch.