[mirotalksfu] - #170 add Mattermost integration, update dep
هذا الالتزام موجود في:
@@ -80,6 +80,7 @@
|
|||||||
- Supports [REST API](app/api/README.md) (Application Programming Interface).
|
- Supports [REST API](app/api/README.md) (Application Programming Interface).
|
||||||
- Integration with [Slack](https://api.slack.com/apps/) for enhanced communication.
|
- Integration with [Slack](https://api.slack.com/apps/) for enhanced communication.
|
||||||
- Integration with [Discord](https://discord.com) for enhanced communication.
|
- Integration with [Discord](https://discord.com) for enhanced communication.
|
||||||
|
- Integration with [Mattermost](https://mattermost.com/) for enhanced communication.
|
||||||
- Utilizes [Sentry](https://sentry.io/) for error reporting.
|
- Utilizes [Sentry](https://sentry.io/) for error reporting.
|
||||||
- And much more...
|
- And much more...
|
||||||
|
|
||||||
|
|||||||
99
app/src/Mattermost.js
Normal file
99
app/src/Mattermost.js
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Client4 } = require('@mattermost/client');
|
||||||
|
|
||||||
|
const { v4: uuidV4 } = require('uuid');
|
||||||
|
|
||||||
|
const config = require('./config');
|
||||||
|
|
||||||
|
const Logger = require('./Logger');
|
||||||
|
|
||||||
|
const log = new Logger('Mattermost');
|
||||||
|
|
||||||
|
class Mattermost {
|
||||||
|
constructor(app) {
|
||||||
|
const {
|
||||||
|
enabled,
|
||||||
|
token,
|
||||||
|
serverUrl,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
commands = '/sfu',
|
||||||
|
texts = '/sfu',
|
||||||
|
} = config.mattermost || {};
|
||||||
|
|
||||||
|
if (!enabled) return; // Check if Mattermost integration is enabled
|
||||||
|
|
||||||
|
this.app = app;
|
||||||
|
this.allowed = config.api.allowed && config.api.allowed.mattermost;
|
||||||
|
this.token = token;
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.commands = commands;
|
||||||
|
this.texts = texts;
|
||||||
|
|
||||||
|
this.client = new Client4();
|
||||||
|
this.client.setUrl(this.serverUrl);
|
||||||
|
this.authenticate();
|
||||||
|
this.setupEventHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
async authenticate() {
|
||||||
|
try {
|
||||||
|
const user = await this.client.login(this.username, this.password);
|
||||||
|
log.debug('--------> Logged into Mattermost as', user.username);
|
||||||
|
} catch (error) {
|
||||||
|
log.error('Failed to log into Mattermost:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupEventHandlers() {
|
||||||
|
this.app.post('/mattermost', (req, res) => {
|
||||||
|
//
|
||||||
|
if (!this.allowed) {
|
||||||
|
return res
|
||||||
|
.status(403)
|
||||||
|
.send('This endpoint has been disabled. Please contact the administrator for further information.');
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug('Mattermost request received:', { header: req.header, body: req.body });
|
||||||
|
|
||||||
|
const { token, text, command, channel_id } = req.body;
|
||||||
|
if (token !== this.token) {
|
||||||
|
return res.status(403).send('Invalid token');
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = { text: '', channel_id };
|
||||||
|
if (this.processInput(command, payload, req) || this.processInput(text, payload, req)) {
|
||||||
|
return res.json(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(200).send('Command not recognized');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
processInput(input, payload, req) {
|
||||||
|
for (const cmd of [...this.commands, ...this.texts]) {
|
||||||
|
if (input.trim() === cmd.name) {
|
||||||
|
switch (cmd.name) {
|
||||||
|
case '/sfu':
|
||||||
|
payload.text = `${cmd.message} ${this.getMeetingURL(req)}`;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMeetingURL(req) {
|
||||||
|
const host = req.headers.host;
|
||||||
|
const protocol = host.includes('localhost') ? 'http' : 'https';
|
||||||
|
return `${protocol}://${host}/join/${uuidV4()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Mattermost;
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
███████ ███████ ██ ██ ████ ███████ ██ ██
|
███████ ███████ ██ ██ ████ ███████ ██ ██
|
||||||
|
|
||||||
prod dependencies: {
|
prod dependencies: {
|
||||||
@ffmpeg-installer/ffmpeg: https://www.npmjs.com/package/@ffmpeg-installer/ffmpeg
|
@mattermost/client : https://www.npmjs.com/package/@mattermost/client
|
||||||
@sentry/node : https://www.npmjs.com/package/@sentry/node
|
@sentry/node : https://www.npmjs.com/package/@sentry/node
|
||||||
axios : https://www.npmjs.com/package/axios
|
axios : https://www.npmjs.com/package/axios
|
||||||
body-parser : https://www.npmjs.com/package/body-parser
|
body-parser : https://www.npmjs.com/package/body-parser
|
||||||
@@ -56,7 +56,7 @@ dev dependencies: {
|
|||||||
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
|
* @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
|
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||||
* @version 1.6.00
|
* @version 1.6.10
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -88,6 +88,7 @@ const swaggerUi = require('swagger-ui-express');
|
|||||||
const swaggerDocument = yaml.load(fs.readFileSync(path.join(__dirname, '/../api/swagger.yaml'), 'utf8'));
|
const swaggerDocument = yaml.load(fs.readFileSync(path.join(__dirname, '/../api/swagger.yaml'), 'utf8'));
|
||||||
const Sentry = require('@sentry/node');
|
const Sentry = require('@sentry/node');
|
||||||
const Discord = require('./Discord.js');
|
const Discord = require('./Discord.js');
|
||||||
|
const Mattermost = require('./Mattermost.js');
|
||||||
const restrictAccessByIP = require('./middleware/IpWhitelist.js');
|
const restrictAccessByIP = require('./middleware/IpWhitelist.js');
|
||||||
const packageJson = require('../../package.json');
|
const packageJson = require('../../package.json');
|
||||||
|
|
||||||
@@ -110,7 +111,6 @@ const CryptoJS = require('crypto-js');
|
|||||||
const qS = require('qs');
|
const qS = require('qs');
|
||||||
const slackEnabled = config.slack.enabled;
|
const slackEnabled = config.slack.enabled;
|
||||||
const slackSigningSecret = config.slack.signingSecret;
|
const slackSigningSecret = config.slack.signingSecret;
|
||||||
const bodyParser = require('body-parser');
|
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@@ -328,12 +328,12 @@ function OIDCAuth(req, res, next) {
|
|||||||
|
|
||||||
function startServer() {
|
function startServer() {
|
||||||
// Start the app
|
// Start the app
|
||||||
|
app.use(express.static(dir.public));
|
||||||
app.use(cors(corsOptions));
|
app.use(cors(corsOptions));
|
||||||
app.use(compression());
|
app.use(compression());
|
||||||
app.use(express.json({ limit: '50mb' })); // Ensure the body parser can handle large files
|
app.use(express.json({ limit: '50mb' })); // Handles JSON payloads
|
||||||
app.use(express.static(dir.public));
|
app.use(express.urlencoded({ extended: true, limit: '50mb' })); // Handles URL-encoded payloads
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(express.raw({ type: 'video/webm', limit: '50mb' })); // Handles raw binary data
|
||||||
app.use(bodyParser.raw({ type: 'video/webm', limit: '50mb' })); // handle raw binary data
|
|
||||||
app.use(restApi.basePath + '/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // api docs
|
app.use(restApi.basePath + '/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // api docs
|
||||||
|
|
||||||
// IP Whitelist check ...
|
// IP Whitelist check ...
|
||||||
@@ -352,6 +352,9 @@ function startServer() {
|
|||||||
});
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Mattermost
|
||||||
|
const mattermost = new Mattermost(app);
|
||||||
|
|
||||||
// POST start from here...
|
// POST start from here...
|
||||||
app.post('*', function (next) {
|
app.post('*', function (next) {
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ module.exports = {
|
|||||||
join: true,
|
join: true,
|
||||||
token: false,
|
token: false,
|
||||||
slack: true,
|
slack: true,
|
||||||
|
mattermost: true,
|
||||||
//...
|
//...
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -273,6 +274,39 @@ module.exports = {
|
|||||||
DSN: '',
|
DSN: '',
|
||||||
tracesSampleRate: 0.5,
|
tracesSampleRate: 0.5,
|
||||||
},
|
},
|
||||||
|
mattermost: {
|
||||||
|
/*
|
||||||
|
Mattermost: https://mattermost.com
|
||||||
|
1. Navigate to Main Menu > Integrations > Slash Commands in Mattermost.
|
||||||
|
2. Click on Add Slash Command and configure the following settings:
|
||||||
|
- Title: Enter a descriptive title (e.g., `P2P Command`).
|
||||||
|
- Command Trigger Word: Set the trigger word to `p2p`.
|
||||||
|
- Callback URLs: Enter the URL for your Express server (e.g., `https://yourserver.com/mattermost`).
|
||||||
|
- Request Method: Select POST.
|
||||||
|
- Enable Autocomplete: Check the box for **Autocomplete**.
|
||||||
|
- Autocomplete Description: Provide a brief description (e.g., `Get MiroTalk P2P meeting room`).
|
||||||
|
3. Save the slash command and copy the generated token here as MATTERMOST_TOKEN.
|
||||||
|
*/
|
||||||
|
enabled: false,
|
||||||
|
serverUrl: 'YourMattermostServerUrl',
|
||||||
|
username: 'YourMattermostUsername',
|
||||||
|
password: 'YourMattermostPassword',
|
||||||
|
token: 'YourMattermostToken',
|
||||||
|
commands: [
|
||||||
|
{
|
||||||
|
name: '/sfu',
|
||||||
|
message: 'Here is your meeting room:',
|
||||||
|
},
|
||||||
|
//....
|
||||||
|
],
|
||||||
|
texts: [
|
||||||
|
{
|
||||||
|
name: '/sfu',
|
||||||
|
message: 'Here is your meeting room:',
|
||||||
|
},
|
||||||
|
//....
|
||||||
|
],
|
||||||
|
},
|
||||||
slack: {
|
slack: {
|
||||||
/*
|
/*
|
||||||
Slack
|
Slack
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mirotalksfu",
|
"name": "mirotalksfu",
|
||||||
"version": "1.6.00",
|
"version": "1.6.10",
|
||||||
"description": "WebRTC SFU browser-based video calls",
|
"description": "WebRTC SFU browser-based video calls",
|
||||||
"main": "Server.js",
|
"main": "Server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -57,9 +57,9 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@mattermost/client": "^10.0.0",
|
||||||
"@sentry/node": "^8.35.0",
|
"@sentry/node": "^8.35.0",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"body-parser": "1.20.3",
|
|
||||||
"colors": "1.4.0",
|
"colors": "1.4.0",
|
||||||
"compression": "1.7.4",
|
"compression": "1.7.4",
|
||||||
"cors": "2.8.5",
|
"cors": "2.8.5",
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
"nodemailer": "^6.9.15",
|
"nodemailer": "^6.9.15",
|
||||||
"openai": "^4.68.4",
|
"openai": "^4.68.4",
|
||||||
"qs": "6.13.0",
|
"qs": "6.13.0",
|
||||||
"socket.io": "4.8.0",
|
"socket.io": "4.8.1",
|
||||||
"swagger-ui-express": "5.0.1",
|
"swagger-ui-express": "5.0.1",
|
||||||
"uuid": "10.0.0"
|
"uuid": "10.0.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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 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
|
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||||
* @version 1.6.00
|
* @version 1.6.10
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -4500,7 +4500,7 @@ function showAbout() {
|
|||||||
imageUrl: image.about,
|
imageUrl: image.about,
|
||||||
customClass: { image: 'img-about' },
|
customClass: { image: 'img-about' },
|
||||||
position: 'center',
|
position: 'center',
|
||||||
title: 'WebRTC SFU v1.6.00',
|
title: 'WebRTC SFU v1.6.10',
|
||||||
html: `
|
html: `
|
||||||
<br />
|
<br />
|
||||||
<div id="about">
|
<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 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
|
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
|
||||||
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
|
||||||
* @version 1.6.00
|
* @version 1.6.10
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
المرجع في مشكلة جديدة
حظر مستخدم