X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=utils%2FTerraSync%2Fterrasync.cxx;h=7404530e1139bc93fa925c50629defee14fcf2f8;hb=c4ac013c42cadbe25e3b41bad6f0abbe85df11ef;hp=70ebf87aa6c5ce9862704a714630060821953b6a;hpb=12009ea6882d9eb8eb90a6fdabd2b59b2cfdeb9e;p=flightgear.git diff --git a/utils/TerraSync/terrasync.cxx b/utils/TerraSync/terrasync.cxx index 70ebf87aa..7404530e1 100644 --- a/utils/TerraSync/terrasync.cxx +++ b/utils/TerraSync/terrasync.cxx @@ -29,13 +29,23 @@ #include #endif +#ifdef __MINGW32__ +#include +#include +#elif defined(_MSC_VER) +#include +#endif #include // atoi() atof() abs() system() +#include // signal() #include #include +#include #include +#include +#include #include #include @@ -54,9 +64,7 @@ # endif #endif -using std::string; -using std::cout; -using std::endl; +using namespace std; const char* source_base = NULL; const char* svn_base = @@ -75,32 +83,51 @@ const char* svn_cmd = "svn checkout"; // display usage static void usage( const string& prog ) { - cout << "Usage: " << endl - << prog << " -p " - << "-R [ -s ] -d " << endl - << prog << " -p " - << "-S [ -s ] -d " << endl; + cout << +"Usage: terrasync [options]\n" +"Options: \n" +" -d destination directory [required]\n" +" -R transport using pipe to rsync\n" +" -S transport using built-in svn\n" +" -p listen on UDP port [default: 5501]\n" +" -s source base [default: '']\n" +" -pid write PID to file\n" +" -v be more verbose\n" +; + #ifdef HAVE_SVN_CLIENT_H cout << " (defaults to the built in subversion)" << endl; #else cout << " (defaults to rsync, using external commands)" << endl; #endif + + cout << "\nExample:\n" +"pid=$(cat $pidfile 2>/dev/null)\n" +"if test -n \"$pid\" && kill -0 $pid ; then\n" +" echo \"terrasync already running: $pid\"\n" +"else\n" +" nice /games/sport/fgs/utils/TerraSync/terrasync \\\n" +" -v -pid $pidfile -S -p 5500 -d /games/orig/terrasync &\n" +"fi" << endl; + } +deque waitingTiles; +typedef map CompletedTiles; +CompletedTiles completedTiles; +netSocket theSocket; + #ifdef HAVE_SVN_CLIENT_H // Things we need for doing subversion checkout - often apr_pool_t *mysvn_pool = NULL; svn_client_ctx_t *mysvn_ctx = NULL; svn_opt_revision_t *mysvn_rev = NULL; +svn_opt_revision_t *mysvn_rev_peg = NULL; static const svn_version_checklist_t mysvn_checklist[] = { { "svn_subr", svn_subr_version }, { "svn_client", svn_client_version }, - { "svn_wc", svn_wc_version }, - { "svn_ra", svn_ra_version }, - { "svn_delta", svn_delta_version }, - { "svn_diff", svn_diff_version }, { NULL, NULL } }; @@ -110,6 +137,9 @@ int mysvn_setup(void) { if (mysvn_pool) return EXIT_SUCCESS; // No, so initialize svn internals generally #ifdef _MSC_VER + // there is a segfault when providing an error stream. + // Apparently, calling setvbuf with a nul buffer is + // not supported under msvc 7.1 ( code inside svn_cmdline_init ) if (svn_cmdline_init("terrasync", 0) != EXIT_SUCCESS) return EXIT_FAILURE; #else @@ -153,11 +183,17 @@ int mysvn_setup(void) { mysvn_ctx->auth_baton = ab; mysvn_ctx->conflict_func = NULL; mysvn_ctx->conflict_baton = NULL; + // Now our magic revisions mysvn_rev = (svn_opt_revision_t*) apr_palloc(pool, sizeof(svn_opt_revision_t)); if (!mysvn_rev) return EXIT_FAILURE; + mysvn_rev_peg = (svn_opt_revision_t*) apr_palloc(pool, + sizeof(svn_opt_revision_t)); + if (!mysvn_rev_peg) + return EXIT_FAILURE; mysvn_rev->kind = svn_opt_revision_head; + mysvn_rev_peg->kind = svn_opt_revision_unspecified; // Success if we got this far mysvn_pool = pool; return EXIT_SUCCESS; @@ -166,7 +202,7 @@ int mysvn_setup(void) { #endif // sync one directory tree -void sync_tree(char* dir) { +void sync_tree(const char* dir) { int rc; char command[512]; SGPath path( dest_base ); @@ -191,11 +227,14 @@ void sync_tree(char* dir) { if (mysvn_setup() != EXIT_SUCCESS) exit(1); apr_pool_t *subpool = svn_pool_create(mysvn_pool); - err = svn_client_checkout(NULL, + err = svn_client_checkout3(NULL, command, dest_base_dir, + mysvn_rev_peg, mysvn_rev, - 1, + svn_depth_infinity, + 0, + 0, mysvn_ctx, subpool); if (err) { @@ -230,9 +269,37 @@ void sync_tree(char* dir) { } } +#ifdef _MSC_VER +typedef void (__cdecl * sighandler_t)(int); +#elif defined( __APPLE__ ) +typedef sig_t sighandler_t; +#endif + +bool terminating = false; +sighandler_t prior_signal_handlers[32]; +int termination_triggering_signals[] = { +#ifndef _MSC_VER + SIGHUP, SIGINT, SIGQUIT, SIGKILL, +#else + SIGINT, SIGILL, SIGFPE, SIGSEGV, SIGTERM, SIGBREAK, SIGABRT, +#endif + 0}; // zero terminated + +void terminate_request_handler(int param) { + char msg[] = "\nReceived signal XX, intend to exit soon.\n" + "repeat the signal to force immediate termination.\n"; + msg[17] = '0' + param / 10; + msg[18] = '0' + param % 10; + write(1, msg, sizeof(msg) - 1); + terminating = true; + signal(param, prior_signal_handlers[param]); + theSocket.close(); +} + const int nowhere = -9999; + // parse message static void parse_message( const string &msg, int *lat, int *lon ) { double dlat, dlon; @@ -240,8 +307,14 @@ static void parse_message( const string &msg, int *lat, int *lon ) { // find GGA string and advance to start of lat string::size_type pos = text.find( "$GPGGA" ); + if ( pos == string::npos ) + { + *lat = nowhere; + *lon = nowhere; + return; + } string tmp = text.substr( pos + 7 ); - pos = text.find( "," ); + pos = tmp.find( "," ); tmp = tmp.substr( pos + 1 ); // cout << "-> " << tmp << endl; @@ -290,6 +363,8 @@ static void parse_message( const string &msg, int *lat, int *lon ) { // sync area static void sync_area( int lat, int lon ) { + if ( lat < -90 || lat > 90 || lon < -180 || lon > 180 ) + return; char NS, EW; int baselat, baselon; @@ -314,20 +389,19 @@ static void sync_area( int lat, int lon ) { } EW = 'w'; } else { - baselon = (int)(lon / 10) * 10; - EW = 'e'; - } - + baselon = (int)(lon / 10) * 10; + EW = 'e'; + } + const char* terrainobjects[3] = { "Terrain", "Objects", 0 }; - const char** tree; - char dir[512]; - - for (tree = &terrainobjects[0]; *tree; tree++) { - snprintf( dir, 512, "%s/%c%03d%c%02d/%c%03d%c%02d", - *tree, - EW, abs(baselon), NS, abs(baselat), - EW, abs(lon), NS, abs(lat) ); - sync_tree(dir); + + for (const char** tree = &terrainobjects[0]; *tree; tree++) { + char dir[512]; + snprintf( dir, 512, "%s/%c%03d%c%02d/%c%03d%c%02d", + *tree, + EW, abs(baselon), NS, abs(baselat), + EW, abs(lon), NS, abs(lat) ); + waitingTiles.push_back( dir ); } } @@ -360,11 +434,28 @@ static void sync_areas( int lat, int lon, int lat_dir, int lon_dir ) { } } +void getWaitingTile() { + while ( !waitingTiles.empty() ) { + CompletedTiles::iterator ii = + completedTiles.find( waitingTiles.front() ); + time_t now = time(0); + if ( ii == completedTiles.end() || ii->second + 600 < now ) { + sync_tree(waitingTiles.front().c_str()); + completedTiles[ waitingTiles.front() ] = now; + waitingTiles.pop_front(); + break; + } + waitingTiles.pop_front(); + } +} int main( int argc, char **argv ) { int port = 5501; - char host[256] = ""; // accept messages from anyone + char host[256] = "localhost"; bool testing = false; + bool do_checkout(true); + int verbose(0); + const char* pidfn = ""; // parse arguments int i = 1; @@ -372,6 +463,10 @@ int main( int argc, char **argv ) { if ( (string)argv[i] == "-p" ) { ++i; port = atoi( argv[i] ); + } else if ( string(argv[i]).find("-pid") == 0 ) { + ++i; + pidfn = argv[i]; + cout << "pidfn: " << pidfn << endl; } else if ( (string)argv[i] == "-s" ) { ++i; source_base = argv[i]; @@ -382,15 +477,33 @@ int main( int argc, char **argv ) { use_svn = false; } else if ( (string)argv[i] == "-S" ) { use_svn = true; + } else if ( (string)argv[i] == "-v" ) { + verbose++; } else if ( (string)argv[i] == "-T" ) { testing = true; + } else if ( (string)argv[i] == "-h" ) { + usage( argv[0] ); + exit(0); } else { + cerr << "Unrecognized verbiage '" << argv[i] << "'" << endl; usage( argv[0] ); exit(-1); } ++i; } + if (*pidfn) { + ofstream pidstream; + pidstream.open(pidfn); + if (!pidstream.good()) { + cerr << "Cannot open pid file '" << pidfn << "': "; + perror(0); + exit(2); + } + pidstream << getpid() << endl; + pidstream.close(); + } + // Use the appropriate default for the "-s" flag if (source_base == NULL) { if (use_svn) @@ -399,25 +512,15 @@ int main( int argc, char **argv ) { source_base = rsync_base; } - // We just want one grid square, no FGFS communications - if (testing) { - sync_areas( 37, -123, 0, 0 ); - exit(0); - } - // Must call this before any other net stuff netInit( &argc,argv ); - netSocket s; - - if ( ! s.open( false ) ) { // open a UDP socket + if ( ! theSocket.open( false ) ) { // open a UDP socket printf("error opening socket\n"); return -1; } - s.setBlocking( false ); - - if ( s.bind( host, port ) == -1 ) { + if ( theSocket.bind( host, port ) == -1 ) { printf("error binding to port %d\n", port); return -1; } @@ -429,20 +532,59 @@ int main( int argc, char **argv ) { int last_lat = nowhere; int last_lon = nowhere; bool recv_msg = false; - int synced_other = 0; - while ( true ) { - recv_msg = false; - while ( (len = s.recv(msg, maxlen, 0)) >= 0 ) { - msg[len] = '\0'; - recv_msg = true; + char synced_other; + if (do_checkout) { + for ( synced_other = 'K'; synced_other <= 'Z'; synced_other++ ) { + char dir[512]; + snprintf( dir, 512, "Airports/%c", synced_other ); + waitingTiles.push_back( dir ); + } + for ( synced_other = 'A'; synced_other <= 'J'; synced_other++ ) { + char dir[512]; + snprintf( dir, 512, "Airports/%c", synced_other ); + waitingTiles.push_back( dir ); + } + if ( use_svn ) { + waitingTiles.push_back( "Models" ); + } + } - parse_message( msg, &lat, &lon ); - cout << "pos in msg = " << lat << "," << lon << endl; + + for (int* sigp=termination_triggering_signals; *sigp; sigp++) { + prior_signal_handlers[*sigp] = + signal(*sigp, *terminate_request_handler); + if (verbose) cout << "Intercepted signal " << *sigp << endl; + } + + while ( !terminating ) { + // main loop + recv_msg = false; + if ( testing ) { + // No FGFS communications + lat = 37; + lon = -123; + recv_msg = (lat != last_lat) || (lon != last_lon); + } else { + if (verbose && waitingTiles.empty()) { + cout << "Idle; waiting for FlightGear position\n"; + } + theSocket.setBlocking(waitingTiles.empty()); + len = theSocket.recv(msg, maxlen, 0); + if (len >= 0) { + msg[len] = '\0'; + recv_msg = true; + if (verbose) cout << "recv length: " << len << endl; + parse_message( msg, &lat, &lon ); + } } if ( recv_msg ) { - if ( lat != last_lat || lon != last_lon ) { + // Ignore messages where the location does not change + if ( lat != last_lat || lon != last_lon ) { + cout << "pos in msg = " << lat << "," << lon << endl; + deque oldRequests; + oldRequests.swap( waitingTiles ); int lat_dir, lon_dir, dist; if ( last_lat == nowhere || last_lon == nowhere ) { lat_dir = lon_dir = 0; @@ -464,29 +606,26 @@ int main( int argc, char **argv ) { cout << "lat_dir = " << lat_dir << " " << "lon_dir = " << lon_dir << endl; sync_areas( lat, lon, lat_dir, lon_dir ); - } else if ( last_lat == nowhere || last_lon == nowhere ) { - cout << "Waiting for FGFS to finish startup" << endl; - } else { - switch (synced_other++) { - case 0: - sync_tree((char*) "Airports/K"); - break; - case 1: - sync_tree((char*) "Airports"); - break; - default: - cout << "Done non-tile syncs" << endl; - break; + while ( !oldRequests.empty() ) { + waitingTiles.push_back( oldRequests.front() ); + oldRequests.pop_front(); } - } + last_lat = lat; + last_lon = lon; + } + } - last_lat = lat; - last_lon = lon; - } + // No messages inbound, so process some pending work + else if ( !waitingTiles.empty() ) { + getWaitingTile(); + } + + else if ( testing ) { + terminating = true; + } else ulSleep( 1 ); - } // while true + } // while !terminating return 0; } -