'Multiping', 'description' => 'Configure when to ping services.', 'page callback' => 'drupal_get_form', 'page arguments' => array('multiping_settings_form'), 'access arguments' => array('administer multiping'), ); $items['admin/config/services/multiping/settings'] = array( 'title' => 'Settings', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 10, ); return $items; } /** * Implements hook_ctools_plugin_type(). */ function multiping_ctools_plugin_type() { return array( 'ping_methods' => array(), ); } /** * Implements hook_permission(). */ function multiping_permission() { return array( 'administer multiping' => array( 'title' => t('Administer ping services'), 'description' => t('Create, edit, delete, and perform ping for ping services.'), ), ); } /** * Implements hook_cron_queue_info(). */ function multiping_cron_queue_info() { $queues['multiping_items'] = array( 'worker callback' => '_multiping_ping_queue_item', 'time' => 60, ); return $queues; } /** * Implements hook_node_insert(). */ function multiping_node_insert($node) { multiping_queue_node($node, 'insert'); } /** * Implements hook_node_update(). */ function multiping_node_update($node) { multiping_queue_node($node, 'update'); } // API /** * Fetch metadata on a specific ping_method plugin. * * @param $ping_method * Name of a ping method. * * @return * An array with information about the requested ping method. */ function multiping_get_ping_method($ping_method) { ctools_include('plugins'); return ctools_get_plugins('multiping', 'ping_methods', $ping_method); } /** * Fetch metadata for all ping_method plugins. * * @return * An array of arrays with information about all available ping methods. */ function multiping_get_ping_methods() { ctools_include('plugins'); return ctools_get_plugins('multiping', 'ping_methods'); } function multiping_queue_node($node, $reason) { $to_queue = array(); foreach (module_implements('multiping_queue_node') as $module) { $module_queue = module_invoke($module, 'multiping_queue_node', $node, $reason); $to_queue = array_merge($to_queue, array_map(function ($item) use ($module, $node, $reason) { $item += array( 'module' => $module, 'node' => $node->nid, 'reason' => $reason, ); return $item; }, $module_queue)); } drupal_alter('multiping_queue_node', $to_queue); // If the settings say to ping at once rather than queue, then do so! if (variable_get('multiping_pingatonce', TRUE)) { foreach ($to_queue as $item) { _multiping_ping_queue_item($item); } } else { $queue = DrupalQueue::get('multiping_items'); foreach ($to_queue as $item) { $queue->createItem($item); } } } // Internal methods function _multiping_ping_queue_item($item) { // Fetch additional data if (is_numeric($item['node'])) { $item['node'] = node_load($item['node']); } // If the triggering module has been disabled or the node removed, just chill if (!module_exists($item['module']) || !$item['node']) { return; } $target = module_invoke($item['module'], 'multiping_target', $item, $item['node']); if ($target) { $item = array_merge($item, $target); unset($item['node']); $item['target'] = url($item['target'], array('absolute' => TRUE)); multiping_ping_item($item); } } function multiping_ping_item($item, $force = FALSE) { // Avoid the same ping from being repeated within the same cron run $fingerprint = drupal_hash_base64(implode('::', array( $item['method'], $item['endpoint'], $item['target'], ))); $last_ping = cache_get('multiping_ping::' . $fingerprint); $cron_last = variable_get('cron_last'); if (!$force && $last_ping && $last_ping->data == $cron_last) { // We have already performed this ping this cron round return; } cache_set('multiping_ping::' . $fingerprint, $cron_last); // Do the ping $method = multiping_get_ping_method($item['method']); if ($method) { $result = call_user_func($method['ping callback'], $item); } $name = empty($item['name']) ? $item['endpoint'] : $item['name']; if (empty($result)) { watchdog('multiping', 'Failed to notify %site about %target.', array( '%site' => $name, '%target' => $item['target'], ), WATCHDOG_ERROR); } else { //TODO: This is _very_ verbose for larger sites! Find a better way! watchdog('multiping', 'Successfully notified %site about %target.', array( '%site' => $name, '%target' => $item['target'], ), WATCHDOG_INFO); } //TODO: Create a retry mechanism! } function multiping_cache_clear() { cache_clear_all('multiping', 'cache', TRUE); } function multiping_path_endpoints($path = NULL, $method = null) { if (!$path) { $path = current_path(); } $router_item = menu_get_item($path); if (!$router_item) { return array(); } $result = array(); foreach (module_implements('multiping_path_endpoints') as $module) { $result = array_merge($result, module_invoke($module, 'multiping_path_endpoints', $router_item['path'], $method)); } return $result; } function _multiping_get_terms($nid) { $terms = &drupal_static(__FUNCTION__); if (empty($terms)) { $terms = array(); } if (!isset($terms[$nid])) { $terms[$nid] = db_query('SELECT tid FROM {taxonomy_index} WHERE nid = :nid', array( ':nid' => $nid ))->fetchCol(); } return $terms[$nid]; } function _multiping_get_vocabularies($nid) { $data = &drupal_static(__FUNCTION__); if (empty($data)) { $data = array(); } if (!isset($data[$nid])) { $data[$nid] = db_query( 'SELECT DISTINCT tv.vid, tv.machine_name FROM {taxonomy_vocabulary} tv ' . 'INNER JOIN {taxonomy_term_data} td ON td.vid = tv.vid ' . 'INNER JOIN {taxonomy_index} ti ON ti.tid = td.tid ' . 'WHERE ti.nid = :nid', array(':nid' => $nid) )->fetchAll(PDO::FETCH_ASSOC); } return $data[$nid]; } function _multiping_module_invoke_until_non_null($hook) { $args = func_get_args(); foreach (module_implements($hook) as $module) { $result = call_user_func_array('module_invoke', array_merge(array($module), $args)); if ($result !== NULL) { return $result; } } } function multiping_settings_form($form, &$form_state) { $form['multiping_pingatonce'] = array( '#type' => 'checkbox', '#title' => t('Ping after post'), '#default_value' => variable_get('multiping_pingatonce', TRUE), '#description' => t('Ping directly after post/update (instead of pinging during the cron job runs). Use this if possible to avoid the added delay a cron job can result.'), ); $form['multiping_timeout'] = array( '#type' => 'select', '#title' => t('Timeout for each ping'), '#default_value' => variable_get('multiping-timeout', 3), '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)), '#description' => t('Time to ping each service in seconds') ); return system_settings_form($form); }