mirror of
https://github.com/MrUnknownDE/VRCX.git
synced 2026-04-14 12:23:52 +02:00
198 lines
7.4 KiB
JavaScript
198 lines
7.4 KiB
JavaScript
import { dbVars } from '../database';
|
|
|
|
import sqliteService from '../sqlite.js';
|
|
|
|
const mutualGraph = {
|
|
async getMutualGraphSnapshot() {
|
|
const snapshot = new Map();
|
|
if (!dbVars.userPrefix) {
|
|
return snapshot;
|
|
}
|
|
const friendTable = `${dbVars.userPrefix}_mutual_graph_friends`;
|
|
const linkTable = `${dbVars.userPrefix}_mutual_graph_links`;
|
|
await sqliteService.execute((dbRow) => {
|
|
const friendId = dbRow[0];
|
|
if (friendId && !snapshot.has(friendId)) {
|
|
snapshot.set(friendId, []);
|
|
}
|
|
}, `SELECT friend_id FROM ${friendTable}`);
|
|
await sqliteService.execute((dbRow) => {
|
|
const friendId = dbRow[0];
|
|
const mutualId = dbRow[1];
|
|
if (!friendId || !mutualId) {
|
|
return;
|
|
}
|
|
let list = snapshot.get(friendId);
|
|
if (!list) {
|
|
list = [];
|
|
snapshot.set(friendId, list);
|
|
}
|
|
list.push(mutualId);
|
|
}, `SELECT friend_id, mutual_id FROM ${linkTable}`);
|
|
return snapshot;
|
|
},
|
|
|
|
async saveMutualGraphSnapshot(entries) {
|
|
if (!dbVars.userPrefix) {
|
|
return;
|
|
}
|
|
const friendTable = `${dbVars.userPrefix}_mutual_graph_friends`;
|
|
const linkTable = `${dbVars.userPrefix}_mutual_graph_links`;
|
|
const metaTable = `${dbVars.userPrefix}_mutual_graph_meta`;
|
|
const pairs = entries instanceof Map ? entries : new Map();
|
|
await sqliteService.executeNonQuery('BEGIN');
|
|
try {
|
|
await sqliteService.executeNonQuery(
|
|
`DELETE FROM ${linkTable} WHERE friend_id NOT IN (SELECT friend_id FROM ${metaTable} WHERE opted_out = 1)`
|
|
);
|
|
await sqliteService.executeNonQuery(
|
|
`DELETE FROM ${friendTable} WHERE friend_id NOT IN (SELECT friend_id FROM ${metaTable} WHERE opted_out = 1)`
|
|
);
|
|
if (pairs.size === 0) {
|
|
await sqliteService.executeNonQuery('COMMIT');
|
|
return;
|
|
}
|
|
let friendValues = '';
|
|
let edgeValues = '';
|
|
pairs.forEach((mutualIds, friendId) => {
|
|
if (!friendId) {
|
|
return;
|
|
}
|
|
const safeFriendId = friendId.replace(/'/g, "''");
|
|
friendValues += `('${safeFriendId}'),`;
|
|
let collection = [];
|
|
if (Array.isArray(mutualIds)) {
|
|
collection = mutualIds;
|
|
} else if (mutualIds instanceof Set) {
|
|
collection = Array.from(mutualIds);
|
|
}
|
|
for (const mutual of collection) {
|
|
if (!mutual) {
|
|
continue;
|
|
}
|
|
const safeMutualId = String(mutual).replace(/'/g, "''");
|
|
edgeValues += `('${safeFriendId}', '${safeMutualId}'),`;
|
|
}
|
|
});
|
|
if (friendValues) {
|
|
friendValues = friendValues.slice(0, -1);
|
|
await sqliteService.executeNonQuery(
|
|
`INSERT OR REPLACE INTO ${friendTable} (friend_id) VALUES ${friendValues}`
|
|
);
|
|
}
|
|
if (edgeValues) {
|
|
edgeValues = edgeValues.slice(0, -1);
|
|
await sqliteService.executeNonQuery(
|
|
`INSERT OR REPLACE INTO ${linkTable} (friend_id, mutual_id) VALUES ${edgeValues}`
|
|
);
|
|
}
|
|
await sqliteService.executeNonQuery('COMMIT');
|
|
} catch (err) {
|
|
await sqliteService.executeNonQuery('ROLLBACK');
|
|
throw err;
|
|
}
|
|
},
|
|
|
|
async updateMutualsForFriend(friendId, mutualIds) {
|
|
if (!dbVars.userPrefix || !friendId) {
|
|
return;
|
|
}
|
|
const friendTable = `${dbVars.userPrefix}_mutual_graph_friends`;
|
|
const linkTable = `${dbVars.userPrefix}_mutual_graph_links`;
|
|
const safeFriendId = friendId.replace(/'/g, "''");
|
|
await sqliteService.executeNonQuery(
|
|
`INSERT OR REPLACE INTO ${friendTable} (friend_id) VALUES ('${safeFriendId}')`
|
|
);
|
|
await sqliteService.executeNonQuery(
|
|
`DELETE FROM ${linkTable} WHERE friend_id='${safeFriendId}'`
|
|
);
|
|
let edgeValues = '';
|
|
for (const mutual of mutualIds) {
|
|
if (!mutual) {
|
|
continue;
|
|
}
|
|
const safeMutualId = String(mutual).replace(/'/g, "''");
|
|
edgeValues += `('${safeFriendId}', '${safeMutualId}'),`;
|
|
}
|
|
if (edgeValues) {
|
|
edgeValues = edgeValues.slice(0, -1);
|
|
await sqliteService.executeNonQuery(
|
|
`INSERT OR REPLACE INTO ${linkTable} (friend_id, mutual_id) VALUES ${edgeValues}`
|
|
);
|
|
}
|
|
},
|
|
|
|
async getMutualCountForAllUsers() {
|
|
const mutualCountMap = new Map();
|
|
if (!dbVars.userPrefix) {
|
|
return mutualCountMap;
|
|
}
|
|
const linkTable = `${dbVars.userPrefix}_mutual_graph_links`;
|
|
await sqliteService.execute((dbRow) => {
|
|
const mutualId = dbRow[0];
|
|
const count = dbRow[1];
|
|
if (mutualId) {
|
|
mutualCountMap.set(mutualId, count);
|
|
}
|
|
}, `SELECT mutual_id, COUNT(*) FROM ${linkTable} GROUP BY mutual_id`);
|
|
return mutualCountMap;
|
|
},
|
|
|
|
async upsertMutualGraphMeta(friendId, { lastFetchedAt, optedOut }) {
|
|
if (!dbVars.userPrefix || !friendId) {
|
|
return;
|
|
}
|
|
const metaTable = `${dbVars.userPrefix}_mutual_graph_meta`;
|
|
const escapedId = friendId.replace(/'/g, "''");
|
|
const time = (lastFetchedAt || new Date().toISOString()).replace(
|
|
/'/g,
|
|
"''"
|
|
);
|
|
const optedOutInt = optedOut ? 1 : 0;
|
|
await sqliteService.executeNonQuery(
|
|
`INSERT OR REPLACE INTO ${metaTable} (friend_id, last_fetched_at, opted_out) VALUES ('${escapedId}', '${time}', ${optedOutInt})`
|
|
);
|
|
},
|
|
|
|
async bulkUpsertMutualGraphMeta(entries) {
|
|
if (!dbVars.userPrefix || !entries || entries.size === 0) {
|
|
return;
|
|
}
|
|
const metaTable = `${dbVars.userPrefix}_mutual_graph_meta`;
|
|
let values = '';
|
|
const now = new Date().toISOString();
|
|
entries.forEach(({ optedOut }, friendId) => {
|
|
if (!friendId) return;
|
|
const escapedId = friendId.replace(/'/g, "''");
|
|
const optedOutInt = optedOut ? 1 : 0;
|
|
values += `('${escapedId}', '${now}', ${optedOutInt}),`;
|
|
});
|
|
if (values) {
|
|
values = values.slice(0, -1);
|
|
await sqliteService.executeNonQuery(
|
|
`INSERT OR REPLACE INTO ${metaTable} (friend_id, last_fetched_at, opted_out) VALUES ${values}`
|
|
);
|
|
}
|
|
},
|
|
|
|
async getMutualGraphMeta() {
|
|
const metaMap = new Map();
|
|
if (!dbVars.userPrefix) {
|
|
return metaMap;
|
|
}
|
|
const metaTable = `${dbVars.userPrefix}_mutual_graph_meta`;
|
|
await sqliteService.execute((dbRow) => {
|
|
const friendId = dbRow[0];
|
|
if (friendId) {
|
|
metaMap.set(friendId, {
|
|
lastFetchedAt: dbRow[1] || null,
|
|
optedOut: dbRow[2] === 1
|
|
});
|
|
}
|
|
}, `SELECT friend_id, last_fetched_at, opted_out FROM ${metaTable}`);
|
|
return metaMap;
|
|
}
|
|
};
|
|
|
|
export { mutualGraph };
|