Compare commits

...

3 Commits

Author SHA1 Message Date
e2fc5059e2 perf(checker): run account checks concurrently using Promise.any
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 22s
Refactors the `singleAccountCheck` function to use `Promise.any` for validating accounts against multiple stream URLs. This replaces the previous sequential `for` loop.

By running the checks concurrently, the process is significantly faster as it no longer waits for each request to finish before trying the next. The function now resolves as soon as the first successful validation occurs.

The fallback logic for 403 errors (from a tor instance to a direct request) is now cleanly encapsulated within each promise.
2025-07-13 17:01:31 +01:00
07340e9341 allow the urls to stull build if a source dies
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 22s
2025-07-13 16:51:40 +01:00
a710f242f4 working autocomplete for account add
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 22s
2025-07-13 16:06:27 +01:00
7 changed files with 78 additions and 86 deletions

2
app.js
View File

@ -8,6 +8,7 @@ var getUserAccounts = require('./routes/getUserAccounts')
var singleUserCheck = require('./routes/singleCheck')
var addAccount = require('./routes/addAccount')
var deleteAccount = require('./routes/deleteAccount')
var getStreamNames = require('./routes/getStreamNames')
var login = require('./routes/login')
var app = express();
@ -26,6 +27,7 @@ app.use('/getUserAccounts', basicAuth(users), getUserAccounts);
app.use('/singleCheck', basicAuth(users), singleUserCheck)
app.use('/addAccount', basicAuth(users), addAccount)
app.use('/deleteAccount', basicAuth(users), deleteAccount)
app.use('/getStreamNames', basicAuth(users), getStreamNames)
// catch 404 and forward to error handler
app.use(function (req, res, next) {

View File

@ -21,17 +21,4 @@ services:
- DATABASE=BBLB_DNS
- DBPORT=3306
- TORSSRV=host.docker.internal
- TORSPWD=KarlMax
# frontend:
# build:
# context: ./client
# dockerfile: Dockerfile.prod
# # dockerfile: .dockerfile
# image: "karl0ss/bblbtv_dns-frontend"
# ports:
# - "6969:6969"
# environment:
# - URL=vps.k-world.me.uk
# - PORT=6969
# links:
# - "backend"
- TORSPWD=KarlMax

View File

@ -33,9 +33,8 @@ let axiosOptions = {
// const delay = ms => new Promise(res => setTimeout(res, ms));
async function buildURL(streamURL, username, password) {
let url = streamURL + "/player_api.php?username=" + username + "&password=" + password
return url
function buildURL(streamURL, username, password) {
return `${streamURL}/player_api.php?username=${username}&password=${password}`
}
async function splitURL(url) {
@ -173,56 +172,48 @@ async function userCheck(accountData) {
}
}
async function accountChecker(accountData, urlList) {
let ip = await inst.get('http://api.ipify.org')
console.log(ip.data);
async function singleAccountCheck(accountData) {
const streamURLS = await getStreamsNew();
const urlList = streamURLS.map(streamURL => buildURL(streamURL, accountData.username, accountData.password));
for (let index = 0; index < urlList.length; index++) {
const url = urlList[index];
console.log(index + 1 + ' of ' + urlList.length + ' urls checked')
const checkUrl = (url) => new Promise(async (resolve, reject) => {
try {
let response = await inst.get(url, axiosOptions)
if (response.data.user_info.auth) {
addNewAccount(accountData, response.data, url)
console.log('New Account Added')
// syncApache()
return true
// Use tor instance first
const response = await inst.get(url, axiosOptions);
if (response.data && response.data.user_info && response.data.user_info.auth) {
return resolve({ url, data: response.data });
}
} catch (error) {
try {
if (error.response.status == 403) {
let response2 = await axios.get(url, axiosOptions)
if (response2.data.user_info.auth) {
try {
await addNewAccount(accountData, response2.data, url)
console.log('New Account Added')
// syncApache()
return true
} catch (error) {
continue
}
// Fallback to regular axios on 403 error
if (error.response && error.response.status === 403) {
try {
const response2 = await axios.get(url, axiosOptions);
if (response2.data && response2.data.user_info && response2.data.user_info.auth) {
return resolve({ url, data: response2.data });
}
} catch (e) {
// If fallback fails, proceed to reject
}
} catch (error) {
continue
}
}
// Reject if any check fails or encounters an error
return reject(new Error(`Check failed for ${url}`));
});
const promises = urlList.map(checkUrl);
try {
// Wait for the first promise to resolve
const { url, data } = await Promise.any(promises);
await addNewAccount(accountData, data, url);
console.log('New Account Added');
// syncApache() was commented out, preserving that.
return true;
} catch (error) {
// This block runs if all promises reject
console.log(`All checks failed for user ${accountData.username}.`);
return false;
}
return false
}
async function singleAccountCheck(accountData) {
streamURLS = await getStreamsNew()
urlList = []
for (let index = 0; index < streamURLS.length; index++) {
const streamURL = streamURLS[index];
urlList.push(await buildURL(streamURL, accountData.username, accountData.password))
}
urlList
return await accountChecker(accountData, urlList)
}

View File

@ -1,12 +1,19 @@
const sql = require('./mysql')
function getStreamNames() {
let data = sql.query(`SELECT id, streamName FROM BBLB_DNS.streams`)
let data = sql.query(`SELECT stream FROM BBLB_DNS.userAccounts`)
// console.log(data)
if (data.length == 0) {
return 'StreamsFailed'
} else {
return data
const cleanedNames = data.map(item => {
if (item.stream) {
return item.stream.split('(')[0].trim();
}
return '';
}).filter(name => name !== '');
const uniqueNames = [...new Set(cleanedNames)];
return uniqueNames;
}
}

View File

@ -1,6 +1,6 @@
{
"name": "react-backend",
"version": "1.0.8",
"version": "1.0.10",
"private": true,
"scripts": {
"start": "node ./bin/www"

View File

@ -3,14 +3,11 @@ var router = express.Router();
const { getStreamNames } = require('../lib/getStreamNames')
/* POST postUser page. */
/* GET stream names. */
router.get('/', async function (req, res, next) {
if (req.cookies.user === undefined) {
res.send('Cookie Not Set')
} else {
let data = await getStreamNames()
res.json(data)
}
});
}
);
module.exports = router;

View File

@ -18,26 +18,34 @@ async function getStreamsNew() {
let jointArray = []
for (let index = 0; index < DNSArray.length; index++) {
const url = DNSArray[index];
requestData = await makeRequest(url)
let DNSList = requestData.body
if (typeof DNSList === 'string' || DNSList instanceof String) {
try {
DNSList = JSON.parse(DNSList)
} catch (error) {
jointArray.unshift(...otherURLs.using)
jointArray = [...new Set(jointArray)]
return jointArray
}
}
try {
DNSList = splitToArray(DNSList.su)
requestData = await makeRequest(url)
let DNSList = requestData.body
if (typeof DNSList === 'string' || DNSList instanceof String) {
try {
DNSList = JSON.parse(DNSList)
} catch (error) {
console.error(`Failed to parse JSON for url: ${url}`);
continue; // skip to next url
}
}
let extractedUrls;
if (DNSList && DNSList.su) {
extractedUrls = splitToArray(DNSList.su);
} else if (DNSList && DNSList.fu) {
extractedUrls = splitToArray(DNSList.fu);
} else {
console.error(`Could not find 'su' or 'fu' for url: ${url}`);
continue; // skip to next url
}
extractedUrls.forEach(url => {
jointArray.push(url)
});
} catch (error) {
DNSList = splitToArray(DNSList.fu)
console.error(`Failed to process url: ${url}`, error);
}
DNSList.forEach(url => {
jointArray.push(url)
});
}
jointArray.unshift(...otherURLs.using)
jointArray = [...new Set(jointArray)]
@ -45,10 +53,10 @@ async function getStreamsNew() {
}
/* GET users listing. */
router.get('/', async function (req, res, next) {
let fullStreamArray = await main()
let fullStreamArray = await getStreamsNew()
res.send(fullStreamArray)
});
module.exports = {
router, getStreamsNew
}
}