<commit_before>import { ApolloClient } from 'apollo-client'
import { DocumentNode } from 'graphql'
import {
	AbstractAPI,
	StateType,
	AbstractTinderAPI,
	IAPIGenericReturn,
	PersonType,
	IAPISendMessage
} from '~/shared/definitions'

import * as logoutMutation from './logout.graphql'
import * as getFBQuery from './getFB.graphql'
import * as showWindow from './showWindow.graphql'
import * as loginFB from './loginFB.graphql'

import {
	GetFbQuery,
	ShowWindowMutation,
	LoginFbMutation,
	LogoutMutation
} from '~/schema'
import {
	VIEW_MATCHES,
	VIEW_AUTH,
	routes,
	success,
	PENDING,
	FAILURE,
	SUCCESS
} from '~/shared/constants'
import { isOnline } from './utils'
import * as uuid from 'uuid'
import { MessageType } from '~/shared/definitions'

export interface IAPIProps {
	client: ApolloClient
	state: StateType
	tinder: AbstractTinderAPI
}

export class API implements AbstractAPI {
	private client: ApolloClient
	private reloginPromise: Promise<void> | null = null
	private state: StateType
	private tinder: AbstractTinderAPI

	constructor(props: IAPIProps) {
		Object.assign(this, props)
	}

	mutate = async <R = {}>(mutation: DocumentNode, variables?: Object) => {
		return (await this.client.mutate<R>({ mutation, variables })).data as R
	}

	query = async <R = {}>(query: DocumentNode, variables?: Object) => {
		return (await this.client.query<R>({ query, variables })).data
	}

	public login = async (silent?: boolean): Promise<IAPIGenericReturn> => {
		this.tinder.resetClient()
		let fb = (await this.query<GetFbQuery>(getFBQuery)).fb
		try {
			if (fb.token === null || fb.id === null) {
				throw new Error('fbToken or fbId is not present')
			}
			await this.tinder.authorize({ fbToken: fb.token, fbId: fb.id })
			return success
		} catch (err) {}

		try {
			fb = (await this.mutate<LoginFbMutation>(loginFB, {
				silent
			})).loginFB

			await this.tinder.authorize(
				{ fbToken: fb.token, fbId: fb.id } as {
					fbToken: string
					fbId: string
				}
			)
			return success
		} catch (err) {
			return { status: 'Unauthorized' }
		}
	}

	public checkDoMatchesExist = async (): Promise<boolean> => {
		const matchesCount = this.state.matches.size

		if (matchesCount !== 0) {
			return true
		} else {
			const history: any = await new Promise(async resolve => {
				let resolved = false
				let history: any | null = null

				while (!resolved || history === null) {
					try {
						history = await this.tinder.getHistory()
						resolved = true
					} catch (err) {
						await this.relogin()
					}
				}

				resolve(history)
			})

			if (history.matches.length === 0) {
				return false
			} else {
				// const matches = normalizeAllMatches(history.matches)

				if (history.matches.length !== 0) {
					this.state.mergeUpdates(history, true)
					return true
				} else {
					return false
				}
			}
		}
	}

	private getUpdates = async () => {
		if (this.tinder.subscriptionPromise === null) {
			this.tinder.subscriptionPromise = new Promise(async resolve => {
				let resolved = false
				let updates: any | null = null

				while (!resolved || updates === null) {
					try {
						updates = await this.tinder.getUpdates()
						// updates.matches = normalizeAllMatches(updates.matches)
						resolved = true
					} catch (err) {
						await this.relogin()
					}
				}

				resolve(updates)
			})

			const updates = await this.tinder.subscriptionPromise
			this.tinder.subscriptionPromise = null
			this.state.mergeUpdates(updates, false)
		}
	}

