Feature: ChatBot integration
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* KiraBot proxy — forwards /api/kirabot/* to KiraStream backend
|
||||
* authenticating on behalf of the current kiratv user.
|
||||
*/
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { requireAuth } = require('../auth');
|
||||
const { sources } = require('../db');
|
||||
const http = require('http');
|
||||
|
||||
const KIRASTREAM_BASE = process.env.KIRASTREAM_BASE_URL || 'http://10.10.10.234';
|
||||
|
||||
// Token cache: { userId: { token, expires } }
|
||||
const _tokenCache = new Map();
|
||||
|
||||
async function _getKirastreamToken(user) {
|
||||
const cached = _tokenCache.get(user.id);
|
||||
if (cached && cached.expires > Date.now()) {
|
||||
return cached.token;
|
||||
}
|
||||
|
||||
// Find user's xtream source pointing to kirastream
|
||||
let db;
|
||||
try {
|
||||
db = await require('../db').loadDb();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const src = db.sources.find(
|
||||
(s) => s.ownerId === user.id && s.type === 'xtream' && s.username && s.password
|
||||
);
|
||||
if (!src) return null;
|
||||
|
||||
// POST form to /api/user/auth/token
|
||||
return new Promise((resolve) => {
|
||||
const body = `username=${encodeURIComponent(src.username)}&password=${encodeURIComponent(src.password)}`;
|
||||
const url = new URL(`${KIRASTREAM_BASE}/api/user/auth/token`);
|
||||
const options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port || 80,
|
||||
path: url.pathname,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Content-Length': Buffer.byteLength(body),
|
||||
},
|
||||
};
|
||||
const req = http.request(options, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => { data += chunk; });
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
if (json.access_token) {
|
||||
_tokenCache.set(user.id, {
|
||||
token: json.access_token,
|
||||
expires: Date.now() + 25 * 60 * 1000, // 25 min
|
||||
});
|
||||
resolve(json.access_token);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
} catch (e) {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
req.on('error', () => resolve(null));
|
||||
req.write(body);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
async function _proxyToKirastream(req, res, path, method, body) {
|
||||
const token = await _getKirastreamToken(req.user);
|
||||
if (!token) {
|
||||
return res.status(401).json({ error: 'No se pudo autenticar con KiraStream' });
|
||||
}
|
||||
|
||||
const url = new URL(`${KIRASTREAM_BASE}/api/user/kirabot${path}`);
|
||||
const bodyStr = body ? JSON.stringify(body) : '';
|
||||
const options = {
|
||||
hostname: url.hostname,
|
||||
port: url.port || 80,
|
||||
path: url.pathname + (url.search || ''),
|
||||
method: method,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(bodyStr),
|
||||
},
|
||||
};
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const proxyReq = http.request(options, (proxyRes) => {
|
||||
let data = '';
|
||||
proxyRes.on('data', (chunk) => { data += chunk; });
|
||||
proxyRes.on('end', () => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
res.status(proxyRes.statusCode).json(json);
|
||||
} catch (e) {
|
||||
res.status(proxyRes.statusCode).send(data);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
proxyReq.on('error', (err) => {
|
||||
res.status(502).json({ error: 'Error de conexión con KiraStream', detail: err.message });
|
||||
resolve();
|
||||
});
|
||||
if (bodyStr) proxyReq.write(bodyStr);
|
||||
proxyReq.end();
|
||||
});
|
||||
}
|
||||
|
||||
router.use(requireAuth);
|
||||
|
||||
router.post('/chat', async (req, res) => {
|
||||
await _proxyToKirastream(req, res, '/chat', 'POST', req.body);
|
||||
});
|
||||
|
||||
router.get('/chat/history', async (req, res) => {
|
||||
await _proxyToKirastream(req, res, '/chat/history', 'GET', null);
|
||||
});
|
||||
|
||||
router.delete('/chat/history', async (req, res) => {
|
||||
await _proxyToKirastream(req, res, '/chat/history', 'DELETE', null);
|
||||
});
|
||||
|
||||
router.get('/status', async (req, res) => {
|
||||
await _proxyToKirastream(req, res, '/status', 'GET', null);
|
||||
});
|
||||
|
||||
router.get('/recordings', async (req, res) => {
|
||||
const qs = req.query.limit ? `?limit=${req.query.limit}` : '';
|
||||
await _proxyToKirastream(req, res, `/recordings${qs}`, 'GET', null);
|
||||
});
|
||||
|
||||
router.post('/recordings', async (req, res) => {
|
||||
await _proxyToKirastream(req, res, '/recordings', 'POST', req.body);
|
||||
});
|
||||
|
||||
router.delete('/recordings/:id', async (req, res) => {
|
||||
await _proxyToKirastream(req, res, `/recordings/${req.params.id}`, 'DELETE', null);
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user