add alfred support and dynamic map creation
|
@ -1,2 +1,3 @@
|
|||
build
|
||||
__pycache__
|
||||
.*.swp
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
## Installation
|
||||
```
|
||||
./install.sh
|
||||
systemctl enable uwsgi-ffmap
|
||||
systemctl enable uwsgi-tiles-links_and_routers
|
||||
systemctl enable uwsgi-tiles-hoods
|
||||
systemctl start uwsgi-ffmap
|
||||
systemctl start uwsgi-tiles-links_and_routers
|
||||
systemctl start uwsgi-tiles-hoods
|
||||
# Then apply NGINX Config
|
||||
```
|
||||
|
||||
## Debian Dependencies
|
||||
```
|
||||
apt-get install python python3 mongodb python3-requests python3-lxml python3-pip python3-flask python3-dateutil python3-numpy python3-scipy python-mapnik python3-pip uwsgi-plugin-python uwsgi-plugin-python3 nginx
|
||||
pip3 install pymongo
|
||||
git clone https://github.com/asdil12/tilelite
|
||||
cd tilelite
|
||||
python setup.py install
|
||||
```
|
||||
|
||||
## NGINX Config
|
||||
```
|
||||
...
|
||||
location / {
|
||||
include uwsgi_params;
|
||||
uwsgi_pass 127.0.0.1:3031;
|
||||
}
|
||||
|
||||
location /tiles/links_and_routers {
|
||||
include uwsgi_params;
|
||||
uwsgi_pass 127.0.0.1:3032;
|
||||
}
|
||||
|
||||
location /tiles/hoods {
|
||||
include uwsgi_params;
|
||||
uwsgi_pass 127.0.0.1:3033;
|
||||
}
|
||||
...
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
uwsgi_python3 -w ffmap.web.application:app --http-socket :9090 --catch-exceptions
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
|
||||
import socket
|
||||
import gzip
|
||||
|
|
|
@ -8,7 +8,7 @@ db = client.freifunk
|
|||
# create db indexes
|
||||
db.hoods.create_index([("position", "2dsphere")])
|
||||
|
||||
db.hoods.insert_many([
|
||||
hoods = [
|
||||
{
|
||||
"keyxchange_id": 1,
|
||||
"name": "default",
|
||||
|
@ -61,4 +61,7 @@ db.hoods.insert_many([
|
|||
"name": "HassbergeSued",
|
||||
"net": "10.50.60.0/22",
|
||||
"position": {"type": "Point", "coordinates": [10.568013390003, 50.08]}
|
||||
}])
|
||||
}]
|
||||
|
||||
for hood in hoods:
|
||||
db.hoods.insert_one(hood)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import routers
|
||||
import chipsets
|
||||
import hoods
|
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from pymongo import MongoClient
|
||||
client = MongoClient()
|
||||
|
||||
db = client.freifunk
|
||||
|
||||
# create db indexes
|
||||
db.routers.create_index("status")
|
||||
db.routers.create_index("last_contact")
|
||||
db.routers.create_index("netifs.mac")
|
||||
db.routers.create_index([("position", "2dsphere")])
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from pymongo import MongoClient
|
||||
|
||||
class FreifunkDB(object):
|
||||
client = None
|
||||
db = None
|
||||
|
||||
@classmethod
|
||||
def handle(cls):
|
||||
if not cls.client:
|
||||
cls.client = MongoClient()
|
||||
if not cls.db:
|
||||
cls.db = cls.client.freifunk
|
||||
return cls.db
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/' + '..'))
|
||||
|
||||
from ffmap.dbtools import FreifunkDB
|
||||
|
||||
import math
|
||||
import numpy as np
|
||||
from scipy.spatial import Voronoi
|
||||
|
||||
db = FreifunkDB().handle()
|
||||
|
||||
CONFIG = {
|
||||
"csv_dir": "/var/lib/ffmap/csv"
|
||||
}
|
||||
|
||||
def touch(fname, times=None):
|
||||
with open(fname, 'a'):
|
||||
os.utime(fname, times)
|
||||
|
||||
def update_mapnik_csv():
|
||||
with open(os.path.join(CONFIG["csv_dir"], "routers.csv"), "w") as csv:
|
||||
csv.write("lng,lat,status\n")
|
||||
for router in db.routers.find({"position.coordinates": {"$exists": True}}):
|
||||
csv.write("%f,%f,%s\n" % (
|
||||
router["position"]["coordinates"][0],
|
||||
router["position"]["coordinates"][1],
|
||||
router["status"]
|
||||
))
|
||||
|
||||
with open(os.path.join(CONFIG["csv_dir"], "links.csv"), "w") as csv:
|
||||
csv.write("WKT,quality\n")
|
||||
for router in db.routers.find({"position.coordinates": {"$exists": True}, "neighbours": {"$exists": True}}):
|
||||
for neighbour in router["neighbours"]:
|
||||
if "position" in neighbour:
|
||||
csv.write("\"LINESTRING (%f %f,%f %f)\",%i\n" % (
|
||||
router["position"]["coordinates"][0],
|
||||
router["position"]["coordinates"][1],
|
||||
neighbour["position"]["coordinates"][0],
|
||||
neighbour["position"]["coordinates"][1],
|
||||
neighbour["quality"]
|
||||
))
|
||||
|
||||
with open(os.path.join(CONFIG["csv_dir"], "hood-points.csv"), "w", encoding="UTF-8") as csv:
|
||||
csv.write("lng,lat,name\n")
|
||||
for hood in db.hoods.find({"position": {"$exists": True}}):
|
||||
csv.write("%f,%f,\"%s\"\n" % (
|
||||
hood["position"]["coordinates"][0],
|
||||
hood["position"]["coordinates"][1],
|
||||
hood["name"]
|
||||
))
|
||||
|
||||
with open(os.path.join(CONFIG["csv_dir"], "hoods.csv"), "w") as csv:
|
||||
EARTH_RADIUS = 6378137.0
|
||||
|
||||
def merc_sphere(lng, lat):
|
||||
x = math.radians(lng) * EARTH_RADIUS
|
||||
y = math.log(math.tan(math.pi/4 + math.radians(lat)/2)) * EARTH_RADIUS
|
||||
return (x,y)
|
||||
|
||||
def merc_sphere_inv(x, y):
|
||||
lng = math.degrees(x / EARTH_RADIUS)
|
||||
lat = math.degrees(2*math.atan(math.exp(y / 6378137.0)) - math.pi/2)
|
||||
return (lng,lat)
|
||||
|
||||
csv.write("WKT\n")
|
||||
hoods = []
|
||||
for hood in db.hoods.find({"position": {"$exists": True}}):
|
||||
# convert coordinates info marcator sphere as voronoi doesn't work with lng/lat
|
||||
x, y = merc_sphere(hood["position"]["coordinates"][0], hood["position"]["coordinates"][1])
|
||||
hoods.append([x, y])
|
||||
|
||||
points = np.array(hoods)
|
||||
vor = Voronoi(points)
|
||||
#mp = voronoi_plot_2d(vor)
|
||||
#mp.show()
|
||||
|
||||
lines = [vor.vertices[line] for line in vor.ridge_vertices if -1 not in line]
|
||||
|
||||
for line in lines:
|
||||
x = [line[0][0], line[1][0]]
|
||||
y = [line[0][1], line[1][1]]
|
||||
for i in range(len(x)-1):
|
||||
# convert mercator coordinates back into lng/lat
|
||||
lng1, lat1 = merc_sphere_inv(x[i], y[i])
|
||||
lng2, lat2 = merc_sphere_inv(x[i+1], y[i+1])
|
||||
csv.write("\"LINESTRING (%f %f,%f %f)\"\n" % (lng1, lat1, lng2, lat2))
|
||||
|
||||
ptp_bound = np.array(merc_sphere(180, 360))
|
||||
center = vor.points.mean(axis=0)
|
||||
|
||||
for pointidx, simplex in zip(vor.ridge_points, vor.ridge_vertices):
|
||||
simplex = np.asarray(simplex)
|
||||
if np.any(simplex < 0):
|
||||
i = simplex[simplex >= 0][0] # finite end Voronoi vertex
|
||||
|
||||
t = vor.points[pointidx[1]] - vor.points[pointidx[0]] # tangent
|
||||
t /= np.linalg.norm(t)
|
||||
n = np.array([-t[1], t[0]]) # normal
|
||||
|
||||
midpoint = vor.points[pointidx].mean(axis=0)
|
||||
direction = np.sign(np.dot(midpoint - center, n)) * n
|
||||
far_point = vor.vertices[i] + direction * ptp_bound.max()
|
||||
|
||||
# convert mercator coordinates back into lng/lat
|
||||
lng1, lat1 = merc_sphere_inv(vor.vertices[i,0], vor.vertices[i,1])
|
||||
lng2, lat2 = merc_sphere_inv(far_point[0], far_point[1])
|
||||
csv.write("\"LINESTRING (%f %f,%f %f)\"\n" % (lng1, lat1, lng2, lat2))
|
||||
|
||||
# touch mapnik XML files to trigger tilelite watcher
|
||||
touch("/usr/share/ffmap/hoods.xml")
|
||||
touch("/usr/share/ffmap/links_and_routers.xml")
|
|
@ -1,19 +1,22 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
|
||||
import netmon
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/' + '..'))
|
||||
|
||||
from ffmap.dbtools import FreifunkDB
|
||||
|
||||
import lxml.etree
|
||||
import datetime
|
||||
from pymongo import MongoClient
|
||||
import requests
|
||||
|
||||
client = MongoClient()
|
||||
db = client.freifunk
|
||||
db = FreifunkDB().handle()
|
||||
|
||||
CONFIG = {
|
||||
"vpn_netif": "fffVPN",
|
||||
}
|
||||
|
||||
def process_router_xml(mac, xml):
|
||||
def load_nodewatcher_xml(mac, xml):
|
||||
try:
|
||||
router = db.routers.find_one({"netifs.mac": mac.lower()})
|
||||
if router:
|
||||
|
@ -25,6 +28,7 @@ def process_router_xml(mac, xml):
|
|||
router_update = {
|
||||
"status": tree.xpath("/data/system_data/status/text()")[0],
|
||||
"hostname": tree.xpath("/data/system_data/hostname/text()")[0],
|
||||
"last_contact": datetime.datetime.utcnow(),
|
||||
"neighbours": [],
|
||||
"netifs": [],
|
||||
"system": {
|
||||
|
@ -118,14 +122,15 @@ def process_router_xml(mac, xml):
|
|||
if router:
|
||||
# keep hood up to date
|
||||
router_update["hood"] = db.hoods.find_one({"position": {"$near": {"$geometry": router["position"]}}})["name"]
|
||||
db.routers.update_one({"netifs.mac": mac.lower()}, {"$set": router_update, "$currentDate": {"last_contact": True}})
|
||||
db.routers.update_one({"netifs.mac": mac.lower()}, {"$set": router_update})
|
||||
else:
|
||||
# new router
|
||||
# fetch additional information from netmon as it is not yet contained in xml
|
||||
router_info = netmon.fetch_router_info(mac)
|
||||
router_info = netmon_fetch_router_info(mac)
|
||||
if router_info:
|
||||
# keep hood up to date
|
||||
router_update["hood"] = db.hoods.find_one({"position": {"$near": {"$geometry": router_info["position"]}}})["name"]
|
||||
router_update["events"] = []
|
||||
router_update.update(router_info)
|
||||
router_id = db.routers.insert_one(router_update).inserted_id
|
||||
status = router_update["status"]
|
||||
|
@ -133,7 +138,8 @@ def process_router_xml(mac, xml):
|
|||
if router:
|
||||
db.routers.update_one({"_id": router_id}, {"$set": {"status": "unknown"}})
|
||||
status = "unknown"
|
||||
finally:
|
||||
|
||||
if router_id:
|
||||
# fire events
|
||||
events = []
|
||||
try:
|
||||
|
@ -169,3 +175,66 @@ def process_router_xml(mac, xml):
|
|||
# calculate RRD statistics (rrdcache?)
|
||||
#FIXME: implementation
|
||||
pass
|
||||
|
||||
def detect_offline_routers():
|
||||
db.routers.update_many({
|
||||
"last_contact": {"$lt": datetime.datetime.utcnow() - datetime.timedelta(minutes=10)},
|
||||
"status": {"$ne": "offline"}
|
||||
}, {
|
||||
"$set": {"status": "offline"},
|
||||
"$push": {"events": {
|
||||
"$each": [{
|
||||
"time": datetime.datetime.utcnow(),
|
||||
"type": "offline"
|
||||
}],
|
||||
"$slice": -10
|
||||
}}
|
||||
})
|
||||
|
||||
def netmon_fetch_router_info(mac):
|
||||
mac = mac.replace(":", "").lower()
|
||||
tree = lxml.etree.fromstring(requests.get("https://netmon.freifunk-franken.de/api/rest/router/%s" % mac, params={"limit": 5000}).content)
|
||||
|
||||
for r in tree.xpath("/netmon_response/router"):
|
||||
user_netmon_id = int(r.xpath("user_id/text()")[0])
|
||||
user = db.users.find_one({"netmon_id": user_netmon_id})
|
||||
if user:
|
||||
user_id = user["_id"]
|
||||
else:
|
||||
user_id = db.users.insert({
|
||||
"netmon_id": user_netmon_id,
|
||||
"nickname": r.xpath("user/nickname/text()")[0]
|
||||
})
|
||||
user = db.users.find_one({"_id": user_id})
|
||||
|
||||
router = {
|
||||
"netmon_id": int(r.xpath("router_id/text()")[0]),
|
||||
"user": {"nickname": user["nickname"], "_id": user["_id"]}
|
||||
}
|
||||
|
||||
try:
|
||||
lng = float(r.xpath("longitude/text()")[0])
|
||||
lat = float(r.xpath("latitude/text()")[0])
|
||||
assert lng != 0
|
||||
assert lat != 0
|
||||
|
||||
router["position"] = {
|
||||
"type": "Point",
|
||||
"coordinates": [lng, lat]
|
||||
}
|
||||
|
||||
# try to get comment
|
||||
position_comment = r.xpath("location/text()")[0]
|
||||
if position_comment != "undefined":
|
||||
router["position"]["comment"] = position_comment
|
||||
except (IndexError, AssertionError):
|
||||
pass
|
||||
|
||||
try:
|
||||
router["description"] = r.xpath("description/text()")[0]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
router["created"] = datetime.datetime.utcnow()
|
||||
|
||||
return router
|
|
@ -1,6 +1,8 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
|
||||
import nodewatcher
|
||||
from ffmap.routertools import *
|
||||
from ffmap.maptools import *
|
||||
from ffmap.dbtools import FreifunkDB
|
||||
|
||||
from flask import Blueprint, request, make_response
|
||||
from pymongo import MongoClient
|
||||
|
@ -9,8 +11,7 @@ import json
|
|||
|
||||
api = Blueprint("api", __name__)
|
||||
|
||||
client = MongoClient()
|
||||
db = client.freifunk
|
||||
db = FreifunkDB().handle()
|
||||
|
||||
@api.route('/get_nearest_router')
|
||||
def get_nearest_router():
|
||||
|
@ -31,9 +32,12 @@ def alfred():
|
|||
r = make_response(json.dumps(set_alfred_data))
|
||||
if request.method == 'POST':
|
||||
alfred_data = request.get_json()
|
||||
# load router status xml data
|
||||
for mac, xml in alfred_data.get("64", {}).items():
|
||||
nodewatcher.process_router_xml(mac, xml)
|
||||
r.headers['X-API-STATUS'] = "ALFRED data imported"
|
||||
if alfred_data:
|
||||
# load router status xml data
|
||||
for mac, xml in alfred_data.get("64", {}).items():
|
||||
load_nodewatcher_xml(mac, xml)
|
||||
r.headers['X-API-STATUS'] = "ALFRED data imported"
|
||||
detect_offline_routers()
|
||||
update_mapnik_csv()
|
||||
r.mimetype = 'application/json'
|
||||
return r
|
|
@ -1,10 +1,14 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
|
||||
from api import api
|
||||
from filters import filters
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/' + '../..'))
|
||||
|
||||
from ffmap.web.api import api
|
||||
from ffmap.web.filters import filters
|
||||
from ffmap.dbtools import FreifunkDB
|
||||
|
||||
from flask import Flask, render_template, request, make_response
|
||||
from pymongo import MongoClient
|
||||
from bson.json_util import dumps as bson2json
|
||||
from bson.objectid import ObjectId
|
||||
import json
|
||||
|
@ -13,12 +17,11 @@ app = Flask(__name__)
|
|||
app.register_blueprint(api, url_prefix='/api')
|
||||
app.register_blueprint(filters)
|
||||
|
||||
client = MongoClient()
|
||||
db = client.freifunk
|
||||
db = FreifunkDB().handle()
|
||||
|
||||
tileurls = {
|
||||
"links_and_routers": "http://localhost:8000",
|
||||
"hoods": "http://localhost:8001",
|
||||
"links_and_routers": "/tiles/links_and_routers",
|
||||
"hoods": "/tiles/hoods",
|
||||
}
|
||||
|
||||
@app.route('/')
|
||||
|
@ -43,5 +46,10 @@ def router_list():
|
|||
def router_info(dbid):
|
||||
return render_template("router.html", router=db.routers.find_one({"_id": ObjectId(dbid)}), tileurls=tileurls)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', debug=True)
|
||||
else:
|
||||
app.template_folder = "/usr/share/ffmap/templates"
|
||||
app.static_folder = "/usr/share/ffmap/static"
|
||||
#app.debug = True
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
|
||||
from flask import Blueprint
|
||||
from dateutil import tz
|
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 561 B |
Before Width: | Height: | Size: 518 B After Width: | Height: | Size: 518 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 592 B After Width: | Height: | Size: 592 B |
|
@ -52,8 +52,19 @@ map.on('click', function(pos) {
|
|||
if (px_distance <= router_pointer_radius) {
|
||||
console.log("Click on '"+router.hostname+"' detected.");
|
||||
console.log(router);
|
||||
var has_neighbours = 'neighbours' in router && router.neighbours.length > 0;
|
||||
var popup_html = "";
|
||||
var has_neighbours = 'neighbours' in router && router.neighbours.length > 0;
|
||||
|
||||
// avoid empty tables
|
||||
if (has_neighbours) {
|
||||
has_neighbours = false;
|
||||
for (neighbour of router.neighbours) {
|
||||
if ('_id' in neighbour) {
|
||||
has_neighbours = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_neighbours) {
|
||||
popup_html += "<div class=\"popup-headline with-neighbours\">";
|
||||
}
|
||||
|
@ -71,7 +82,7 @@ map.on('click', function(pos) {
|
|||
popup_html += "<th>Outgoing Interface</th>";
|
||||
popup_html += "</tr>";
|
||||
for (neighbour of router.neighbours) {
|
||||
// skip unknown neighbours (FIXME: avoid empty table)
|
||||
// skip unknown neighbours
|
||||
if ('_id' in neighbour) {
|
||||
var tr_color = "#04ff0a";
|
||||
if (neighbour.quality < 105) { tr_color = "#ff1e1e"; }
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -vp /var/lib/ffmap/csv
|
||||
#FIXME: create dummy csv files
|
||||
chown -R www-data:www-data /var/lib/ffmap
|
||||
|
||||
mkdir -vp /usr/share/ffmap
|
||||
cp -v mapnik/{hoods,links_and_routers}.xml /usr/share/ffmap
|
||||
sed -i -e 's#>csv/#>/var/lib/ffmap/csv/#' /usr/share/ffmap/{hoods,links_and_routers}.xml
|
||||
chown www-data:www-data /usr/share/ffmap/{hoods,links_and_routers}.xml
|
||||
cp -v wsgi/{hoods,links_and_routers,web}.wsgi /usr/share/ffmap
|
||||
cp -rv ffmap/web/static /usr/share/ffmap
|
||||
cp -rv ffmap/web/templates /usr/share/ffmap
|
||||
|
||||
mkdir -vp /var/cache/tiles/{hoods,links_and_routers}
|
||||
chown -R www-data:www-data /var/cache/tiles/
|
||||
|
||||
cp -v systemd/*.service /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
|
||||
python3 setup.py install
|
|
@ -1,58 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import lxml.etree
|
||||
import requests
|
||||
import datetime
|
||||
from pymongo import MongoClient
|
||||
|
||||
client = MongoClient()
|
||||
db = client.freifunk
|
||||
|
||||
def fetch_router_info(mac):
|
||||
mac = mac.replace(":", "").lower()
|
||||
tree = lxml.etree.fromstring(requests.get("https://netmon.freifunk-franken.de/api/rest/router/%s" % mac, params={"limit": 5000}).content)
|
||||
|
||||
for r in tree.xpath("/netmon_response/router"):
|
||||
user_netmon_id = int(r.xpath("user_id/text()")[0])
|
||||
user = db.users.find_one({"netmon_id": user_netmon_id})
|
||||
if user:
|
||||
user_id = user["_id"]
|
||||
else:
|
||||
user_id = db.users.insert({
|
||||
"netmon_id": user_netmon_id,
|
||||
"nickname": r.xpath("user/nickname/text()")[0]
|
||||
})
|
||||
user = db.users.find_one({"_id": user_id})
|
||||
|
||||
router = {
|
||||
"netmon_id": int(r.xpath("router_id/text()")[0]),
|
||||
"user": {"nickname": user["nickname"], "_id": user["_id"]}
|
||||
}
|
||||
|
||||
try:
|
||||
lng = float(r.xpath("longitude/text()")[0])
|
||||
lat = float(r.xpath("latitude/text()")[0])
|
||||
assert lng != 0
|
||||
assert lat != 0
|
||||
|
||||
router["position"] = {
|
||||
"type": "Point",
|
||||
"coordinates": [lng, lat]
|
||||
}
|
||||
|
||||
# try to get comment
|
||||
position_comment = r.xpath("location/text()")[0]
|
||||
if position_comment != "undefined":
|
||||
router["position"]["comment"] = position_comment
|
||||
except (IndexError, AssertionError):
|
||||
pass
|
||||
|
||||
try:
|
||||
router["description"] = r.xpath("description/text()")[0]
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
router["last_contact"] = datetime.datetime.utcnow()
|
||||
router["created"] = datetime.datetime.utcnow()
|
||||
|
||||
return router
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="transparent">
|
||||
<Map background-color="transparent" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
|
||||
<Style name="hoodpoint">
|
||||
<Rule>
|
||||
<TextSymbolizer face-name="DejaVu Sans Book" size="12" fill="#1e42ff" halo-radius="2" text-transform="capitalize">[name]</TextSymbolizer>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE Map>
|
||||
<Map background-color="transparent">
|
||||
<Map background-color="transparent" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs">
|
||||
<Style name="routerpoint" filter-mode="first">
|
||||
<Rule>
|
||||
<Filter>([status] = 'online')</Filter>
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python3
|
||||
|
||||
import math
|
||||
import numpy as np
|
||||
|
@ -31,7 +31,7 @@ with open("csv/links.csv", "w") as csv:
|
|||
neighbour["quality"]
|
||||
))
|
||||
|
||||
with open("csv/hood-points.csv", "w") as csv:
|
||||
with open("csv/hood-points.csv", "w", encoding="UTF-8") as csv:
|
||||
csv.write("lng,lat,name\n")
|
||||
for hood in db.hoods.find({"position": {"$exists": True}}):
|
||||
csv.write("%f,%f,\"%s\"\n" % (
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
setup(
|
||||
name='ffmap',
|
||||
version='0.0.1',
|
||||
license='GPL',
|
||||
description='FF-MAP',
|
||||
author='Dominik Heidler',
|
||||
author_email='dominik@heidler.eu',
|
||||
url='http://github.com/asdil12/ff-map',
|
||||
#requires=['flask', 'flup'],
|
||||
packages=['ffmap', 'ffmap.web'],
|
||||
#scripts=['bin/aurbs'],
|
||||
#data_files=[
|
||||
# ('/etc', ['templates/aurbs.yml']),
|
||||
# ('/usr/share/aurbs/cfg', ['templates/gpg.conf']),
|
||||
# ('/usr/share/doc/aurbs', ['templates/lighttpd.conf.sample']),
|
||||
#],
|
||||
)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=FF-MAP Web UI
|
||||
After=syslog.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/uwsgi_python3 -s 127.0.0.1:3031 -w ffmap.web.application:app --master --processes 4 --enable-threads --uid www-data --gid www-data
|
||||
Restart=always
|
||||
KillSignal=SIGQUIT
|
||||
Type=notify
|
||||
StandardError=syslog
|
||||
NotifyAccess=all
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=FF-MAP Tiles: Hoods
|
||||
After=syslog.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/uwsgi_python -s 127.0.0.1:3033 --wsgi-file /usr/share/ffmap/hoods.wsgi --uid www-data --gid www-data --enable-threads
|
||||
Restart=always
|
||||
KillSignal=SIGQUIT
|
||||
Type=notify
|
||||
StandardError=syslog
|
||||
NotifyAccess=all
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,14 @@
|
|||
[Unit]
|
||||
Description=FF-MAP Tiles: Links and Routers
|
||||
After=syslog.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/uwsgi_python -s 127.0.0.1:3032 --wsgi-file /usr/share/ffmap/links_and_routers.wsgi --uid www-data --gid www-data --enable-threads
|
||||
Restart=always
|
||||
KillSignal=SIGQUIT
|
||||
Type=notify
|
||||
StandardError=syslog
|
||||
NotifyAccess=all
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
To setup TileLite on a production server using Apache and ModWSGI
|
||||
create a virtualhost or otherwise insert the WSGI configuration into
|
||||
your Apache configuration like so:
|
||||
|
||||
WSGIScriptAlias /<url> /path/to/this/tilelite.wsgi
|
||||
WSGIDaemonProcess <process name> user=<user> group=<group> processes=10 threads=1
|
||||
WSGIProcessGroup <process name>
|
||||
|
||||
* 'tilelite.wsgi' is the name of the simple python script below that associates the
|
||||
tilelite.Server instance with a Mapnik xml file. It can be named anything you like
|
||||
but should end with either a '.wsgi' or '.py' extension.
|
||||
|
||||
* <url> can be either be '/' (to mount the script at http://yourserver.com/) or it can be
|
||||
a path such as '/tiles' to mount the server at http://yourserver.com/tiles
|
||||
|
||||
* <process name> can be any unique name like 'tileliteserver'
|
||||
|
||||
* <user> and <group> should be a unix user that has permissions to the 'tilelite.wsgi'
|
||||
|
||||
* Note: this is a multiprocess (not threaded) server so you *can* set 'processes' >= 1
|
||||
but threads *must be* == 1, otherwise this server will not work within Apache.
|
||||
|
||||
An example setup would be:
|
||||
|
||||
## TileLite sample setup ##
|
||||
WSGIScriptAlias /tiles /home/mapnik/projects/tilelite/tilelite.wsgi
|
||||
WSGIDaemonProcess tileliteserver user=www-data group=www-data processes=10 threads=1
|
||||
WSGIProcessGroup tileliteserver
|
||||
|
||||
Next, edit the script code below and place it where the WSGIScriptAlias path points to.
|
||||
|
||||
Then test your apache configuration and restart. On debian linux this might look like:
|
||||
|
||||
$ sudo apache2ctl configtest
|
||||
$ /etc/init.d/apache restart
|
||||
|
||||
Then go to:
|
||||
|
||||
http://yourserver.com/tiles/
|
||||
|
||||
"""
|
||||
|
||||
from tilelite import Server
|
||||
|
||||
options = {
|
||||
'watch_mapfile': True,
|
||||
'paletted': False,
|
||||
'cache_force': False,
|
||||
'format': 'png',
|
||||
'max_failures': 6,
|
||||
'max_zoom': 22,
|
||||
'debug': True,
|
||||
'cache_path': '/var/cache/tiles/hoods/',
|
||||
'watch_interval': 2,
|
||||
'caching': True,
|
||||
'buffer_size': 128,
|
||||
'size': 256
|
||||
}
|
||||
|
||||
# note: this variable must be called 'application'
|
||||
application = Server('/usr/share/ffmap/hoods.xml', options=options)
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
To setup TileLite on a production server using Apache and ModWSGI
|
||||
create a virtualhost or otherwise insert the WSGI configuration into
|
||||
your Apache configuration like so:
|
||||
|
||||
WSGIScriptAlias /<url> /path/to/this/tilelite.wsgi
|
||||
WSGIDaemonProcess <process name> user=<user> group=<group> processes=10 threads=1
|
||||
WSGIProcessGroup <process name>
|
||||
|
||||
* 'tilelite.wsgi' is the name of the simple python script below that associates the
|
||||
tilelite.Server instance with a Mapnik xml file. It can be named anything you like
|
||||
but should end with either a '.wsgi' or '.py' extension.
|
||||
|
||||
* <url> can be either be '/' (to mount the script at http://yourserver.com/) or it can be
|
||||
a path such as '/tiles' to mount the server at http://yourserver.com/tiles
|
||||
|
||||
* <process name> can be any unique name like 'tileliteserver'
|
||||
|
||||
* <user> and <group> should be a unix user that has permissions to the 'tilelite.wsgi'
|
||||
|
||||
* Note: this is a multiprocess (not threaded) server so you *can* set 'processes' >= 1
|
||||
but threads *must be* == 1, otherwise this server will not work within Apache.
|
||||
|
||||
An example setup would be:
|
||||
|
||||
## TileLite sample setup ##
|
||||
WSGIScriptAlias /tiles /home/mapnik/projects/tilelite/tilelite.wsgi
|
||||
WSGIDaemonProcess tileliteserver user=www-data group=www-data processes=10 threads=1
|
||||
WSGIProcessGroup tileliteserver
|
||||
|
||||
Next, edit the script code below and place it where the WSGIScriptAlias path points to.
|
||||
|
||||
Then test your apache configuration and restart. On debian linux this might look like:
|
||||
|
||||
$ sudo apache2ctl configtest
|
||||
$ /etc/init.d/apache restart
|
||||
|
||||
Then go to:
|
||||
|
||||
http://yourserver.com/tiles/
|
||||
|
||||
"""
|
||||
|
||||
from tilelite import Server
|
||||
|
||||
options = {
|
||||
'watch_mapfile': True,
|
||||
'paletted': False,
|
||||
'cache_force': False,
|
||||
'format': 'png',
|
||||
'max_failures': 6,
|
||||
'max_zoom': 22,
|
||||
'debug': True,
|
||||
'cache_path': '/var/cache/tiles/links_and_routers/',
|
||||
'watch_interval': 2,
|
||||
'caching': True,
|
||||
'buffer_size': 128,
|
||||
'size': 256
|
||||
}
|
||||
|
||||
# note: this variable must be called 'application'
|
||||
application = Server('/usr/share/ffmap/links_and_routers.xml', options=options)
|