Groundnet Scan

This commit is contained in:
portree_kid 2019-12-17 21:10:58 +01:00
parent b81348bdb8
commit 6adffb8878
29 changed files with 1744 additions and 1496 deletions

4
airports.json Normal file
View File

@ -0,0 +1,4 @@
{
"type": "FeatureCollection",
"features": []
}

1
airports_DB.json Normal file

File diff suppressed because one or more lines are too long

0
airports_DB.json~ Normal file
View File

1555
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -57,50 +57,62 @@
}, },
"dependencies": { "dependencies": {
"axios": "^0.18.0", "axios": "^0.18.0",
"electron-debug": "^3.0.1",
"element-ui": "^2.12.0", "element-ui": "^2.12.0",
"file-url": "^3.0.0",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"fs": "0.0.1-security",
"idb": "^4.0.5",
"leaflet": "^1.5.1", "leaflet": "^1.5.1",
"leaflet-editable": "^1.2.0",
"leaflet-sidebar-v2": "^3.2.1", "leaflet-sidebar-v2": "^3.2.1",
"lokijs": "^1.5.8",
"mathjs": "^6.2.5",
"path": "^0.12.7",
"vue": "^2.5.16", "vue": "^2.5.16",
"vue-electron": "^1.0.6", "vue-electron": "^1.0.6",
"vue-idb": "^0.2.0",
"vue-leaflet": "^0.1.0", "vue-leaflet": "^0.1.0",
"vue-router": "^3.0.1", "vue-router": "^3.0.1",
"vue2-leaflet": "^2.2.1", "vue2-leaflet": "^2.2.1",
"vuetify": "^2.1.9", "vuetify": "^2.1.9",
"vuex": "^3.0.1", "vuex": "^3.0.1",
"vuex-electron": "^1.0.0" "vuex-electron": "^1.0.0",
"vuex-persistedstate": "^2.7.0",
"worker-threads": "^1.0.0",
"xamel": "^0.3.1"
}, },
"devDependencies": { "devDependencies": {
"ajv": "^6.5.0", "ajv": "^6.5.0",
"babel-core": "^6.26.3", "babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-loader": "^7.1.4", "babel-loader": "^7.1.4",
"babel-plugin-istanbul": "^4.1.6",
"babel-plugin-transform-runtime": "^6.23.0", "babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0", "babel-preset-env": "^1.7.0",
"babel-preset-stage-0": "^6.24.1", "babel-preset-stage-0": "^6.24.1",
"babel-register": "^6.26.0", "babel-register": "^6.26.0",
"babili-webpack-plugin": "^0.1.2", "babili-webpack-plugin": "^0.1.2",
"cfonts": "^2.1.2", "cfonts": "^2.1.2",
"chai": "^4.1.2",
"chalk": "^2.4.1", "chalk": "^2.4.1",
"copy-webpack-plugin": "^4.5.1", "copy-webpack-plugin": "^4.5.1",
"cross-env": "^5.1.6", "cross-env": "^5.1.6",
"css-loader": "^0.28.11", "css-loader": "^0.28.11",
"del": "^3.0.0", "del": "^3.0.0",
"devtron": "^1.4.0", "devtron": "^1.4.0",
"electron": "^2.0.4", "electron": "^4.2.12",
"electron-debug": "^1.5.0", "electron-builder": "^21.2.0",
"electron-devtools-installer": "^2.2.4", "electron-devtools-installer": "^2.2.4",
"electron-builder": "^20.19.2",
"babel-eslint": "^8.2.3",
"eslint": "^4.19.1", "eslint": "^4.19.1",
"eslint-config-standard": "^11.0.0",
"eslint-friendly-formatter": "^4.0.1", "eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.0.0", "eslint-loader": "^2.0.0",
"eslint-plugin-html": "^4.0.3", "eslint-plugin-html": "^4.0.3",
"eslint-config-standard": "^11.0.0",
"eslint-plugin-import": "^2.12.0", "eslint-plugin-import": "^2.12.0",
"eslint-plugin-node": "^6.0.1", "eslint-plugin-node": "^6.0.1",
"eslint-plugin-promise": "^3.8.0", "eslint-plugin-promise": "^3.8.0",
"eslint-plugin-standard": "^3.1.0", "eslint-plugin-standard": "^3.1.0",
"mini-css-extract-plugin": "0.4.0",
"file-loader": "^1.1.11", "file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"inject-loader": "^4.0.1", "inject-loader": "^4.0.1",
@ -112,23 +124,22 @@
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-spec-reporter": "^0.0.32", "karma-spec-reporter": "^0.0.32",
"karma-webpack": "^3.0.0", "karma-webpack": "^3.0.0",
"require-dir": "^1.0.0", "mini-css-extract-plugin": "0.4.0",
"spectron": "^3.8.0",
"babel-plugin-istanbul": "^4.1.6",
"chai": "^4.1.2",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"multispinner": "^0.2.1", "multispinner": "^0.2.1",
"node-loader": "^0.6.0", "node-loader": "^0.6.0",
"node-sass": "^4.9.2", "node-sass": "^4.9.2",
"require-dir": "^1.0.0",
"sass-loader": "^7.0.3", "sass-loader": "^7.0.3",
"spectron": "^3.8.0",
"style-loader": "^0.21.0", "style-loader": "^0.21.0",
"url-loader": "^1.0.1", "url-loader": "^1.0.1",
"vue-html-loader": "^1.2.4", "vue-html-loader": "^1.2.4",
"vue-loader": "^15.2.4", "vue-loader": "^15.2.4",
"vue-style-loader": "^4.1.0", "vue-style-loader": "^4.1.0",
"vue-template-compiler": "^2.5.16", "vue-template-compiler": "^2.5.16",
"webpack-cli": "^3.0.8",
"webpack": "^4.15.1", "webpack": "^4.15.1",
"webpack-cli": "^3.0.8",
"webpack-dev-server": "^3.1.4", "webpack-dev-server": "^3.1.4",
"webpack-hot-middleware": "^2.22.2", "webpack-hot-middleware": "^2.22.2",
"webpack-merge": "^4.1.3" "webpack-merge": "^4.1.3"

View File

@ -6,9 +6,9 @@ import { app, BrowserWindow } from 'electron'
* Set `__static` path to static files in production * Set `__static` path to static files in production
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
*/ */
if (process.env.NODE_ENV !== 'development') { // if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') // global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
} // }
let mainWindow let mainWindow
const winURL = process.env.NODE_ENV === 'development' const winURL = process.env.NODE_ENV === 'development'
@ -22,9 +22,12 @@ function createWindow () {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
height: 563, height: 563,
useContentSize: true, useContentSize: true,
webPreferences: {
nodeIntegration: true,
nodeIntegrationInWorker: true
},
width: 1000 width: 1000
}) })
mainWindow.loadURL(winURL) mainWindow.loadURL(winURL)
mainWindow.on('closed', () => { mainWindow.on('closed', () => {

View File

@ -0,0 +1,54 @@
<template>
<section class="edit-layer">
<h1>edit-layer Component</h1>
</section>
</template>
<script lang="js">
import L from 'leaflet'
export default {
name: 'edit-layer',
props: [],
mounted () {
this.add()
},
beforeDestroy () {
this.remove()
},
data () {
return {
}
},
methods: {
deferredMountedTo (parent) {
this.sidebar = L.control.sidebar({
autopan: false, // whether to maintain the centered map point when opening the sidebar
closeButton: true, // whether t add a close button to the panes
container: 'sidebar', // the DOM container or #ID of a predefined sidebar container that should be used
position: 'left' // left or right
})
parent.addControl(this.sidebar)
},
remove () {
if (this.sidebar) {
this.$parent.removeLayer(this.sidebar)
}
},
add () {
if (this.$parent._isMounted) {
this.deferredMountedTo(this.$parent.mapObject)
}
}
},
computed: {
}
}
</script>
<style scoped lang="scss">
.edit-layer {
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<label class="directory-select">
<div class="select-button">
...
</div>
<input type="file" @change="handleFileChange" webkitdirectory directory/>
</label>
</template>
<script>
export default {
props: {
value: File
},
methods: {
handleFileChange (e) {
this.$emit('input', e.target.files[0])
}
}
}
</script>
<style scoped>
.directory-select > .select-button {
padding: 0rem;
color: white;
background-color: #2EA169;
border-radius: .3rem;
text-align: center;
font-weight: bold;
}
.directory-select > input[type="file"] {
display: none;
}
</style>

View File

@ -0,0 +1,54 @@
<template>
<section class="edit-layer">
<h1>edit-layer Component</h1>
</section>
</template>
<script lang="js">
import L from 'leaflet'
export default {
name: 'edit-layer',
props: [],
mounted () {
this.add()
},
beforeDestroy () {
this.remove()
},
data () {
return {
}
},
methods: {
deferredMountedTo (parent) {
this.sidebar = L.control.sidebar({
autopan: false, // whether to maintain the centered map point when opening the sidebar
closeButton: true, // whether t add a close button to the panes
container: 'sidebar', // the DOM container or #ID of a predefined sidebar container that should be used
position: 'left' // left or right
})
parent.addControl(this.sidebar)
},
remove () {
if (this.sidebar) {
this.$parent.removeLayer(this.sidebar)
}
},
add () {
if (this.$parent._isMounted) {
this.deferredMountedTo(this.$parent.mapObject)
}
}
},
computed: {
}
}
</script>
<style scoped lang="scss">
.edit-layer {
}
</style>

View File

@ -0,0 +1,41 @@
<template>
<label class="file-select">
<div class="select-button">
<span v-if="value">Selected File: {{value.name}}</span>
<span v-else>Select File</span>
</div>
<input type="file" @change="handleFileChange"/>
</label>
</template>
<script>
export default {
props: {
value: File
},
methods: {
handleFileChange (e) {
this.$emit('input', e.target.files[0])
}
}
}
</script>
<style scoped>
.file-select > .select-button {
padding: 1rem;
color: white;
background-color: #2EA169;
border-radius: .3rem;
text-align: center;
font-weight: bold;
}
.file-select > input[type="file"] {
display: none;
}
</style>

View File

@ -3,6 +3,7 @@
<l-tile-layer :url="url" :attribution="attribution"></l-tile-layer> <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
<l-marker :lat-lng="marker"></l-marker> <l-marker :lat-lng="marker"></l-marker>
<LeafletSidebar></LeafletSidebar> <LeafletSidebar></LeafletSidebar>
<EditLayer></EditLayer>
</l-map> </l-map>
</template> </template>
@ -10,6 +11,7 @@
import 'leaflet/dist/leaflet.css' import 'leaflet/dist/leaflet.css'
import { LMap, LTileLayer, LMarker } from 'vue2-leaflet' import { LMap, LTileLayer, LMarker } from 'vue2-leaflet'
import LeafletSidebar from './LeafletSidebar' import LeafletSidebar from './LeafletSidebar'
import EditLayer from './EditLayer'
import L from 'leaflet' import L from 'leaflet'
// https://github.com/KoRiGaN/Vue2Leaflet/issues/103 // https://github.com/KoRiGaN/Vue2Leaflet/issues/103
@ -22,7 +24,7 @@
}) })
export default { export default {
name: 'flightgear-map', name: 'flightgear-map',
components: { LMap, LTileLayer, LMarker, LeafletSidebar }, components: { LMap, LTileLayer, LMarker, LeafletSidebar, EditLayer },
props: [], props: [],
mounted () { mounted () {

View File

@ -1,73 +0,0 @@
<template>
<div>
<div class="title">Information</div>
<div class="items">
<div class="item">
<div class="name">Path:</div>
<div class="value">{{ path }}</div>
</div>
<div class="item">
<div class="name">Route Name:</div>
<div class="value">{{ name }}</div>
</div>
<div class="item">
<div class="name">Vue.js:</div>
<div class="value">{{ vue }}</div>
</div>
<div class="item">
<div class="name">Electron:</div>
<div class="value">{{ electron }}</div>
</div>
<div class="item">
<div class="name">Node:</div>
<div class="value">{{ node }}</div>
</div>
<div class="item">
<div class="name">Platform:</div>
<div class="value">{{ platform }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
electron: process.versions.electron,
name: this.$route.name,
node: process.versions.node,
path: this.$route.path,
platform: require('os').platform(),
vue: require('vue/package.json').version
}
}
}
</script>
<style scoped>
.title {
color: #888;
font-size: 18px;
font-weight: initial;
letter-spacing: .25px;
margin-top: 10px;
}
.items { margin-top: 8px; }
.item {
display: flex;
margin-bottom: 6px;
}
.item .name {
color: #6a6a6a;
margin-right: 6px;
}
.item .value {
color: #35495e;
font-weight: bold;
}
</style>

View File

@ -4,8 +4,7 @@
<div class="leaflet-sidebar-tabs"> <div class="leaflet-sidebar-tabs">
<ul role="tablist"> <!-- top aligned tabs --> <ul role="tablist"> <!-- top aligned tabs -->
<li><a href="#home" role="tab"><i class="fa fa-bars"></i></a></li> <li><a href="#home" role="tab"><i class="fa fa-bars"></i></a></li>
<li><a href="#messages" role="tab"><i class="fa fa-envelope"></i></a></li> <li><a href="#scan" role="tab"><i class="fa fa-search"></i></a></li>
<li><a href="#profile" role="tab"><i class="fa fa-user"></i></a></li>
</ul> </ul>
<ul role="tablist"> <!-- bottom aligned tabs --> <ul role="tablist"> <!-- bottom aligned tabs -->
@ -22,14 +21,11 @@
</h1> </h1>
<p>A responsive sidebar for mapping libraries</p> <p>A responsive sidebar for mapping libraries</p>
</div> </div>
<div class="leaflet-sidebar-pane" id="scan">
<div class="leaflet-sidebar-pane" id="messages"> <RunScan></RunScan>
<h1 class="leaflet-sidebar-header">Messages<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div></h1>
<el-select v-model="value" placeholder="Select"><el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select>
</div> </div>
<div class="leaflet-sidebar-pane" id="settings">
<div class="leaflet-sidebar-pane" id="profile"> <SettingsPanel></SettingsPanel>
<h1 class="leaflet-sidebar-header">Profile<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div></h1>
</div> </div>
</div> </div>
</div> </div>
@ -41,10 +37,12 @@
import {} from 'leaflet-sidebar-v2' import {} from 'leaflet-sidebar-v2'
import L from 'leaflet' import L from 'leaflet'
import SettingsPanel from './SettingsPanel' import SettingsPanel from './SettingsPanel'
import RunScan from './RunScan'
import FileSelect from './FileSelect'
export default { export default {
name: 'leaflet-sidebar', name: 'leaflet-sidebar',
components: { SettingsPanel }, components: { SettingsPanel, RunScan, FileSelect },
props: [], props: [],
mounted () { mounted () {
this.add() this.add()
@ -54,25 +52,6 @@
}, },
data () { data () {
return { return {
message: 'BLBL',
checkbox: true,
options: [{
value: 'Option1',
label: 'Option1'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
} }
}, },
methods: { methods: {
@ -84,20 +63,6 @@
position: 'left' // left or right position: 'left' // left or right
}) })
parent.addControl(this.sidebar) parent.addControl(this.sidebar)
this.sidebar.addPanel({
id: 'properties',
tab: '<i class="fa fa-road vertical-center"/>',
title: 'Properties',
pane: '<div id="properties-tab"></div>'
})
this.sidebar.addPanel({
id: 'settings',
tab: '<i class="fa fa-gear vertical-center"/>',
title: 'Settings',
pane: '<div id="settings-div"></div>'
})
}, },
remove () { remove () {
if (this.sidebar) { if (this.sidebar) {
@ -108,6 +73,8 @@
if (this.$parent._isMounted) { if (this.$parent._isMounted) {
this.deferredMountedTo(this.$parent.mapObject) this.deferredMountedTo(this.$parent.mapObject)
} }
},
scan () {
} }
}, },
computed: { computed: {

View File

@ -0,0 +1,104 @@
<template>
<div>
<el-container direction='vertical'>
<el-button @click="scanAPT()">Scan APT File</el-button>
<el-button @click="scanGroundnets()">Scan Groundnet Files</el-button>
<el-button @click="scanTraffic()">Scan Traffic Files</el-button>
</el-container>
</div>
</template>
<script lang="js">
// import scanner from '../utils/scan'
import fileUrl from 'file-url'
const path = require('path')
export default {
name: 'run-scan',
components: {},
props: [],
mounted () {
},
beforeDestroy () {
},
data () {
return {
}
},
methods: {
scanAPT () {
try {
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/src/renderer/utils/worker.js`
: `file://${__dirname}/worker.js`
console.log('make a worker: ', path.resolve(__dirname, 'worker.js'))
const worker = new Worker(winURL)
console.log(fileUrl('src/renderer/utils/worker.js'))
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
worker.postMessage('scanapt')
// the reply
worker.onmessage = function (e) {
if (e.data === 'DONE') {
console.log('DONE')
}
console.log(e.data)
}
} catch (err) {
console.error(err)
}
},
scanGroundnets () {
try {
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/src/renderer/utils/worker.js`
: `file://${__dirname}/worker.js`
console.log('make a worker: ', path.resolve(__dirname, 'worker.js'))
const worker = new Worker(winURL)
console.log(fileUrl('src/renderer/utils/worker.js'))
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
worker.postMessage('scan')
// the reply
worker.onmessage = function (e) {
if (e.data === 'DONE') {
console.log('DONE')
}
console.log(e.data)
}
} catch (err) {
console.error(err)
}
},
scanTraffic () {
// let flightgearDirectory = this.$store.state.settings.flightgearDirectory
try {
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/src/renderer/utils/worker.js`
: `file://${__dirname}/worker.js`
console.log('make a worker: ', path.resolve(__dirname, 'worker.js'))
const worker = new Worker(winURL)
console.log(fileUrl('src/renderer/utils/worker.js'))
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
worker.postMessage('scanai')
// the reply
worker.onmessage = function (e) {
if (e.data === 'DONE') {
console.log('DONE')
}
console.log(e.data)
}
} catch (err) {
console.error(err)
}
}
},
computed: {
}
}
</script>

View File

@ -1,34 +1,62 @@
<template> <template>
<div>
<h1 class="leaflet-sidebar-header">
Settings
<div class="leaflet-sidebar-close">
<i class="fa fa-caret-left"></i>
</div>
</h1>
<div id="panel" width="100%">
<el-row>
<el-col :span="7">Flightgear Directory</el-col>
<el-col :span="15">{{ flightgear_directory }}</el-col>
<el-col :span="2">
<directory-select @input="directorySelect"></directory-select>
</el-col>
</el-row>
</div>
</div>
</template> </template>
<script lang="js"> <script lang="js">
import FileSelect from './FileSelect'
import DirectorySelect from './DirectorySelect'
export default { export default {
name: 'settings-panel', name: 'settings-panel',
components: { DirectorySelect, FileSelect },
props: [], props: [],
mounted () { mounted () {
if (this.$parent._isMounted) {
this.$parent.sidebar.addPanel({
id: 'settings',
tab: '<i class="fa fa-gear vertical-center"/>',
title: 'Settings',
pane: '<div id="settings-div"></div>'
})
}
}, },
data () { data () {
return { return {
selected: 'Undefined'
} }
}, },
methods: { methods: {
buttonClick: function () {
this.$store.commit('TOGGLE_HYDRATED')
},
directorySelect: function (flightgearDirectory) {
console.log(flightgearDirectory)
this.$store.commit('SETTINGS_DIRECTORY', flightgearDirectory.path)
}
}, },
computed: { computed: {
hydrated: function () {
return this.$store.state.hydrated
},
flightgear_directory: function () {
return this.$store.state.settings.flightgearDirectory
}
} }
} }
</script> </script>
<style scoped lang="scss"> <style>
.el-row {
margin-bottom: 20px;
}
.el-col {
border-radius: 4px;
}
</style> </style>

19
src/renderer/db/index.js Normal file
View File

@ -0,0 +1,19 @@
import Vue from 'vue'
import VueIdb from 'vue-idb'
Vue.use(VueIdb)
export default new VueIdb({
database: 'test',
schemas: [
{ tests: 'id, label, created_at, updated_at' }
],
options: {
tests: { type: 'list', primary: 'id', label: 'title', updated_at: 'updated_at' }
},
apis: {
bigs: {
all: () => axios.get('/dev/data/data.json')
}
}
})

View File

@ -0,0 +1,24 @@
import Vue from 'vue'
import Vuex from 'vuex'
import L from 'leaflet'
import { createPersistedState, createSharedMutations } from 'vuex-electron'
import modules from './modules'
Vue.use(Vuex)
export default new Vuex.Store({
modules,
plugins: [
createPersistedState(),
createSharedMutations()
],
strict: process.env.NODE_ENV !== 'production',
state: { zoom: 13,
center: L.latLng(47.413220, -1.219482),
url: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
marker: L.latLng(47.413220, -1.219482)}
})

View File

@ -1,24 +1,25 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
// import from 'electron-settings'
import L from 'leaflet' import createPersistedState from 'vuex-persistedstate'
import { createPersistedState, createSharedMutations } from 'vuex-electron'
import modules from './modules'
Vue.use(Vuex) Vue.use(Vuex)
export default new Vuex.Store({ export default new Vuex.Store({
modules, state: {
plugins: [ settings: { flightgearDirectory: '.' }
createPersistedState(), },
createSharedMutations() actions: {
], },
strict: process.env.NODE_ENV !== 'production', mutations: {
state: { zoom: 13, 'DELETE_INDEXED_DB' () {},
center: L.latLng(47.413220, -1.219482), 'SETTINGS_DIRECTORY' (state, flightgearDirectory) {
url: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png', state.settings.flightgearDirectory = flightgearDirectory
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors', }
marker: L.latLng(47.413220, -1.219482)} },
getters: {
hydrated: state => state.hydrated
},
plugins: [createPersistedState()],
strict: true
}) })

View File

@ -0,0 +1,25 @@
const state = {
main: 0
}
const mutations = {
DECREMENT_MAIN_COUNTER (state) {
state.main--
},
INCREMENT_MAIN_COUNTER (state) {
state.main++
}
}
const actions = {
someAsyncTask ({ commit }) {
// do something async
commit('INCREMENT_MAIN_COUNTER')
}
}
export default {
state,
mutations,
actions
}

View File

@ -0,0 +1,25 @@
const state = {
flightgearPath: ''
}
const mutations = {
DECREMENT_MAIN_COUNTER (state) {
state.main--
},
INCREMENT_MAIN_COUNTER (state) {
state.main++
}
}
const actions = {
someAsyncTask ({ commit }) {
// do something async
commit('INCREMENT_MAIN_COUNTER')
}
}
export default {
state,
mutations,
actions
}

View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Tobias Nickel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,149 @@
# tXml
a very small and probably the fastest xml parser in pure javascript.
This lib only provides one single method. **tXml()**
1. this code is about 230 lines, can be easily extended.
2. this code is 0.9kb minified + gzipped.
3. this code is 5 - 10 times faster then sax/xml2js.
4. this code can running in a worker.
5. this code is parsing at average the same speed as native DOMParser + potential to be faster.
6. this code is easy to read and good for study.
7. this code creates a domObject with minimal footprint, that is easy to traverse.
8. this code has proven in different projects, like RSS reader, openStreetmap, websites.
9. this code can even parse handwritten XML that contains various errors.
10. this code is working in client and server.
11. this code is 100% covered by unit tests.
so, there are good reasons to give tXml.js a try.
## XML - features
1. tags
2. childTags
3. text-nodes
4. white-spaces
5. attributes with single and double quotes
6. attributes without value
7. xmlComments (ignored)
8. embedded CSS and Javascript
9. HTML singleTag elements br, img, link, meta, hr
10. doctype definitions
11. xml namespaces
12. sync API for a sync process
13. getElementsById/-Class direct on the xmlString
14. simplify, similar to PHP's [SimpleXML](http://php.net/manual/en/book.simplexml.php)
15. filter, similar to underscore, as a alternative to CSS selectors
16. monomorphism for fast processing and fewer if statements (a node always has tagName:'', attributes:{} and children:[])
17. streamSupport ! ! !
## Try Online
you can to some test without installing online: [tnickel.de](http://tnickel.de/2017/04/02/txml-online/)
## Installation
In browser you load it how ever you want. For example as tag: <script src="tXml.js"></script>.
In node and browseryfy, run **"npm install txml"** in your project.
and then in your script you require it by "var tXml = require('txml');
## Methods
### **tXml** *(XML-string, options)*
1. **XML string** is the XML to parse.
2. **options** is optional
**searchId** an ID of some object. that can be queried. Using this is incredible fast.
**filter** a method, to filter for interesting nodes, use it like Array.filter.
**simplify** to simplify the object, to an easier access
EXAMPLE 1: tXml("<user is='great'><name>Tobias</name><familyName>Nickel</familyName><profession>Software Developer</profession><location>Shanghai / China</location></user>");
```js
// will return an object like:
[{
"tagName": "user",
"attributes": {
"is": "great"
},
"children": [{
"tagName": "name",
"children": [ "Tobias" ]
}, {
"tagName": "familyName",
"children": [ "Nickel" ]
}, {
"tagName": "profession",
"children": [ "Software Developer" ]
}, {
"tagName": "location",
"children": [ "Shanghai / China" ]
}
]
}]
```
EXAMLPLE 2: tXml("<user is='great'><name>Tobias</name><familyName>Nickel</familyName><profession>Software Developer</profession><location>Shanghai / China</location></user>",{simplify:1});
```js
// will return an object like:
{
"user": {
"name": "Tobias",
"familyName": "Nickel",
"profession": "Software Developer",
"location": "Shanghai / China",
"_attributes": {
"is": "great"
}
}
}
```
### **tXml.simpify** *(tXml_DOM_Object)*
this method is used with the simplify parameter;
1. **tXml_DOM_Object** the object to simplify.
### **tXml.filter** *(tXml_DOM_Object, f)*
this method is used with the filter parameter, it is used like Array.filter.
1. **tXml_DOM_Object** the object to filter.
2. **f** a function that returns true if you want this elements in the result set.
### **tXml.getElementById** (xml,id)
to find an element by ID. if you are only interested for the information on, a specific node, this is easy and fast, because not the entire xml need to get parsed to a tDOM Object. returns the element not simplified, you can do with tXml.simplify()
1. **xml** the xml string to search in.
2. **id** the id of the element to find
### **tXml.getElementsByClassName** (xml,className)
find the elements with the given class, without parsing the entire xml into a tDOM. so it is very fast and convenient. returns a list of elements.
1. **xml** the xml string to search in.
2. **className** the className of the element to find
### **txml.parseStream** (stream, offset)
1. stream is the stream or fileName,
2. offset requires you to set short before the first item.
usually files begin with simething like "<!DOCTYPE osm><osm>"
so the offset need to be before the first item starts so that
between that item and the offset is no "<" character.
alternatively, pass astring, containing this preample.
return stream, triggers even "xml" to get notified when a complete node has been parsed.
is usefull for huge files, OSM-world, wikipedia-dump.
### **txml.transformStream** (offset)
2. offset optional you to set short before the first item.
usually files begin with simething like "<!DOCTYPE osm><osm>"
so the offset need to be before the first item starts so that
between that item and the offset is no "<" character.
alternatively, pass astring, containing this preample.
return transformStream.
```js
const xmlStream = fs.createReadStream('your.xml').pipe(txml.transformStream())
for await(let element of xmlStream) {
// your logic here ...
}
```
## Developer
[Tobias Nickel](http://tnickel.de/) German software developer in Shanghai.
![alt text](https://avatars1.githubusercontent.com/u/4189801?s=150)

7
src/renderer/txml/tXml.min.js vendored Normal file
View File

@ -0,0 +1,7 @@
function tXml(a,c){function d(){for(var c=[];a[b];)if(60==a.charCodeAt(b)){if(47===a.charCodeAt(b+1)){b=a.indexOf(">",b);b+1&&(b+=1);break}else if(33===a.charCodeAt(b+1)){if(45==a.charCodeAt(b+2)){for(;-1!==b&&(62!==a.charCodeAt(b)||45!=a.charCodeAt(b-1)||45!=a.charCodeAt(b-2)||-1==b);)b=a.indexOf(">",b+1);-1===b&&(b=a.length)}else for(b+=2;62!==a.charCodeAt(b)&&a[b];)b++;b++;continue}var d=g();c.push(d)}else d=b,b=a.indexOf("<",b)-1,-2===b&&(b=a.length),d=a.slice(d,b+1),0<d.trim().length&&c.push(d),
b++;return c}function k(){for(var c=b;-1===m.indexOf(a[b])&&a[b];)b++;return a.slice(c,b)}function g(){b++;for(var c=k(),g={},f=[];62!==a.charCodeAt(b)&&a[b];){var e=a.charCodeAt(b);if(64<e&&91>e||96<e&&123>e){var h=k();for(e=a.charCodeAt(b);e&&39!==e&&34!==e&&!(64<e&&91>e||96<e&&123>e)&&62!==e;)b++,e=a.charCodeAt(b);if(39===e||34===e){e=a[b];var l=++b;b=a.indexOf(e,l);e=a.slice(l,b);if(-1===b)return{tagName:c,attributes:g,children:f}}else e=null,b--;g[h]=e}b++}47!==a.charCodeAt(b-1)?"script"==c?
(f=b+1,b=a.indexOf("\x3c/script>",b),f=[a.slice(f,b-1)],b+=9):"style"==c?(f=b+1,b=a.indexOf("</style>",b),f=[a.slice(f,b-1)],b+=8):-1==n.indexOf(c)&&(b++,f=d(h)):b++;return{tagName:c,attributes:g,children:f}}function f(){var b=(new RegExp("\\s"+c.attrName+"\\s*=['\"]"+c.attrValue+"['\"]")).exec(a);return b?b.index:-1}c=c||{};var b=c.pos||0,m="\n\t>/= ",n=c.noChildNodes||["img","br","input","meta","link"],h=null;if(void 0!==c.attrValue)for(c.attrName=c.attrName||"id",h=[];-1!==(b=f());)b=a.lastIndexOf("<",
b),-1!==b&&h.push(g()),a=a.substr(b),b=0;else h=c.parseNode?g():d();c.filter&&(h=tXml.filter(h,c.filter));c.setPos&&(h.pos=b);return h}tXml.simplify=function(a){var c={};if(!a.length)return"";if(1===a.length&&"string"==typeof a[0])return a[0];a.forEach(function(a){if("object"===typeof a){c[a.tagName]||(c[a.tagName]=[]);var d=tXml.simplify(a.children||[]);c[a.tagName].push(d);a.attributes&&(d._attributes=a.attributes)}});for(var d in c)1==c[d].length&&(c[d]=c[d][0]);return c};
tXml.filter=function(a,c){var d=[];a.forEach(function(a){"object"===typeof a&&c(a)&&d.push(a);a.children&&(a=tXml.filter(a.children,c),d=d.concat(a))});return d};
tXml.stringify=function(a){function c(a){if(a)for(var g=0;g<a.length;g++)if("string"==typeof a[g])d+=a[g].trim();else{var f=void 0,b=a[g];d+="<"+b.tagName;for(f in b.attributes)d=null===b.attributes[f]?d+(" "+f):-1===b.attributes[f].indexOf('"')?d+(" "+f+'="'+b.attributes[f].trim()+'"'):d+(" "+f+"='"+b.attributes[f].trim()+"'");d+=">";c(b.children);d+="</"+b.tagName+">"}}var d="";c(a);return d};
tXml.toContentString=function(a){if(Array.isArray(a)){var c="";a.forEach(function(a){c+=" "+tXml.toContentString(a);c=c.trim()});return c}return"object"===typeof a?tXml.toContentString(a.children):" "+a};tXml.getElementById=function(a,c,d){a=tXml(a,{attrValue:c});return d?tXml.simplify(a):a[0]};tXml.getElementsByClassName=function(a,c,d){a=tXml(a,{attrName:"class",attrValue:"[a-zA-Z0-9-s ]*"+c+"[a-zA-Z0-9-s ]*"});return d?tXml.simplify(a):a};

View File

@ -0,0 +1,95 @@
/* eslint-disable */
const loki = require('lokijs');
const fs = require('fs');
var db = new loki('airports_DB.json');
var features = null;
export async function init() {
var promise = new Promise(function (resolve, reject) {
console.log("Init " + (features == null));
if (features == null) {
console.log("Loading DB");
db.loadDatabase({}, function (err) {
if (err) {
console.error("Error loading DB");
console.error(err);
db.addCollection('features', {
unique: ["properties.icao"], autoupdate: true
});
features = db.getCollection('features');
}
features = db.getCollection('features');
if( features == null ){
db.addCollection('features', {
unique: ["properties.icao"], autoupdate: true
});
features = db.getCollection('features');
}
console.log("Loaded " + features.count() + " features");
resolve(features);
});
}
else {
resolve(features);
}
});
return promise;
}
export function getAirport(apts, icao) {
console.log("Getting Airport " + icao);
var results = apts.where(function (f) {
return f.properties['icao'] === icao;
});
var feature;
if (results.length == 0) {
feature = {
"type": "Feature",
'properties': { 'icao': icao, 'twr': false, 'threshold': false, 'flights': 0 },
'geometry': {
"type": "Point"
}
};
feature = apts.insert(feature);
// apts.update(feature);
console.log("Added New");
console.log(JSON.stringify(feature));
return feature;
}
else {
console.debug("retrieved " + JSON.stringify(results[0]));
return results[0];
}
}
export function save() {
if (!features || !features.data)
return;
var mappedData = features.data.map(function (f) {
delete f.meta;
delete f.$loki;
if(f.properties.airlines) {
f.properties.airlines = f.properties.airlines.join(' ');
}
else {
f.properties.airlines = [];
}
return f;
});
mappedData = mappedData.filter(feature => feature.properties['twr'] || feature.properties['threshold']);
//console.log(mappedData);
var featureCollection = { type: "FeatureCollection", features: mappedData };
let data = JSON.stringify(featureCollection, null, 2);
fs.writeFileSync('airports.json', data);
db.saveDatabase(function (err) {
if (err) {
console.error(err);
}
});
}

View File

@ -0,0 +1,143 @@
/* eslint-disable */
var features = null;
async function initDB() {
var promise = new Promise(function (resolve, reject) {
console.log("Init " + (features == null));
if (features == null) {
console.log("Loading DB");
console.log(this.indexedDB);
// var deleteRequest = indexedDB.deleteDatabase("flightgear");
// deleteRequest.onerror = function (event) {
// console.log(event);
// reject(event);
// };
// deleteRequest.onsuccess = function (event) {
// console.log(event);
// };
var request = this.indexedDB.open("flightgear", 2);
request.onerror = function (event) {
reject(event);
};
request.onsuccess = function (event) {
console.log('Opened DB ' + event);
features = request.result;
resolve(features);
};
request.onupgradeneeded = function (event) {
var db = event.target.result;
console.log("Migrate " + event);
// Create an objectStore to hold information about our customers. We're
// going to use "ssn" as our key path because it's guaranteed to be
// unique.
if (event.oldVersion < 1) {
// Version 1 is the first version of the database.
var objectStore = db.createObjectStore("airports", { keyPath: "properties.icao" });
}
if (event.oldVersion < 2) {
// Version 1 is the first version of the database.
var objectStore = event.target.transaction.objectStore("airports");
var indexNames = objectStore.indexNames;
var desiredKeyPathForMyIndex = "properties.icao";
console.log(indexNames);
if(indexNames.contains('myIndexName')) {
var myIndex = objectStore.index('myIndexName');
var currentKeyPath = myIndex.keyPath;
if(currentKeyPath != desiredKeyPathForMyIndex) {
objectStore.deleteIndex('myIndexName');
objectStore.createIndex('myIndexName', desiredKeyPathForMyIndex);
}
} else {
objectStore.createIndex('myIndexName', desiredKeyPathForMyIndex);
}
}
};
// db.loadDatabase({}, function (err) {
// if (err) {
// console.error("Error loading DB");
// console.error(err);
// db.addCollection('features', {
// unique: ["properties.icao"], autoupdate: true
// });
// features = db.getCollection('features');
// }
// features = db.getCollection('features');
// if( features == null ){
// db.addCollection('features', {
// unique: ["properties.icao"], autoupdate: true
// });
// features = db.getCollection('features');
// }
// console.log("Loaded " + features.count() + " features");
// resolve(features);
// });
}
else {
resolve(features);
}
});
return promise;
}
function getAirport(apts, icao) {
console.log("Getting Airport " + icao);
var results = apts.where(function (f) {
return f.properties['icao'] === icao;
});
var feature;
if (results.length == 0) {
feature = {
"type": "Feature",
'properties': { 'icao': icao, 'twr': false, 'threshold': false, 'flights': 0 },
'geometry': {
"type": "Point"
}
};
feature = apts.insert(feature);
// apts.update(feature);
console.log("Added New");
console.log(JSON.stringify(feature));
return feature;
}
else {
console.debug("retrieved " + JSON.stringify(results[0]));
return results[0];
}
}
function save() {
if (!features || !features.data)
return;
var mappedData = features.data.map(function (f) {
delete f.meta;
delete f.$loki;
if (f.properties.airlines) {
f.properties.airlines = f.properties.airlines.join(' ');
}
else {
f.properties.airlines = [];
}
return f;
});
mappedData = mappedData.filter(feature => feature.properties['twr'] || feature.properties['threshold']);
//console.log(mappedData);
var featureCollection = { type: "FeatureCollection", features: mappedData };
let data = JSON.stringify(featureCollection, null, 2);
fs.writeFileSync('airports.json', data);
// db.saveDatabase(function (err) {
// if (err) {
// console.error(err);
// }
// });
}

View File

@ -0,0 +1,50 @@
/* eslint-disable */
const lineReader = require('readline');
const fs = require('fs');
const airports = require('./airports');
var scanMethods = {
1: (l, apts) => {
console.log('Airport:', l);
var airportFeature = airports.getAirport(apts, l[4]);
console.log(JSON.stringify(airportFeature));
airportFeature.properties.name = l.slice(5).join(' ').replace('\t', ' ');
console.debug(airportFeature.properties.name);
// apts.update(airportFeature);
},
99: (l) => {
console.log('Finished');
}
};
function scan (f, apts) {
console.log(f);
lineReader.createInterface({
input: fs.createReadStream(f)
}).on('line', function (line) {
var fields = line.split(/[ ]+/);
// var fields = line.match('([0-9]+)');
if (fields == null)
return;
var scanMethod = scanMethods[fields[0]];
if (scanMethod != null) {
scanMethod(fields, apts);
}
else {
if (fields[0] == '99') {
lineReader.close();
}
// console.log('Ignored:', line);
}
}).on('error', function (err) {
console.log(err);
lr.close();
}).on('close', function () {
console.log("End");
airports.save();
});
}
// export default { scan, name }

90
src/renderer/utils/apt.js Normal file
View File

@ -0,0 +1,90 @@
/* eslint-disable */
const lineReader = require('readline');
var scanMethods = {
1: (l, apts) => {
console.log('Airport:', l);
saveName(apts, l[4], l.slice(5).join(' ').replace('\t', ' '));
},
99: (l) => {
console.log('Finished');
}
};
async function saveName(features, icao, name) {
var promise = new Promise(function (resolve, reject) {
var transaction = features.transaction("airports", "readwrite");
var objectStore = transaction.objectStore("airports");
var objectStoreRequest = objectStore.get(icao);
objectStoreRequest.onsuccess = function (event) {
console.log(event);
var feature = objectStoreRequest.result;
if (!feature) {
feature = {
"type": "Feature",
'properties': { 'icao': icao, 'twr': false, 'threshold': false, 'flights': 0, airlines: [] },
'geometry': {
"type": "Point"
}
};
}
feature.properties.name = name;
feature.properties.icao = icao;
console.log("ICAO : " + feature.properties.icao);
// Create another request that inserts the item back into the database
var updateAirportRequest = objectStore.put(feature);
// Log the transaction that originated this request
console.log("The transaction that originated this request is " + updateAirportRequest.updateAirportRequest);
// When this new request succeeds, run the displayData() function again to update the display
updateAirportRequest.onsuccess = function () {
console.log("Stored");
resolve();
};
updateAirportRequest.onerror = function (event) {
console.log("Error " + event);
reject(event);
};
};
objectStoreRequest.onerror = function (event) {
console.log("Error " + event);
reject(event);
};
});
return promise;
}
function scanAPTIntoDB(f, apts) {
console.log(f);
lineReader.createInterface({
input: fs.createReadStream(f)
}).on('line', function (line) {
var fields = line.split(/[ ]+/);
// var fields = line.match('([0-9]+)');
if (fields == null)
return;
var scanMethod = scanMethods[fields[0]];
if (scanMethod != null) {
scanMethod(fields, apts);
}
else {
if (fields[0] == '99') {
lineReader.close();
}
// console.log('Ignored:', line);
}
}).on('error', function (err) {
console.log(err);
lr.close();
}).on('close', function () {
console.log("End");
apts.close();
});
}
// export default { scan, name }

386
src/renderer/utils/scan.js Normal file
View File

@ -0,0 +1,386 @@
/* eslint-disable */
// const fs = require('fs');
// const path = require('path');
// const math = require('mathjs');
// const util = require('util');
// const airports = require('./airports.js');
// const homedir = require('os').homedir();
// const apt = require('apt.js');
async function asyncForEach(array, callback) {
console.log("Len " + array.length);
for (let index = 0; index < array.length; index++) {
try {
var res = await callback(array[index], index, array);
console.log("Index " + index + " " + res);
} catch (error) {
console.error(error);
}
}
}
function scanAPT_Old(p) {
return airports.init().then(features => {
var d = path.join(homedir, 'Documents/apt.dat');
console.log(d);
apt.scan(d, features);
});
}
async function waitFor(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
async function scanGroundnetFiles(p, features) {
var promise = new Promise(function (resolve, reject) {
try {
console.log('Start Groundnets ' + p);
var files = traverseDir(p);
console.log(files);
asyncForEach(files, async f => {
//await waitFor(5000);
try {
var text = await readGroundnet(f, features);
console.log(text);
resolve(text);
} catch (error) {
console.error(error);
reject(error);
}
}).then(t => {
console.log("Finished");
features.close();
resolve();
}).catch(reason => {
console.log("Crashed");
console.log(reason);
features.close()
});
//walkDir(p, f => { readGroundnet(f, features) });
} catch (error) {
console.log(error);
reject(error);
}
});
}
function scanTrafficIntoDB(p, features) {
try {
console.log('Start Traffic ' + p + ' ' + features);
var objectStore = features.transaction("airports").objectStore("airports");
objectStore.openCursor().onsuccess = function (event) {
var cursor = event.target.result;
if (cursor) {
feature.value.properties.flights = 0
feature.value.properties.airlines = [];
console.log("Name for SSN " + cursor.key + " is " + cursor.value.name);
cursor.continue();
}
else {
console.log("No more entries!");
}
};
walkDir(p, f => { readAI(f, features) });
console.log("Closing");
features.close();
console.log("End Traffic");
} catch (error) {
console.log(error);
}
}
function traverseDir(dir) {
var result = [];
fs.readdirSync(dir).forEach(file => {
let fullPath = path.join(dir, file);
if (fs.lstatSync(fullPath).isDirectory()) {
console.log(fullPath);
var children = traverseDir(fullPath);
result = result.concat(children);
} else {
console.log(fullPath);
result.push(fullPath);
}
});
return result;
}
function walkDir(dir, callback) {
fs.readdirSync(dir).forEach(f => {
try {
let dirPath = path.join(dir, f);
let isDirectory = fs.statSync(dirPath).isDirectory();
isDirectory ?
walkDir(dirPath, callback) : callback(path.join(dir, f));
} catch (error) {
console.error(error);
}
});
}
function readAI(f, apts) {
try {
console.log(path.basename(f));
// Reset
var airline = path.basename(f).match('([^.]+)');
if (airline == null)
return;
var xmlSource = fs.readFileSync(f, 'utf8').toString();
console.debug("read " + path.basename(f));
// var doc = new domParser().parseFromString(xmlSource );
// console.log("parsed ");
// var flights = xpath.select("/trafficlist/flight", doc);
// console.log("selected flight ");
// console.log(flights);
var dat = tXml(xmlSource);
// console.log(dat);
console.log(dat[0].children[0]);
var flightNodes = dat[0].children[0].children.filter(e => e.tagName === 'flight');
flightNodes = tXml.simplify(flightNodes);
console.log(flightNodes.flight);
console.log("Departure flights " + flightNodes.flight.length);
var merged = new Array();
flightNodes.flight.map(n => {
merged.push(n.departure.port);
merged.push(n.arrival.port);
}).sort();
var counts = {};
for (var i = 0; i < merged.length; i++) {
counts[merged[i]] = 1 + (counts[merged[i]] || 0);
}
for (var key in counts) {
store(key, airline[0], counts[key]);
}
// var flights = xpath.select("/trafficlist/flight/departure/port/text()", doc);
// console.log(nodes);
// console.log(nodes);
// nodes = xpath.select("/trafficlist/flight/arrival/port/text()", doc);
// console.log(nodes);
} catch (error) {
console.error(error);
}
}
/**
* Store airline info into DB
* @param {*} icao
* @param {*} airline
* @param {*} value
*/
function store(icao, airline, value) {
var promise = new Promise(function (resolve, reject) {
console.log("Airport " + icao + " has " + value + " flights");
// Make a request to get a record by key from the object store
var transaction = features.transaction("airports", "readwrite");
var objectStore = transaction.objectStore("airports");
var objectStoreRequest = objectStore.get(icao);
objectStoreRequest.onsuccess = function (event) {
console.log(event);
var feature = objectStoreRequest.result;
if (!feature) {
feature = createFeature(icao);
}
feature.properties.flights += value;
console.log("Airline " + airline);
feature.properties.airlines.push(airline);
feature.properties.airlines.sort();
console.log("ICAO : " + feature.properties.icao + " Flights : " + feature.properties.flights);
// Create another request that inserts the item back into the database
var updateAirportRequest = objectStore.put(feature);
// Log the transaction that originated this request
console.log("The transaction that originated this request is " + updateAirportRequest);
// When this new request succeeds, run the displayData() function again to update the display
updateAirportRequest.onsuccess = function () {
console.log("Stored");
resolve();
};
updateAirportRequest.onerror = function (event) {
console.log("Error storing " + event);
reject(event);
};
};
objectStoreRequest.onerror = function (event) {
console.log("Error " + event);
reject(event);
};
});
return promise;
}
/**
* read a groundnet xml file
* @param {*} f
* @param {*} apts
*/
async function readGroundnet(f, features) {
var promise = new Promise(function (resolve, reject) {
try {
var filename = path.basename(f).match('^([^.]+)\\.([^.]+)\\.([^.]+)');
if (filename == null) {
resolve("File didn't match");
}
else {
console.log('Parsing ' + f);
fs.readFile(f, 'utf8', (err, data) => {
if (err) {
console.log('Error reading file ' + err);
reject(err);
}
console.log(data);
var dat = tXml.simplify(tXml(data));
console.log('Simplified ' + filename);
if (dat['?xml']) {
console.log("parsed " + f);
var transaction = features.transaction("airports", "readonly");
// report on the success of the transaction completing, when everything is done
transaction.oncomplete = function (event) {
console.log('Read Transaction complete ' + event);
};
transaction.onerror = function (event) {
console.log('Transaction error ' + event);
};
var objectStore = transaction.objectStore("airports");
var objectStoreRequest = objectStore.get(filename[1]);
objectStoreRequest.onsuccess = function (event) {
console.log(dat['?xml'].groundnet);
var feature = event.result;
console.log("Got Airport : " + feature);
if (!feature) {
feature = createFeature(filename[1]);
}
if (filename[2] == 'threshold') {
try {
console.log('threshold : ' + filename[1]);
var nodes = dat['?xml'].PropertyList.runway;
if (nodes.threshold == 0) {
console.log("No Runway");
resolve();
}
nodes.forEach(r => {
var lat1 = parseFloat(r.threshold[0].lat);
var lon1 = parseFloat(r.threshold[0].lon);
var lat2 = parseFloat(r.threshold[1].lat);
var lon2 = parseFloat(r.threshold[1].lon);
if (!feature.geometry.coordinates) {
feature.geometry.coordinates = [mean(lon1, lon2), mean(lat1, lat2)];
console.log(feature.geometry.coordinates);
}
});
feature.properties['threshold'] = true;
} catch (error) {
console.log(error);
}
} else if (filename[2] == 'twr') {
try {
console.log('twr : ' + filename[1]);
var nodes = dat['?xml'].PropertyList.tower.twr;
if (nodes.length == 0) {
console.log("No Tower");
resolve();
}
var lat = parseFloat(nodes.lat);
var lon = parseFloat(nodes.lon);
feature.properties['twr'] = true;
feature.geometry.coordinates = [lon, lat];
} catch (error) {
console.log(error);
}
} else if (filename[2] == 'groundnet') {
console.log('groundnet : ' + filename[1]);
var nodes = dat['?xml'].groundnet.TaxiNodes;
feature['properties']['groundnet'] = nodes ? true : false;
var nodes = dat['?xml'].groundnet.Parking;
feature['properties']['parking'] = nodes ? true : false;
} else if (filename[2] == 'ils') {
console.log('ils : ' + filename[1]);
if (dat['?xml'].PropertyList.runways) {
var nodes = dat['?xml'].PropertyList.runways.ils;
feature.properties['ils'] = nodes !== undefined;
}
}
var transaction = features.transaction("airports", "readwrite");
// report on the success of the transaction completing, when everything is done
transaction.oncomplete = function (event) {
console.log('Write Transaction complete ' + event);
resolve("Stored " + filename[1]);
};
transaction.onerror = function (event) {
console.log('Transaction error ' + event);
};
var objectStore = transaction.objectStore("airports");
var updateAirportRequest = objectStore.put(feature);
// Log the transaction that originated this request
console.log("The transaction that originated this request is " + updateAirportRequest.transaction);
// When this new request succeeds, run the displayData() function again to update the display
updateAirportRequest.onsuccess = function () {
console.log("Stored");
};
updateAirportRequest.onerror = function (event) {
console.log("Error storing " + event);
reject(event);
};
}
objectStoreRequest.onerror = function (event) {
console.log("Read Errpr : " + event);
resolve(event);
}
}
else {
resolve('No root');
}
});
}
} catch (error) {
console.error(error);
reject(error);
}
});
return promise;
}
function createFeature(icao) {
return {
"type": "Feature",
'properties': { 'icao': icao, 'twr': false, 'threshold': false, 'flights': 0, airlines: [] },
'geometry': {
"type": "Point"
}
};
}
function mean(coord1, coord2) {
return (coord1 + coord2) / 2;
}
// export default { scanAPT, scanTraffic, scanGroundnet }

View File

@ -0,0 +1,81 @@
/* eslint-disable */
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/src/renderer/utils/`
: `file://D:/GIT/flightgear-airports/src/renderer/utils/`
var scanner = importScripts(`${winURL}scan.js`);
var apt = importScripts(`${winURL}apt.js`);
var path = require('path');
const fs = require('fs');
const homedir = require('os').homedir();
var airports = importScripts(`${winURL}airports.js`);
importScripts('../txml/tXml.min.js');
function errorReceiver(event) {
throw event.data;
}
onmessage = function (event) {
postMessage('scanStarted');
console.log(event.data);
if (event.data === 'scan') {
scanGroundnet().then(result => {
console.log("DONE Scanning");
postMessage('DONE', 'this');
// event.origin.webContents.send('scanFinished');
}
).catch(result => {
console.log('Crashed');
console.log(result);
});
} else if (event.data === 'scanai') {
scanai().then(result => {
console.log("DONE Scanning");
postMessage('DONE');
// event.origin.webContents.send('scanFinished');
}
).catch(result => {
console.log('Crashed');
console.log(result);
});
}
else if (event.data === 'scanapt') {
scanAPT().then(result => {
console.log("DONE Scanning");
postMessage('DONE');
// event.origin.webContents.send('scanFinished');
}
).catch(result => {
console.log('Crashed');
console.log(result);
});
}
};
async function scanGroundnet() {
var promise = new Promise(function (resolve, reject) {
return initDB().then(features => {
var d = path.join(homedir, '/Documents/Flightgear/main/Airports/A');
scanGroundnetFiles(d, features);
});
});
return promise;
}
function scanai() {
return initDB().then(features => {
scanTrafficIntoDB("C:/GIT/fgmeta/fgdata/AI/Traffic", features);
});
}
async function scanAPT() {
return initDB().then(features => {
var d = path.join(homedir, 'Documents/apt.dat');
scanAPTIntoDB(d, features);
features.close();
console.log("Closed DB");
});
}