跳到主要内容

HTTP 实时接收器

共同轮询、暂停恢复、失效响应与地图持有

SQSAPI-11.4c1 为已配置 sqsLive 的 GeoJSON 图源接通共同 HTTP 轮询。先用 MapLibre 风格的 addSource/getSource,再使用 source.sqs.connectLive 扩展。数据格式见实时协议,手动批次与独立快照见实时图源。WebSocket 与重连 已另行接通;场景所有权及移动宿主仍由后续阶段接入。

import {map} from 'sqsmap';
map.addSource('positions',{type:'geojson',data:{type:'FeatureCollection',features:[]},sqsLive:{fields:{n:'number'},allowDelta:true}});
await map.sqs.flush();
const source=await map.getSource('positions');
const receiver=await source.sqs.connectLive({protocol:'gis-live-v1',transport:{type:'http-poll',url:'https://your-server.example/live',intervalMs:2000}});
const state=await receiver.getState();
await receiver.pause();
await receiver.resume();
const frozen=await source.sqs.freezeLiveSnapshot();
await receiver.stop();

以上地址是占位,须替换为提供 gis-live-v1 原始 JSON 批次的服务。每次响应是一个 snapshot 或 delta;浏览器服务须允许页面来源的 CORS。独立 SDK 用相同的 source.sqs 调用与 map.flush();共同脚本用 map.sqs.flush()。创建成功只确认接收器注册及请求排队,不代表首份数据已到达;监听 sourcedata/error 确认结果。禁止将十进制 u128 消息序列转成 JS number。

connectLive 返回 {id,sourceInstanceId,receiverInstanceId,getState,pause,resume,stop} 句柄;getLiveReceiver() 返回当前句柄,不存在返回 undefined。getState() 返回独立的小快照:{source:{id,sourceInstanceId},receiverInstanceId,transport:'http-poll',status:'running'|'paused'|'stopped',loading,intervalMs,lastError,dataRevision}。pause/resume/stop 返回 Promise,重复暂停或停止可安全确认。停止后的接收器不能恢复(CONFLICT),用 connectLive 创建新身份。删除重建图源或重新连接后,旧句柄返回 STALE_HANDLE。

协议默认 gis-live-v1,transport.type 当前只支持 http-poll;未知字段、协议或传输返回 INVALID_ARGUMENT。URL 必须为无内嵌用户名密码的绝对 HTTP/HTTPS,最多4096字节。intervalMs 默认2000,范围500..60000毫秒,从上一响应完成后计算,同源请求不重叠。请求采用 no-store;浏览器仍允许共同请求转换钩子进行授权,事件和错误不回显 URL/令牌/响应数据。每源一个活动或暂停接收器,每图最多8个,和普通源请求共用8个下载槽。接收器选项、错误与协议历史计入图源驻留预算。单响应8MiB、4096点/32字段等限制仍适用。

暂停取消在途请求并保留数据及协议,恢复立即请求;停止取消请求、释放活动配额并保留最后数据。活动或暂停期间手动 applyLiveUpdate 返回 CONFLICT,避免多个写入者。接收器属于地图/图源,一次性脚本结束、退出或关闭脚本运行器不会停止它;用 stop、removeSource 或销毁地图结束持有,删除图源前需移除依赖图层。此处不等同于后续 scene 所有权。

网络、字段、连续性、聚合或显示错误保留最后数据/协议并记录 lastError,然后按同间隔重试。连续性错误需服务端重新提供完整快照,接收器不会编造丢失的 delta。重复帧不增加 dataRevision/protocolRevision、不重建聚合身份,但 HTTP 完成仍发 sourcedata,因此不要把每次完成都计为数据变化。暂停/停止发 sourcedataabort,连接/恢复/下一轮发 sourcedataloading,成功发 sourcedata,失败发 error;历史事件包含可选 sqsLiveReceiver 和 sqsLive,嵌套状态不可变且不含 URL。旧 generation 响应或销毁后回调不写入地图。

浏览器能力 map.capabilities.liveHttpPolling;动态库标志 SQSM_MAP_LIVE_HTTP(268435456)。C ABI v1 不新增函数:source JSON 方法为 sqs.connectLive/getLiveReceiver/liveState/pauseLive/resumeLive/stopLive。前两项用 SourceIdentity,连接另带 options;状态/控制用 {id,sourceInstanceId,receiverInstanceId}。C 连接/查询返回状态 DTO 或 null;控制返回 {changed,state}。宿主持久调用资源请求入口和事件泵,并按 state.resources.repaintAfterMs 唤醒;资源元数据 format:'gis-live-v1',cache:'no-store' 使用同一资源响应通道,取消按 generation 执行。核心无 HTTP 库或后台网络线程,C 宿主负责超时、8MiB流式预算、并发、取消、缓存和回到地图创建线程提交。

