s2maps-gpu
Version:
S2 Maps GPU - An open source, high-performance, and GPU-accelerated map engine for rendering large-scale, interactive maps.
132 lines (131 loc) • 4.69 kB
JavaScript
import { adjustURL } from 'util/index.js';
/**
* Session Manager
*
* Keep up to date with API keys and session tokens
*/
export default class Session {
analytics;
sessionKeys = {}; // [mapID]: session
workers = [];
currWorker = 0;
totalWorkers = 0;
sessionPromise;
/**
* Load a style via a URL, sending off analytics and utilizing the apiKey if needed
* @param mapID - the id of the map
* @param analytics - basic analytics about the GPU and screen dimensions
* @param apiKey - the api key if needed
*/
loadStyle(mapID, analytics, apiKey) {
this.analytics = analytics;
this.sessionKeys[mapID] = { apiKey };
}
/**
* Load a worker
* @param _messagePort - unused
* @param postPort - the port for a worker to send session messages to
* @param id - the id of the worker
*/
loadWorker(_messagePort, postPort, id) {
this.totalWorkers++;
this.workers[id] = postPort;
}
/**
* Request a worker to process data
* @returns the port for the worker
*/
requestWorker() {
const worker = this.workers[this.currWorker];
this.currWorker++;
if (this.currWorker >= this.totalWorkers)
this.currWorker = 0;
return worker;
}
/**
* Check if the map has an API key
* @param mapID - the id of the map
* @returns true if the map has an API key
*/
hasAPIKey(mapID) {
return this.sessionKeys[mapID]?.apiKey !== undefined;
}
/**
* Request a style from the server
* @param mapID - the id of the map
* @param style - the style url
* @param urlMap - the url map to properly modify and resolve urls
*/
async requestStyle(mapID, style, urlMap) {
// grab the auth token
const Authorization = await this.requestSessionToken(mapID);
if (Authorization === undefined)
return;
// fetch the style
const json = await fetch(adjustURL(style, urlMap), { headers: { Authorization } })
.then(async (res) => {
if (res.status !== 200)
return null;
return await res.json();
})
.catch((err) => {
console.error(err);
return null;
});
// send style back to map
if (json !== null)
postMessage({ type: 'setStyle', mapID, style: json, ignorePosition: false });
}
/**
* Request a session token from the server to start fetching data
* @param mapID - the id of the map
* @returns the session token if available and/or successful
*/
async requestSessionToken(mapID) {
const failed = 'failed';
const mapSessionKey = this.sessionKeys[mapID];
// if there is no apiKey, then the map doesn't requre a session token
if (mapSessionKey === undefined)
return undefined;
// check if the token is already fresh
const { apiKey, token, exp } = mapSessionKey;
if (apiKey === undefined)
return failed;
if (exp !== undefined && token !== undefined && exp - new Date().getTime() > 0)
return token;
const { gpu, context, language, width, height } = this.analytics ?? {};
// grab a new token
if (this.sessionPromise === undefined) {
// TODO: use urlMap to adjust the URL
this.sessionPromise = fetch(adjustURL('apiURL://session'), {
method: 'POST',
body: JSON.stringify({ apiKey, gpu, context, language, width, height }),
headers: { 'Content-Type': 'application/json' },
})
.then(async (res) => {
if (res.status !== 200 && res.status !== 206)
return undefined;
return await res.json();
})
.then((t) => {
if (t === undefined)
return undefined;
const expDate = new Date();
expDate.setSeconds(expDate.getSeconds() + t.maxAge);
return { token: t.token, exp: expDate.getTime() };
})
.catch((err) => {
console.error(err);
return undefined;
});
}
const sessionKey = await this.sessionPromise;
this.sessionPromise = undefined;
// store the new key, exp, and return the key to use
if (sessionKey === undefined)
return failed;
mapSessionKey.token = sessionKey.token;
mapSessionKey.exp = sessionKey.exp;
return mapSessionKey.token ?? failed;
}
}