nodevk-ts
Version:
Simple Node.js module that allows you to interact with the VKontakte API.
157 lines (156 loc) • 6.21 kB
JavaScript
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();
});
}