mirror of
https://github.com/MrTalon63/NeoMap.git
synced 2026-01-11 11:59:13 +01:00
POC
This commit is contained in:
parent
75ce77128e
commit
9f8406ae3e
8 changed files with 434 additions and 0 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -86,3 +86,5 @@ typings/
|
||||||
|
|
||||||
# DynamoDB Local files
|
# DynamoDB Local files
|
||||||
.dynamodb/
|
.dynamodb/
|
||||||
|
|
||||||
|
*.sqlite
|
||||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
FROM denoland/deno:alpine
|
||||||
|
EXPOSE 8000
|
||||||
|
WORKDIR /app
|
||||||
|
COPY deno.* .
|
||||||
|
COPY public ./public
|
||||||
|
COPY src ./src
|
||||||
|
RUN deno cache src/server.ts
|
||||||
|
RUN deno eval --unstable-ffi "import '@db/sqlite'"
|
||||||
|
CMD ["run", "-A", "src/server.ts"]
|
||||||
12
deno.json
Normal file
12
deno.json
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"tasks": {
|
||||||
|
"dev": "deno run --watch -A src/server.ts"
|
||||||
|
},
|
||||||
|
"imports": {
|
||||||
|
"@db/sqlite": "jsr:@db/sqlite@^0.12.0",
|
||||||
|
"@deno-library/compress": "jsr:@deno-library/compress@^0.5.5",
|
||||||
|
"@std/assert": "jsr:@std/assert@1",
|
||||||
|
"h3-js": "npm:h3-js@^4.1.0",
|
||||||
|
"hono": "npm:hono@^4.6.19"
|
||||||
|
}
|
||||||
|
}
|
||||||
149
deno.lock
generated
Normal file
149
deno.lock
generated
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
{
|
||||||
|
"version": "4",
|
||||||
|
"specifiers": {
|
||||||
|
"jsr:@db/sqlite@0.12": "0.12.0",
|
||||||
|
"jsr:@db/sqlite@0.12.0": "0.12.0",
|
||||||
|
"jsr:@deno-library/compress@~0.5.5": "0.5.5",
|
||||||
|
"jsr:@deno-library/crc32@1.0.2": "1.0.2",
|
||||||
|
"jsr:@denosaurs/plug@1": "1.0.6",
|
||||||
|
"jsr:@std/assert@0.217": "0.217.0",
|
||||||
|
"jsr:@std/assert@0.221": "0.221.0",
|
||||||
|
"jsr:@std/assert@1": "1.0.11",
|
||||||
|
"jsr:@std/bytes@^1.0.2": "1.0.4",
|
||||||
|
"jsr:@std/encoding@0.221": "0.221.0",
|
||||||
|
"jsr:@std/fmt@0.221": "0.221.0",
|
||||||
|
"jsr:@std/fs@0.221": "0.221.0",
|
||||||
|
"jsr:@std/fs@1.0.5": "1.0.5",
|
||||||
|
"jsr:@std/internal@^1.0.5": "1.0.5",
|
||||||
|
"jsr:@std/io@0.225.0": "0.225.0",
|
||||||
|
"jsr:@std/path@0.217": "0.217.0",
|
||||||
|
"jsr:@std/path@0.221": "0.221.0",
|
||||||
|
"jsr:@std/path@1.0.8": "1.0.8",
|
||||||
|
"jsr:@std/path@^1.0.7": "1.0.8",
|
||||||
|
"jsr:@std/streams@^1.0.7": "1.0.8",
|
||||||
|
"jsr:@std/tar@0.1.3": "0.1.3",
|
||||||
|
"jsr:@zip-js/zip-js@2.7.53": "2.7.53",
|
||||||
|
"npm:h3-js@*": "4.1.0",
|
||||||
|
"npm:h3-js@^4.1.0": "4.1.0",
|
||||||
|
"npm:hono@^4.6.19": "4.6.19"
|
||||||
|
},
|
||||||
|
"jsr": {
|
||||||
|
"@db/sqlite@0.12.0": {
|
||||||
|
"integrity": "dd1ef7f621ad50fc1e073a1c3609c4470bd51edc0994139c5bf9851de7a6d85f",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@denosaurs/plug",
|
||||||
|
"jsr:@std/path@0.217"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@deno-library/compress@0.5.5": {
|
||||||
|
"integrity": "18b651a33eac87d96ae8c941487045724a665d654e9d94120da43777393655d9",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@deno-library/crc32",
|
||||||
|
"jsr:@std/fs@1.0.5",
|
||||||
|
"jsr:@std/io",
|
||||||
|
"jsr:@std/path@1.0.8",
|
||||||
|
"jsr:@std/tar",
|
||||||
|
"jsr:@zip-js/zip-js"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@deno-library/crc32@1.0.2": {
|
||||||
|
"integrity": "d2061bfee30c87c97f285dfca0fdc4458e632dc072a33ecfc73ca5177a5a39a0"
|
||||||
|
},
|
||||||
|
"@denosaurs/plug@1.0.6": {
|
||||||
|
"integrity": "6cf5b9daba7799837b9ffbe89f3450510f588fafef8115ddab1ff0be9cb7c1a7",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/encoding",
|
||||||
|
"jsr:@std/fmt",
|
||||||
|
"jsr:@std/fs@0.221",
|
||||||
|
"jsr:@std/path@0.221"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/assert@0.217.0": {
|
||||||
|
"integrity": "c98e279362ca6982d5285c3b89517b757c1e3477ee9f14eb2fdf80a45aaa9642"
|
||||||
|
},
|
||||||
|
"@std/assert@0.221.0": {
|
||||||
|
"integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a"
|
||||||
|
},
|
||||||
|
"@std/assert@1.0.11": {
|
||||||
|
"integrity": "2461ef3c368fe88bc60e186e7744a93112f16fd110022e113a0849e94d1c83c1",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/internal"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/bytes@1.0.4": {
|
||||||
|
"integrity": "11a0debe522707c95c7b7ef89b478c13fb1583a7cfb9a85674cd2cc2e3a28abc"
|
||||||
|
},
|
||||||
|
"@std/encoding@0.221.0": {
|
||||||
|
"integrity": "d1dd76ef0dc5d14088411e6dc1dede53bf8308c95d1537df1214c97137208e45"
|
||||||
|
},
|
||||||
|
"@std/fmt@0.221.0": {
|
||||||
|
"integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a"
|
||||||
|
},
|
||||||
|
"@std/fs@0.221.0": {
|
||||||
|
"integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/assert@0.221",
|
||||||
|
"jsr:@std/path@0.221"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/fs@1.0.5": {
|
||||||
|
"integrity": "41806ad6823d0b5f275f9849a2640d87e4ef67c51ee1b8fb02426f55e02fd44e",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/path@^1.0.7"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/internal@1.0.5": {
|
||||||
|
"integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba"
|
||||||
|
},
|
||||||
|
"@std/io@0.225.0": {
|
||||||
|
"integrity": "c1db7c5e5a231629b32d64b9a53139445b2ca640d828c26bf23e1c55f8c079b3",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/bytes"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/path@0.217.0": {
|
||||||
|
"integrity": "1217cc25534bca9a2f672d7fe7c6f356e4027df400c0e85c0ef3e4343bc67d11",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/assert@0.217"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/path@0.221.0": {
|
||||||
|
"integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/assert@0.221"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@std/path@1.0.8": {
|
||||||
|
"integrity": "548fa456bb6a04d3c1a1e7477986b6cffbce95102d0bb447c67c4ee70e0364be"
|
||||||
|
},
|
||||||
|
"@std/streams@1.0.8": {
|
||||||
|
"integrity": "b41332d93d2cf6a82fe4ac2153b930adf1a859392931e2a19d9fabfb6f154fb3"
|
||||||
|
},
|
||||||
|
"@std/tar@0.1.3": {
|
||||||
|
"integrity": "531270fc707b37ab9b5f051aa4943e7b16b86905e0398a4ebe062983b0c93115",
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@std/streams"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"@zip-js/zip-js@2.7.53": {
|
||||||
|
"integrity": "acea5bd8e01feb3fe4c242cfbde7d33dd5e006549a4eb1d15283bc0c778ed672"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npm": {
|
||||||
|
"h3-js@4.1.0": {
|
||||||
|
"integrity": "sha512-LQhmMl1dRQQjMXPzJc7MpZ/CqPOWWuAvVEoVJM9n/s7vHypj+c3Pd5rLQCkAsOgAoAYKbNCsYFE++LF7MvSfCQ=="
|
||||||
|
},
|
||||||
|
"hono@4.6.19": {
|
||||||
|
"integrity": "sha512-Xw5DwU2cewEsQ1DkDCdy6aBJkEBARl5loovoL1gL3/gw81RdaPbXrNJYp3LoQpzpJ7ECC/1OFi/vn3UZTLHFEw=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"dependencies": [
|
||||||
|
"jsr:@db/sqlite@0.12",
|
||||||
|
"jsr:@deno-library/compress@~0.5.5",
|
||||||
|
"jsr:@std/assert@1",
|
||||||
|
"npm:h3-js@^4.1.0",
|
||||||
|
"npm:hono@^4.6.19"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
125
public/index.html
Normal file
125
public/index.html
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="pl">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>NepMap</title>
|
||||||
|
<style>
|
||||||
|
#map {
|
||||||
|
height: 80vh;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.filter-menu {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
z-index: 1000;
|
||||||
|
background: white;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.filter-group {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
|
||||||
|
<script src="https://unpkg.com/h3-js@4.1.0/dist/h3-js.umd.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="filter-menu">
|
||||||
|
<div class="filter-group">
|
||||||
|
<h3>Czas aktualizacji</h3>
|
||||||
|
<select id="timeFilter">
|
||||||
|
<option value="any">Dowolny czas</option>
|
||||||
|
<option value="3600">Ostatnia godzina</option>
|
||||||
|
<option value="86400">Ostatnie 24 godziny</option>
|
||||||
|
<option value="604800">Ostatnie 7 dni</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter-group">
|
||||||
|
<h3>Filtry sygnałów</h3>
|
||||||
|
<label><input type="checkbox" class="signal-filter" value="wifi" /> WiFi</label>
|
||||||
|
<label><input type="checkbox" class="signal-filter" value="ble" /> BLE</label>
|
||||||
|
<label><input type="checkbox" class="signal-filter" value="gsm" /> GSM</label>
|
||||||
|
<label><input type="checkbox" class="signal-filter" value="wcdma" /> WCDMA</label>
|
||||||
|
<label><input type="checkbox" class="signal-filter" value="lte" /> LTE</label>
|
||||||
|
<p style="color: #666; margin-top: 5px">(Zaznacz jakie sygnały mają być obecne)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="map"></div>
|
||||||
|
<script>
|
||||||
|
let currentMarkers = [];
|
||||||
|
const map = L.map("map").setView([50.3, 18.7], 13);
|
||||||
|
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||||
|
}).addTo(map);
|
||||||
|
generateHexes();
|
||||||
|
async function generateHexes() {
|
||||||
|
const req = await fetch("/api/v1/hexes");
|
||||||
|
const hexes = await req.json();
|
||||||
|
|
||||||
|
const timeFilter = document.getElementById("timeFilter").value;
|
||||||
|
const selectedSignals = Array.from(document.querySelectorAll(".signal-filter:checked")).map((x) => x.value);
|
||||||
|
|
||||||
|
currentMarkers.forEach((marker) => map.removeLayer(marker));
|
||||||
|
currentMarkers = [];
|
||||||
|
|
||||||
|
hexes.forEach((hex) => {
|
||||||
|
const isTimeValid = timeFilter === "any" || Date.now() / 1000 - hex.last_update < timeFilter;
|
||||||
|
const hasAllSignals = selectedSignals.every((signal) => hex[signal] === 1);
|
||||||
|
const isSignalValid = selectedSignals.length === 0 || hasAllSignals;
|
||||||
|
|
||||||
|
if (isTimeValid && isSignalValid) {
|
||||||
|
const latLngs = h3.cellToBoundary(hex.hex_id).map((coord) => [coord[0], coord[1]]);
|
||||||
|
const marker = L.polygon(latLngs, {
|
||||||
|
color: "#3388ff",
|
||||||
|
fillColor: getColorForSignals(hex),
|
||||||
|
fillOpacity: 0.2,
|
||||||
|
})
|
||||||
|
.bindPopup(
|
||||||
|
`
|
||||||
|
<div style="line-height: 1.5;">
|
||||||
|
<strong>H3 ID:</strong> ${hex.hex_id}<br>
|
||||||
|
<strong>Aktualizacja:</strong> ${new Date(hex.last_update * 1000).toLocaleString("PL")}<br>
|
||||||
|
<strong>Technologie:</strong><br>
|
||||||
|
<strong>WiFi:</strong> ${hex.wifi ? "Tak" : "Nie"}<br>
|
||||||
|
<strong>BLE:</strong> ${hex.ble ? "Tak" : "Nie"}<br>
|
||||||
|
<strong>GSM:</strong> ${hex.gsm ? "Tak" : "Nie"}<br>
|
||||||
|
<strong>WCDMA:</strong> ${hex.wcdma ? "Tak" : "Nie"}<br>
|
||||||
|
<strong>LTE:</strong> ${hex.lte ? "Tak" : "Nie"}<br>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
)
|
||||||
|
.addTo(map);
|
||||||
|
currentMarkers.push(marker);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSignalInfo(hex) {
|
||||||
|
return Object.entries(hex)
|
||||||
|
.filter(([key]) => ["wifi", "gsm", "lte"].includes(key))
|
||||||
|
.map(([key, value]) => `<b>${key.toUpperCase()}:</b> ${value ? "✓" : "✗"}<br>`)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColorForSignals(hex) {
|
||||||
|
const activeSignals = [hex.wifi && "#00ff00", hex.gsm && "#0000ff", hex.lte && "#ff0000"].filter(Boolean);
|
||||||
|
|
||||||
|
return activeSignals.length > 0 ? activeSignals[0] : "#3388ff";
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll("select, input").forEach((element) => {
|
||||||
|
element.addEventListener("change", generateHexes);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
4
src/db.ts
Normal file
4
src/db.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
import { Database } from "jsr:@db/sqlite@0.12.0";
|
||||||
|
|
||||||
|
export const db = await new Database("./neomap.sqlite");
|
||||||
|
db.prepare("CREATE TABLE IF NOT EXISTS hexes (hex_id TEXT PRIMARY KEY NOT NULL CHECK(hex_id GLOB '[0-9a-f]*'), wifi INTEGER DEFAULT 0 NOT NULL, gsm INTEGER DEFAULT 0 NOT NULL, wcdma INTEGER DEFAULT 0 NOT NULL, lte INTEGER DEFAULT 0 NOT NULL, ble INTEGER DEFAULT 0 NOT NULL, created_at INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL, last_update INTEGER DEFAULT (strftime('%s', 'now')) NOT NULL);").run();
|
||||||
94
src/server.ts
Normal file
94
src/server.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
import h3 from "npm:h3-js";
|
||||||
|
import { gunzip, gzip } from "@deno-library/compress";
|
||||||
|
import { Hono } from "hono";
|
||||||
|
import { serveStatic } from "hono/deno";
|
||||||
|
import { logger } from "hono/logger";
|
||||||
|
|
||||||
|
import { db } from "./db.ts";
|
||||||
|
import { Geosubmit } from "./types.d.ts";
|
||||||
|
|
||||||
|
const app = new Hono();
|
||||||
|
|
||||||
|
app.use(logger());
|
||||||
|
app.use("/", serveStatic({ root: "./public" }));
|
||||||
|
|
||||||
|
app.post("/api/v1/geosubmit", async (c) => {
|
||||||
|
const enconding = await c.req.header("Content-Encoding");
|
||||||
|
if (enconding !== "gzip") {
|
||||||
|
return c.json({ status: 400, message: "Bad Request" });
|
||||||
|
}
|
||||||
|
const body = await c.req.arrayBuffer();
|
||||||
|
|
||||||
|
const ftch = await fetch("https://api.beacondb.net/v2/geosubmit", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Content-Encoding": "gzip",
|
||||||
|
},
|
||||||
|
body: body,
|
||||||
|
});
|
||||||
|
if (ftch.status !== 200) {
|
||||||
|
return c.json({ status: ftch.status, message: "Bad Request" });
|
||||||
|
}
|
||||||
|
|
||||||
|
let json: Geosubmit;
|
||||||
|
const arr = new Uint8Array(body);
|
||||||
|
const data = await gunzip(arr);
|
||||||
|
json = JSON.parse(new TextDecoder().decode(data));
|
||||||
|
json.items.forEach((item) => {
|
||||||
|
const timestamp = Math.floor(item.timestamp / 1000);
|
||||||
|
const hex = h3.latLngToCell(item.position.latitude, item.position.longitude, 11);
|
||||||
|
let hasGsm = false,
|
||||||
|
hasWcdma = false,
|
||||||
|
hasLte = false,
|
||||||
|
hasWifi = false,
|
||||||
|
hasBle = false;
|
||||||
|
if (item.cellTowers) {
|
||||||
|
item.cellTowers.forEach((cell) => {
|
||||||
|
if (hasGsm && hasWcdma && hasLte) return;
|
||||||
|
if (cell.radioType === "gsm") hasGsm = true;
|
||||||
|
if (cell.radioType === "wcdma") hasWcdma = true;
|
||||||
|
if (cell.radioType === "lte") hasLte = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (item.wifiAccessPoints) {
|
||||||
|
item.wifiAccessPoints.forEach((wifi) => {
|
||||||
|
if (hasWifi) return;
|
||||||
|
hasWifi = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (item.bluetoothBeacons) {
|
||||||
|
item.bluetoothBeacons.forEach((ble) => {
|
||||||
|
if (hasBle) return;
|
||||||
|
hasBle = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isHexInDb = db.prepare("SELECT hex_id FROM hexes WHERE hex_id = ?").get(hex);
|
||||||
|
if (isHexInDb) {
|
||||||
|
db.prepare(
|
||||||
|
`
|
||||||
|
UPDATE hexes
|
||||||
|
SET
|
||||||
|
wifi = MAX(wifi, ?),
|
||||||
|
gsm = MAX(gsm, ?),
|
||||||
|
wcdma = MAX(wcdma, ?),
|
||||||
|
lte = MAX(lte, ?),
|
||||||
|
ble = MAX(ble, ?),
|
||||||
|
last_update = ?
|
||||||
|
WHERE hex_id = ?
|
||||||
|
`,
|
||||||
|
).run(hasWifi, hasGsm, hasWcdma, hasLte, hasBle, timestamp, hex);
|
||||||
|
} else {
|
||||||
|
db.prepare("INSERT INTO hexes (hex_id, wifi, gsm, wcdma, lte, ble, last_update) VALUES (?, ?, ?, ?, ?, ?, ?)").run(hex, hasWifi, hasGsm, hasWcdma, hasLte, hasBle, timestamp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return c.json({ status: 200, message: "OK" });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get("/api/v1/hexes", async (c) => {
|
||||||
|
const hexes = db.prepare("SELECT hex_id, wifi, gsm, wcdma, lte, ble, last_update FROM hexes").all();
|
||||||
|
return c.json(hexes);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.serve(app.fetch);
|
||||||
39
src/types.d.ts
vendored
Normal file
39
src/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
export type Geosubmit = {
|
||||||
|
items: {
|
||||||
|
timestamp: number;
|
||||||
|
position: {
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
accuracy: number;
|
||||||
|
age: number;
|
||||||
|
altitude: number;
|
||||||
|
altitudeAccuracy: number;
|
||||||
|
heading: number;
|
||||||
|
speed: number;
|
||||||
|
source: string;
|
||||||
|
};
|
||||||
|
cellTowers?: {
|
||||||
|
radioType: "gsm" | "wcdma" | "lte";
|
||||||
|
mobileCountryCode: number;
|
||||||
|
mobileNetworkCode: number;
|
||||||
|
age: number;
|
||||||
|
asu: number;
|
||||||
|
primaryScramblingCode: number;
|
||||||
|
serving: number;
|
||||||
|
signalStrength: number;
|
||||||
|
arfcn: number;
|
||||||
|
}[];
|
||||||
|
wifiAccessPoints?: {
|
||||||
|
macAddress: string;
|
||||||
|
signalStrength: number;
|
||||||
|
channel: number;
|
||||||
|
ssid: string;
|
||||||
|
}[];
|
||||||
|
bluetoothBeacons?: {
|
||||||
|
macAddress: string;
|
||||||
|
signalStrength: number;
|
||||||
|
age: number;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
Loading…
Add table
Reference in a new issue