Plugin Directory

Changeset 3472274


Ignore:
Timestamp:
03/01/2026 10:33:24 PM (5 weeks ago)
Author:
zubbin
Message:

Release version 1.4.50

Location:
zubbin-uptime-node
Files:
5 edited
11 copied

Legend:

Unmodified
Added
Removed
  • zubbin-uptime-node/tags/1.4.50/includes/admin.php

    r3458420 r3472274  
    1212    add_action('admin_post_zubbin_un_bootstrap', [__CLASS__, 'bootstrap']);
    1313    add_action('admin_post_zubbin_un_auto_register', [__CLASS__, 'auto_register']);
     14    add_action('admin_post_zubbin_un_reset_registration', [__CLASS__, 'reset_registration']);
    1415    add_action('admin_post_zubbin_un_force_sync', [__CLASS__, 'force_sync']);
    1516    add_action('admin_post_zubbin_un_test_auth', [__CLASS__, 'test_auth']);
     
    320321    } else {
    321322      self::notice('success','This node is already registered with Central.');
     323
     324      echo '<h3 style="margin-top:16px;color:#b32d2e;">Reset registration</h3>';
     325      echo '<p class="description">If this site was already registered on Central (or you changed domains), you can reset the local node key/secret and register again.</p>';
     326      echo '<form method="post" action="'.esc_url(admin_url('admin-post.php')).'" onsubmit="return confirm(\'Reset registration on this site? You will need to auto-register again.\');">';
     327      wp_nonce_field('zubbin_un_reset_registration');
     328      echo '<input type="hidden" name="action" value="zubbin_un_reset_registration">';
     329      submit_button('Reset Registration','delete');
     330      echo '</form>';
     331
    322332    }
    323333
     
    383393    $err = (string)($r['body']['error'] ?? 'auto_bootstrap_failed');
    384394    $msg = (string)($r['body']['message'] ?? '');
     395    $raw = isset($r['body']['raw']) ? (string)$r['body']['raw'] : '';
     396    if ($msg === '' && $raw !== '') $msg = $raw;
    385397    ZUBBIN_UN_Settings::save(['last_error' => $msg !== '' ? ($err . ': ' . $msg) : $err]);
    386398    if (class_exists('ZUBBIN_UN_Logger')) {
     
    388400    }
    389401    wp_safe_redirect(admin_url('admin.php?page=zubbin_un&tab=onboarding&err=auto_register_failed'));
     402    exit;
     403  }
     404
     405
     406  static function reset_registration() {
     407    if (!current_user_can('manage_options')) wp_die('Forbidden');
     408    check_admin_referer('zubbin_un_reset_registration');
     409
     410    // Keep Central URL & contact info, but clear all pairing/identity + cached API base and entitlement.
     411    ZUBBIN_UN_Settings::save([
     412      'node_key' => '',
     413      'node_secret' => '',
     414      'central_api_base' => '',
     415      'last_error' => '',
     416      'billing_status' => '',
     417      'block_reason' => '',
     418      'plan_key' => '',
     419      'limits' => null,
     420      'features' => null,
     421    ]);
     422
     423    if (class_exists('ZUBBIN_UN_Logger')) {
     424      ZUBBIN_UN_Logger::info('reset', 'Registration reset from admin', []);
     425    }
     426
     427    wp_safe_redirect(admin_url('admin.php?page=zubbin_un&tab=onboarding&msg=reset_done'));
    390428    exit;
    391429  }
  • zubbin-uptime-node/tags/1.4.50/includes/client.php

    r3456245 r3472274  
    66  static function post_json($url, $body=[], $headers=[], $timeout=20) {
    77    $res = wp_remote_post($url, [
    8       'timeout' => $timeout,
    9       'headers' => array_merge(['Content-Type'=>'application/json'], $headers),
    10       'body' => wp_json_encode($body),
     8      'timeout'     => $timeout,
     9      'redirection' => 5,
     10      'blocking'    => true,
     11      'headers'     => array_merge([
     12        'Content-Type' => 'application/json',
     13        'Accept'       => 'application/json',
     14      ], $headers),
     15      'body'        => wp_json_encode($body),
    1116    ]);
    1217
     
    1520    }
    1621
    17     $http = (int)wp_remote_retrieve_response_code($res);
    18     $raw  = (string)wp_remote_retrieve_body($res);
    19     $json = json_decode($raw, true);
     22    $http = (int) wp_remote_retrieve_response_code($res);
     23    $raw  = (string) wp_remote_retrieve_body($res);
    2024
    21     if (!is_array($json)) $json = ['ok'=>false,'error'=>'bad_json','raw'=>$raw];
     25    // Some hosts/security layers prepend HTML/notices before JSON.
     26    // Try to recover the JSON payload if possible.
     27    $raw_trim = trim($raw);
     28    $json = json_decode($raw_trim, true);
     29
     30    if (!is_array($json)) {
     31      $first_obj = strpos($raw_trim, '{');
     32      $last_obj  = strrpos($raw_trim, '}');
     33      $first_arr = strpos($raw_trim, '[');
     34      $last_arr  = strrpos($raw_trim, ']');
     35
     36      $cand = '';
     37      if ($first_obj !== false && $last_obj !== false && $last_obj > $first_obj) {
     38        $cand = substr($raw_trim, $first_obj, $last_obj - $first_obj + 1);
     39      } elseif ($first_arr !== false && $last_arr !== false && $last_arr > $first_arr) {
     40        $cand = substr($raw_trim, $first_arr, $last_arr - $first_arr + 1);
     41      }
     42
     43      if ($cand !== '') {
     44        $json = json_decode($cand, true);
     45      }
     46    }
     47
     48    if (!is_array($json)) {
     49      $snippet = $raw_trim;
     50      if (strlen($snippet) > 600) $snippet = substr($snippet, 0, 600).'…';
     51      $json = ['ok'=>false,'error'=>'bad_json','http'=>$http,'raw'=>$snippet];
     52    }
    2253
    2354    return ['http'=>$http,'body'=>$json];
     55  }
     56
     57
     58  static function post_json_fallback($central_url, $route, $body=[], $headers=[], $timeout=20) {
     59    $urls = ZUBBIN_UN_Settings::endpoint_urls($central_url, $route);
     60    $last = ['http'=>0,'body'=>['ok'=>false,'error'=>'no_endpoints','message'=>'No Central endpoint URLs could be built']];
     61    foreach ($urls as $u) {
     62      $res = self::post_json($u, $body, $headers, $timeout);
     63      $last = $res;
     64
     65      if ((int)($res['http'] ?? 0) !== 404) {
     66        $base = $u;
     67        $pos = strpos($base, '/wsum/v2');
     68        if ($pos !== false) $base = substr($base, 0, $pos + strlen('/wsum/v2'));
     69        ZUBBIN_UN_Settings::set_cached_api_base($base);
     70        return $res;
     71      }
     72    }
     73
     74    $attempts = $urls;
     75    $b = $last['body'];
     76    if (!is_array($b)) $b = ['ok'=>false,'error'=>'bad_json','message'=>''];
     77    if (!isset($b['attempted_urls'])) $b['attempted_urls'] = $attempts;
     78    $last['body'] = $b;
     79    return $last;
    2480  }
    2581
     
    2985
    3086  static function bootstrap($central_url, $bootstrap_token) {
    31     return self::post_json(ZUBBIN_UN_Settings::base($central_url).'/bootstrap', [
     87    return self::post_json_fallback($central_url, '/bootstrap', [
    3288      'bootstrap_token' => (string)$bootstrap_token,
    3389      'site_url' => home_url('/'),
     
    3894  // Tokenless onboarding (Central must expose /auto-bootstrap)
    3995  static function auto_bootstrap($central_url) {
    40     return self::post_json(ZUBBIN_UN_Settings::base($central_url).'/auto-bootstrap', [
     96    return self::post_json_fallback($central_url, '/auto-bootstrap', [
    4197      'site_url'  => home_url('/'),
    4298      'site_name' => get_bloginfo('name'),
     
    47103    $payload = [
    48104      'node_key' => (string)$s['node_key'],
     105      'node_secret' => (string)$s['node_secret'],
    49106      'status' => (string)$status,
    50107      'http_code' => (int)$http_code,
     
    58115    }
    59116
    60     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/heartbeat', $payload, self::hdrs($s), 25);
     117    return self::post_json_fallback($s['central_url'], '/heartbeat', $payload, self::hdrs($s), 25);
    61118  }
    62119
    63120  static function sync($s) {
    64     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/sync', [
     121    return self::post_json_fallback($s['central_url'], '/sync', [
    65122      'node_key' => (string)$s['node_key'],
     123      'node_secret' => (string)$s['node_secret'],
    66124      'notify_email' => (string)$s['notify_email'],
    67125      'contact_name' => (string)$s['contact_name'],
     
    78136
    79137  static function plans($s) {
    80     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/plans', [
     138    return self::post_json_fallback($s['central_url'], '/plans', [
    81139      'node_key' => (string)$s['node_key'],
     140      'node_secret' => (string)$s['node_secret'],
    82141    ], self::hdrs($s), 20);
    83142  }
    84143
    85144  static function checkout($s, $plan_key, $cadence) {
    86     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/checkout', [
     145    return self::post_json_fallback($s['central_url'], '/checkout', [
    87146      'node_key' => (string)$s['node_key'],
     147      'node_secret' => (string)$s['node_secret'],
    88148      'plan_key' => sanitize_key((string)$plan_key),
    89149      'cadence'  => ($cadence==='yearly') ? 'yearly' : 'monthly',
     
    92152
    93153  static function portal($s) {
    94     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/portal', [
     154    return self::post_json_fallback($s['central_url'], '/portal', [
    95155      'node_key' => (string)$s['node_key'],
     156      'node_secret' => (string)$s['node_secret'],
    96157    ], self::hdrs($s), 25);
    97158  }
     
    99160  static function test_auth($s) {
    100161    // lightweight call: sync with no changes (still validates headers/secret)
    101     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/sync', [
     162    return self::post_json_fallback($s['central_url'], '/sync', [
    102163      'node_key' => (string)$s['node_key'],
     164      'node_secret' => (string)$s['node_secret'],
    103165    ], self::hdrs($s), 20);
    104166  }
  • zubbin-uptime-node/tags/1.4.50/includes/settings.php

    r3458420 r3472274  
    9090    return [
    9191      'central_url' => defined('ZUBBIN_UN_DEFAULT_CENTRAL_URL') ? (string)ZUBBIN_UN_DEFAULT_CENTRAL_URL : '',
     92      'central_api_base' => '',
    9293      'node_key' => '',
    9394      'node_secret' => '',
     
    153154  }
    154155
     156  static function api_bases($central_url) {
     157    $u = rtrim((string)$central_url, '/');
     158    if ($u === '') return [];
     159    $c = [];
     160
     161    if (strpos($u, 'rest_route=') !== false) {
     162      $c[] = $u;
     163    } elseif (strpos($u, '/wp-json/') !== false) {
     164      if (preg_match('#/wp-json/wsum/v\d+#', $u)) {
     165        $c[] = $u;
     166      } else {
     167        $c[] = rtrim($u, '/').'/wsum/v2';
     168      }
     169    } else {
     170      $c[] = $u.'/wp-json/wsum/v2';
     171      $c[] = $u.'/index.php?rest_route=/wsum/v2';
     172      $c[] = $u.'/?rest_route=/wsum/v2';
     173    }
     174
     175    $out = [];
     176    foreach ($c as $x) {
     177      if (!in_array($x, $out, true)) $out[] = $x;
     178    }
     179    return $out;
     180  }
     181
     182  static function cached_api_base() {
     183    $s = self::get();
     184    $b = (string)($s['central_api_base'] ?? '');
     185    return $b === '' ? '' : $b;
     186  }
     187
     188  static function set_cached_api_base($base) {
     189    $base = trim((string)$base);
     190    if ($base !== '') self::save(['central_api_base' => $base]);
     191  }
     192
     193  static function endpoint_urls($central_url, $route) {
     194    $route = '/'.ltrim((string)$route, '/');
     195
     196    $bases = [];
     197    $cached = self::cached_api_base();
     198    if ($cached !== '') $bases[] = rtrim($cached, '/');
     199    foreach (self::api_bases($central_url) as $b) $bases[] = rtrim($b, '/');
     200
     201    $uniq = [];
     202    foreach ($bases as $b) {
     203      if ($b === '') continue;
     204      if (!in_array($b, $uniq, true)) $uniq[] = $b;
     205    }
     206
     207    $urls = [];
     208    foreach ($uniq as $b) {
     209      if (strpos($b, 'rest_route=') !== false) {
     210        if (preg_match('/rest_route=([^&]*)/', $b)) {
     211          $urls[] = preg_replace('/rest_route=([^&]*)/', 'rest_route='.rawurlencode('/wsum/v2'.$route), $b);
     212        } else {
     213          $glue = (strpos($b, '?') !== false) ? '&' : '?';
     214          $urls[] = $b.$glue.'rest_route='.rawurlencode('/wsum/v2'.$route);
     215        }
     216      } else {
     217        $urls[] = $b.$route;
     218      }
     219    }
     220    return $urls;
     221  }
     222
    155223  static function base($central_url) {
    156     return rtrim((string)$central_url, '/').'/wp-json/wsum/v2';
     224    $bases = self::api_bases($central_url);
     225    return isset($bases[0]) ? $bases[0] : rtrim((string)$central_url, '/').'/wp-json/wsum/v2';
    157226  }
    158227
  • zubbin-uptime-node/tags/1.4.50/readme.txt

    r3458420 r3472274  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 1.4.46
     7Stable tag: 1.4.50
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
  • zubbin-uptime-node/tags/1.4.50/zubbin-uptime-node.php

    r3458420 r3472274  
    33 * Plugin Name: Z UpTime – Uptime Monitoring Node
    44 * Description: Lightweight WordPress uptime monitoring node that reports heartbeat and health to a Central dashboard. Alerts are handled by Central.
    5  * Version: 1.4.46
     5 * Version: 1.4.50
    66 * Author: Zubbin
    77 * Text Domain: zubbin-uptime-node
     
    1313if (!defined('ABSPATH')) exit;
    1414
    15 define('ZUBBIN_UN_VERSION','1.4.46');
     15define('ZUBBIN_UN_VERSION', '1.4.48');
    1616
    1717// Default Central URL for client installs (override in wp-config.php if needed)
  • zubbin-uptime-node/trunk/includes/admin.php

    r3458420 r3472274  
    1212    add_action('admin_post_zubbin_un_bootstrap', [__CLASS__, 'bootstrap']);
    1313    add_action('admin_post_zubbin_un_auto_register', [__CLASS__, 'auto_register']);
     14    add_action('admin_post_zubbin_un_reset_registration', [__CLASS__, 'reset_registration']);
    1415    add_action('admin_post_zubbin_un_force_sync', [__CLASS__, 'force_sync']);
    1516    add_action('admin_post_zubbin_un_test_auth', [__CLASS__, 'test_auth']);
     
    320321    } else {
    321322      self::notice('success','This node is already registered with Central.');
     323
     324      echo '<h3 style="margin-top:16px;color:#b32d2e;">Reset registration</h3>';
     325      echo '<p class="description">If this site was already registered on Central (or you changed domains), you can reset the local node key/secret and register again.</p>';
     326      echo '<form method="post" action="'.esc_url(admin_url('admin-post.php')).'" onsubmit="return confirm(\'Reset registration on this site? You will need to auto-register again.\');">';
     327      wp_nonce_field('zubbin_un_reset_registration');
     328      echo '<input type="hidden" name="action" value="zubbin_un_reset_registration">';
     329      submit_button('Reset Registration','delete');
     330      echo '</form>';
     331
    322332    }
    323333
     
    383393    $err = (string)($r['body']['error'] ?? 'auto_bootstrap_failed');
    384394    $msg = (string)($r['body']['message'] ?? '');
     395    $raw = isset($r['body']['raw']) ? (string)$r['body']['raw'] : '';
     396    if ($msg === '' && $raw !== '') $msg = $raw;
    385397    ZUBBIN_UN_Settings::save(['last_error' => $msg !== '' ? ($err . ': ' . $msg) : $err]);
    386398    if (class_exists('ZUBBIN_UN_Logger')) {
     
    388400    }
    389401    wp_safe_redirect(admin_url('admin.php?page=zubbin_un&tab=onboarding&err=auto_register_failed'));
     402    exit;
     403  }
     404
     405
     406  static function reset_registration() {
     407    if (!current_user_can('manage_options')) wp_die('Forbidden');
     408    check_admin_referer('zubbin_un_reset_registration');
     409
     410    // Keep Central URL & contact info, but clear all pairing/identity + cached API base and entitlement.
     411    ZUBBIN_UN_Settings::save([
     412      'node_key' => '',
     413      'node_secret' => '',
     414      'central_api_base' => '',
     415      'last_error' => '',
     416      'billing_status' => '',
     417      'block_reason' => '',
     418      'plan_key' => '',
     419      'limits' => null,
     420      'features' => null,
     421    ]);
     422
     423    if (class_exists('ZUBBIN_UN_Logger')) {
     424      ZUBBIN_UN_Logger::info('reset', 'Registration reset from admin', []);
     425    }
     426
     427    wp_safe_redirect(admin_url('admin.php?page=zubbin_un&tab=onboarding&msg=reset_done'));
    390428    exit;
    391429  }
  • zubbin-uptime-node/trunk/includes/client.php

    r3456245 r3472274  
    66  static function post_json($url, $body=[], $headers=[], $timeout=20) {
    77    $res = wp_remote_post($url, [
    8       'timeout' => $timeout,
    9       'headers' => array_merge(['Content-Type'=>'application/json'], $headers),
    10       'body' => wp_json_encode($body),
     8      'timeout'     => $timeout,
     9      'redirection' => 5,
     10      'blocking'    => true,
     11      'headers'     => array_merge([
     12        'Content-Type' => 'application/json',
     13        'Accept'       => 'application/json',
     14      ], $headers),
     15      'body'        => wp_json_encode($body),
    1116    ]);
    1217
     
    1520    }
    1621
    17     $http = (int)wp_remote_retrieve_response_code($res);
    18     $raw  = (string)wp_remote_retrieve_body($res);
    19     $json = json_decode($raw, true);
     22    $http = (int) wp_remote_retrieve_response_code($res);
     23    $raw  = (string) wp_remote_retrieve_body($res);
    2024
    21     if (!is_array($json)) $json = ['ok'=>false,'error'=>'bad_json','raw'=>$raw];
     25    // Some hosts/security layers prepend HTML/notices before JSON.
     26    // Try to recover the JSON payload if possible.
     27    $raw_trim = trim($raw);
     28    $json = json_decode($raw_trim, true);
     29
     30    if (!is_array($json)) {
     31      $first_obj = strpos($raw_trim, '{');
     32      $last_obj  = strrpos($raw_trim, '}');
     33      $first_arr = strpos($raw_trim, '[');
     34      $last_arr  = strrpos($raw_trim, ']');
     35
     36      $cand = '';
     37      if ($first_obj !== false && $last_obj !== false && $last_obj > $first_obj) {
     38        $cand = substr($raw_trim, $first_obj, $last_obj - $first_obj + 1);
     39      } elseif ($first_arr !== false && $last_arr !== false && $last_arr > $first_arr) {
     40        $cand = substr($raw_trim, $first_arr, $last_arr - $first_arr + 1);
     41      }
     42
     43      if ($cand !== '') {
     44        $json = json_decode($cand, true);
     45      }
     46    }
     47
     48    if (!is_array($json)) {
     49      $snippet = $raw_trim;
     50      if (strlen($snippet) > 600) $snippet = substr($snippet, 0, 600).'…';
     51      $json = ['ok'=>false,'error'=>'bad_json','http'=>$http,'raw'=>$snippet];
     52    }
    2253
    2354    return ['http'=>$http,'body'=>$json];
     55  }
     56
     57
     58  static function post_json_fallback($central_url, $route, $body=[], $headers=[], $timeout=20) {
     59    $urls = ZUBBIN_UN_Settings::endpoint_urls($central_url, $route);
     60    $last = ['http'=>0,'body'=>['ok'=>false,'error'=>'no_endpoints','message'=>'No Central endpoint URLs could be built']];
     61    foreach ($urls as $u) {
     62      $res = self::post_json($u, $body, $headers, $timeout);
     63      $last = $res;
     64
     65      if ((int)($res['http'] ?? 0) !== 404) {
     66        $base = $u;
     67        $pos = strpos($base, '/wsum/v2');
     68        if ($pos !== false) $base = substr($base, 0, $pos + strlen('/wsum/v2'));
     69        ZUBBIN_UN_Settings::set_cached_api_base($base);
     70        return $res;
     71      }
     72    }
     73
     74    $attempts = $urls;
     75    $b = $last['body'];
     76    if (!is_array($b)) $b = ['ok'=>false,'error'=>'bad_json','message'=>''];
     77    if (!isset($b['attempted_urls'])) $b['attempted_urls'] = $attempts;
     78    $last['body'] = $b;
     79    return $last;
    2480  }
    2581
     
    2985
    3086  static function bootstrap($central_url, $bootstrap_token) {
    31     return self::post_json(ZUBBIN_UN_Settings::base($central_url).'/bootstrap', [
     87    return self::post_json_fallback($central_url, '/bootstrap', [
    3288      'bootstrap_token' => (string)$bootstrap_token,
    3389      'site_url' => home_url('/'),
     
    3894  // Tokenless onboarding (Central must expose /auto-bootstrap)
    3995  static function auto_bootstrap($central_url) {
    40     return self::post_json(ZUBBIN_UN_Settings::base($central_url).'/auto-bootstrap', [
     96    return self::post_json_fallback($central_url, '/auto-bootstrap', [
    4197      'site_url'  => home_url('/'),
    4298      'site_name' => get_bloginfo('name'),
     
    47103    $payload = [
    48104      'node_key' => (string)$s['node_key'],
     105      'node_secret' => (string)$s['node_secret'],
    49106      'status' => (string)$status,
    50107      'http_code' => (int)$http_code,
     
    58115    }
    59116
    60     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/heartbeat', $payload, self::hdrs($s), 25);
     117    return self::post_json_fallback($s['central_url'], '/heartbeat', $payload, self::hdrs($s), 25);
    61118  }
    62119
    63120  static function sync($s) {
    64     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/sync', [
     121    return self::post_json_fallback($s['central_url'], '/sync', [
    65122      'node_key' => (string)$s['node_key'],
     123      'node_secret' => (string)$s['node_secret'],
    66124      'notify_email' => (string)$s['notify_email'],
    67125      'contact_name' => (string)$s['contact_name'],
     
    78136
    79137  static function plans($s) {
    80     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/plans', [
     138    return self::post_json_fallback($s['central_url'], '/plans', [
    81139      'node_key' => (string)$s['node_key'],
     140      'node_secret' => (string)$s['node_secret'],
    82141    ], self::hdrs($s), 20);
    83142  }
    84143
    85144  static function checkout($s, $plan_key, $cadence) {
    86     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/checkout', [
     145    return self::post_json_fallback($s['central_url'], '/checkout', [
    87146      'node_key' => (string)$s['node_key'],
     147      'node_secret' => (string)$s['node_secret'],
    88148      'plan_key' => sanitize_key((string)$plan_key),
    89149      'cadence'  => ($cadence==='yearly') ? 'yearly' : 'monthly',
     
    92152
    93153  static function portal($s) {
    94     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/portal', [
     154    return self::post_json_fallback($s['central_url'], '/portal', [
    95155      'node_key' => (string)$s['node_key'],
     156      'node_secret' => (string)$s['node_secret'],
    96157    ], self::hdrs($s), 25);
    97158  }
     
    99160  static function test_auth($s) {
    100161    // lightweight call: sync with no changes (still validates headers/secret)
    101     return self::post_json(ZUBBIN_UN_Settings::base($s['central_url']).'/sync', [
     162    return self::post_json_fallback($s['central_url'], '/sync', [
    102163      'node_key' => (string)$s['node_key'],
     164      'node_secret' => (string)$s['node_secret'],
    103165    ], self::hdrs($s), 20);
    104166  }
  • zubbin-uptime-node/trunk/includes/settings.php

    r3458420 r3472274  
    9090    return [
    9191      'central_url' => defined('ZUBBIN_UN_DEFAULT_CENTRAL_URL') ? (string)ZUBBIN_UN_DEFAULT_CENTRAL_URL : '',
     92      'central_api_base' => '',
    9293      'node_key' => '',
    9394      'node_secret' => '',
     
    153154  }
    154155
     156  static function api_bases($central_url) {
     157    $u = rtrim((string)$central_url, '/');
     158    if ($u === '') return [];
     159    $c = [];
     160
     161    if (strpos($u, 'rest_route=') !== false) {
     162      $c[] = $u;
     163    } elseif (strpos($u, '/wp-json/') !== false) {
     164      if (preg_match('#/wp-json/wsum/v\d+#', $u)) {
     165        $c[] = $u;
     166      } else {
     167        $c[] = rtrim($u, '/').'/wsum/v2';
     168      }
     169    } else {
     170      $c[] = $u.'/wp-json/wsum/v2';
     171      $c[] = $u.'/index.php?rest_route=/wsum/v2';
     172      $c[] = $u.'/?rest_route=/wsum/v2';
     173    }
     174
     175    $out = [];
     176    foreach ($c as $x) {
     177      if (!in_array($x, $out, true)) $out[] = $x;
     178    }
     179    return $out;
     180  }
     181
     182  static function cached_api_base() {
     183    $s = self::get();
     184    $b = (string)($s['central_api_base'] ?? '');
     185    return $b === '' ? '' : $b;
     186  }
     187
     188  static function set_cached_api_base($base) {
     189    $base = trim((string)$base);
     190    if ($base !== '') self::save(['central_api_base' => $base]);
     191  }
     192
     193  static function endpoint_urls($central_url, $route) {
     194    $route = '/'.ltrim((string)$route, '/');
     195
     196    $bases = [];
     197    $cached = self::cached_api_base();
     198    if ($cached !== '') $bases[] = rtrim($cached, '/');
     199    foreach (self::api_bases($central_url) as $b) $bases[] = rtrim($b, '/');
     200
     201    $uniq = [];
     202    foreach ($bases as $b) {
     203      if ($b === '') continue;
     204      if (!in_array($b, $uniq, true)) $uniq[] = $b;
     205    }
     206
     207    $urls = [];
     208    foreach ($uniq as $b) {
     209      if (strpos($b, 'rest_route=') !== false) {
     210        if (preg_match('/rest_route=([^&]*)/', $b)) {
     211          $urls[] = preg_replace('/rest_route=([^&]*)/', 'rest_route='.rawurlencode('/wsum/v2'.$route), $b);
     212        } else {
     213          $glue = (strpos($b, '?') !== false) ? '&' : '?';
     214          $urls[] = $b.$glue.'rest_route='.rawurlencode('/wsum/v2'.$route);
     215        }
     216      } else {
     217        $urls[] = $b.$route;
     218      }
     219    }
     220    return $urls;
     221  }
     222
    155223  static function base($central_url) {
    156     return rtrim((string)$central_url, '/').'/wp-json/wsum/v2';
     224    $bases = self::api_bases($central_url);
     225    return isset($bases[0]) ? $bases[0] : rtrim((string)$central_url, '/').'/wp-json/wsum/v2';
    157226  }
    158227
  • zubbin-uptime-node/trunk/readme.txt

    r3458420 r3472274  
    55Tested up to: 6.9
    66Requires PHP: 7.4
    7 Stable tag: 1.4.46
     7Stable tag: 1.4.50
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
  • zubbin-uptime-node/trunk/zubbin-uptime-node.php

    r3458420 r3472274  
    33 * Plugin Name: Z UpTime – Uptime Monitoring Node
    44 * Description: Lightweight WordPress uptime monitoring node that reports heartbeat and health to a Central dashboard. Alerts are handled by Central.
    5  * Version: 1.4.46
     5 * Version: 1.4.50
    66 * Author: Zubbin
    77 * Text Domain: zubbin-uptime-node
     
    1313if (!defined('ABSPATH')) exit;
    1414
    15 define('ZUBBIN_UN_VERSION','1.4.46');
     15define('ZUBBIN_UN_VERSION', '1.4.48');
    1616
    1717// Default Central URL for client installs (override in wp-config.php if needed)
Note: See TracChangeset for help on using the changeset viewer.