View source
<?php
use Drupal\Core\Asset\AttachedAssetsInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Url;
use Drupal\Core\Site\Settings;
use Drupal\Core\Session\AnonymousUserSession;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Drupal\nodejs\Nodejs;
function nodejs_get_nodejs() {
return \Drupal::service('nodejs.nodejs');
}
function nodejs_generate_content_token() {
return Crypt::hmacBase64(uniqid(mt_rand(), TRUE), \Drupal::service('private_key')
->get() . ($hash_salt = Settings::getHashSalt()));
}
function nodejs_send_content_channel_message($message) {
nodejs_get_nodejs()
->sendContentTokenMessage($message);
}
function nodejs_send_content_channel_token($channel, $notify_on_disconnect = FALSE, $user_data = FALSE) {
$message = (object) array(
'token' => nodejs_generate_content_token(),
'channel' => $channel,
'notifyOnDisconnect' => $notify_on_disconnect,
'userData' => $user_data,
);
if ($node_response = nodejs_get_nodejs()
->sendContentToken($message)) {
if ($node_response->status == 'success') {
nodejs_get_nodejs()
->enqueueContentToken($channel, $message->token);
$node_response->token = $message->token;
return $node_response;
}
else {
\Drupal::logger('nodejs')
->error(t('Error sending content channel token for channel "%channel". Node.js server response: %error', array(
'%channel' => $channel,
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_get_content_channel_users($channel) {
$message = (object) array(
'channel' => $channel,
);
if ($node_response = nodejs_get_nodejs()
->getContentTokenUsers($message)) {
if (isset($node_response->error)) {
\Drupal::logger('nodejs')
->error(t('Error getting content channel users for channel "%channel" on the Node.js server. Server response: %error', array(
'%channel' => $channel,
'%error' => $node_response->error,
)));
return FALSE;
}
else {
return array(
'uids' => !empty($node_response->users->uids) ? $node_response->users->uids : array(),
'authTokens' => !empty($node_response->users->authTokens) ? $node_response->users->authTokens : array(),
);
}
}
else {
return FALSE;
}
}
function nodejs_kick_user($uid) {
if ($node_response = nodejs_get_nodejs()
->kickUser($uid)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
\Drupal::logger('nodejs')
->error(t('Error kicking uid "%uid" from the Node.js server. Server response: %error', array(
'%uid' => $uid,
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_logout_user($token) {
if ($node_response = nodejs_get_nodejs()
->logoutUser($token)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
\Drupal::logger('nodejs')
->error(t('Error logging out token "%token" from the Node.js server. Server response: %error', array(
'%token' => $token,
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_set_user_presence_list($uid, array $uids) {
if ($node_response = nodejs_get_nodejs()
->setUserPresenceList($uid, $uids)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
\Drupal::logger('nodejs')
->error(t('Error setting user presence list for uid "%uid" on the Node.js server. Server response: %error', array(
'%uid' => $uid,
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_broadcast_message($subject, $body) {
$message = (object) array(
'broadcast' => TRUE,
'data' => (object) array(
'subject' => $subject,
'body' => $body,
),
'channel' => 'nodejs_notify',
);
nodejs_enqueue_message($message);
}
function nodejs_send_channel_message($channel, $subject, $body) {
$message = (object) array(
'data' => (object) array(
'subject' => $subject,
'body' => $body,
),
'channel' => $channel,
);
nodejs_enqueue_message($message);
}
function nodejs_send_user_message($uid, $subject, $body) {
$message = (object) array(
'data' => (object) array(
'subject' => $subject,
'body' => $body,
),
'channel' => 'nodejs_user_' . $uid,
'callback' => 'nodejsNotify',
);
nodejs_enqueue_message($message);
}
function nodejs_send_user_message_multiple($uids, $subject, $body) {
if (!is_array($uids)) {
$uids = explode(',', $uids);
}
foreach ($uids as $uid) {
nodejs_send_user_message($uid, $subject, $body);
}
}
function nodejs_send_role_message($role_name, $subject, $body) {
$query = \Drupal::database()
->select('users', 'u');
$query
->join('users_roles', 'ur', 'ur.uid = u.uid');
$query
->join('role', 'r', 'ur.rid = r.rid');
$uids = $query
->fields('u', array(
'uid',
))
->condition('r.name', $role_name)
->execute()
->fetchCol();
nodejs_send_user_message_multiple($uids, $subject, $body);
}
function nodejs_add_js_to_page_check() {
$account = \Drupal::currentUser();
$path = \Drupal::service('path_alias.manager')
->getAliasByPath(Url::fromRoute('<current>')
->toString());
$config_paths = \Drupal::config('nodejs.config')
->get('pages');
$valid_page = \Drupal::service('path.matcher')
->matchPath($path, $config_paths);
if (\Drupal::config('nodejs.config')
->get('authenticated_users_only')) {
$valid_user = $account
->id() > 0;
}
else {
$valid_user = TRUE;
}
return $valid_page && $valid_user;
}
function nodejs_get_socketio_js_config($nodejs_config) {
$socket_io_config = \Drupal::config('nodejs.config')
->get('socket_io');
if (!$socket_io_config['path']) {
$socket_io_config['path'] = $nodejs_config['client']['scheme'] . '://' . $nodejs_config['client']['host'] . ':' . $nodejs_config['client']['port'] . '/socket.io/socket.io.js';
}
return $socket_io_config;
}
function nodejs_get_js_handlers() {
$handlers = \Drupal::moduleHandler()
->invokeAll('nodejs_handlers_info', $args = array());
\Drupal::moduleHandler()
->alter('nodejs_js_handlers', $handlers);
return $handlers;
}
function nodejs_js_settings_alter(array &$settings, AttachedAssetsInterface $assets) {
if (nodejs_add_js_to_page_check()) {
$nodejs_config = nodejs_get_config();
$settings['nodejs'] = [
'nodejs' => $nodejs_config['nodejs'],
'client' => $nodejs_config['client'],
'authToken' => nodejs_auth_get_token(\Drupal::service('session')),
];
$tokens = nodejs_get_nodejs()
->getContentTokens();
foreach ($tokens as $channel => $token) {
$settings['nodejs']['contentTokens'][$channel] = $token;
}
}
}
function nodejs_page_attachments_alter(array &$attachments) {
if (nodejs_add_js_to_page_check()) {
$libraries = [
'nodejs/socketio',
'nodejs/init',
];
foreach (nodejs_get_js_handlers() as $library) {
$libraries[] = $library;
}
foreach ($libraries as $library) {
if (!in_array($library, $attachments['#attached']['library'])) {
$attachments['#attached']['library'][] = $library;
}
}
}
}
function nodejs_library_info_build() {
$nodejs_config = nodejs_get_config();
$socket_io_config = nodejs_get_socketio_js_config($nodejs_config);
$libraries['socketio'] = [
'js' => [
$socket_io_config['path'] => [
'type' => $socket_io_config['type'],
],
],
];
return $libraries;
}
function nodejs_add_channel($channel) {
if ($node_response = nodejs_get_nodejs()
->addChannel($channel)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
\Drupal::logger('nodejs')
->error(t('Error adding channel to the Node.js server. Server response: %error', array(
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_check_channel($channel) {
if ($node_response = nodejs_get_nodejs()
->checkChannel($channel)) {
if ($node_response->status == 'success') {
return $node_response->result;
}
else {
\Drupal::logger('nodejs')
->error(t('Error checking channel on the Node.js server. Server response: %error', array(
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_remove_channel($channel) {
if ($node_response = nodejs_get_nodejs()
->removeChannel($channel)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
\Drupal::logger('nodejs')
->error(t('Error removing channel from the Node.js server. Server response: %error', array(
'%error' => $node_response->error,
)));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_enqueue_message(StdClass $message) {
$message->broadcast = isset($message->broadcast) ? $message->broadcast : FALSE;
nodejs_get_nodejs()
->enqueueMessage($message);
}
function nodejs_send_message(StdClass $message) {
$message->broadcast = isset($message->broadcast) ? $message->broadcast : FALSE;
return nodejs_get_nodejs()
->sendMessage($message);
}
function nodejs_nodejs_user_channels($account) {
if (\Drupal::config('nodejs.config')
->get('enable_userchannel') && $account->uid) {
return array(
'nodejs_user_' . $account->uid,
);
}
return array();
}
function nodejs_user_logout($account) {
if (isset($_SESSION['nodejs_config']['authToken'])) {
nodejs_logout_user($_SESSION['nodejs_config']['authToken']);
}
}
function nodejs_is_valid_service_key($service_key) {
return $service_key == \Drupal::config('nodejs.config')
->get('service_key');
}
function nodejs_auth_check($message) {
$nodejs_auth_check_callback = \Drupal::config('nodejs.config')
->get('auth_check_callback');
if (!function_exists($nodejs_auth_check_callback)) {
throw new Exception("No nodejs_auth_check callback found - looked for '{$nodejs_auth_check_callback}'.");
}
$uid = $nodejs_auth_check_callback($message['authToken']);
$account = $uid > 0 ? \Drupal::service('entity_type.manager')
->getStorage('user')
->load($uid) : new AnonymousUserSession();
$auth_user = new stdClass();
$auth_user->uid = $account
->id();
$auth_user->authToken = $message['authToken'];
$auth_user->nodejsValidAuthToken = $uid !== FALSE;
$auth_user->clientId = $message['clientId'];
if ($auth_user->nodejsValidAuthToken) {
$auth_user->channels = array();
foreach (\Drupal::moduleHandler()
->getImplementations('nodejs_user_channels') as $module) {
$function = $module . '_nodejs_user_channels';
foreach ($function($auth_user) as $channel) {
$auth_user->channels[] = $channel;
}
}
$auth_user->presenceUids = array_unique(\Drupal::moduleHandler()
->invokeAll('nodejs_user_presence_list', [
$auth_user,
]));
\Drupal::moduleHandler()
->alter('nodejs_auth_user', $auth_user);
if ($auth_user->uid) {
nodejs_user_set_online($auth_user->uid);
}
$auth_user->contentTokens = isset($message['contentTokens']) ? $message['contentTokens'] : array();
}
return $auth_user;
}
function nodejs_auth_check_callback($auth_token) {
return \Drupal::database()
->query("SELECT uid FROM {sessions} WHERE MD5(sid) = :auth_key", array(
':auth_key' => $auth_token,
))
->fetchField();
}
function nodejs_auth_get_token(SessionInterface $session) {
$nodejs_auth_get_token_callback = \Drupal::config('nodejs.config')
->get('auth_get_token_callback');
if (!function_exists($nodejs_auth_get_token_callback)) {
throw new Exception("Cannot proceed without a valid nodejs_auth_get_token callback - looked for '{$nodejs_auth_get_token_callback}'.");
}
return $nodejs_auth_get_token_callback($session);
}
function nodejs_auth_get_token_callback(SessionInterface $session) {
return md5(Crypt::hashBase64($session
->getId()));
}
function nodejs_user_set_online($uid) {
try {
\Drupal::database()
->query('INSERT INTO {nodejs_presence} (uid, login_time) VALUES (:uid, :login_time)', array(
':uid' => $uid,
':login_time' => time(),
));
} catch (Exception $e) {
}
}
function nodejs_user_set_offline($uid) {
try {
\Drupal::database()
->query('DELETE FROM {nodejs_presence} WHERE uid = :uid', array(
':uid' => $uid,
));
} catch (Exception $e) {
}
}
function nodejs_get_config() {
return \Drupal::config('nodejs.config')
->get();
}
function nodejs_get_url($config, $callback = '') {
return $config['nodejs']['scheme'] . '://' . $config['nodejs']['host'] . ':' . $config['nodejs']['port'] . '/' . $callback;
}
function nodejs_remove_user_from_channel($uid, $channel) {
if ($node_response = nodejs_get_nodejs()
->removeUserFromChannel($uid, $channel)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
$params = array(
'%uid' => $uid,
'%channel' => $channel,
'%error' => $node_response->error,
);
\Drupal::logger('nodejs')
->error(t('Error removing user with uid: %uid from channel %channel on the Node.js server. Server response: %error', $params));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_add_user_to_channel($uid, $channel) {
if ($node_response = nodejs_get_nodejs()
->addUserToChannel($uid, $channel)) {
if ($node_response->status == 'success') {
return TRUE;
}
else {
$params = array(
'%uid' => $uid,
'%channel' => $channel,
'%error' => $node_response->error,
);
\Drupal::logger('nodejs')
->error(t('Error adding user with uid: %uid to channel %channel on the Node.js server. Server response: %error', $params));
return FALSE;
}
}
else {
return FALSE;
}
}
function nodejs_get_client_socket_id() {
$client_socket_id = isset($_POST['nodejs_client_socket_id']) ? $_POST['nodejs_client_socket_id'] : '';
return preg_match('/^[0-9a-z_-]+$/i', $client_socket_id) ? $client_socket_id : '';
}