It’s been five years since we started the Grijjy Blog!
Thank you to everyone who has taken the time to read our blog articles and use our code and examples. The articles on the site have been viewed over 250K times since we started from all over the world. I have spoken to many of you who have incorporated the Grijjy Foundation, into your own products for a variety of purposes.
The Grijjy team had no preconceived ideas about where this blog would take us when we started, but we have been blown away by the community response. We decided, from the beginning, to provide our source code and examples free of charge, without restrictions, even for commerical purposes.
Embarcadero invited the team to become MVP members during our first year, something we are very proud to be. Most importantly, we have had numerous conversations with community members on interesting topics related to Delphi which has evolved into a handful of customers for Grijjy which have kept us very busy including our largest project, Lumicademy.
In honor of our 5th anniversary we are providing a new blog article on building geolocation in Delphi.
Build your own Geolocation
Since we build scalable backend services that run in the cloud, we frequently get requests about how to handle geolocation and geotargetting. If you distribute backend services in the cloud you need to provide a service that performs well for users regardless of their location on the planet. This means you need to consider where you distribute your services and how you might connect clients to those services that are running your application.
There are a variety of commerical geolocation services available that allow you to consume geolocation into your cloud services. Many of them expose an API that converts a given IP address into a location. The major cloud providers (like Amazon Web Services) offer these APIs. These services typically either charge a fee for this service or they limit the number of API requests you can perform. Additionally they may introduce overhead to your service that slows down your process while it waits for a response from the API service.
In this article we are going to discuss how you can build your own Geolocation service or Geotargetting API in Delphi for a fixed cost and without a dependency on a connected service provider on the Internet, and do these lookups in an efficient manner.
How we consume and use geolocation
Our application, Lumicademy, is an example of this requirement. We need to quickly look up the endpoint location and direct a connecting user to a conference server that is regionally based. The conference servers operate as a mesh and can proxy communications with each other so ideally the user connects to a conference server that is regionally based to the user.
In addition to the API service providers for geolocation, there are a variety of companies that offer a large collection of TCP/IP ranges for a subscription fee. These companies update and maintain their database on a regular basis for you. All you have to do is subscribe and load the collection into a database of your choosing. One such company that I recommend is IP2Location. I have used their services in numerous products over the years to handle our geolocation needs and recommend you reach out to them for your needs.
Looking up IP address efficiently
The IP2Location main database contains currently around 10M lookup records that represent ranges of IP addresses. In addition to each range of IP addresses, there is a variety of options for additional data such as City, Country Code and Longitude and Latitude available to you, depending upon the database you acquire. For example:
Searching through a database of 10M records could be a time consuming process, depending upon your approach. To make things efficient, most of the services that provide a subscription database, convert IP addresses into an Int64 equivalent value using a simple formula,
function IP4AddrToNumber(const AIP4: String): Int64; var Octets: TArray<String>; function ToIP4(const A, B, C, D: Byte): Int64; begin Result := (A shl 24) + (B shl 16) + (C shl 8) + D; end; begin Octets := AIP4.Split(['.']); if Length(Octets) <> 4 then Exit(0); Result := ToIP4(Octets.ToInteger, Octets.ToInteger, Octets.ToInteger, Octets.ToInteger); end;
Once your given IP address is converted to an Int64 you can perform a query against the collection for a value that is greater-than-or-equal to the “IP_FROM” field and less-than-or-equal to the “IP_TO” value.
Note: To make this process even more efficient you could index the collection by the “IP_TO” field in ascending order and then query the “IP_TO” field for the first record in the collection that is greater-than the IP address you are searching. The first match will be the desired record.
Using Longitude and Latitude to measure distance
Once you know the Longitude and Latitude of a given IP address you can compare the Longitude and Latitude of a different IP address to determine an approximate distance between the 2 different IP addresses. For example,
function HaversineDist(const ALat1, ALong1, ALat2, ALong2: Double): Double; var D1, D2, D: Double; begin D1 := Abs(ALat1 - ALat2); D2 := Abs(ALong1 - ALong2); D := Sqrt(Sqr(D1) + Sqr(D2)); Result := D * (111120 * 0.946); end;
The above example is only a rough estimate of the distance, but it good enough for our purposes and most scenarios. You could get much more accurate by compensating for the curve of the earth while adjusting for the fact the earth is an irregularly shaped ellipsoid but that is probably just taking it too far.
Note: In most scenarios you are looking up the IP address of the client user that is connecting to your service. That is usually determined at the backend cloud service by examining the “peer” address of the remotely connected client and comparing it to the location of the server or cloud service provider location.
While geolocation and geotargetting does a good job of estimating location and distance, it’s not perfect. It is only as good as the database information and users can use VPNs to mask their true location. From experience these issues exists with all geolocation services, so creating your own should be on par with what you should expect from paid geolocation providers.
As you can see, it is really fairly easy to build your own geolocation logic to do this and without a concern that an offline geolocation provider prevents your customers from interacting properly with your cloud service.
As always, thank you for reading our blog articles and we are looking forward to many more years of Delphi related content to come!