[mirotalsfu] - add stats endpoint
هذا الالتزام موجود في:
33
app/api/stats/stats.js
Normal file
33
app/api/stats/stats.js
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
async function getStats() {
|
||||
try {
|
||||
// Use dynamic import with await
|
||||
const { default: fetch } = await import('node-fetch');
|
||||
|
||||
const API_KEY_SECRET = 'mirotalksfu_default_secret';
|
||||
const MIROTALK_URL = 'https://sfu.mirotalk.com/api/v1/stats';
|
||||
//const MIROTALK_URL = 'http://localhost:3010/api/v1/stats';
|
||||
|
||||
const response = await fetch(MIROTALK_URL, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
authorization: API_KEY_SECRET,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
console.log('Error:', data.error);
|
||||
} else {
|
||||
if (data) {
|
||||
const formattedData = JSON.stringify(data, null, 2);
|
||||
console.log(formattedData);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
}
|
||||
}
|
||||
|
||||
getStats();
|
||||
29
app/api/stats/stats.php
Normal file
29
app/api/stats/stats.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
$API_KEY_SECRET = "mirotalksfu_default_secret";
|
||||
$MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/stats";
|
||||
//$MIROTALK_URL = "http://localhost:3010/api/v1/stats";
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $MIROTALK_URL);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_HTTPGET, true);
|
||||
|
||||
$headers = [
|
||||
'authorization:' . $API_KEY_SECRET,
|
||||
'Content-Type: application/json'
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
$response = curl_exec($ch);
|
||||
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
echo "Status code: $httpcode \n";
|
||||
|
||||
if ($response) {
|
||||
echo json_encode(json_decode($response), JSON_PRETTY_PRINT);
|
||||
} else {
|
||||
echo "Failed to retrieve data.\n";
|
||||
}
|
||||
26
app/api/stats/stats.py
Normal file
26
app/api/stats/stats.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# pip3 install requests
|
||||
import requests
|
||||
import json
|
||||
|
||||
API_KEY_SECRET = "mirotalksfu_default_secret"
|
||||
MIROTALK_URL = "https://sfu.mirotalk.com/api/v1/stats"
|
||||
#MIROTALK_URL = "http://localhost:3010/api/v1/stats"
|
||||
|
||||
headers = {
|
||||
"authorization": API_KEY_SECRET,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
MIROTALK_URL,
|
||||
headers=headers
|
||||
)
|
||||
|
||||
print("Status code:", response.status_code)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
pretty_printed_data = json.dumps(data, indent=4)
|
||||
print(data)
|
||||
else:
|
||||
print("Failed to retrieve data. Error:", response.text)
|
||||
10
app/api/stats/stats.sh
Executable file
10
app/api/stats/stats.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
API_KEY_SECRET="mirotalksfu_default_secret"
|
||||
MIROTALK_URL="https://sfu.mirotalk.com/api/v1/stats"
|
||||
#MIROTALK_URL="http://localhost:3010/api/v1/stats"
|
||||
|
||||
curl $MIROTALK_URL \
|
||||
--header "authorization: $API_KEY_SECRET" \
|
||||
--header "Content-Type: application/json" \
|
||||
--request GET
|
||||
@@ -12,6 +12,24 @@ schemes:
|
||||
- http
|
||||
|
||||
paths:
|
||||
/stats:
|
||||
get:
|
||||
tags:
|
||||
- 'stats'
|
||||
summary: 'Get stats'
|
||||
description: 'Get meetings'
|
||||
produces:
|
||||
- 'application/json'
|
||||
security:
|
||||
- secretApiKey: []
|
||||
responses:
|
||||
'200':
|
||||
description: 'Get Stats done'
|
||||
schema:
|
||||
$ref: '#/definitions/StatsResponse'
|
||||
'403':
|
||||
description: 'Unauthorized!'
|
||||
|
||||
/meetings:
|
||||
get:
|
||||
tags:
|
||||
@@ -107,6 +125,13 @@ securityDefinitions:
|
||||
description: 'Format like this: authorization: {API_KEY_SECRET}'
|
||||
|
||||
definitions:
|
||||
StatsResponse:
|
||||
type: object
|
||||
properties:
|
||||
meetings:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Stats'
|
||||
MeetingsResponse:
|
||||
type: object
|
||||
properties:
|
||||
@@ -193,6 +218,15 @@ definitions:
|
||||
browser:
|
||||
type: string
|
||||
|
||||
Stats:
|
||||
type: object
|
||||
properties:
|
||||
success:
|
||||
type: boolean
|
||||
totalRooms:
|
||||
type: integer
|
||||
totalUser:
|
||||
type: integer
|
||||
Meeting:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -55,7 +55,7 @@ dev dependencies: {
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.6.53
|
||||
* @version 1.6.54
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -924,6 +924,48 @@ function startServer() {
|
||||
// REST API
|
||||
// ####################################################
|
||||
|
||||
app.get([restApi.basePath + '/stats'], (req, res) => {
|
||||
try {
|
||||
// Check if endpoint allowed
|
||||
if (restApi.allowed && !restApi.allowed.stats) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: 'This endpoint has been disabled. Please contact the administrator for further information.',
|
||||
});
|
||||
}
|
||||
// check if user was authorized for the api call
|
||||
const { host, authorization } = req.headers;
|
||||
const api = new ServerApi(host, authorization);
|
||||
|
||||
if (!api.isAuthorized()) {
|
||||
log.debug('MiroTalk get meetings - Unauthorized', {
|
||||
header: req.headers,
|
||||
body: req.body,
|
||||
});
|
||||
return res.status(403).json({ error: 'Unauthorized!' });
|
||||
}
|
||||
|
||||
const { totalRooms, totalUsers } = api.getStats(roomList);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
totalUsers,
|
||||
totalRooms,
|
||||
});
|
||||
|
||||
// log.debug the output if all done
|
||||
log.debug('MiroTalk get stats - Authorized', {
|
||||
header: req.headers,
|
||||
body: req.body,
|
||||
totalUsers,
|
||||
totalRooms,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching stats', error);
|
||||
res.status(500).json({ success: false, error: 'Failed to retrieve stats.' });
|
||||
}
|
||||
});
|
||||
|
||||
// request meetings list
|
||||
app.get([restApi.basePath + '/meetings'], (req, res) => {
|
||||
// Check if endpoint allowed
|
||||
|
||||
@@ -21,6 +21,12 @@ module.exports = class ServerApi {
|
||||
return true;
|
||||
}
|
||||
|
||||
getStats(roomList) {
|
||||
const totalUsers = Array.from(roomList.values()).reduce((total, room) => total + room.peers.size, 0);
|
||||
const totalRooms = roomList.size;
|
||||
return { totalUsers, totalRooms };
|
||||
}
|
||||
|
||||
getMeetings(roomList) {
|
||||
const meetings = Array.from(roomList.entries()).map(([id, room]) => {
|
||||
const peers = Array.from(room.peers.values()).map(
|
||||
|
||||
@@ -141,6 +141,7 @@ module.exports = {
|
||||
keySecret: 'mirotalksfu_default_secret',
|
||||
// Define which endpoints are allowed
|
||||
allowed: {
|
||||
stats: true,
|
||||
meetings: false,
|
||||
meeting: true,
|
||||
join: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mirotalksfu",
|
||||
"version": "1.6.53",
|
||||
"version": "1.6.54",
|
||||
"description": "WebRTC SFU browser-based video calls",
|
||||
"main": "Server.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.6.53
|
||||
* @version 1.6.54
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -4619,7 +4619,7 @@ function showAbout() {
|
||||
imageUrl: image.about,
|
||||
customClass: { image: 'img-about' },
|
||||
position: 'center',
|
||||
title: 'WebRTC SFU v1.6.53',
|
||||
title: 'WebRTC SFU v1.6.54',
|
||||
html: `
|
||||
<br />
|
||||
<div id="about">
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
||||
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||
* @version 1.6.53
|
||||
* @version 1.6.54
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
@@ -38,6 +38,60 @@ describe('test-ServerAPI', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getStats', () => {
|
||||
it('should return total number of rooms and users', () => {
|
||||
const roomList = new Map([
|
||||
[
|
||||
'room1',
|
||||
{
|
||||
peers: new Map([
|
||||
['peer1', { peer_info: { peer_name: 'John Doe' } }],
|
||||
['peer2', { peer_info: { peer_name: 'Jane Doe' } }],
|
||||
]),
|
||||
},
|
||||
],
|
||||
[
|
||||
'room2',
|
||||
{
|
||||
peers: new Map([['peer3', { peer_info: { peer_name: 'Sam Smith' } }]]),
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
const result = serverApi.getStats(roomList);
|
||||
|
||||
result.should.deepEqual({
|
||||
totalUsers: 3,
|
||||
totalRooms: 2,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 0 users when there are no peers in any room', () => {
|
||||
const roomList = new Map([
|
||||
['room1', { peers: new Map() }],
|
||||
['room2', { peers: new Map() }],
|
||||
]);
|
||||
|
||||
const result = serverApi.getStats(roomList);
|
||||
|
||||
result.should.deepEqual({
|
||||
totalUsers: 0,
|
||||
totalRooms: 2,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 0 rooms when roomList is empty', () => {
|
||||
const roomList = new Map();
|
||||
|
||||
const result = serverApi.getStats(roomList);
|
||||
|
||||
result.should.deepEqual({
|
||||
totalUsers: 0,
|
||||
totalRooms: 0,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMeetings', () => {
|
||||
it('should return formatted meetings with peer information', () => {
|
||||
const roomList = new Map([
|
||||
|
||||
المرجع في مشكلة جديدة
حظر مستخدم