Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ This is a simple node js server that emulates the osu v1 api for gulag to enable
### How to run:
#### Requirements:
- Gulag db running on MySQL 8.0+
- Node.JS
- Node.JS >= 14

#### Required packages
```
npm install express express-rate-limit mysql8 util
```
#### Remember to set up the config before running!

#### Remember to install requiremenets and set up the config before running!
```sh
> npm install
> cp ext/config_sample.js config.js
> nano config.js
```
Expand All @@ -21,21 +19,31 @@ npm install express express-rate-limit mysql8 util
# Using the included script:
> ./sausage.sh

# Using node directly:
# Using npm to start:
> npm start
# or run directly:
> node init.js
```

### Handled Routes:
```css
@/ - done
@/get_beatmaps - will not be handled, :: gulag does not save enough beatmap data to
emulate this endpoint efficiently, you can continue using bancho's v1 endpoint for this.
@/get_beatmaps - added proxy, use `k-overwrite` if you need two seprate api key for gulag and proxy destination.
@/get_user - done
@/get_scores - done
@/get_user_best - done
@/get_user_recent - done
@/get_match - will not be handled (?) , gulag does not save matches after they finish.
@/get_replay - use gulag's built in endpoint
```
### extended parameters
#### api key overwritting `k-overwrite`
if api-key are required in both gulag and your apiv1 proxy target, use `k-overwrite` to pass `k` to proxied server
#### mode `m`
|--|--|--|--|mode|
|:--:|:--:|:--:|:--:|:--|
0 | 1 | 2 | 3 |`vanilla`
4 | 5 | 6 | 7 |`Relax`
8 | | | | `AP`

\- from Jakatebel with ♥
80 changes: 28 additions & 52 deletions endpoints.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,26 @@ const config = require('./config');
const db = require('./utils/db');
const { OsuUser, OsuScore } = require('./utils/objects');

const log = require('./utils/logger')
const getTimestamp = require('./utils/timestamp')
const isValidKey = require('./utils/is-valid-key')
//respond to request
function respond(res, text) {
res.statusCode = 200;
//res.setHeader('Content-Type', 'text/plain');
res.setHeader('Content-Type', 'text/html');
res.end(text);
}

//formats timestamps to mimic bancho v1's format
function getTimestamp (d) {
const pad = (n,s=2) => (`${new Array(s).fill(0)}${n}`).slice(-s);
return `${pad(d.getFullYear(),4)}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

function log(message) {
var time = new Date(Date.now());
console.log("[LOG " + time.getHours() + ":" + time.getMinutes() + ":" + time.getSeconds() + "]\t" + message );
}

//verifies if the endpoint has a valid key
async function key(k) {
if (config.requireKey && k != undefined && k != "") {
var t = null;
try {
t = await db.query("SELECT `name`, `api_key` FROM users WHERE `api_key` = ?", k);
} catch { } // failed db query
if (t != undefined && t != null && t != "") {
return t[0];
} else
return false;

} else
return true;
}

const routes = express();
// function respond(res, text) {
// res.statusCode = 200;
// //res.setHeader('Content-Type', 'text/plain');
// res.setHeader('Content-Type', 'text/html');
// res.end(text);
// }


const routes = router = express.Router()
const apiL = rlimit({
windowMs: config.ratelimit.time,
max: config.ratelimit.requests,
message: config.messages.rate_limited
});
routes.use("/", apiL);
//routes.use(compressor()); //enable gzip
routes.disable('x-powered-by'); //disable exposing the server header