用户自行编写图层及按钮 UI。以下完整代码包含 HTML/CSS、五个按钮、署名、事件和 pagehide 销毁。输入你自己的可达 endpoint,复制与匹配 SDK目录一起通过 HTTP 提供。下载完整 HTML和验收共同脚本;验收脚本使用回环服务3131,复现需启动仓库工具目录的 fixture.mjs,不是公共在线数据服务。

<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>SqsMap live HTTP</title>
<style>body{margin:0;font:16px system-ui}#map{height:70vh}form{display:flex;flex-wrap:wrap;gap:.5rem;padding:1rem}input{flex:1;min-width:16rem}button,input{font:inherit;padding:.4rem}pre,footer{padding:0 1rem;white-space:pre-wrap}</style>
<div id="map"></div><form id="tools"><input id="url" type="url" required placeholder="Your gis-live-v1 HTTP endpoint"><button id="connect">Connect</button><button type="button" id="pause">Pause</button><button type="button" id="resume">Resume</button><button type="button" id="stop">Stop</button><button type="button" id="freeze">Freeze snapshot</button></form><pre id="status">Enter your HTTP endpoint.</pre><footer id="credits"></footer>
<script type="module">
import {MapView} from './dist/index.js';
const status=document.querySelector('#status');let map,source,receiver;const offs=[];
async function act(fn){try{await fn();}catch(error){status.textContent=String(error);}}
try{
 map=await MapView.create(document.querySelector('#map'),{worker:false});if(!map.capabilities.liveHttpPolling)throw Error('Matched live HTTP SDK/WASM required');
 map.jumpTo({center:[0,0],zoom:12});map.addSource('positions',{type:'geojson',data:{type:'FeatureCollection',features:[]},sqsLive:{fields:{n:'number'},allowDelta:true},attribution:'Live positions supplied by the endpoint owner'});map.addLayer({id:'positions',type:'circle',source:'positions',paint:{'circle-radius':8,'circle-color':'#ff0000'}});await map.flush();source=await map.getSource('positions');
 for(const type of ['sourcedataloading','sourcedata','sourcedataabort','error'])offs.push(map.on(type,event=>{if(event.sourceId==='positions')status.textContent=JSON.stringify({type,protocol:event.sqsLive,receiver:event.sqsLiveReceiver},null,2);}));
 offs.push(map.on('sqs.attributionschange',event=>{document.querySelector('#credits').textContent=event.attributions.text;}));document.querySelector('#credits').textContent=(await map.getAttributions()).text;
 document.querySelector('#tools').onsubmit=event=>{event.preventDefault();act(async()=>{if(receiver&&(await receiver.getState()).status!=='stopped')await receiver.stop();receiver=await source.sqs.connectLive({transport:{type:'http-poll',url:document.querySelector('#url').value,intervalMs:1000}});});};
 document.querySelector('#pause').onclick=()=>act(async()=>{if(!receiver)throw Error('Connect first.');await receiver.pause();});
 document.querySelector('#resume').onclick=()=>act(async()=>{if(!receiver)throw Error('Connect first.');await receiver.resume();});
 document.querySelector('#stop').onclick=()=>act(async()=>{if(!receiver)throw Error('Connect first.');await receiver.stop();});
 document.querySelector('#freeze').onclick=()=>act(async()=>{status.textContent=JSON.stringify(await source.sqs.freezeLiveSnapshot(),null,2);});
 window.addEventListener('pagehide',()=>{offs.forEach(off=>off());map.destroy();},{once:true});
}catch(error){status.textContent=String(error);offs.forEach(off=>off());map?.destroy();}
</script></html>

本机同一共同脚本在持续原生 QuickJS+C资源泵、实际桌面 ScriptService+HTTP下载器、浏览器主线程与严格 Worker 验收;详细结果及限制见 tools/live-http-contract。Linux 原生软件 Vulkan、浏览器 Gl;Windows/macOS由用户另机验证,移动设备、硬件 WebGPU、正式发行与远端部署仍待验收。

共同场景与接收器归属 提供草稿、启动、暂停、恢复、停止和历史事件;静态场景资源、播放、轨迹与移动验收仍分别推进。

场景静态资源与图层显隐提供同源多层的草稿隐藏、状态控制、查询/署名和完整HTML。