' . getSocketConnectionLabel() . ' ';
$desc .= "Socket Plugin, WebSockets allow for a higher amount of efficiency compared to REST because they do not require the HTTP request/response overhead for each message sent and received ";
$desc .= " To start it on server now sudo " . YPTSocket::getStartServerCommand() . "";
$desc .= " To test use php {$global['systemRootPath']}plugin/YPTSocket/test.php";
$desc .= " To start it on server reboot add it on your crontab (Ubuntu 18+) sudo crontab -eu root than add this code on the last line @reboot sleep 60;" . YPTSocket::getStartServerCommand() . "";
$desc .= " If you use Certbot to renew your SSL use (Ubuntu 18+) sudo crontab -eu root than add this code on the last line 0 1 * * * nohup php {$global['systemRootPath']}plugin/YPTSocket/serverCertbot.php &";
$help = " run this command start the server Help";
//$desc .= $this->isReadyLabel(array('YPTWallet'));
return $desc . $help;
}
public function getName()
{
return "YPTSocket";
}
public function getUUID()
{
return "YPTSocket-5ee8405eaaa16";
}
public function getPluginVersion()
{
return "2.2";
}
public static function getServerVersion()
{
return "7.4";
}
public function updateScript()
{
global $global;
/*
if (AVideoPlugin::compareVersion($this->getName(), "2.0") < 0) {
sqlDal::executeFile($global['systemRootPath'] . 'plugin/PayPerView/install/updateV2.0.sql');
}
*
*/
return true;
}
public static function getDataObjectDeprecated()
{
return array(
'forceNonSecure',
'uri',
'debugSocket',
'debugAllUsersSocket',
'allow_self_signed',
'forceNonSecure',
'showTotalOnlineUsersPerVideo',
'showTotalOnlineUsersPerLive',
'showTotalOnlineUsersPerLiveLink',
);
}
public static function getDataObjectAdvanced()
{
return array(
'forceNonSecure',
'uri',
'debugSocket',
'debugAllUsersSocket',
'allow_self_signed',
'forceNonSecure',
'showTotalOnlineUsersPerVideo',
'showTotalOnlineUsersPerLive',
'showTotalOnlineUsersPerLiveLink',
);
}
public function getEmptyDataObject()
{
global $global;
$obj = new stdClass();
$host = parse_url($global['webSiteRootURL'], PHP_URL_HOST);
$server_crt_file = "/etc/letsencrypt/live/{$host}/fullchain.pem";
$server_key_file = "/etc/letsencrypt/live/{$host}/privkey.pem";
$host = parse_url($global['webSiteRootURL'], PHP_URL_HOST);
$obj->forceNonSecure = false;
self::addDataObjectHelper('forceNonSecure', 'Force not to use wss (non secure)', 'This is good if a reverse proxy is giving you a SSL');
$obj->port = "2053";
self::addDataObjectHelper('port', 'Server Port', 'You also MUST open this port on the firewall');
$obj->uri = "0.0.0.0";
self::addDataObjectHelper('uri', 'Server URI', 'You should not change it, only if you know what you are doing');
$obj->host = $host;
self::addDataObjectHelper('host', 'Server host', 'If your site is HTTPS make sure this host also handle the SSL connection');
$obj->debugSocket = true;
self::addDataObjectHelper('debugSocket', 'Show server debugger to admin', 'This will show a panel with some socket informations to the ADMIN user only');
$obj->debugAllUsersSocket = false;
self::addDataObjectHelper('debugAllUsersSocket', 'Show server debugger to all', 'Same as above but will show the panel to all users');
$obj->server_crt_file = $server_crt_file;
self::addDataObjectHelper('server_crt_file', 'SSL Certificate File', 'If your site use HTTPS, you MUST provide one');
$obj->server_key_file = $server_key_file;
self::addDataObjectHelper('server_key_file', 'SSL Certificate Key File', 'If your site use HTTPS, you MUST provide one');
$obj->allow_self_signed = true;
self::addDataObjectHelper('allow_self_signed', 'Allow self signed certs', 'Should be unchecked in production');
$obj->showTotalOnlineUsersPerVideo = true;
self::addDataObjectHelper('showTotalOnlineUsersPerVideo', 'Show Total Online Users Per Video');
$obj->showTotalOnlineUsersPerLive = true;
self::addDataObjectHelper('showTotalOnlineUsersPerLive', 'Show Total Online Users Per Live');
$obj->showTotalOnlineUsersPerLiveLink = true;
self::addDataObjectHelper('showTotalOnlineUsersPerLiveLink', 'Show Total Online Users Per LiveLink');
$obj->enableCalls = false;
self::addDataObjectHelper('enableCalls', 'Enable Meeting Calls', 'This feature requires the meet plugin enabled');
return $obj;
}
public function getFooterCode()
{
self::getSocketJS();
self::getCallerJS();
}
public static function getSocketJS()
{
global $global;
include_once $global['systemRootPath'] . 'plugin/YPTSocket/footer.php';
}
public static function getCallerJS()
{
global $global;
include_once $global['systemRootPath'] . 'plugin/YPTSocket/footerCaller.php';
}
public static function sendAsync($msg, $callbackJSFunction = "", $users_id = "", $send_to_uri_pattern = "")
{
global $global;
if (!is_string($msg)) {
$msg = json_encode($msg);
}
$command = get_php() . " {$global['systemRootPath']}plugin/YPTSocket/send.json.php '$msg' '$callbackJSFunction' '$users_id' '$send_to_uri_pattern'";
execAsync($command);
}
/**
* Clean up a given object by removing properties that exceed a specified size.
*
* @param object|array $data The object or array to clean up.
* @param int $maxSize The maximum allowed size for any parameter (in bytes).
* @return object|array The cleaned object or array.
*/
static function cleanupSocketSendObj($data, $maxSize = 2048)
{
// Iterate through each property if it's an object or array
if (is_object($data) || is_array($data)) {
foreach ($data as $key => &$value) {
// If the value is an object or array, recursively clean it
if (is_object($value) || is_array($value)) {
$value = self::cleanupSocketSendObj($value, $maxSize);
} else {
// Check the size of the value
$size = strlen(serialize($value));
if ($size > $maxSize && $key != 'webSocketToken' && $key != 'msg') {
unset($data->$key);
}
}
}
}
return $data;
}
public static function send($msg, $callbackJSFunction = "", $users_id = "", $send_to_uri_pattern = "")
{
global $global, $SocketSendObj, $SocketSendUsers_id, $SocketSendResponseObj, $SocketURL;
_mysql_close();
@_session_write_close();
if (!is_string($msg)) {
$msg = json_encode($msg);
}
$SocketSendUsers_id = $users_id;
if (!is_array($SocketSendUsers_id)) {
$SocketSendUsers_id = array($SocketSendUsers_id);
}
$SocketSendObj = new stdClass();
$SocketSendObj->msg = $msg;
$SocketSendObj->isCommandLine = isCommandLineInterface();
$SocketSendObj->json = _json_decode($msg);
$SocketSendObj->webSocketToken = getEncryptedInfo(0, $send_to_uri_pattern);
$SocketSendObj->callback = $callbackJSFunction;
$SocketSendResponseObj = new stdClass();
$SocketSendResponseObj->error = true;
$SocketSendResponseObj->msg = "";
$SocketSendResponseObj->msgObj = $SocketSendObj;
$SocketSendResponseObj->callbackJSFunction = $callbackJSFunction;
require_once $global['systemRootPath'] . 'objects/autoload.php';
$SocketURL = self::getWebSocketURL(true, $SocketSendObj->webSocketToken, isDocker());
//_error_log("Socket Send: {$SocketURL}");
\Ratchet\Client\connect($SocketURL)->then(function ($conn) use ($SocketSendUsers_id, $SocketSendObj, $SocketSendResponseObj) {
global $SocketSendResponseObj;
_error_log("Socket {$SocketSendResponseObj->callbackJSFunction} line=" . __LINE__);
$conn->on('message', function ($msg) use ($conn, $SocketSendResponseObj) {
_error_log("Socket on message {$SocketSendResponseObj->callbackJSFunction} line=" . __LINE__);
$SocketSendResponseObj->error = false;
$SocketSendResponseObj->msg = $msg;
});
$conn->on('open', function () use ($conn) {
_error_log("Socket connection opened successfully.");
});
// Log when the connection is closed
$conn->on('close', function ($code = null, $reason = null) {
_error_log("Socket connection closed. Code: $code, Reason: $reason line=" . __LINE__);
});
$sendMessages = function ($users, $index = 0) use ($conn, $SocketSendObj, &$sendMessages) {
_error_log("Socket sendMessages $index line=" . __LINE__ . ' users=' . json_encode($users));
if ($index < count($users)) {
_error_log("Socket sendMessages $index line=" . __LINE__);
$SocketSendObj->to_users_id = $users[$index];
$SocketSendObj = self::cleanupSocketSendObj($SocketSendObj);
$message = json_encode($SocketSendObj);
if ($message === false) {
_error_log("Socket sendMessages: JSON encoding failed. Error: " . json_last_error_msg());
} else {
_error_log("Socket sendMessages: Sending message ");
$conn->send($message, function () use ($users, $index, $sendMessages) {
_error_log("Socket sendMessages $index total=" . count($users) . " line=" . __LINE__);
});
}
if ($index + 1 >= count($users)) {
_error_log("Socket close $index total=" . count($users) . " line=" . __LINE__);
$conn->close();
} else {
_error_log("Socket sendMessages $index total=" . count($users) . " line=" . __LINE__);
$sendMessages($users, $index + 1);
}
} else {
_error_log("Socket close line=" . __LINE__);
$conn->close();
}
_error_log("Socket sendMessages $index line=" . __LINE__);
};
_error_log("Socket connect {$SocketSendResponseObj->callbackJSFunction} line=" . __LINE__);
$sendMessages($SocketSendUsers_id);
}, function ($e) {
global $SocketURL;
_error_log("Could not connect: {$e->getMessage()} {$SocketURL} line=" . __LINE__, AVideoLog::$ERROR);
});
_error_log("Socket SocketSendResponseObj {$SocketSendResponseObj->callbackJSFunction} line=" . __LINE__);
return $SocketSendResponseObj;
}
public static function getWebSocketURL($isCommandLine = false, $webSocketToken = '', $internalDocker = false)
{
global $global;
$socketobj = AVideoPlugin::getDataObject("YPTSocket");
$address = $socketobj->host;
$port = $socketobj->port;
$protocol = "ws";
$scheme = parse_url($global['webSiteRootURL'], PHP_URL_SCHEME);
if (isDocker()) {
$protocol = "wss";
$dockerVars = getDockerVars();
$port = $dockerVars->SOCKET_PORT;
$address = $dockerVars->SERVER_NAME;
} else if (strtolower($scheme) === 'https') {
$protocol = "wss";
}
if (empty($webSocketToken)) {
$webSocketToken = getEncryptedInfo(0);
}
return "{$protocol}://{$address}:{$port}?webSocketToken={$webSocketToken}&isCommandLine=" . intval($isCommandLine);
}
public function onUserSocketConnect()
{
$obj = AVideoPlugin::getDataObjectIfEnabled('YPTSocket');
if (!empty($obj->enableCalls)) {
echo 'callerNewConnection(response);';
}
echo 'socketNewConnection(response);';
return '';
}
public function onUserSocketDisconnect()
{
$obj = AVideoPlugin::getDataObjectIfEnabled('YPTSocket');
if (!empty($obj->enableCalls)) {
echo 'callerDisconnection(response);';
}
echo 'socketDisconnection(response);';
return '';
}
public static function getUserOnlineLabel($users_id, $class = '', $style = '')
{
global $global;
$users_id = intval($users_id);
$varsArray = array('users_id' => $users_id, 'class' => $class, 'style' => $style);
$filePath = $global['systemRootPath'] . 'plugin/YPTSocket/userOnlineLabel.php';
return getIncludeFileContent($filePath, $varsArray);
}
public static function shouldShowCaller()
{
global $_YPTSocketshouldShowCaller;
if (!isset($_YPTSocketshouldShowCaller)) {
$obj = new stdClass();
$obj->show = false;
$obj->reason = '';
if (!User::isLogged()) {
$obj->reason = 'Not logged';
} else {
$objSocket = AVideoPlugin::getDataObjectIfEnabled('YPTSocket');
if (empty($objSocket->enableCalls)) {
$obj->reason = 'YPTSocket enableCalls = false';
} else {
$obj->show = true;
}
}
$_YPTSocketshouldShowCaller = $obj;
}
return $_YPTSocketshouldShowCaller;
}
static public function scheduleRestart()
{
$scheduler_commands_id = Scheduler::add(strtotime('+5 seconds'), 'none', array('users_id' => User::getId()), 'SocketRestart');
return $scheduler_commands_id;
}
public function getPluginMenu()
{
global $global;
$btn = '';
return $btn;
}
static public function restart()
{
global $global;
exec("php {$global['systemRootPath']}plugin/YPTSocket/stopServer.php");
exec("sleep 1");
execAsync(YPTSocket::getStartServerCommand());
return true;
}
function executeEveryDay()
{
self::restart();
}
static public function getStartServerCommand()
{
global $global;
$command = "nohup bash -c 'ulimit -n 1048576 && php {$global['systemRootPath']}plugin/YPTSocket/server.php &'";
return $command;
}
function getChannelPageButtons($users_id)
{
return getUserOnlineLabel($users_id, 'pull-right', 'padding: 0 5px;');;
}
}