diff --git a/.eslintignore b/.eslintignore index 527f9e0dde..faeb86ddaa 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1102,6 +1102,9 @@ packages/lib/fs-driver-node.js.map packages/lib/fsDriver.test.d.ts packages/lib/fsDriver.test.js packages/lib/fsDriver.test.js.map +packages/lib/geolocation-node.d.ts +packages/lib/geolocation-node.js +packages/lib/geolocation-node.js.map packages/lib/hooks/useAsyncEffect.d.ts packages/lib/hooks/useAsyncEffect.js packages/lib/hooks/useAsyncEffect.js.map diff --git a/.gitignore b/.gitignore index d2b877d8d3..89370612af 100644 --- a/.gitignore +++ b/.gitignore @@ -1092,6 +1092,9 @@ packages/lib/fs-driver-node.js.map packages/lib/fsDriver.test.d.ts packages/lib/fsDriver.test.js packages/lib/fsDriver.test.js.map +packages/lib/geolocation-node.d.ts +packages/lib/geolocation-node.js +packages/lib/geolocation-node.js.map packages/lib/hooks/useAsyncEffect.d.ts packages/lib/hooks/useAsyncEffect.js packages/lib/hooks/useAsyncEffect.js.map diff --git a/packages/lib/geolocation-node.js b/packages/lib/geolocation-node.js deleted file mode 100644 index 7ece9e3635..0000000000 --- a/packages/lib/geolocation-node.js +++ /dev/null @@ -1,25 +0,0 @@ -const shim = require('./shim').default; - -class GeolocationNode { - static async currentPosition(options = null) { - if (!options) options = {}; - - let response = await shim.fetch('https://freegeoip.app/json/'); - if (!response.ok) throw new Error(`Could not get geolocation: ${await response.text()}`); - - response = await response.json(); - - if (!('latitude' in response) || !('longitude' in response)) throw new Error(`Invalid geolocation response: ${response ? JSON.stringify(response) : ''}`); - - return { - timestamp: new Date().getTime(), - coords: { - longitude: response.longitude, - altitude: 0, - latitude: response.latitude, - }, - }; - } -} - -module.exports = { GeolocationNode }; diff --git a/packages/lib/geolocation-node.ts b/packages/lib/geolocation-node.ts new file mode 100644 index 0000000000..614da8cc29 --- /dev/null +++ b/packages/lib/geolocation-node.ts @@ -0,0 +1,76 @@ +import Logger from './Logger'; +import shim from './shim'; + +const logger = Logger.create('geolocation-node'); + +interface CurrentPositionResponseCoordinates { + longitude: number; + latitude: number; + altitude: number; +} + +interface CurrentPositionResponse { + timestamp: number; + coords: CurrentPositionResponseCoordinates; +} + +interface CurrentPositionOptions {} + +type GeoipService = ()=> Promise; + +const fetchJson = async (url: string): Promise => { + let r = await shim.fetch(url); + if (!r.ok) throw new Error(`Could not get geolocation: ${await r.text()}`); + r = await r.json(); + return r; +}; + +const geoipServices: Record = { + + ipwhois: async (): Promise => { + const r = await fetchJson('https://ipwho.is/'); + if (!('latitude' in r) || !('longitude' in r)) throw new Error(`Invalid geolocation response: ${r ? JSON.stringify(r) : ''}`); + + return { + timestamp: Date.now(), + coords: { + longitude: r.longitude, + altitude: 0, + latitude: r.latitude, + }, + }; + }, + + geoplugin: async (): Promise => { + const r = await fetchJson('http://www.geoplugin.net/json.gp'); + if (!('geoplugin_latitude' in r) || !('geoplugin_longitude' in r)) throw new Error(`Invalid geolocation response: ${r ? JSON.stringify(r) : ''}`); + + return { + timestamp: Date.now(), + coords: { + longitude: Number(r.geoplugin_longitude), + altitude: 0, + latitude: Number(r.geoplugin_latitude), + }, + }; + }, + +}; + +export default class { + static async currentPosition(options: CurrentPositionOptions = null) { + if (!options) options = {}; + + for (const [serviceName, handler] of Object.entries(geoipServices)) { + try { + const response = await handler(); + return response; + } catch (error) { + logger.warn(`Could not get geolocation from service "${serviceName}"`); + logger.warn(error); + } + } + + throw new Error('Could not get geolocation from any of the services'); + } +} diff --git a/packages/lib/models/BaseItem.test.js b/packages/lib/models/BaseItem.test.js index e2be6d3341..fefb3a8a33 100644 --- a/packages/lib/models/BaseItem.test.js +++ b/packages/lib/models/BaseItem.test.js @@ -63,7 +63,12 @@ describe('models/BaseItem', function() { expect(unserialized.longitude).toEqual('0.00000000'); expect(unserialized.altitude).toEqual('0.0000'); - await Note.updateGeolocation(note.id); + await Note.save({ + id: note.id, + longitude: -3.459, + altitude: 0, + latitude: 48.732, + }); note = await Note.load(note.id); serialized = await Note.serialize(note); @@ -77,7 +82,12 @@ describe('models/BaseItem', function() { it('should serialize and unserialize notes', (async () => { const folder = await Folder.save({ title: 'folder' }); const note = await Note.save({ title: 'note', parent_id: folder.id }); - await Note.updateGeolocation(note.id); + await Note.save({ + id: note.id, + longitude: -3.459, + altitude: 0, + latitude: 48.732, + }); const noteBefore = await Note.load(note.id); const serialized = await Note.serialize(noteBefore); diff --git a/packages/lib/shim-init-node.js b/packages/lib/shim-init-node.js index 58ae4f4b4c..114c4f998c 100644 --- a/packages/lib/shim-init-node.js +++ b/packages/lib/shim-init-node.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const shim = require('./shim').default; -const { GeolocationNode } = require('./geolocation-node.js'); +const GeolocationNode = require('./geolocation-node').default; const { FileApiDriverLocal } = require('./file-api-driver-local.js'); const { setLocale, defaultLocale, closestSupportedLocale } = require('./locale'); const FsDriverNode = require('./fs-driver-node').default;