215 lines
4.2 KiB
JavaScript
215 lines
4.2 KiB
JavaScript
'use strict';
|
|
|
|
const fetch = require('node-fetch');
|
|
const { URLSearchParams } = require('url');
|
|
|
|
var apiProto = {};
|
|
|
|
apiProto.__getApiDoc = async function(host){
|
|
try{
|
|
let setupRes = await fetch(host || this.host+'/pve-docs/api-viewer/apidoc.js', { method: 'GET'});
|
|
let text = await setupRes.text()
|
|
|
|
text = text.split('// avoid errors when running without development tools')[0];
|
|
|
|
return eval(text += '; pveapi;');
|
|
|
|
}catch(error){
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
apiProto.__makeMap = async function(APItree){
|
|
APItree = APItree || await this.__getApiDoc();
|
|
let apiMap = {};
|
|
|
|
function __rec(obj){
|
|
for(let item of obj){
|
|
if(item.children){
|
|
__rec(item.children);
|
|
}
|
|
if(item.path){
|
|
delete item.children;
|
|
apiMap[item.path] = item;
|
|
item.methods = item.info;
|
|
delete item.info;
|
|
}
|
|
}
|
|
}
|
|
|
|
__rec(APItree);
|
|
|
|
return apiMap
|
|
};
|
|
|
|
//these helper functions are to build the fetch call
|
|
apiProto.__buildHeaders = function(){
|
|
let headers = {};
|
|
if(this.authInfo.apiToken){
|
|
headers = {
|
|
"Authorization": `PVEAPIToken=${this.authInfo.username}=${this.authInfo.apiToken}`
|
|
}
|
|
}else{
|
|
headers = {
|
|
'Cookie': 'PVEAuthCookie='+this.user.ticket,
|
|
'CSRFPreventionToken': this.user.CSRFPreventionToken
|
|
}
|
|
}
|
|
|
|
return headers;
|
|
};
|
|
|
|
// this function takes an iterable of 'key':'value' pairs
|
|
apiProto.__buildBody = function(props, data){
|
|
const params = new URLSearchParams();
|
|
for (let key in props){
|
|
if(data[key]){
|
|
params.append(key, data[key])
|
|
continue;
|
|
}
|
|
if(props[key].optional !==1){
|
|
// console.log(props[key])
|
|
throw new Error('MissingKey');
|
|
}
|
|
}
|
|
return params;
|
|
};
|
|
|
|
apiProto.__getEndPoint = function(args){
|
|
let endpoint = this.apiMap[args.path]
|
|
if(!args || !endpoint) throw new Error('endpointNotFound');
|
|
if(!endpoint.methods[args.method]) throw new Error('methodNotFound');
|
|
|
|
return endpoint;
|
|
};
|
|
|
|
apiProto.__fetch = async function(method, path, params, data){
|
|
try{
|
|
let endpoint = this.__getEndPoint({path, method});
|
|
|
|
let fetchOptions = {
|
|
method: method,
|
|
headers: this.__buildHeaders(),
|
|
}
|
|
|
|
if(['PUT', 'POST'].includes(method)){
|
|
fetchOptions.body = this.__buildBody(
|
|
endpoint.methods[method].parameters.properties,
|
|
data
|
|
)
|
|
}
|
|
|
|
let HTTPres = await fetch(this.BASEURL+path, fetchOptions);
|
|
|
|
// console.log(HTTPres)
|
|
|
|
return {
|
|
statusCode: HTTPres.status,
|
|
statusText: HTTPres.statusText,
|
|
json: (await HTTPres.json()).data,
|
|
}
|
|
|
|
}catch(error){
|
|
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
apiProto.GET = async function(args){
|
|
try{
|
|
|
|
return await this.__fetch(
|
|
'GET',
|
|
args.path,
|
|
args.parama || {},
|
|
);
|
|
|
|
}catch(error){
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
apiProto.DELETE = async function(args){
|
|
try{
|
|
|
|
return await this.__fetch(
|
|
'DELETE',
|
|
args.path,
|
|
args.parama || {},
|
|
);
|
|
|
|
}catch(error){
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
apiProto.POST = async function(args){
|
|
try{
|
|
|
|
return await this.__fetch(
|
|
'POST',
|
|
args.path,
|
|
args.parama || {},
|
|
args.data || {}
|
|
);
|
|
|
|
}catch(error){
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
apiProto.PUT = async function(args){
|
|
try{
|
|
|
|
return await this.__fetch(
|
|
'PUT',
|
|
args.path,
|
|
args.parama || {},
|
|
args.data || {}
|
|
);
|
|
|
|
}catch(error){
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
apiProto.auth = async function(authInfo){
|
|
try{
|
|
this.user = (await this.POST({
|
|
path: '/access/ticket',
|
|
data: authInfo || this.authInfo
|
|
})).json
|
|
|
|
return authInfo;
|
|
|
|
}catch(error){
|
|
throw error;
|
|
}
|
|
};
|
|
|
|
apiProto.__init = async function(conf){
|
|
try{
|
|
this.user = {};
|
|
this.BASEURL = conf.host+'/api2/json';
|
|
this.apiMap = await this.__makeMap();
|
|
|
|
if(!this.authInfo.apiToken) await this.auth();
|
|
|
|
return this;
|
|
|
|
}catch(error){
|
|
throw(error);
|
|
}
|
|
};
|
|
|
|
async function API(conf){
|
|
let instance = Object.create(apiProto);
|
|
Object.assign(instance, conf);
|
|
|
|
return await instance.__init(conf);
|
|
}
|
|
|
|
|
|
module.exports = API;
|
|
|