// Routes
// Docs:
Expand Down Expand Up @@ -84,14 +60,14 @@ routes.get("/get_user", async (req, res, next) => {
log(req.ip + "\t" + req.originalUrl);
var params = req.query;

var xkey = await key(params["k"]);
var xkey = await isValidKey(params.k);
if (!xkey) {
log(req.ip + "\t" + req.originalUrl + " - invalid key");
res.end(config.messages.invalid_api_key);
return;
}

var us = params["u"];
var us = params.u;
if (!us || us == "") {
res.end(config.messages.invalid_user_param);
return;
Expand All @@ -114,7 +90,7 @@ routes.get("/get_user", async (req, res, next) => {
a.join_date = getTimestamp(new Date(data.creation_time * 1000)); //from unix timestamp //convert format!

var mode = 0;
if (!isNaN(params["m"]) && params["m"] >= 0 && params["m"] < 8) mode = params["m"];
if (!isNaN(params.m) && params.m >= 0 && params.m < 8) mode = params.m;

stat_data = await db.query("SELECT * FROM stats WHERE `id` = ? AND `mode` = ?", [ data.id, mode ]);
stat_data = stat_data[0];
Expand Down Expand Up @@ -162,24 +138,24 @@ routes.get("/get_scores", async (req, res, next) => {
log(req.ip + "\t" + req.originalUrl);
var params = req.query;

var xkey = await key(params["k"]);
var xkey = await isValidKey(params.k);
if (!xkey) {
log(req.ip + "\t" + req.originalUrl + " - invalid key");
res.end(config.messages.invalid_api_key);
return;
}

var bid = params["b"];
var bid = params.b;
if (!bid || bid == "") {
res.end(config.messages.missing_bmap_param);
return;
}

var us = params["u"];
var us = params.u;
//if (!us || us == "")

var mode = 0;
if (!isNaN(params["m"]) && params["m"] >= 0 && params["m"] < 8) mode = params["m"];
if (!isNaN(params.m) && params.m >= 0 && params.m < 8) mode = params.m;

var mods = -1;
if (!isNaN(params["mods"])) mods = parseInt(params["mods"]);
Expand All @@ -188,7 +164,7 @@ routes.get("/get_scores", async (req, res, next) => {
if (!isNaN(params["limit"]) && params["limit"] > 0 && params["limit"] < 501) limit = parseInt(params["limit"]);

try {
var bmap_data = await db.query("SELECT `md5`, `id`, `set_id` FROM maps WHERE `id` = ?", params["b"]);
var bmap_data = await db.query("SELECT `md5`, `id`, `set_id` FROM maps WHERE `id` = ?", params.b);
bmap_data = bmap_data[0];

var table = mode < 4 ? 'scores_vn' : mode < 7 ? 'scores_rx' : 'scores_ap';
Expand Down Expand Up @@ -236,14 +212,14 @@ routes.get("/get_user_best", async (req, res, next) => {
log(req.ip + "\t" + req.originalUrl);
var params = req.query;

var xkey = await key(params["k"]);
var xkey = await isValidKey(params.k);
if (!xkey) {
log(req.ip + "\t" + req.originalUrl + " - invalid key");
res.end(config.messages.invalid_api_key);
return;
}

var us = params["u"];
var us = params.u;
if (!us || us == "") {
res.end(config.messages.invalid_user_param);
return;
Expand All @@ -261,12 +237,12 @@ routes.get("/get_user_best", async (req, res, next) => {
}

var mode = 0;
if (!isNaN(params["m"]) && params["m"] >= 0 && params["m"] < 8) mode = params["m"];
if (!isNaN(params.m) && params.m >= 0 && params.m < 8) mode = params.m;

var limit = 100;
if (!isNaN(params["limit"]) && params["limit"] > 0 && params["limit"] < 501) limit = parseInt(params["limit"]);

var bmap_data = await db.query("SELECT `md5`, `id`, `set_id` FROM maps WHERE `id` = ?", params["b"]);
var bmap_data = await db.query("SELECT `md5`, `id`, `set_id` FROM maps WHERE `id` = ?", params.b);
bmap_data = bmap_data[0];

var table = mode < 4 ? 'scores_vn' : mode < 7 ? 'scores_rx' : 'scores_ap';
Expand Down Expand Up @@ -315,14 +291,14 @@ routes.get("/get_user_recent", async (req, res, next) => {
log(req.ip + "\t" + req.originalUrl);
var params = req.query;

var xkey = await key(params["k"]);
var xkey = await isValidKey(params.k);
if (!xkey) {
log(req.ip + "\t" + req.originalUrl + " - invalid key");
res.end(config.messages.invalid_api_key);
return;
}

var us = params["u"];
var us = params.u;
if (!us || us == "") {
res.end(config.messages.invalid_user_param);
return;
Expand All @@ -340,12 +316,12 @@ routes.get("/get_user_recent", async (req, res, next) => {
}

var mode = 0;
if (!isNaN(params["m"]) && params["m"] >= 0 && params["m"] < 8) mode = params["m"];
if (!isNaN(params.m) && params.m >= 0 && params.m < 8) mode = params.m;

var limit = 100;
if (!isNaN(params["limit"]) && params["limit"] > 0 && params["limit"] < 501) limit = parseInt(params["limit"]);

var bmap_data = await db.query("SELECT `md5`, `id`, `set_id` FROM maps WHERE `id` = ?", params["b"]);
var bmap_data = await db.query("SELECT `md5`, `id`, `set_id` FROM maps WHERE `id` = ?", params.b);
bmap_data = bmap_data[0];

var table = mode < 4 ? 'scores_vn' : mode < 7 ? 'scores_rx' : 'scores_ap';
Expand Down
11 changes: 11 additions & 0 deletions ext/config_sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ config.messages = {
// default = false
config.disable_main = false;


// unavailable api proxy
config.proxy = {
enabled: {
'api-get-beatmaps': '/get_beatmaps'
},
baseUrl: process.env.PROXY_BANCHO_API_V1_BASE_URL || 'https://osu.ppy.sh/api'
}



//export config
config.version = "0.11.6b";
module.exports = config;
10 changes: 9 additions & 1 deletion init.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
const http = require('http');
const app = require('./endpoints');
const express = require('express')
const useBancho = require('./utils/proxy-generator')

const config = require('./config');
const otherStuffRouter = require('./endpoints')

const app = express();
app.disable('x-powered-by'); //disable exposing the server header
app.use(useBancho('api-get-beatmaps'))
app.use('/', otherStuffRouter)

const server = http.createServer(app);

Expand Down
Loading