/
index.js
198 lines (172 loc) · 5.42 KB
/
index.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
* kamergotchi-bot v1.0.0
* Licensed under the MIT License
* https://git.io/kamergotchi
*/
const request = require('request-promise')
require('colors')
let kamerbotchi = {}
kamerbotchi.API_ENDPOINT = 'https://api.kamergotchi.nl'
kamerbotchi.CURRENT_GAME = false
kamerbotchi.LAST_RESPONSE = false
/**
* Output of logs can be useful for CLI apps or for debugging purposes.
* @type {Boolean}
*/
kamerbotchi.logging = false
/**
* Send a request to the Kamergotchi API.
* @private
* @param {String} uri
* @param {String} method
* @param {Object} body
* @param {String} token
* @return {Promise<Object>}
*/
kamerbotchi.request = async (uri, method = 'GET', body = false, token) => {
let response = false
// Set the request opions we can fill in right away.
let options = {
uri: kamerbotchi.API_ENDPOINT + uri,
json: true,
method: method
}
// If there's a token set, pass it on to the headers.
if (token) {
options.headers = { 'x-player-token': token }
}
// If there's a body given, set it in our options.
if (body) options.body = body
try {
// Await the response from the api.
response = await request(options)
} catch (error) {
// Catch any HTTP response errors.
if (error.statusCode === 401) {
if (kamerbotchi.logging) {
console.log('[!] [API] 401 Given player token is not valid.'.red)
}
return { error: { message: 'Given player token is not valid.', code: 401 } }
} else if (error.statusCode === 429) {
if (kamerbotchi.logging) {
console.log('[!] [API] 429 Request denied, too many requests.'.yellow)
}
// The request failed, so we return the last known good response.
// this will make the bot do the previous action again.
//
// I know, this is a lazy version of 'exponential backoff', without
// the back-off implemented ¯\_(ツ)_/¯
//
// The API will just return the original error.
if (!kamerbotchi.LAST_RESPONSE) {
return { error: { message: 'Request denied, too many requests.', code: 429 } }
}
return kamerbotchi.LAST_RESPONSE
} else if (error.statusCode === 504) {
if (kamerbotchi.logging) {
console.log('[!] [API] 504 Gateway timeout.'.red)
}
return kamerbotchi.LAST_RESPONSE
} else {
// We handle all errors above silently because we can recover from those.
// It's not safe to continue with an unknown error so we stop right here.
console.log('[!] [API] '.red + String(error.statusCode).red + ' caught an unrecoverable error.'.red)
console.log(error)
process.exit(1)
}
}
// Update the current game global object.
// This saves us a few status requests to the api.
if (response.game) {
kamerbotchi.CURRENT_GAME = response.game
kamerbotchi.LAST_RESPONSE = response
}
return response
}
/**
* Get info of the curent game.
* @public
* @param {String} token
* @return {Promise<Object>}
*/
kamerbotchi.status = async (token) => {
const status = await kamerbotchi.request('/game', null, null, token)
if (kamerbotchi.logging) console.log(' requested game status.'.grey)
if (status.error) return status
return status.game
}
/**
* Spend care points on the given type of care.
* @public
* @param {String} careType food|knowledge|attention
* @param {String} token
* @return {Promise<Object>}
*/
kamerbotchi.spendCareOn = async (careType, token) => {
const updatedGame = await kamerbotchi.request('/game/care', 'POST', { bar: careType }, token)
if (updatedGame.error) return updatedGame
if (kamerbotchi.logging) {
console.log(' Score ' + String(updatedGame.game.score).bold + ' - ' + 'Spent care point on ' + careType.bold)
}
return updatedGame.game
}
/**
* Attempt to claim a points bonus.
* @public
* @param {String} token
* @return {Promise<Object>}
*/
kamerbotchi.claim = async (token) => {
const updatedGame = await kamerbotchi.request('/game/claim', 'POST', null, token)
if (updatedGame.error) return updatedGame
if (kamerbotchi.logging) {
console.log(' Score ' + String(updatedGame.game.score).bold + ' - ' + 'Clamed bonus points.'.yellow)
}
return updatedGame.game
}
/**
* Register a new kamergotchi or update an existing account.
* @param {String} username
* @param {Integer} age
* @param {String} gender male|female|other
* @param {String} [token=false]
* @return {Promise}
*/
kamerbotchi.register = async (username = 'kamerbotchi', age = 18, gender = 'male', token = false) => {
const body = {
registration: {
nickname: username,
age: age,
gender: gender,
supportCode: null
}
}
if (token) {
body.registration.token = token
} else {
body.registration.token = 'bot:' + Math.floor(Math.random() * 10e20)
}
const playerObject = await kamerbotchi.request('/players/register', 'POST', body, false)
if (playerObject.player) {
if (kamerbotchi.logging) console.log(String('[!] Registered or updated player ' + playerObject.player.nickname + '!').green)
return playerObject
}
return false
}
/**
* Legacy functions.
*/
/**
* Set the global player token
* @deprecated since version 2.0.0
* @param {String} token
*/
kamerbotchi.setToken = (token) => {
console.log('kamergotchi.setToken has been deprecated since version 2.0.0')
console.log('Use the `token` parameter for applicable functions instead.')
return false
}
/**
* Export the module.
*/
module.exports = kamerbotchi