Example #1
0
        /// <summary>
        /// Initalizes the fix archiver instance.
        /// </summary>
        /// <param name="node">The parent <see cref="GeoTrackerNode" /> instance.</param>
        /// <param name="args">
        /// This implementation's settings come directly from the application
        /// configuration as described below.
        /// </param>
        /// <remarks>
        /// <note>
        /// <para>
        /// Note that some of the application log settings are loaded directly from the application's <b>LillTek.AppLog</b>
        /// configuration settings section as described in <see cref="AppLog" />.  The valid arguments passed to the
        /// <see cref="Start" /> are:
        /// </para>
        /// <list type="table">
        ///     <item>
        ///         <term><b>LogName</b></term>
        ///         <description>
        ///         The name of the application log.  This defaults to <b>GeoTrackerFixes</b>.
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term><b>MaxSize</b></term>
        ///         <description>
        ///         The approximate maximum size of the log on disk or zero for no limit.
        ///         This defaults to <b>5GB</b>.
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term><b>PurgeInterval</b></term>
        ///         <description>
        ///         The interval at which the log will purge old log files so that the
        ///         total log size remains within the <b>MaxSize</b> limit.
        ///         This defaults to <b>5 minutes</b>.
        ///         </description>
        ///     </item>
        /// </list>
        /// <see cref="IGeoFixArchiver" /> implementations must silently handle any internal
        /// error conditions.  <see cref="GeoTrackerNode" /> does not expect to see any
        /// exceptions raised from calls to any of these methods.  Implementations should
        /// catch any exceptions thrown internally and log errors or warnings as necessary.
        /// </note>
        /// </remarks>
        public void Start(GeoTrackerNode node, ArgCollection args)
        {
            lock (syncLock)
            {
                try
                {
                    if (this.logWriter != null)
                    {
                        throw new InvalidOperationException("AppLogGeoFixArchiver: Archiver has already been started.");
                    }

                    if (this.isStopped)
                    {
                        throw new InvalidOperationException("AppLogGeoFixArchiver: Cannot restart a stopped archiver.");
                    }

                    this.node                    = node;
                    this.logName                 = args.Get("LogName", "GeoTrackerFixes");
                    this.maxSize                 = args.Get("MaxSize", 5L * 1024L * 1024L * 1024L);
                    this.purgeInterval           = args.Get("PurgeInterval", TimeSpan.FromMinutes(5));
                    this.logWriter               = new AppLogWriter(logName, SchemaName, SchemaVersion, maxSize);
                    this.logWriter.PurgeInterval = purgeInterval;
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }
        }
Example #2
0
        /// <summary>
        /// Initalizes the fix archiver instance.
        /// </summary>
        /// <param name="node">The parent <see cref="GeoTrackerNode" /> instance.</param>
        /// <param name="args">This implementation recognizes special arguments (see the remarks).</param>
        /// <remarks>
        /// <para>
        /// This archiver recognizes the following arguments:
        /// </para>
        /// <list type="table">
        ///     <item>
        ///         <term><b>ConnectionString</b></term>
        ///         <description>
        ///         <b>Required:</b> This specifies the SQL connection string the archiver will use
        ///         to connect to the database server.
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term><b>BufferSize</b></term>
        ///         <description>
        ///         <b>Optional:</b> This specifies the number of fixes the archiver will buffer before
        ///         submitting the fixes to the database in a batch.  (defaults to <b>1000</b>).
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term><b>BufferInterval</b></term>
        ///         <description>
        ///         <b>Optional: </b> The maximum length of time the archiver will buffer fixes before
        ///         flushing to the database, regardless of how full thbe buffer is.  (defaults to <b>5 minutes</b>).
        ///         </description>
        ///     </item>
        ///     <item>
        ///         <term><b>AddScript</b></term>
        ///         <description>
        ///         <para>
        ///         The SQL script template the archiver will use for submitting fixes to the database.
        ///         This script will include macros where the archiver will substitute the values
        ///         from the <see cref="GeoFix" /> being persisted.  Here are the supported macros:
        ///         </para>
        ///         <list type="table">
        ///             <item>
        ///                 <term><b>@(TimeUtc)</b></term>
        ///                 <description>
        ///                 The time (UTC) the fix was taken.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(EntityID)</b></term>
        ///                 <description>
        ///                 The ID of the entity being tracked.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(GroupID)</b></term>
        ///                 <description>
        ///                 <b>Nullable:</b> The ID of the group the entity belongs to.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(Technology)</b></term>
        ///                 <description>
        ///                 The technology used to obtain the position.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(Latitude)</b></term>
        ///                 <description>
        ///                 The latitude.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(Longitude)</b></term>
        ///                 <description>
        ///                 The longitude.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(Altitude)</b></term>
        ///                 <description>
        ///                 <b>Nullable:</b> The altitude in meters.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(Course)</b></term>
        ///                 <description>
        ///                 <b>Nullable:</b> The direction of travel in degrees from true north.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(Speed)</b></term>
        ///                 <description>
        ///                 <b>Nullable:</b> The speed in kilometers per hour.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(HorizontalAccuracy)</b></term>
        ///                 <description>
        ///                 <b>Nullable:</b> The estimated horizontal accuracy of the fix in meters.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(VerticalAccurancy)</b></term>
        ///                 <description>
        ///                 <b>Nullable:</b> The estimated vertical accuracy of the fix in meters.
        ///                 </description>
        ///             </item>
        ///             <item>
        ///                 <term><b>@(NetworkStatus)</b></term>
        ///                 <description>
        ///                 Identifies how or if the entity was connected to the Internet when the fix was taken.
        ///                 </description>
        ///             </item>
        ///         </list>
        ///         <note>
        ///         We're using the <b>"@"</b> rather than the usual <b>"$"</b> character to mark the
        ///         macro name to avoid conflicting with environment variable expansions performed
        ///         when loading the application configuration.
        ///         </note>
        ///         </description>
        ///     </item>
        /// </list>
        /// <para>
        /// The most important archiver parameter is <b>AddScript</b>.  This is the template the archiver
        /// will use to generate the SQL statements that will add <see cref="GeoFix" />es to the database.
        /// The script can be as simple as an ad-hoc table <b>insert</b> or a call to a stored procedure.
        /// Add one or more of the macro identifiers listed above to the script.  The archiver will replace
        /// these macros with actual fields from the <see cref="GeoFix" />, quoting them as necessary.
        /// Null <see cref="GeoFix" /> fields or numeric fields set to <see cref="double.NaN" /> will
        /// be generated as <c>null</c>.  See the <b>Nullable</b> tags in the macro definitions above.
        /// </para>
        /// <para>
        /// Here's an exmple of a simple sample script that will insert the <see cref="GeoFix.TimeUtc" />,
        /// <b>entity ID</b>, <see cref="GeoFix.Latitude" />, and <see cref="GeoFix.Longitude" />
        /// <see cref="GeoFix" /> fields into a table.
        /// </para>
        /// <code language="none">
        /// insert into FixArchive(Time,Entity,Lat,Lon) values (@(TimeUtc),@(EntityID),@(Latitude),@(longitude))
        /// </code>
        /// <note>
        /// <see cref="IGeoFixArchiver" /> implementations must silently handle any internal
        /// error conditions.  <see cref="GeoTrackerNode" /> does not expect to see any
        /// exceptions raised from calls to any of these methods.  Implementations should
        /// catch any exceptions thrown internally and log errors or warnings as necessary.
        /// </note>
        /// </remarks>
        public void Start(GeoTrackerNode node, ArgCollection args)
        {
            lock (syncLock)
            {
                try
                {
                    if (isRunning)
                    {
                        throw new InvalidProgramException("SqlGeoFixArchiver: Archiver has already been started.");
                    }

                    if (isStopped)
                    {
                        throw new InvalidOperationException("SqlGeoFixArchiver: Cannot restart a stopped archiver.");
                    }

                    this.node           = node;
                    this.settings       = node.Settings;
                    this.bufferedFixes  = new List <FixRecord>();
                    this.conString      = args.Get("ConnectionString", string.Empty);
                    this.bufferSize     = args.Get("BufferSize", 1000);
                    this.bufferInterval = args.Get("BufferInterval", TimeSpan.FromMinutes(5));
                    this.addScript      = args.Get("AddScript", string.Empty).Replace("@(", "$(");

                    if (string.IsNullOrWhiteSpace(this.conString))
                    {
                        throw new ArgumentException("SqlGeoFixArchiver: The [ConnectionString] argument is required.");
                    }

                    if (string.IsNullOrWhiteSpace(this.addScript))
                    {
                        throw new ArgumentException("SqlGeoFixArchiver: The [AddScript] argument is required.");
                    }

                    this.isRunning   = true;
                    this.flushTimer  = new PolledTimer(bufferInterval, false);
                    this.flushThread = new Thread(new ThreadStart(FlushThread));
                    this.flushThread.Start();
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }
        }
Example #3
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="node">The parent GeoTracker node.</param>
        public MercatorIndex(GeoTrackerNode node)
        {
            // Initialize the top-level blocks.

            this.topLevelBlocks = new MercatorBlock[TopLevelColumnCount, TopLevelRowCount];

            for (int row = 0; row < TopLevelRowCount; row++)
            {
                for (int col = 0; col < TopLevelColumnCount; col++)
                {
                    var neCorner = new GeoCoordinate(90.0 - row * 10, -180.0 + (col + 1) * 10.0);
                    var swCorner = new GeoCoordinate(90.0 - (row + 1) * 10.0, -180.0 + col * 10.0);
                    var bounds   = new GeoRectangle(neCorner, swCorner);

                    topLevelBlocks[row, col] = new MercatorBlock(node.Settings, bounds, 0);
                }
            }
        }
Example #4
0
        /// <summary>
        /// Constructs the instance and starts the background downloading thread.
        /// </summary>
        /// <param name="node">The parent <see cref="GeoTrackerNode" /> instance.</param>
        /// <remarks>
        /// <note>
        /// The constructor will not start a background thread if IP geocoding is disabled.
        /// </note>
        /// </remarks>
        public IPGeocoder(GeoTrackerNode node)
        {
            settings = node.Settings;

            if (!settings.IPGeocodeEnabled)
            {
                return;
            }

            // Initialize the service including loading the MaxMind database if present.

            running     = true;
            stopPending = false;
            pollDataNow = false;
            maxMind     = null;

            try
            {
                if (File.Exists(dataPath))
                {
                    maxMind = new LookupService(dataPath, LookupService.GEOIP_MEMORY_CACHE);
                    maxMind.close();
                }
            }
            catch (Exception e)
            {
                // Assume that the database file is corrupted if there's an exception
                // and delete it so the download thread will download a new copy.

                SysLog.LogException(e);
                SysLog.LogError("GeoTracker: The MaxMind database file [{0}] appears to be corrupted.  This will be deleted so the downloader can get a fresh copy.", dataPath);

                Helper.DeleteFile(dataPath);
            }

            // Start the background downloader thread.

            downloadThread      = new Thread(new ThreadStart(DownloadThread));
            downloadThread.Name = "GeoTracker: GeoData Downloader";
            downloadThread.Start();
        }
Example #5
0
 /// <summary>
 /// Initalizes the fix archiver instance.
 /// </summary>
 /// <param name="node">The parent <see cref="GeoTrackerNode" /> instance.</param>
 /// <param name="args">This implementation defines no special arguments.</param>
 /// <remarks>
 /// <note>
 /// <see cref="IGeoFixArchiver" /> implementations must silently handle any internal
 /// error conditions.  <see cref="GeoTrackerNode" /> does not expect to see any
 /// exceptions raised from calls to any of these methods.  Implementations should
 /// catch any exceptions thrown internally and log errors or warnings as necessary.
 /// </note>
 /// </remarks>
 public void Start(GeoTrackerNode node, ArgCollection args)
 {
 }