-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathworldanvil.js
100 lines (81 loc) · 3.16 KB
/
worldanvil.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
const fetch = require('node-fetch');
const Bottleneck = require('bottleneck');
const baseurl = "https://www.worldanvil.com/api/aragorn/";
const version = 1;
const limiter = new Bottleneck({
id: "link-of-the-anvil",
reservoir: 100,
reservoirIncreaseInterval: 250,
reservoirIncreaseAmount: 10,
maxConcurrent: 10,
minTime: 50,
datastore: "redis",
clientOptions: {
host: process.env.REDIS_HOST || "localhost",
port: process.env.REDIS_PORT || 6379
}
});
const limitFetch = limiter.wrap(fetch);
const headers = {
"x-application-key":process.env.APP_KEY,
"ContentType":"application/json"
}
function handleResponse(res){
if(res.status != 200)throw new WorldAnvilError("An error occured while connecting to the World Anvil API", res.status);
return res.json();
}
function getHeaders(authToken){
return {
...headers,
"x-auth-token": authToken
};
}
function getCurrentUser(authToken){
return limitFetch(baseurl + "user", {headers:getHeaders(authToken)})
.then(handleResponse)
}
function getUserWorlds(authToken, userId){
return limitFetch(baseurl + "user/" + userId + "/worlds", {headers: getHeaders(authToken)})
.then(x => x.json())
}
function getWorld(authToken, worldId){
return limitFetch(baseurl + "world/" + worldId, {headers: getHeaders(authToken)})
.then(x => x.json())
}
function getWorldArticles(authToken, worldId, offset=0){
return limitFetch(baseurl + "world/" + worldId + "/articles?offset=" + offset, {headers: getHeaders(authToken)})
.then(x => x.json())
}
function getAllWorldArticles(authToken, worldId, offset=0){
return getWorldArticles(authToken, worldId, offset)
.then(x => {console.log(x); return x;})
.then(x => (!x.articles || x.articles.length < x.limit)? (x.articles?x.articles:[]):getAllWorldArticles(authToken, worldId, parseInt(offset) + parseInt(x.limit)).then(y => y.concat(x.articles)));
}
function getArticle(authToken, articleId){
console.log(baseurl + "article/" + articleId);
return limitFetch(baseurl + "article/" + articleId, {headers: getHeaders(authToken)})
.then(x => x.json());
}
const concurrentRequests = 20;
async function enrichWithData(authToken, articles){
for(var i=0; i < articles.length; i+=concurrentRequests){
await Promise.all(articles.slice(i, i+concurrentRequests).map(async(article) => {
article.data = await getArticle(authToken, article.id);
}));
}
return articles;
}
class WorldAnvilError extends Error{
constructor(message, statusCode, exception) {
super(message);
// Ensure the name of this error is the same as the class name
this.name = this.constructor.name;
// This clips the constructor invocation from the stack trace.
// It's not absolutely essential, but it does make the stack trace a little nicer.
// @see Node.js reference (bottom)
Error.captureStackTrace(this, this.constructor);
this.statusCode = statusCode;
this.exception = exception;
}
}
module.exports = {getCurrentUser,getUserWorlds, getAllWorldArticles, enrichWithData, getWorld, WorldAnvilError}