@apidog/longpoll
Advanced tools
Comparing version 0.0.1 to 0.0.2
module.exports = { | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
}; | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
}; |
{ | ||
"name": "@apidog/longpoll", | ||
"version": "0.0.1", | ||
"version": "0.0.2", | ||
"description": "APIdog LongPoll service and typings", | ||
"main": "src/index.ts", | ||
"main": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"type": "module", | ||
"scripts": { | ||
"start": "npx tsc && node build/index.js", | ||
"test": "jest" | ||
"start": "npx tsc && node dist/index.js", | ||
"prepare": "npm run build", | ||
"build": "tsc", | ||
"test": "npx jest" | ||
}, | ||
"author": "", | ||
"license": "GPLv3", | ||
"author": "APIdog", | ||
"license": "GPL-3.0", | ||
"bugs": { | ||
"url" : "https://github.com/APIdogRU/apidog-longpoll/issues", | ||
"email" : "vladislav805@yandex.com" | ||
"url": "https://github.com/APIdogRU/longpoll/issues" | ||
}, | ||
"repository": { | ||
"type" : "git", | ||
"url" : "github:APIdogRU/apidog-longpoll" | ||
"type": "git", | ||
"url": "github:APIdogRU/longpoll" | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"@apidog/vk-client": "0.0.3" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^24.0.23", | ||
"@types/node": "^12.12.14", | ||
"jest": "^24.9.0", | ||
"ts-jest": "^24.2.0", | ||
"typescript": "^3.7.2" | ||
"@apidog/vk-typings": "git://github.com/APIdogRU/vk-typings.git", | ||
"@types/jest": "24.0.23", | ||
"@types/node": "12.12.14", | ||
"jest": "24.9.0", | ||
"ts-jest": "24.2.0", | ||
"typescript": "3.7.2" | ||
} | ||
} |
180
src/index.ts
@@ -1,13 +0,18 @@ | ||
import request from './request'; | ||
import { IVKApiGetLongPollRequest } from './typings/vkapi'; | ||
import { IVKLongPollResult, IVKLongPollUpdate } from './typings/longpoll'; | ||
import { stringify } from 'querystring'; | ||
import { flatten } from './utils/array-flat'; | ||
import { request } from './request'; | ||
import converters from './utils/converter'; | ||
import { IVKMessage } from './typings'; | ||
import { apiClient, ApiClient } from './utils/apiRequests'; | ||
import { VKAPIClient } from '@apidog/vk-client'; | ||
import { | ||
IVKApiGetLongPollRequest, | ||
IVKLongPollResult, | ||
IVKLongPollUpdate | ||
} from '@apidog/vk-typings'; | ||
import { ClientRequest } from 'http'; | ||
export interface ILongPollProps { | ||
token: string; | ||
version?: number; // TODO | ||
wait?: number; // TODO | ||
mode?: number; // TODO | ||
versionApi?: string; | ||
versionLongPoll?: number; | ||
wait?: number; | ||
mode?: number; | ||
} | ||
@@ -31,7 +36,19 @@ | ||
const defaultProps: Partial<ILongPollProps> = { | ||
versionApi: '5.108', | ||
versionLongPoll: 3, | ||
mode: 202, | ||
wait: 25 | ||
}; | ||
const __debug = process.env.DEBUG_LP !== undefined; | ||
const l = (msg: string) => __debug && process.stdout.write(`[LongPoll] ${msg}\n`); | ||
export class LongPoll { | ||
private isActive: boolean = false; | ||
private active: boolean = false; | ||
private server: ILongPollServer; | ||
private listener: Partial<Record<TLongPollEventType, ILongPollEventListener[]>> = {}; | ||
private requester: ApiClient; | ||
private apiRequester: VKAPIClient; | ||
private lastRequest?: ClientRequest; | ||
@@ -45,14 +62,39 @@ private static readonly eventId2ListenerKey: Record<number, TLongPollEventType[]> = { | ||
constructor(token: string) { | ||
if (!token) { | ||
throw new Error('token is not specified'); | ||
/** | ||
* Получение инстанса LongPoll | ||
*/ | ||
public static getInstance = async(auth: string | VKAPIClient, props: ILongPollProps = {}): Promise<LongPoll> => { | ||
const lp = new LongPoll(auth, props); | ||
await lp.fetchServer(); | ||
return lp; | ||
}; | ||
private constructor(auth: string | VKAPIClient, private readonly props: ILongPollProps = {}) { | ||
if (!auth) { | ||
throw new Error('token or VKAPIClient is not specified'); | ||
} | ||
this.requester = apiClient(token); | ||
if (typeof auth === 'string') { | ||
const v = this.getProp('versionApi') as string; | ||
this.apiRequester = VKAPIClient.getInstance(auth, { v }); | ||
} else { | ||
this.apiRequester = auth; | ||
} | ||
l('Логгирование LongPoll включено'); | ||
} | ||
fetchServer = async() => { | ||
private getProp = (key: keyof ILongPollProps) => this.props[key] || defaultProps[key]; | ||
private fetchServer = async() => { | ||
if (this.server) { | ||
throw new Error('Server already fetched'); | ||
} | ||
const server = await this.requester<IVKApiGetLongPollRequest>('messages.getLongPollServer'); | ||
l('Получение URL для запросов к LongPoll...'); | ||
const params = { lp_version: this.getProp('versionLongPoll') }; | ||
const server = await this.apiRequester.perform<IVKApiGetLongPollRequest>('messages.getLongPollServer', params); | ||
this.setServer(server); | ||
@@ -63,4 +105,8 @@ }; | ||
this.server = server; | ||
l(`Изменены данные URL для запросов: server = ${server.server}; key = ${server.key}; ts = ${server.ts}`); | ||
}; | ||
/** | ||
* Подписка на события | ||
*/ | ||
public on = (event: TLongPollEventType, listener: ILongPollEventListener) => { | ||
@@ -74,6 +120,13 @@ if (!this.listener[event]) { | ||
/** | ||
* Проверка статуса запуска LongPoll | ||
*/ | ||
public isActive = () => this.active; | ||
/** | ||
* Запуск пулинга | ||
*/ | ||
public start = async() => { | ||
this.isActive = true; | ||
while (this.isActive) { | ||
console.log('active, started, ts = ' + this.server.ts); | ||
this.active = true; | ||
while (this.active) { | ||
await this.makeRequest(); | ||
@@ -83,16 +136,62 @@ } | ||
public stop = () => { | ||
if (!this.active) { | ||
return; | ||
} | ||
if (this.lastRequest) { | ||
this.lastRequest.abort(); | ||
} | ||
this.active = false; | ||
}; | ||
/** | ||
* Запрос к LongPoll серверу | ||
*/ | ||
private makeRequest = async() => { | ||
const json = await request<IVKLongPollResult>(`https://${this.server.server}?act=a_check&key=${this.server.key}&wait=25&ts=${this.server.ts}&mode=202`, {}); | ||
const params = { | ||
act: 'a_check', | ||
ts: this.server.ts, | ||
key: this.server.key, | ||
wait: this.getProp('wait'), | ||
mode: this.getProp('mode') | ||
}; | ||
this.server.ts = json.ts; | ||
this.handleEvents(json.updates); | ||
const url = `https://${this.server.server}?${stringify(params)}`; | ||
try { | ||
const json = await request<IVKLongPollResult>(url, this.requestHandler); | ||
this.server.ts = json.ts; | ||
this.handleEvents(json.updates); | ||
} catch (e) { | ||
l(`Произошла ошибка при опросе: ${e.message}`); | ||
l('Пуллинг запросов остановлен'); | ||
this.active = false; | ||
throw e; | ||
} | ||
}; | ||
/** | ||
* Обработчик запрсов | ||
*/ | ||
private requestHandler = (request: ClientRequest) => { | ||
this.lastRequest = request; | ||
}; | ||
/** | ||
* Обработка сырых данных, конвертация в объекты и вызо | ||
*/ | ||
private handleEvents = (updates: IVKLongPollUpdate[]) => { | ||
if (!this.active) { | ||
return; | ||
} | ||
updates.forEach(async update => { | ||
const [eventId] = update; | ||
const listenerKeys = LongPoll.eventId2ListenerKey[eventId] || []; | ||
const hasListener = listenerKeys.some(key => this.listener[key] && this.listener[key].length); | ||
const listenerKeys = this.getListenersByEventId(eventId); | ||
const listeners = flatten(listenerKeys.map(key => this.listener[key])); | ||
if (!hasListener) { | ||
if (!listeners) { | ||
return; | ||
@@ -103,27 +202,12 @@ } | ||
listenerKeys.forEach(key => { | ||
this.listener[key] && this.listener[key].map(listener => listener(event)); | ||
}); | ||
listeners.forEach(listener => listener(event)); | ||
}); | ||
}; | ||
} | ||
/** | ||
* Получение слушателей события по идентификатору события | ||
*/ | ||
private getListenersByEventId = (eventId: number) => LongPoll.eventId2ListenerKey[eventId] || []; | ||
const getLongPoll = async(props: ILongPollProps): Promise<LongPoll> => { | ||
const lp = new LongPoll(props.token); | ||
await lp.fetchServer(); | ||
return lp; | ||
}; | ||
//export default start; | ||
getLongPoll({ | ||
token: process.env.token, | ||
mode: 202 | ||
}).then(longpoll => { | ||
console.log('get long') | ||
longpoll.on('message', (event: ILongPollEvent<IVKMessage>) => { | ||
console.log(event); | ||
}); | ||
longpoll.start(); | ||
}); | ||
public getServer = () => this.server; | ||
} |
@@ -1,9 +0,12 @@ | ||
import https from 'https'; | ||
import { request as req } from 'https'; | ||
import { ClientRequest } from 'http'; | ||
export default async<T>(url: string, params: Record<string, string> = {}) => new Promise<T>((resolve, reject) => { | ||
https.get(url, res => { | ||
export type FHandlerRequest = (request: ClientRequest) => any; | ||
export const request = async<T>(url: string, handler?: FHandlerRequest) => new Promise<T>((resolve, reject) => { | ||
const request = req(url, res => { | ||
let data = ''; | ||
res.on('data', chunk => data += chunk); | ||
res.on('end', () => { | ||
@@ -19,2 +22,4 @@ try { | ||
}); | ||
handler && handler(request); | ||
}); |
@@ -9,5 +9,5 @@ import { | ||
IVKLongPollUpdateFlagSet, | ||
IVKLongPollUpdateFlagReset | ||
} from '../typings/longpoll'; | ||
import { IVKMessage } from '../typings'; | ||
IVKLongPollUpdateFlagReset, | ||
IVKMessage | ||
} from '@apidog/vk-typings'; | ||
@@ -14,0 +14,0 @@ export type ILongPollConverter<T> = (update: IVKLongPollUpdate) => Promise<T>; |
@@ -8,5 +8,7 @@ { | ||
"moduleResolution": "node", | ||
"declaration": true, | ||
"declarationDir": "dist", | ||
"outDir": "dist", | ||
"sourceMap": false, | ||
"outDir": "build", | ||
"baseUrl": "." | ||
"baseUrl": "src" | ||
}, | ||
@@ -13,0 +15,0 @@ "include": [ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Copyleft License
License(Experimental) Copyleft license information was found
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Non-permissive License
License(Experimental) A license not known to be considered permissive was found
Found 1 instance in 1 package
No README
QualityPackage does not have a README. This may indicate a failed publish or a low quality package.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
36824
850
0
1
22
Yes
1
6
23
2
70
1
2
+ Added@apidog/vk-client@0.0.3
+ Added@apidog/vk-client@0.0.3(transitive)