Include system data on PK profiles

This commit is contained in:
Cadence Ember 2024-01-22 22:30:31 +13:00
parent 6a06dc14ce
commit a71c9515ec
4 changed files with 49 additions and 25 deletions

View file

@ -24,7 +24,7 @@ async function editMessage(message, guild, row) {
if (row.speedbump_id === "466378653216014359") { if (row.speedbump_id === "466378653216014359") {
const root = await registerPkUser.fetchMessage(message.id) const root = await registerPkUser.fetchMessage(message.id)
assert(root.member) assert(root.member)
senderMxid = await registerPkUser.ensureSimJoined(root.member, roomID) senderMxid = await registerPkUser.ensureSimJoined(root, roomID)
} }
} }

View file

@ -16,17 +16,17 @@ const registerUser = sync.require("./register-user")
/** /**
* A sim is an account that is being simulated by the bridge to copy events from the other side. * A sim is an account that is being simulated by the bridge to copy events from the other side.
* @param {Ty.PkMember} member * @param {Ty.PkMessage} pkMessage
* @returns mxid * @returns mxid
*/ */
async function createSim(member) { async function createSim(pkMessage) {
// Choose sim name // Choose sim name
const simName = "_pk_" + member.id const simName = "_pk_" + pkMessage.member.id
const localpart = reg.ooye.namespace_prefix + simName const localpart = reg.ooye.namespace_prefix + simName
const mxid = `@${localpart}:${reg.ooye.server_name}` const mxid = `@${localpart}:${reg.ooye.server_name}`
// Save chosen name in the database forever // Save chosen name in the database forever
db.prepare("INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(member.uuid, simName, localpart, mxid) db.prepare("INSERT INTO sim (user_id, sim_name, localpart, mxid) VALUES (?, ?, ?, ?)").run(pkMessage.member.uuid, simName, localpart, mxid)
// Register matrix user with that name // Register matrix user with that name
try { try {
@ -34,7 +34,7 @@ async function createSim(member) {
} catch (e) { } catch (e) {
// If user creation fails, manually undo the database change. Still isn't perfect, but should help. // If user creation fails, manually undo the database change. Still isn't perfect, but should help.
// (I would prefer a transaction, but it's not safe to leave transactions open across event loop ticks.) // (I would prefer a transaction, but it's not safe to leave transactions open across event loop ticks.)
db.prepare("DELETE FROM sim WHERE user_id = ?").run(member.uuid) db.prepare("DELETE FROM sim WHERE user_id = ?").run(pkMessage.member.uuid)
throw e throw e
} }
return mxid return mxid
@ -43,32 +43,32 @@ async function createSim(member) {
/** /**
* Ensure a sim is registered for the user. * Ensure a sim is registered for the user.
* If there is already a sim, use that one. If there isn't one yet, register a new sim. * If there is already a sim, use that one. If there isn't one yet, register a new sim.
* @param {Ty.PkMember} member * @param {Ty.PkMessage} pkMessage
* @returns {Promise<string>} mxid * @returns {Promise<string>} mxid
*/ */
async function ensureSim(member) { async function ensureSim(pkMessage) {
let mxid = null let mxid = null
const existing = select("sim", "mxid", {user_id: member.uuid}).pluck().get() const existing = select("sim", "mxid", {user_id: pkMessage.member.uuid}).pluck().get()
if (existing) { if (existing) {
mxid = existing mxid = existing
} else { } else {
mxid = await createSim(member) mxid = await createSim(pkMessage)
} }
return mxid return mxid
} }
/** /**
* Ensure a sim is registered for the user and is joined to the room. * Ensure a sim is registered for the user and is joined to the room.
* @param {Ty.PkMember} member * @param {Ty.PkMessage} pkMessage
* @param {string} roomID * @param {string} roomID
* @returns {Promise<string>} mxid * @returns {Promise<string>} mxid
*/ */
async function ensureSimJoined(member, roomID) { async function ensureSimJoined(pkMessage, roomID) {
// Ensure room ID is really an ID, not an alias // Ensure room ID is really an ID, not an alias
assert.ok(roomID[0] === "!") assert.ok(roomID[0] === "!")
// Ensure user // Ensure user
const mxid = await ensureSim(member) const mxid = await ensureSim(pkMessage)
// Ensure joined // Ensure joined
const existing = select("sim_member", "mxid", {room_id: roomID, mxid}).pluck().get() const existing = select("sim_member", "mxid", {room_id: roomID, mxid}).pluck().get()
@ -89,16 +89,17 @@ async function ensureSimJoined(member, roomID) {
} }
/** /**
* @param {Ty.PkMember} member * @param {Ty.PkMessage} pkMessage
*/ */
async function memberToStateContent(member) { async function memberToStateContent(pkMessage) {
const displayname = member.display_name || member.name const systemname = pkMessage.system.tag || ""
const avatar = member.avatar_url || member.webhook_avatar_url const displayname = (pkMessage.member.display_name || pkMessage.member.name) + systemname
const avatar = pkMessage.member.avatar_url || pkMessage.member.webhook_avatar_url || pkMessage.system.avatar_url
const content = { const content = {
displayname, displayname,
membership: "join", membership: "join",
"moe.cadence.ooye.pk_member": member "moe.cadence.ooye.pk_member": pkMessage.member
} }
if (avatar) content.avatar_url = await file.uploadDiscordFileToMxc(avatar) if (avatar) content.avatar_url = await file.uploadDiscordFileToMxc(avatar)
@ -111,12 +112,12 @@ async function memberToStateContent(member) {
* 2. Make an object of what the new room member state content would be, including uploading the profile picture if it hasn't been done before * 2. Make an object of what the new room member state content would be, including uploading the profile picture if it hasn't been done before
* 3. Compare against the previously known state content, which is helpfully stored in the database * 3. Compare against the previously known state content, which is helpfully stored in the database
* 4. If the state content has changed, send it to Matrix and update it in the database for next time * 4. If the state content has changed, send it to Matrix and update it in the database for next time
* @param {Ty.PkMember} member * @param {Ty.PkMessage} pkMessage
* @returns {Promise<string>} mxid of the updated sim * @returns {Promise<string>} mxid of the updated sim
*/ */
async function syncUser(member, roomID) { async function syncUser(pkMessage, roomID) {
const mxid = await ensureSimJoined(member, roomID) const mxid = await ensureSimJoined(pkMessage, roomID)
const content = await memberToStateContent(member) const content = await memberToStateContent(pkMessage)
const currentHash = registerUser._hashProfileContent(content) const currentHash = registerUser._hashProfileContent(content)
const existingHash = select("sim_member", "hashed_profile_content", {room_id: roomID, mxid}).safeIntegers().pluck().get() const existingHash = select("sim_member", "hashed_profile_content", {room_id: roomID, mxid}).safeIntegers().pluck().get()
// only do the actual sync if the hash has changed since we last looked // only do the actual sync if the hash has changed since we last looked
@ -127,7 +128,7 @@ async function syncUser(member, roomID) {
return mxid return mxid
} }
/** @returns {Promise<{member?: Ty.PkMember}>} */ /** @returns {Promise<Ty.PkMessage>} */
function fetchMessage(messageID) { function fetchMessage(messageID) {
return fetch(`https://api.pluralkit.me/v2/messages/${messageID}`).then(res => res.json()) return fetch(`https://api.pluralkit.me/v2/messages/${messageID}`).then(res => res.json())
} }

View file

@ -36,8 +36,13 @@ async function sendMessage(message, guild, row) {
// Handle the PluralKit public instance // Handle the PluralKit public instance
if (row.speedbump_id === "466378653216014359") { if (row.speedbump_id === "466378653216014359") {
const root = await registerPkUser.fetchMessage(message.id) const root = await registerPkUser.fetchMessage(message.id)
assert(root.member) // Member is null if member was deleted. We just got this message, so member surely exists. // Member is null if member was deleted. We just got this message, so member surely exists.
senderMxid = await registerPkUser.syncUser(root.member, roomID) if (!root.member) {
const e = new Error("PK API did not return a member")
e["response"] = root
throw e
}
senderMxid = await registerPkUser.syncUser(root, roomID)
} }
} }

18
types.d.ts vendored
View file

@ -34,6 +34,19 @@ export type WebhookCreds = {
token: string token: string
} }
export type PkSystem = {
id: string
uuid: string
name: string | null
description: string | null
tag: string | null
pronouns: string | null
avatar_url: string | null
banner: string | null
color: string | null
created: string | null
}
export type PkMember = { export type PkMember = {
id: string id: string
uuid: string uuid: string
@ -54,6 +67,11 @@ export type PkMember = {
last_message_timestamp: string last_message_timestamp: string
} }
export type PkMessage = {
system: PkSystem
member: PkMember
}
export namespace Event { export namespace Event {
export type Outer<T> = { export type Outer<T> = {
type: string type: string