Last active
April 30, 2020 23:27
-
-
Save FlyInk13/82912737552bc24a200af015e76dddd4 to your computer and use it in GitHub Desktop.
vk api without vk-bridge (with jsonp)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = {}; | |
this.api = new PromiseAPI(); | |
this.api.view = this; | |
// vk brirge | |
this.api.access_token = 'vk bridge token'; | |
// call | |
this.api.callMethod('users.get', {}).then(console.log).catch(console.error); | |
} | |
render() { | |
return ( | |
<View | |
popout={this.state.popout} | |
activePanel={this.state.activePanel} | |
> | |
<Home id="home"/> | |
</View> | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Input, Alert } from '@vkontakte/vkui'; | |
import React from "react"; | |
class PromiseAPI { | |
constructor() { | |
// user data | |
this.access_token = false; | |
this.view = false; | |
this.v = 5.92; | |
// requests map { request_id: request_data }; | |
this.requests = {}; | |
// requests cart [request_id, request_id, ...]; | |
this.cart = []; | |
// internal vars | |
this.log = false; | |
this.pause = false; | |
// connect transport | |
this.subscribe(); | |
} | |
subscribe() { | |
window.apiCallback = window.apiCallback || {}; | |
} | |
debug(...args) { | |
if (!this.log) return; | |
console.log(...args); | |
} | |
cartCheck(request_id, ignoreCart) { | |
if (!this.pause && (!this.interval || ignoreCart)) { | |
const request = this.requests[request_id]; | |
this.sendRequest(request); | |
this.debug('cartCheck', 'call', request); | |
return; | |
} | |
this.debug('cartCheck', 'push'); | |
this.cart.push(request_id); | |
} | |
cartTick() { | |
this.debug('cartTick', this.cart.length); | |
if (!this.cart.length) { | |
clearInterval(this.interval); | |
delete this.interval; | |
return; | |
} | |
const request_id = this.cart.shift(); | |
this.cartCheck(request_id, true); | |
} | |
cartInit() { | |
this.debug('cartInit'); | |
if (this.interval) return; | |
this.interval = setInterval(() => this.cartTick(), 334); | |
} | |
showCaptcha(method, params, error) { | |
if (!this.view) { | |
throw error; | |
} | |
this.pause = 1; | |
return new Promise((resolve) => { | |
const view = this.view; | |
const oldPopout = view.state.popout; | |
const { captcha_img } = error; | |
view.setState({ | |
popout: ( | |
<Alert | |
actionsLayout="vertical" | |
actions={[ | |
{ | |
title: 'OK', | |
autoclose: true, | |
} | |
]} | |
onClose={() => { | |
resolve(view.state.captchaCode); | |
view.setState({ popout: oldPopout, captchaCode: null }); | |
}} | |
> | |
<h2>Введите код с картинки</h2> | |
<img src={captcha_img} style={{ width: 238, borderRadius: 3 }} alt={captcha_img}/> | |
<Input defaultValue='' onChange={(e) => { | |
const captchaCode = e.currentTarget.value; | |
view.setState({ captchaCode }); | |
}}/> | |
</Alert> | |
) | |
}); | |
}).then((captcha_key) => { | |
this.pause = 0; | |
const captcha_sid = error.captcha_sid; | |
return this.callMethod(method, { | |
...params, | |
captcha_key, | |
captcha_sid, | |
}); | |
}); | |
} | |
callMethod = (method, params = {}) => { | |
return new Promise((resolve, reject) => { | |
const request_id = (Math.random() * 1e20).toString(32); | |
const data = { | |
method, | |
params: { | |
access_token: this.access_token, | |
v: this.v, | |
...params, | |
}, | |
request_id, | |
}; | |
this.requests[request_id] = { resolve, reject, data }; | |
this.cartCheck(request_id); | |
}).catch((error) => { | |
error = error || {}; | |
const apiError = error.error_reason || error; | |
const errorCode = apiError.error_code || 0; | |
switch (errorCode) { | |
case 6: | |
this.cartInit(); | |
return this.callMethod(method, params); | |
case 14: | |
return this.showCaptcha(method, params, apiError); | |
default: | |
throw apiError; | |
} | |
}); | |
}; | |
parseError = (data) => { | |
const { error_data, request_id } = data; | |
if (!this.requests[request_id]) return; | |
this.requests[request_id].reject(error_data); | |
delete this.requests[request_id]; | |
}; | |
parseResponse = (data) => { | |
const { response, request_id } = data; | |
if (!this.requests[request_id]) return; | |
this.requests[request_id].resolve(response); | |
delete this.requests[request_id]; | |
}; | |
callback(request_id, callback_name, { error: error_data, response }) { | |
if (error_data) { | |
this.parseError({ error_data, request_id }); | |
} else { | |
this.parseResponse({ response, request_id }); | |
} | |
document.getElementById(callback_name).outerHTML = ''; | |
delete window.apiCallback[callback_name]; | |
} | |
sendJSON(callback_name, method, params) { | |
const script = document.createElement('script'); | |
let src = 'https://api.vk.com/method/' + method + '/?'; | |
params.callback = 'apiCallback.' + callback_name; | |
Object.entries(params).forEach(([key, value]) => { | |
value = encodeURIComponent(String(value)); | |
src += `&${key}=${value}`; | |
}); | |
script.id = callback_name; | |
script.src = src; | |
script.onerror = (error) => { | |
window.apiCallback[callback_name]({ error }); | |
}; | |
document.head.appendChild(script); | |
} | |
sendRequest({ data: { method, params, request_id }}) { | |
const callback_name = 'fn' + request_id.replace('.', '_'); | |
window.apiCallback[callback_name] = this.callback.bind(this, request_id, callback_name); | |
this.sendJSON(callback_name, method, params); | |
} | |
} | |
export default PromiseAPI; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment