14 changed files with 207 additions and 4 deletions
@ -0,0 +1,44 @@ |
|||||
|
import aiohttp |
||||
|
from pymongo.asynchronous.database import AsyncDatabase |
||||
|
|
||||
|
from logger import logger |
||||
|
from time import time |
||||
|
|
||||
|
class TileManager: |
||||
|
domain = 'a.tile.openstreetmap.org' |
||||
|
format = "png" |
||||
|
|
||||
|
def __init__(self, core): |
||||
|
self.core = core |
||||
|
self.dbStore:AsyncDatabase = self.core.dbStore |
||||
|
|
||||
|
def generateHeaders(self): |
||||
|
return { |
||||
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", |
||||
|
"Referer": "http://localhost:4200/", |
||||
|
"Accept": "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8" |
||||
|
} |
||||
|
|
||||
|
async def grabTile(self, z:int, x:int, y:int): |
||||
|
#grab from db |
||||
|
collection = self.dbStore['openstreetmap'] |
||||
|
query = {"x":x, "y":y, "z": z} |
||||
|
t = await collection.find_one(query) |
||||
|
if t: |
||||
|
return t["img"] |
||||
|
else: |
||||
|
#ищем картинку чтож поделать |
||||
|
url = f"https://{self.domain}/{z}/{x}/{y}.{self.format}" |
||||
|
async with aiohttp.ClientSession() as session: |
||||
|
async with session.get(url, ssl=False, headers=self.generateHeaders()) as resp: |
||||
|
# Read the entire response body as bytes |
||||
|
img = await resp.read() |
||||
|
logger.info(url, resp.status) |
||||
|
if resp.status == 200: |
||||
|
query['ts'] = time() |
||||
|
query['img'] = img |
||||
|
query['format'] = self.format |
||||
|
await collection.insert_one(query) |
||||
|
return img |
||||
|
else: |
||||
|
raise Exception("cannot get img") |
||||
@ -0,0 +1,69 @@ |
|||||
|
import {Component, OnInit} from "@angular/core"; |
||||
|
import * as L from 'leaflet'; |
||||
|
import {HttpClient} from "@angular/common/http"; |
||||
|
import {NodeDTO} from "../../entities/NodeDTO"; |
||||
|
import {Subscription} from "rxjs"; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: "app-nodes-map", |
||||
|
styleUrls: ['nodes.styles.scss'], |
||||
|
template: ` |
||||
|
<div style="width:80%"> |
||||
|
<div class="map-container"> |
||||
|
<div class="map-frame"> |
||||
|
<div id="map"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
` |
||||
|
}) |
||||
|
export class NodesMapComponent implements OnInit { |
||||
|
map!: L.Map; |
||||
|
nodes: NodeDTO[] = [] |
||||
|
|
||||
|
constructor(private http: HttpClient) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.http.get(`api/nodes/list?p=true`).subscribe( |
||||
|
(obj) => { |
||||
|
this.nodes = (obj as NodeDTO[]) |
||||
|
} |
||||
|
).add( |
||||
|
() => { |
||||
|
|
||||
|
this.createMap(this.convertPosition(this.nodes.filter((node) => node.havePosition).pop())).add( |
||||
|
() => { |
||||
|
this.nodes.filter((node) => node.havePosition).forEach( |
||||
|
(node) => { |
||||
|
L.marker(this.convertPosition(node)).addTo(this.map) |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
convertPosition(node:NodeDTO|undefined):[number, number] { |
||||
|
if (node) { |
||||
|
let lat = node.position.latitude_i / 10000000; |
||||
|
let lng = node.position.longitude_i / 10000000; |
||||
|
return [lat, lng]; |
||||
|
} else return [0,0]; |
||||
|
} |
||||
|
|
||||
|
createMap(center:[number, number]) { |
||||
|
this.map = L.map("map",{ |
||||
|
center: center, |
||||
|
zoom: 11 |
||||
|
}); |
||||
|
const tiles = L.tileLayer('api/tile/{z}/{x}/{y}.png', { |
||||
|
maxZoom: 18, |
||||
|
minZoom: 3, |
||||
|
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' |
||||
|
}); |
||||
|
tiles.addTo(this.map) |
||||
|
return Subscription.EMPTY; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
.map-container { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
margin: 30px; |
||||
|
} |
||||
|
|
||||
|
.map-frame { |
||||
|
border: 2px solid black; |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
#map { |
||||
|
height: 100%; |
||||
|
} |
||||
|
|
||||
|
:host ::ng-deep .leaflet-control-attribution { |
||||
|
display: none; |
||||
|
} |
||||
@ -1,7 +1,13 @@ |
|||||
import {NodeMiniDTO} from "./NodeMiniDTO"; |
import {NodeMiniDTO} from "./NodeMiniDTO"; |
||||
|
import {PositionDTO} from "./node/PositionDTO"; |
||||
|
import {DeviceMetricsDTO} from "./node/DeviceMetricsDTO"; |
||||
|
|
||||
export interface NodeDTO extends NodeMiniDTO { |
export interface NodeDTO extends NodeMiniDTO { |
||||
snr: number, |
snr: number, |
||||
hops_away: number, |
hops_away: number, |
||||
ts: number |
ts: number |
||||
|
havePosition:boolean, |
||||
|
position: PositionDTO, |
||||
|
haveMetrics:boolean, |
||||
|
device_metrics: DeviceMetricsDTO |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,7 @@ |
|||||
|
export interface DeviceMetricsDTO { |
||||
|
battery_level: number, |
||||
|
voltage: number, |
||||
|
channel_utilization: number, |
||||
|
air_util_tx: number, |
||||
|
uptime_seconds: number |
||||
|
} |
||||
@ -0,0 +1,6 @@ |
|||||
|
export interface PositionDTO { |
||||
|
latitude_i: number, |
||||
|
longitude_i: number, |
||||
|
time: number, |
||||
|
location_source: number |
||||
|
} |
||||
Loading…
Reference in new issue