欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iD学习 - 心跳

程序员文章站 2022-05-03 19:19:25
...

心跳

心跳顾名思义,就是以固定的频率向其他节点汇报当前节点状态的方式。收到心跳,一般可以认为一个节点和现在的网络拓扑是良好的。当然,心跳汇报时,一般也会携带一些附加的状态、元数据信息,以便管理。

代码说明

iD调用后台接口代码在/modules/services/osm.js里。获取后台状态方法如下:

// Fetch the status of the OSM API
// GET /api/capabilities
status: function(callback) {
    var url = urlroot + '/api/capabilities';
    var errback = wrapcb(this, done, _connectionID);
    d3_xml(url)
        .then(function(data) { 
            errback(null, data); 
         })
        .catch(function(err) { 
            errback(err.message); 
        });

    function done(err, xml) {
        if (err) {
            // the status is null if no response could be retrieved
            return callback(err, null);
        }

        // update blacklists
        var elements = xml.getElementsByTagName('blacklist');
        var regexes = [];
        for (var i = 0; i < elements.length; i++) {
            var regex = elements[i].getAttribute('regex');  // needs unencode?
            if (regex) {
                regexes.push(regex);
            }
        }
        if (regexes.length) {
            _blacklists = regexes;
        }

        if (_rateLimitError) {
            return callback(_rateLimitError, 'rateLimited');
        } else {
            var apiStatus = xml.getElementsByTagName('status');
            var val = apiStatus[0].getAttribute('api');
            return callback(undefined, val);
        }
    }
}

iD通过OSM的/api/capabilities接口获取服务器状态。如获取不到则显示如下:
iD学习 - 心跳
OSM API共有4种异常状态,显示信息1如下:

"osm_api_status": {
    "message": {
        "error": "无法连接到 OpenStreetMap API。你的编辑在本地是安全的。请检查你的网络连接。",
        "offline": "OpenStreetMap API 当前离线。你的编辑在本地是安全的。请稍后再来。",
        "readonly": "OpenStreetMap API 当前为只读状态。你可以继续编辑,但需要等待一段时间才能保存。",
        "rateLimit": "OpenStreetMap API 限制了匿名连接。你可以通过登录来解决此问题。"
    },
    "retry": "重试"
}

用于显示修改状态显示的代码在/modules/ui/status.js

import _throttle from 'lodash-es/throttle';
import { event as d3_event } from 'd3-selection';

import { t } from '../util/locale';
import { svgIcon } from '../svg/icon';


export function uiStatus(context) {
    var osm = context.connection();


    return function(selection) {
        if (!osm) return;

        function update(err, apiStatus) {
            selection.html('');

            if (err) {
                if (apiStatus === 'connectionSwitched') {
                    // if the connection was just switched, we can't rely on
                    // the status (we're getting the status of the previous api)
                    return;

                } else if (apiStatus === 'rateLimited') {
                    selection
                        .text(t('osm_api_status.message.rateLimit'))
                        .append('a')
                        .attr('class', 'api-status-login')
                        .attr('target', '_blank')
                        .call(svgIcon('#iD-icon-out-link', 'inline'))
                        .append('span')
                        .text(t('login'))
                        .on('click.login', function() {
                            d3_event.preventDefault();
                            osm.authenticate();
                        });
                } else {

                    // don't allow retrying too rapidly
                    var throttledRetry = _throttle(function() {
                        // try loading the visible tiles
                        context.loadTiles(context.projection);
                        // manually reload the status too in case all visible tiles were already loaded
                        osm.reloadApiStatus();
                    }, 2000);

                    // eslint-disable-next-line no-warning-comments
                    // TODO: nice messages for different error types
                    selection
                        .text(t('osm_api_status.message.error') + ' ')
                        .append('a')
                        // let the user manually retry their connection directly
                        .text(t('osm_api_status.retry'))
                        .on('click.retry', function() {
                            d3_event.preventDefault();
                            throttledRetry();
                        });
                }

            } else if (apiStatus === 'readonly') {
                selection.text(t('osm_api_status.message.readonly'));
            } else if (apiStatus === 'offline') {
                selection.text(t('osm_api_status.message.offline'));
            }

            selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
        }

        osm.on('apiStatusChange.uiStatus', update);

        // reload the status periodically regardless of other factors
        window.setInterval(function() {
            osm.reloadApiStatus();
        }, 90000);

        // load the initial status in case no OSM data was loaded yet
        osm.reloadApiStatus();
    };
}

系统每隔90秒获取一次状态。

接口返回值

OSM API 返回值如下:

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="OpenStreetMap server" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
  <api>
    <version minimum="0.6" maximum="0.6"/>
    <area maximum="0.25"/>
    <note_area maximum="25"/>
    <tracepoints per_page="5000"/>
    <waynodes maximum="2000"/>
    <changesets maximum_elements="10000"/>
    <timeout seconds="300"/>
    <status database="online" api="online" gpx="online"/>
  </api>
  <policy>
    <imagery>
      <blacklist regex=".*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*"/>
      <blacklist regex="http://xdworld\.vworld\.kr:8080/.*"/>
      <blacklist regex=".*\.here\.com[/:].*"/>
    </imagery>
  </policy>
</osm>

其中status为api状态,正常值为online,代码中获取的是apiStatus[0].getAttribute(‘api’)的值,因此判断的是status中api的值,其他属性还不清楚使用的方法。

黑名单

接口返回值中的黑名单,用于限制背景影响显示,凡是符合黑名单正则表达式的链接都不会加载。在/modules/svg/data.js和/modules/renderer/background.js里都有使用。

// test source against OSM imagery blacklists..
var osm = context.connection();
if (osm) {
    var blacklists = osm.imageryBlacklists();
    var fail = false;
    var tested = 0;
    var regex;

    for (var i = 0; i < blacklists.length; i++) {
        try {
            regex = new RegExp(blacklists[i]);
            fail = regex.test(val);
            tested++;
            if (fail) break;
        } catch (e) {
            /* noop */
        }
    }

    // ensure at least one test was run.
    if (!tested) {
        regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
        fail = regex.test(val);
    }
}

  1. iD支持多语言,字典放在/dist/locales目录下,简体中文为zh-CN.json文件。 ↩︎

相关标签: iD学习