1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-02 16:08:31 +00:00
* Changed: Start fetching FFZ badges based on user ID rather than user login, for both data savings and resilience against name changes.
* Changed: Implement a hot path for the Supporter badge (which is now applied to over 20,000 users) to reduce resource usage, notably RAM.
* API Changed: Update to a newer method of getting an APIv2 authentication token that doesn't require a socket server connection.
This commit is contained in:
SirStendec 2020-07-14 21:24:07 -04:00
parent bc1ca88a1e
commit 22fd300b28
4 changed files with 112 additions and 12 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.20.6", "version": "4.20.7",
"description": "FrankerFaceZ is a Twitch enhancement suite.", "description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0", "license": "Apache-2.0",
"scripts": { "scripts": {

View file

@ -169,6 +169,13 @@ export default class Badges extends Module {
this.inject('experiments'); this.inject('experiments');
this.style = new ManagedStyle('badges'); this.style = new ManagedStyle('badges');
// Special data structure for supporters to greatly reduce
// memory usage and speed things up for people who only have
// a supporter badge.
this.supporter_id = null;
this.supporters = new Set;
this.badges = {}; this.badges = {};
this.twitch_badges = {}; this.twitch_badges = {};
@ -646,8 +653,13 @@ export default class Badges extends Module {
global_user = this.parent.getUser(user_id, user_login, true), global_user = this.parent.getUser(user_id, user_login, true),
room_user = room && room.getUser(user_id, user_login, true); room_user = room && room.getUser(user_id, user_login, true);
return (global_user ? global_user.badges._cache : []).concat( const out = (global_user ? global_user.badges._cache : []).concat(
room_user ? room_user.badges._cache : []); room_user ? room_user.badges._cache : []);
if ( this.supporter_id && this.supporters.has(`${user_id}`) )
out.push({id: this.supporter_id});
return out;
} }
@ -656,11 +668,11 @@ export default class Badges extends Module {
if ( this.experiments.getAssignment('api_load') && tries < 1 ) if ( this.experiments.getAssignment('api_load') && tries < 1 )
try { try {
fetch(`${NEW_API}/v1/badges`).catch(() => {}); fetch(`${NEW_API}/v2/badges`).catch(() => {});
} catch(err) { /* do nothing */ } } catch(err) { /* do nothing */ }
try { try {
response = await fetch(`${API_SERVER}/v1/badges`); response = await fetch(`${API_SERVER}/v1/badges/ids`);
} catch(err) { } catch(err) {
tries++; tries++;
if ( tries < 10 ) if ( tries < 10 )
@ -694,13 +706,21 @@ export default class Badges extends Module {
if ( has(data.users, badge_id) ) { if ( has(data.users, badge_id) ) {
const badge = this.badges[badge_id]; const badge = this.badges[badge_id];
let c = 0; let c = 0;
for(const user_login of data.users[badge_id]) {
const user = this.parent.getUser(undefined, user_login); if ( badge?.name === 'supporter' ) {
if ( user.addBadge('ffz-global', badge_id) ) { this.supporter_id = badge_id;
c++; for(const user_id of data.users[badge_id])
users++; this.supporters.add(`${user_id}`);
c = this.supporters.size;
} else
for(const user_id of data.users[badge_id]) {
const user = this.parent.getUser(user_id, undefined);
if ( user.addBadge('ffz-global', badge_id) ) {
c++;
users++;
}
} }
}
if ( c > 0 ) if ( c > 0 )
this.log.info(`Added "${badge ? badge.name : `#${badge_id}`}" to ${c} users.`); this.log.info(`Added "${badge ? badge.name : `#${badge_id}`}" to ${c} users.`);

View file

@ -0,0 +1,6 @@
.ffz--meta-tray {
& > :first-child > :first-child {
display: none !important;
margin-right: 0 !important;
}
}

View file

@ -7,6 +7,7 @@
import Module from 'utilities/module'; import Module from 'utilities/module';
import {DEBUG, WS_CLUSTERS} from 'utilities/constants'; import {DEBUG, WS_CLUSTERS} from 'utilities/constants';
import { on } from 'utilities/dom';
export const State = { export const State = {
@ -140,7 +141,80 @@ export default class SocketClient extends Module {
return new Promise((s, f) => { return new Promise((s, f) => {
this._token_waiters.push([s, f]); this._token_waiters.push([s, f]);
this.call('get_api_token').then(token => { let done = false, timer = null;
const fail = err => {
if ( done )
return;
clearTimeout(timer);
done = true;
this.log.error('Unable to get API token.', err);
const waiters = this._token_waiters;
this._token_waiters = null;
for(const pair of waiters)
pair[1](err);
}
const user = this.resolve('site')?.getUser?.();
if ( ! user || ! user.id )
return fail(new Error('Unable to get current user or not logged in.'));
const es = new EventSource(`https://api-test.frankerfacez.com/auth/ext_verify/${user.id}`);
on(es, 'challenge', event => {
const conn = this.resolve('site.chat')?.ChatService?.first?.client?.connection;
if ( conn && conn.send )
conn.send(`PRIVMSG #frankerfacezauthorizer :AUTH ${event.data}`);
});
on(es, 'token', event => {
if ( done )
return;
clearTimeout(timer);
let token = null;
try {
token = JSON.parse(event.data);
} catch(err) {
fail(err);
return;
}
if ( ! token || ! token.token ) {
fail(new Error('Received empty token from server.'));
return;
}
token.expires = (new Date(token.expires)).getTime();
this._cached_token = token;
done = true;
const waiters = this._token_waiters;
this._token_waiters = null;
for(const pair of waiters)
pair[0](token);
});
on(es, 'error', err => {
fail(err);
});
on(es, 'close', () => {
es.close();
if ( ! done )
fail(new Error('Connection closed unexpectedly.'));
});
timer = setTimeout(() => {
fail(new Error('timeout'));
}, 5000);
/*this.call('get_api_token').then(token => {
token.expires = (new Date(token.expires)).getTime(); token.expires = (new Date(token.expires)).getTime();
this._cached_token = token; this._cached_token = token;
@ -157,7 +231,7 @@ export default class SocketClient extends Module {
for(const pair of waiters) for(const pair of waiters)
pair[1](err); pair[1](err);
}); });*/
}); });
} }