loadTracksFromJson.js (3611B)
1 import utf8 from 'utf8'; 2 3 import * as urlSafeBase64 from '../../parsers/urlSafeBase64'; 4 import {TRACKLIST_TRACK_COLORS} from '../../../track-list'; 5 import loadFromUrl from '../../loadFromUrl'; 6 7 function parseWaypoint(rawPoint) { 8 let name = rawPoint.n; 9 let lat = Number(rawPoint.lt); 10 let lng = Number(rawPoint.ln); 11 if (typeof name !== 'string' || !name || isNaN(lat) || isNaN(lng) || 12 lat < -90 || lat > 90 || lng < -180 || lng > 180) { 13 return {valid: false}; 14 } 15 return { 16 valid: true, 17 point: {lat, lng, name} 18 }; 19 } 20 21 function parseTrack(rawTrack) { 22 if (!rawTrack.length) { 23 return {valid: false}; 24 } 25 const track = []; 26 for (let rawSegment of rawTrack) { 27 let segment = []; 28 if (!rawSegment || !rawSegment.length) { 29 return {valid: false}; 30 } 31 for (let rawPoint of rawSegment) { 32 if (!rawPoint || rawPoint.length !== 2) { 33 return {valid: false}; 34 } 35 let [lat, lng] = rawPoint.map(Number); 36 if (isNaN(lat) || isNaN(lng) || lat < -90 || lat > 90) { 37 return {valid: false}; 38 } 39 segment.push({lat, lng}); 40 } 41 track.push(segment); 42 } 43 return {valid: true, track}; 44 } 45 46 async function loadTracksFromJson(value) { // eslint-disable-line complexity 47 const errCorrupt = [{name: 'Track in url', error: 'CORRUPT'}]; 48 let jsonString = urlSafeBase64.decode(value); 49 try { 50 jsonString = utf8.decode(jsonString); 51 } catch (e) { 52 // so it was not encoded in utf-8, leave it as it is 53 } 54 let data; 55 try { 56 data = JSON.parse(jsonString); 57 } catch (e) { 58 return errCorrupt; 59 } 60 if (!data || !data.length) { 61 return errCorrupt; 62 } 63 const geoDataArray = []; 64 65 for (let el of data) { 66 // Each track should contain either url or at least one of tracks and points 67 if (!el.u && !(el.p || el.t)) { 68 return errCorrupt; 69 } 70 let geodata; 71 if (el.u) { 72 geodata = await 73 loadFromUrl(el.u); 74 if (el.n && geodata.length === 1 && !geodata[0].error) { 75 geodata[0].name = el.n; 76 } 77 } else { 78 geodata = {}; 79 geodata.name = el.n || 'Track'; 80 if (el.t) { 81 const res = parseTrack(el.t); 82 if (!res.valid) { 83 return errCorrupt; 84 } 85 geodata.tracks = res.track; 86 } 87 if (el.p) { 88 geodata.points = []; 89 for (let rawPoint of el.p) { 90 let res = parseWaypoint(rawPoint); 91 // eslint-disable-next-line max-depth 92 if (!res.valid) { 93 return errCorrupt; 94 } 95 geodata.points.push(res.point); 96 } 97 } 98 geodata = [geodata]; 99 } 100 let viewProps = {}; 101 if ('c' in el) { 102 let color = Number(el.c); 103 if (color < 0 || color >= TRACKLIST_TRACK_COLORS.length) { 104 return errCorrupt; 105 } 106 viewProps.color = color; 107 } 108 if ('v' in el) { 109 viewProps.trackHidden = !el.v; 110 } 111 if ('m' in el) { 112 viewProps.measureTicksShown = Boolean(el.m); 113 } 114 geodata.forEach((el) => Object.assign(el, viewProps)); 115 geoDataArray.push(...geodata); 116 } 117 return geoDataArray; 118 } 119 120 export default loadTracksFromJson;