UNPKG

nodevk-ts

Version:

Simple Node.js module that allows you to interact with the VKontakte API.

157 lines (156 loc) 6.21 kB
import http from "http"; import https from "https"; import { URL, URLSearchParams } from "url"; ; export var RequestMethod; (function (RequestMethod) { RequestMethod["GET"] = "get"; RequestMethod["POST"] = "post"; })(RequestMethod || (RequestMethod = {})); var RequestProtocol; (function (RequestProtocol) { RequestProtocol["HTTP"] = "http"; RequestProtocol["HTTPS"] = "https"; })(RequestProtocol || (RequestProtocol = {})); function getURL(request) { if (request.url) { return request.url instanceof URL ? request.url : new URL(request.url); } else if (request.host) { if (!request.protocol) request.protocol = RequestProtocol.HTTPS; return new URL(`${request.protocol}://${request.host}/${request.path || ""}`); } else { throw new Error("Укажите хотя бы host или url"); } } function random(min = 0, max = 100) { return Math.floor(Math.random() * (max - min)) + min; } function genStr(length = 12) { const charset = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"; let str = ""; for (; length > 0; length--) str += charset[random(0, 62)]; return str; } const NEW_LINE = "\r\n"; class FormData { constructor() { this.data = {}; this.boundary = `-------------${genStr()}`; } append(name, data) { this.data[name] = data; } get length() { const bound_l = this.boundary.length; let length = 4 + bound_l; for (const field in this.data) { length += 49 + bound_l + field.length; const data = this.data[field]; if (typeof data === "string") { length += data.length; } else { length += 29 + data.filename.length + data.content.length + (data.mime ? data.mime.length : 10); } } return length; } getBoundary() { return this.boundary; } toString() { let str = ""; for (const field in this.data) { const data = this.data[field]; str += `--${this.boundary}` + NEW_LINE + `Content-Disposition: form-data; name="${field}"`; if (typeof data !== "string") str += `; filename="${data.filename}"` + NEW_LINE + `Content-Type: ${data.mime || "text/plain"}`; str += NEW_LINE + NEW_LINE; if (typeof data !== "string") { if (data.content instanceof Buffer) str += data.content.toString("binary"); else str += data.content; } else { str += data; } str += NEW_LINE; } str += `--${this.boundary}--`; return str; } } export default function request(requestSettings) { if (typeof requestSettings == "string" || requestSettings instanceof URL) return request({ url: requestSettings }); const debug = requestSettings.debug ? console.log : () => { }; const have_file = requestSettings.data ? Object.keys(requestSettings.data).findIndex(e => typeof requestSettings.data[e] !== "string") != -1 : false; if (!requestSettings.headers) requestSettings.headers = {}; if (!requestSettings.method) requestSettings.method = have_file ? RequestMethod.POST : RequestMethod.GET; if (have_file) { if (!requestSettings.headers.hasOwnProperty("Content-Type")) requestSettings.headers["Content-Type"] = "multipart/form-data"; else if (requestSettings.headers["Content-Type"].toString().toLowerCase() != "multipart/form-data") throw new ReferenceError("For upload file use Content-Type: multipart/form-data"); } const url = getURL(requestSettings); let data; if (requestSettings.data) { if (requestSettings.headers["Content-Type"] && requestSettings.headers["Content-Type"].toString().toLowerCase() == "multipart/form-data") { data = new FormData(); requestSettings.headers["Content-Type"] += `; boundary=${data.getBoundary()}`; } else data = new URLSearchParams(url.searchParams); for (const key in requestSettings.data) { const value = requestSettings.data[key]; if (data instanceof FormData) data.append(key, value); else if (typeof value == "string") data.append(key, value); } if (requestSettings.method == RequestMethod.GET) url.search = data.toString(); } const protocol = /^https/.test(url.protocol) ? https : http; const options = {}; options.headers = requestSettings.headers; options.headers["Host"] = url.host; options.method = requestSettings.method; if (requestSettings.method == RequestMethod.POST) options.headers["Content-Length"] = data instanceof FormData ? data.length : data.toString().length; return new Promise((r, e) => { const _request = protocol.request(url, options); _request.on("response", response => { debug("encoding:", requestSettings.encoding); if (requestSettings.encoding) response.setEncoding(requestSettings.encoding); const buffers = []; response.on("data", (chunk) => { debug("chunk:" + chunk); buffers.push(chunk); }); response.on('end', () => { if (response.headers.location) { requestSettings.url = response.headers.location; r(request(requestSettings)); } if (buffers[0] instanceof Buffer) r(Buffer.concat(buffers)); else r(buffers.join("")); }); response.on('error', e); }); if (requestSettings.method == RequestMethod.POST) _request.write(data.toString(), "binary"); _request.end(); }); }