	public subscribeToUpdates = async (): Promise<IAPIGenericReturn> => {
		if (this.tinder.subscriptionInterval !== null) {
			clearInterval(this.tinder.subscriptionInterval)
			this.tinder.subscriptionInterval = null
		}

		let defaults = this.state.defaults || this.tinder.getDefaults()
		if (defaults === null) {
			while (defaults === null) {
				await this.relogin()
				defaults = this.tinder.getDefaults()
			}
			// defaults.user = normalizePerson(defaults.user)
			this.state.setDefaults(defaults)
		}

		const interval = defaults.globals.updates_interval
		this.tinder.subscriptionInterval = setInterval(
			() => this.getUpdates(),<commit_msg>Proper subscription<commit_after>import { ApolloClient } from 'apollo-client'
import { DocumentNode } from 'graphql'
import {
	AbstractAPI,
	StateType,
	AbstractTinderAPI,
	IAPIGenericReturn,
	PersonType,
	IAPISendMessage
} from '~/shared/definitions'

import * as logoutMutation from './logout.graphql'
import * as getFBQuery from './getFB.graphql'
import * as showWindow from './showWindow.graphql'
import * as loginFB from './loginFB.graphql'

import {
	GetFbQuery,
	ShowWindowMutation,
	LoginFbMutation,
	LogoutMutation
} from '~/schema'
import {
	VIEW_MATCHES,
	VIEW_AUTH,
	routes,
	success,
	PENDING,
	FAILURE,
	SUCCESS
} from '~/shared/constants'
import { isOnline } from './utils'
import * as uuid from 'uuid'
import { MessageType } from '~/shared/definitions'

export interface IAPIProps {
	client: ApolloClient
	state: StateType
	tinder: AbstractTinderAPI
}

export class API implements AbstractAPI {
	private client: ApolloClient
	private reloginPromise: Promise<void> | null = null
	private state: StateType
	private tinder: AbstractTinderAPI

	constructor(props: IAPIProps) {
		Object.assign(this, props)
	}

	mutate = async <R = {}>(mutation: DocumentNode, variables?: Object) => {
		return (await this.client.mutate<R>({ mutation, variables })).data as R
	}

	query = async <R = {}>(query: DocumentNode, variables?: Object) => {
		return (await this.client.query<R>({ query, variables })).data
	}

	public login = async (silent?: boolean): Promise<IAPIGenericReturn> => {
		this.tinder.resetClient()
		let fb = (await this.query<GetFbQuery>(getFBQuery)).fb
		try {
			if (fb.token === null || fb.id === null) {
				throw new Error('fbToken or fbId is not present')
			}
			await this.tinder.authorize({ fbToken: fb.token, fbId: fb.id })
			return success
		} catch (err) {}

		try {
			fb = (await this.mutate<LoginFbMutation>(loginFB, {
				silent
			})).loginFB

			await this.tinder.authorize(
				{ fbToken: fb.token, fbId: fb.id } as {
					fbToken: string
					fbId: string
				}
			)
			return success
		} catch (err) {
			return { status: 'Unauthorized' }
		}
	}

	public checkDoMatchesExist = async (): Promise<boolean> => {
		const matchesCount = this.state.matches.size

		if (matchesCount !== 0) {
			return true
		} else {
			const history: any = await new Promise(async resolve => {
				let resolved = false
				let history: any | null = null

				while (!resolved || history === null) {
					try {
						history = await this.tinder.getHistory()
						resolved = true
					} catch (err) {
						await this.relogin()
					}
				}

				resolve(history)
			})

			if (history.matches.length === 0) {
				return false
			} else {
				// const matches = normalizeAllMatches(history.matches)

				if (history.matches.length !== 0) {
					this.state.mergeUpdates(history, true)
					return true
				} else {
					return false
				}
			}
		}
	}

	private getUpdates = async () => {
		if (this.tinder.subscriptionPromise === null) {
			this.tinder.subscriptionPromise = new Promise(async resolve => {
				let resolved = false
				let updates: any | null = null

				while (!resolved || updates === null) {
					try {
						updates = await this.tinder.getUpdates()
						// updates.matches = normalizeAllMatches(updates.matches)
						resolved = true
					} catch (err) {
						await this.relogin()
					}
				}

				resolve(updates)
			})

			const updates = await this.tinder.subscriptionPromise
			this.tinder.subscriptionPromise = null
			this.state.mergeUpdates(updates, false)
		}
	}

	public subscribeToUpdates = async (): Promise<IAPIGenericReturn> => {
		if (this.tinder.subscriptionInterval !== null) {
			clearInterval(this.tinder.subscriptionInterval)
			this.tinder.subscriptionInterval = null
		}

		if (this.state.defaults === null) {
			while (this.tinder.getDefaults() === null) {
				await this.relogin()
			}
			this.state.setDefaults(this.tinder.getDefaults())
		}
		const { defaults } = this.state

		const interval = defaults!.globals.updates_interval
		this.tinder.subscriptionInterval = window.setInterval(
			() => this.getUpdates(),
{'fraction_non_alphanumeric': 0.12443741637270406, 'fraction_numerical': 0.0007298382191947452, 'mean_word_length': 3.35949098621421, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5738313', 'n_tokens_mistral': 3148, 'n_tokens_neox': 2656, 'n_words': 643}