diff --git a/brouter-server/src/main/java/btools/server/NearRecentWps.java b/brouter-server/src/main/java/btools/server/NearRecentWps.java new file mode 100644 index 0000000..7f33649 --- /dev/null +++ b/brouter-server/src/main/java/btools/server/NearRecentWps.java @@ -0,0 +1,75 @@ +package btools.server; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.TreeSet; + +import btools.router.OsmNodeNamed; +import btools.router.OsmTrack; +import btools.router.RoutingContext; +import btools.router.RoutingEngine; +import btools.server.request.ProfileUploadHandler; +import btools.server.request.RequestHandler; +import btools.server.request.ServerHandler; + +public class NearRecentWps +{ + private static OsmNodeNamed[] recentWaypoints = new OsmNodeNamed[2000]; + private static int nextRecentIndex = 0; + + public static void add( List wplist ) + { + synchronized( recentWaypoints ) + { + for( OsmNodeNamed wp : wplist ) + { + recentWaypoints[nextRecentIndex++] = wp; + if ( nextRecentIndex >= recentWaypoints.length ) + { + nextRecentIndex = 0; + } + } + } + } + + public static int count( long id ) + { + int cnt = 0; + int ilon = (int) ( id >> 32 ); + int ilat = (int) ( id & 0xffffffff ); + synchronized( recentWaypoints ) + { + for ( int i=0; i -29999 && dlat < 29999 && dlon > -39999 && dlon < 39999 ) + { + cnt++; + } + } + } + } + return cnt; + } +} diff --git a/brouter-server/src/main/java/btools/server/RouteServer.java b/brouter-server/src/main/java/btools/server/RouteServer.java index 130cf54..588957c 100644 --- a/brouter-server/src/main/java/btools/server/RouteServer.java +++ b/brouter-server/src/main/java/btools/server/RouteServer.java @@ -112,6 +112,12 @@ public class RouteServer extends Thread return; } } + else if ( url.startsWith( "/brouter/suspects" ) ) + { + writeHttpHeader(bw, "text/html"); + SuspectManager.process( url, bw ); + return; + } else { throw new IllegalArgumentException( "unknown request syntax: " + getline ); @@ -119,6 +125,11 @@ public class RouteServer extends Thread RoutingContext rc = handler.readRoutingContext(); List wplist = handler.readWayPointList(); + if ( wplist.size() < 10 ) + { + NearRecentWps.add( wplist ); + } + cr = new RoutingEngine( null, null, serviceContext.segmentDir, wplist, rc ); cr.quite = true; cr.doRun( maxRunningTime ); diff --git a/brouter-server/src/main/java/btools/server/SuspectManager.java b/brouter-server/src/main/java/btools/server/SuspectManager.java new file mode 100644 index 0000000..59635f4 --- /dev/null +++ b/brouter-server/src/main/java/btools/server/SuspectManager.java @@ -0,0 +1,298 @@ +package btools.server; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.StringTokenizer; +import java.util.TreeSet; + +public class SuspectManager extends Thread +{ + private static String formatAge( File f ) + { + long age = System.currentTimeMillis() - f.lastModified(); + long minutes = age / 60000; + if ( minutes < 60 ) + { + return minutes + " minutes"; + } + long hours = minutes / 60; + if ( hours < 24 ) + { + return hours + " hours"; + } + long days = hours / 24; + return days + " days"; + } + + private static String getLevelDecsription( int level ) + { + switch( level ) + { + case 30 : return "motorway"; + case 28 : return "trunk"; + case 26 : return "primary"; + case 24 : return "secondary"; + case 22 : return "tertiary"; + default: return "none"; + } + } + + public static void process( String url, BufferedWriter bw ) throws IOException + { + bw.write( "\n" ); + + StringTokenizer tk = new StringTokenizer( url, "/" ); + tk.nextToken(); + tk.nextToken(); + long id = 0L; + String country = null; + + if ( tk.hasMoreTokens() ) + { + String ctry = tk.nextToken(); + if ( new File( "suspects/suspects_" + ctry + ".txt" ).exists() ) + { + country = ctry; + } + } + if ( country == null ) // generate country list + { + File[] files = new File( "suspects" ).listFiles(); + TreeSet names = new TreeSet(); + for ( File f : files ) + { + String name = f.getName(); + if ( name.startsWith( "suspects_" ) && name.endsWith( ".txt" ) ) + { + names.add( name.substring( 9, name.length() - 4 ) ); + } + } + for ( String ctry : names ) + { + String url2 = "/brouter/suspects/" + ctry; + bw.write( "" + ctry + "
\n" ); + } + bw.write( "\n" ); + bw.flush(); + return; + } + + boolean showWatchList = false; + if ( tk.hasMoreTokens() ) + { + String t = tk.nextToken(); + if ( "watchlist".equals( t ) ) + { + showWatchList = true; + } + else + { + id = Long.parseLong( t ); + } + } + + if ( showWatchList ) + { + File suspects = new File( "suspects/suspects_" + country + ".txt" ); + bw.write( "watchlist for " + country + "\n" ); + bw.write( "
back to country list

\n" ); + if ( suspects.exists() ) + { + BufferedReader r = new BufferedReader( new FileReader( suspects ) ); + for ( ;; ) + { + String line = r.readLine(); + if ( line == null ) + break; + StringTokenizer tk2 = new StringTokenizer( line ); + id = Long.parseLong( tk2.nextToken() ); + String countryId = country + "/" + id; + + if ( new File( "falsepositives/" + id ).exists() ) + { + continue; // known false positive + } + File fixedEntry = new File( "fixedsuspects/" + id ); + File confirmedEntry = new File( "confirmednegatives/" + id ); + if ( !( fixedEntry.exists() && confirmedEntry.exists() ) ) + { + continue; + } + long age = System.currentTimeMillis() - confirmedEntry.lastModified(); + if ( age / 1000 < 3600 * 24 * 8 ) + { + continue; + } + String hint = "   confirmed " + formatAge( confirmedEntry ) + " ago"; + int ilon = (int) ( id >> 32 ); + int ilat = (int) ( id & 0xffffffff ); + double dlon = ( ilon - 180000000 ) / 1000000.; + double dlat = ( ilat - 90000000 ) / 1000000.; + String url2 = "/brouter/suspects/" + countryId; + bw.write( "" + dlon + "," + dlat + "" + hint + "
\n" ); + } + r.close(); + } + bw.write( "\n" ); + bw.flush(); + return; + } + + String message = null; + if ( tk.hasMoreTokens() ) + { + String command = tk.nextToken(); + if ( "falsepositive".equals( command ) ) + { + int wps = NearRecentWps.count( id ); + if ( wps < 8 ) + { + message = "marking false-positive requires at least 10 recent nearby waypoints from BRouter-Web, found: " + wps; + } + else + { + new File( "falsepositives/" + id ).createNewFile(); + id = 0L; + } + } + if ( "confirm".equals( command ) ) + { + int wps = NearRecentWps.count( id ); + if ( wps < 2 ) + { + message = "marking confirmed requires at least 2 recent nearby waypoints from BRouter-Web, found: " + wps; + } + else + { + new File( "confirmednegatives/" + id ).createNewFile(); + } + } + if ( "fixed".equals( command ) ) + { + new File( "fixedsuspects/" + id ).createNewFile(); + id = 0L; + } + } + if ( id != 0L ) + { + String countryId = country + "/" + id; + + int ilon = (int) ( id >> 32 ); + int ilat = (int) ( id & 0xffffffff ); + double dlon = ( ilon - 180000000 ) / 1000000.; + double dlat = ( ilat - 90000000 ) / 1000000.; + + String url1 = "http://brouter.de/brouter-web/#zoom=18&lat=" + dlat + "&lon=" + dlon + + "&layer=OpenStreetMap&lonlats=" + dlon + "," + dlat + "&profile=car-eco-de"; + + // String url1 = "http://localhost:8080/brouter-web/#map=18/" + dlat + "/" + // + dlon + "/Mapsforge Tile Server&lonlats=" + dlon + "," + dlat; + + String url2 = "https://www.openstreetmap.org/?mlat=" + dlat + "&mlon=" + dlon + "#map=19/" + dlat + "/" + dlon + "&layers=N"; + + double slon = 0.00156; + double slat = 0.001; + String url3 = "http://osmose.openstreetmap.fr/de/josm_proxy?load_and_zoom?left=" + ( dlon - slon ) + + "&bottom=" + ( dlat - slat ) + "&right=" + ( dlon + slon ) + "&top=" + ( dlat + slat ); + + if ( message != null ) + { + bw.write( "" + message + "

\n" ); + } + bw.write( "Open in BRouter-Web

\n" ); + bw.write( "Open in OpenStreetmap

\n" ); + bw.write( "Open in JOSM (via remote control)

\n" ); + File fixedEntry = new File( "fixedsuspects/" + id ); + if ( fixedEntry.exists() ) + { + bw.write( "

back to watchlist

\n" ); + } + else + { + bw.write( "mark false positive (=not an issue)

\n" ); + File confirmedEntry = new File( "confirmednegatives/" + id ); + if ( confirmedEntry.exists() ) + { + bw.write( "mark as fixed

\n" ); + } + else + { + bw.write( "mark as a confirmed issue

\n" ); + } + bw.write( "

back to issue list

\n" ); + } + } + else + { + File suspects = new File( "suspects/suspects_" + country + ".txt" ); + bw.write( "suspect list for " + country + "\n" ); + bw.write( "
see watchlist\n" ); + bw.write( "
back to country list

\n" ); + if ( suspects.exists() ) + { + int maxprio = 0; + for ( int pass = 1; pass <= 2; pass++ ) + { + if ( pass == 2 ) + { + bw.write( "current level: " + getLevelDecsription( maxprio ) + "

\n" ); + } + + BufferedReader r = new BufferedReader( new FileReader( suspects ) ); + for ( ;; ) + { + String line = r.readLine(); + if ( line == null ) + break; + StringTokenizer tk2 = new StringTokenizer( line ); + id = Long.parseLong( tk2.nextToken() ); + int prio = Integer.parseInt( tk2.nextToken() ); + prio = ( ( prio + 1 ) / 2 ) * 2; // normalize (no link prios) + String countryId = country + "/" + id; + + String hint = ""; + + if ( new File( "falsepositives/" + id ).exists() ) + { + continue; // known false positive + } + if ( new File( "fixedsuspects/" + id ).exists() ) + { + continue; // known fixed + } + if ( pass == 1 ) + { + if ( prio > maxprio ) + maxprio = prio; + continue; + } + else + { + if ( prio < maxprio ) + continue; + } + File confirmedEntry = new File( "confirmednegatives/" + id ); + if ( confirmedEntry.exists() ) + { + hint = "   confirmed " + formatAge( confirmedEntry ) + " ago"; + } + int ilon = (int) ( id >> 32 ); + int ilat = (int) ( id & 0xffffffff ); + double dlon = ( ilon - 180000000 ) / 1000000.; + double dlat = ( ilat - 90000000 ) / 1000000.; + String url2 = "/brouter/suspects/" + countryId; + bw.write( "" + dlon + "," + dlat + "" + hint + "
\n" ); + } + r.close(); + } + } + } + bw.write( "\n" ); + bw.flush(); + return; + } + +}