Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(followage): load data from api each call
  • Loading branch information
sogehige committed Apr 9, 2019
1 parent d9aec3b commit 74904bf
Show file tree
Hide file tree
Showing 12 changed files with 51 additions and 38 deletions.
4 changes: 3 additions & 1 deletion d.ts/index.d.ts
Expand Up @@ -46,8 +46,10 @@ declare namespace NodeJS {
events: import("../src/bot/events").Events,
widgets: any,
oauth: {
channelId: string,
settings: {
_: {
channelId: string,
},
broadcaster: {
username: string,
},
Expand Down
39 changes: 22 additions & 17 deletions src/bot/api.js
Expand Up @@ -27,6 +27,8 @@ class API {
}

constructor () {
this.timeouts = {}

if (isMainThread) {
global.panel.addMenu({ category: 'logs', name: 'api', id: 'apistats' })

Expand Down Expand Up @@ -80,8 +82,6 @@ class API {
})
}

this.timeouts = {}

this.rate_limit_follower_check = new Set()

this.chatMessagesAtStart = global.linesParsed
Expand Down Expand Up @@ -394,7 +394,7 @@ class API {
if (!isMainThread) throw new Error('API can run only on master')
opts = opts || {}

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
let url = `https://api.twitch.tv/helix/subscriptions?broadcaster_id=${cid}&first=100`
if (opts.cursor) url += '&after=' + opts.cursor
if (typeof opts.count === 'undefined') opts.count = -1 // start at -1 because owner is subbed as well
Expand Down Expand Up @@ -494,7 +494,7 @@ class API {
async getChannelDataOldAPI (opts) {
if (!isMainThread) throw new Error('API can run only on master')

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/kraken/channels/${cid}`

const token = await global.oauth.settings.bot.accessToken
Expand Down Expand Up @@ -550,7 +550,7 @@ class API {
async getChannelHosts () {
if (!isMainThread) throw new Error('API can run only on master')

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId

if (_.isNil(cid) || cid === '') {
return { state: false }
Expand All @@ -577,7 +577,7 @@ class API {
}

async updateChannelViews () {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/users/?id=${cid}`

const token = await global.oauth.settings.bot.accessToken
Expand Down Expand Up @@ -617,7 +617,7 @@ class API {
}

async getLatest100Followers (quiet) {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/users/follows?to_id=${cid}&first=100`
const token = await global.oauth.settings.bot.accessToken
const needToWait = _.isNil(cid) || cid === '' || _.isNil(global.overlays) || token === ''
Expand Down Expand Up @@ -762,7 +762,7 @@ class API {
async getCurrentStreamData (opts) {
if (!isMainThread) throw new Error('API can run only on master')

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/streams?user_id=${cid}`

const token = await global.oauth.settings.bot.accessToken
Expand Down Expand Up @@ -990,7 +990,7 @@ class API {
if (!isMainThread) throw new Error('API can run only on master')

args = _.defaults(args, { title: null }, { game: null })
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/kraken/channels/${cid}`

const token = await global.oauth.settings.bot.accessToken
Expand Down Expand Up @@ -1178,7 +1178,7 @@ class API {

_.defaults(opts, { hasDelay: true })

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/clips?broadcaster_id=${cid}`

const token = await global.oauth.settings.bot.accessToken
Expand Down Expand Up @@ -1263,19 +1263,22 @@ class API {
}

async isFollowerUpdate (user) {
if (!isMainThread) throw new Error('API can run only on master')
if (!user.id) return

// reload user from db
user = await global.users.getById(user.id);

clearTimeout(this.timeouts['isFollowerUpdate-' + user.id])

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/users/follows?from_id=${user.id}&to_id=${cid}`

const token = await global.oauth.settings.bot.accessToken
const needToWait = _.isNil(cid) || cid === '' || _.isNil(global.overlays) || token === ''
const needToWait = _.isNil(cid) || cid === '' || (_.isNil(global.overlays) && isMainThread) || token === ''
const notEnoughAPICalls = this.calls.bot.remaining <= 40 && this.calls.bot.refresh > _.now() / 1000
if (needToWait || notEnoughAPICalls) {
this.timeouts['isFollowerUpdate-' + user.id] = setTimeout(() => this.isFollowerUpdate(user), 1000)
return
return null
}

var request
Expand All @@ -1302,7 +1305,7 @@ class API {

global.log.error(`API: ${url} - ${e.stack}`)
if (global.panel && global.panel.io) global.panel.io.emit('api.stats', { timestamp: _.now(), call: 'isFollowerUpdate', api: 'helix', endpoint: url, code: e.response.status, data: e.stack, remaining: this.calls.bot.remaining })
return
return null
}

if (request.data.total === 0) {
Expand All @@ -1315,6 +1318,7 @@ class API {
const followedAt = user.lock && user.lock.followed_at ? Number(user.time.follow) : 0
const isFollower = user.lock && user.lock.follower ? user.is.follower : false
global.users.setById(user.id, { username: user.username, is: { follower: isFollower }, time: { followCheck: new Date().getTime(), follow: followedAt } }, user.is.follower)
return { isFollower: false, followedAt: null }
} else {
// is follower
if (!user.is.follower && new Date().getTime() - moment(request.data.data[0].followed_at).format('x') < 60000 * 60) {
Expand Down Expand Up @@ -1347,12 +1351,13 @@ class API {
const followedAt = user.lock && user.lock.followed_at ? Number(user.time.follow) : parseInt(moment(request.data.data[0].followed_at).format('x'), 10)
const isFollower = user.lock && user.lock.follower ? user.is.follower : true
global.users.set(user.username, { id: user.id, is: { follower: isFollower }, time: { followCheck: new Date().getTime(), follow: followedAt } }, !user.is.follower)
return { isFollower, followedAt }
}
}

async createMarker () {
const token = global.oauth.settings.bot.accessToken
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId

const url = 'https://api.twitch.tv/helix/streams/markers'
try {
Expand Down Expand Up @@ -1410,7 +1415,7 @@ class API {
}

async getTopClips (opts) {
let url = 'https://api.twitch.tv/helix/clips?broadcaster_id=' + global.oauth.channelId
let url = 'https://api.twitch.tv/helix/clips?broadcaster_id=' + global.oauth.settings._.channelId
const token = global.oauth.settings.bot.accessToken
try {
if (token === '') throw Error('No broadcaster access token')
Expand Down
2 changes: 1 addition & 1 deletion src/bot/events.ts
Expand Up @@ -177,7 +177,7 @@ class Events extends Core {
}

public async fireStartCommercial(operation, attributes) {
const cid = global.oauth.channelId;
const cid = global.oauth.settings._.channelId;
const url = `https://api.twitch.tv/kraken/channels/${cid}/commercial`;

const token = await global.oauth.settings.bot.accessToken;
Expand Down
4 changes: 2 additions & 2 deletions src/bot/oauth.js
Expand Up @@ -13,14 +13,14 @@ const constants = require('./constants')
class OAuth extends Core {
timeouts: Object = {}
currentChannel: string = ''
channelId: string = ''

constructor () {
const settings = {
_: {
broadcaster: '',
bot: '',
clientId: '',
channelId: '',
botId: '',
broadcasterId: ''
},
Expand Down Expand Up @@ -141,7 +141,7 @@ class OAuth extends Core {
this.currentChannel = this.settings.general.channel
const cid = await global.api.getIdFromTwitch(this.settings.general.channel, true)
if (typeof cid !== 'undefined' && cid !== null) {
this.channelId = cid
this.settings._.channelId = cid
global.log.info('Channel ID set to ' + cid)
global.tmi.reconnect('bot')
global.tmi.reconnect('broadcaster')
Expand Down
4 changes: 2 additions & 2 deletions src/bot/overlays/emotes.js
Expand Up @@ -206,7 +206,7 @@ class Emotes extends Overlay {
}

async fetchEmotesSubsribers () {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
this.fetch.subscribers = true

if (cid && (Date.now() - this.settings._.lastSubscriberEmoteChk > 1000 * 60 * 60 * 24 * 7 || this.settings._.lastChannelChk !== cid)) {
Expand Down Expand Up @@ -245,7 +245,7 @@ class Emotes extends Overlay {
}

async fetchEmotesFFZ () {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
this.fetch.ffz = true

// fetch FFZ emotes
Expand Down
2 changes: 1 addition & 1 deletion src/bot/systems/commercial.js
Expand Up @@ -57,7 +57,7 @@ class Commercial extends System {
return
}

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
// check if duration is correct (30, 60, 90, 120, 150, 180)
if (_.includes([30, 60, 90, 120, 150, 180], commercial.duration)) {
const url = `https://api.twitch.tv/kraken/channels/${cid}/commercial`
Expand Down
2 changes: 1 addition & 1 deletion src/bot/systems/highlights.js
Expand Up @@ -55,7 +55,7 @@ class Highlights extends System {
async main (opts) {
const when = await global.cache.when()
const token = global.oauth.settings.bot.accessToken
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/videos?user_id=${cid}&type=archive&first=1`

try {
Expand Down
6 changes: 6 additions & 0 deletions src/bot/systems/userinfo.ts
Expand Up @@ -2,6 +2,7 @@ import _ from 'lodash';
import { DateTime } from 'luxon';

import { getLocalizedName, prepare, sendMessage } from '../commons';
import { debug } from '../debug';
import System from './_interface';

/*
Expand Down Expand Up @@ -59,6 +60,11 @@ class UserInfo extends System {
username = parsed[0].toLowerCase();
}

const isFollowerUpdate = await global.api.isFollowerUpdate({
id: opts.sender.userId,
});
debug('userinfo.followage', JSON.stringify(isFollowerUpdate));

const user = await global.users.getByName(username);
if (_.isNil(user) || _.isNil(user.time) || _.isNil(user.time.follow) || _.isNil(user.is.follower) || !user.is.follower) {
sendMessage(prepare('followage.' + (opts.sender.username === username.toLowerCase() ? 'successSameUsername' : 'success') + '.never', { username }), opts.sender);
Expand Down
2 changes: 1 addition & 1 deletion src/bot/users.js
Expand Up @@ -286,7 +286,7 @@ class Users extends Core {
})
socket.on('followedAt.viewer', async (id, cb) => {
try {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const url = `https://api.twitch.tv/helix/users/follows?from_id=${id}&to_id=${cid}`

const token = global.oauth.settings.bot.accessToken
Expand Down
12 changes: 6 additions & 6 deletions src/bot/webhooks.js
Expand Up @@ -45,7 +45,7 @@ class Webhooks {
async unsubscribe (type) {
clearTimeout(this.timeouts[`unsubscribe-${type}`])

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const clientId = await global.oauth.settings._.clientId
if (cid === '' || clientId === '') {
this.timeouts[`unsubscribe-${type}`] = setTimeout(() => this.subscribe(type), 1000)
Expand Down Expand Up @@ -97,7 +97,7 @@ class Webhooks {
async subscribe (type, quiet) {
clearTimeout(this.timeouts[`subscribe-${type}`])

const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const clientId = await global.oauth.settings._.clientId
if (cid === '' || clientId === '') {
this.timeouts[`subscribe-${type}`] = setTimeout(() => this.subscribe(type), 1000)
Expand Down Expand Up @@ -161,14 +161,14 @@ class Webhooks {

async event (aEvent, res) {
// somehow stream doesn't have a topic
if (_.get(aEvent, 'topic', null) === `https://api.twitch.tv/helix/users/follows?first=1&to_id=${global.oauth.channelId}`) this.follower(aEvent) // follow
if (_.get(aEvent, 'topic', null) === `https://api.twitch.tv/helix/users/follows?first=1&to_id=${global.oauth.settings._.channelId}`) this.follower(aEvent) // follow
else if (_.get(!_.isNil(aEvent.data[0]) ? aEvent.data[0] : {}, 'type', null) === 'live') this.stream(aEvent) // streams

res.sendStatus(200)
}

async challenge (req, res) {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
// set webhooks enabled
switch (req.query['hub.topic']) {
case `https://api.twitch.tv/helix/users/follows?first=1&to_id=${cid}`:
Expand Down Expand Up @@ -197,7 +197,7 @@ class Webhooks {
*/
async follower (aEvent) {
try {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
const data = aEvent.data
if (_.isEmpty(cid)) setTimeout(() => this.follower(aEvent), 10) // wait until channelId is set
if (parseInt(data.to_id, 10) !== parseInt(cid, 10)) return
Expand Down Expand Up @@ -278,7 +278,7 @@ class Webhooks {
}
*/
async stream (aEvent) {
const cid = global.oauth.channelId
const cid = global.oauth.settings._.channelId
if (cid === '') setTimeout(() => this.stream(aEvent), 1000) // wait until channelId is set

// stream is online
Expand Down
6 changes: 3 additions & 3 deletions test/tests/api/getLatest100Followers.js
Expand Up @@ -73,8 +73,8 @@ describe('API - getLatest100Followers()', () => {

global.api.timeouts['getLatest100Followers'].isPaused = true

global.oauth.channelId = '12345'
await variable.isEqual('global.oauth.channelId', '12345')
global.oauth.settings._.channelId = '12345'
await variable.isEqual('global.oauth.settings._.channelId', '12345')
global.oauth.settings.bot.accessToken = 'foobar'
await variable.isEqual('global.oauth.settings.bot.accessToken', 'foobar')
global.oauth.settings.bot.username = '__bot_username__'
Expand All @@ -83,7 +83,7 @@ describe('API - getLatest100Followers()', () => {

after(() => {
global.api.timeouts['getLatest100Followers'].isPaused = false
global.oauth.channelId = ''
global.oauth.settings._.channelId = ''
global.oauth.settings.bot.accessToken = ''
})

Expand Down
6 changes: 3 additions & 3 deletions test/tests/webhooks/follower.js
Expand Up @@ -9,14 +9,14 @@ const message = require('../../general.js').message

// users
const id = _.random(99999, false)
const channelId = _.random(9999999, false)
const channelId = String(_.random(9999999, false))
const testuser = { username: 'testuser', id }

describe('libs/webhooks - follower()', () => {
before(async () => {
await db.cleanup()
await message.prepare()
global.oauth.channelId = channelId
global.oauth.settings._.channelId = channelId
})

it('testuser should not be in webhooks cache', async () => {
Expand All @@ -37,7 +37,7 @@ describe('libs/webhooks - follower()', () => {
data: {
from_id: id,
from_name: 'testuser',
to_id: global.oauth.channelId,
to_id: global.oauth.settings._.channelId,
to_name: 'channeluser'
}
})
Expand Down

0 comments on commit 74904bf

Please sign in to comment.