Autobot is a microservice that provides a small API for looking up vehicle data by license plate, VIN number and possibly other vehicle master data.
The purpose of this service, which was developed for OmniCar A/S, is to provide a caching mechanism for vehicle lookups, which can be expensive as existing providers often charge a fee per lookup.
To further reduce the need for external lookups, a data synchronization service is included, which is currently integrated with DMR, the Danish Motor vehicle Registry. Others can be added fairly easily.
From the command line, assuming that you already have Go on your system:
go get github.com/mkock/autobot
cd /path/go/autobot
make install
Make will currently only build for OSX and Linux. For testing locally, you'll need Redis as well.
You'll need a configuration file with non-trivial connection parameters to get started. You can run:
autobot init
to generate a starting point, config.toml
. Edit this file with connection parameters to Redis and each data provider
and try it out by running:
autobot status
This command should also provide some useful information to get started:
autobot --help
Autobot stores and provides easy access to vehicle history and registration information, using the following key data for the core service:
- License plate number
- VIN
- Brand name
- Model name
- Fuel-type name
- First registration date
- Body type (if available)
- The microservice itself is written in Golang, v1.11
- Data is kept in a memory store: Redis for local development and Google Memory Store when deployed
- On a more detailed level, TOML is used for configuration files, FTP for DMR integration and Redis/Memory Store is the main vehicle store and indexing mechanism. The rest is just idiomatic Go :-)
Autobot talks to several external systems and thefore require some configuration. Autobot configuration is provided via a TOML file, which controls aspects of FTP connectivity, memory store integration, the actual synchronization algorithm etc.
GET /
returns a simple status, ie. uptime etc.GET /vehiclestore/status
returns a status for the vehicle store, ie. last sync time and number of vehicles.GET /lookup
looks up a vehicle by hash value or a combination of country and registration- or VIN number.PATCH /vehicle
disables/enables a vehicle by hash value.PUT /vehicle
(planned) updates a vehicle's master data
config
- contains app configuration and a loader that reads configuration data from a local TOML file.vehicle
- contains the Vehicle entity and related functions, plus the implementation of the vehicle store.dataprovider
- contains abstractions and implementations for loading data from varying sources, currently ftp and the local file system.dmr
- contains the integration with DMR, the Danish Motor Registry: parsers and data representations.app
- the entrance to the application itself: command line parser and runner that will both execute CLI commands and control the webservice.webservice
- this is the webservice part of the application which provides a REST-style HTTP API.main
- application bootstrapping.
Redis / Google Memory Store is used for caching of vehicles. Vehicle lookups are supported via VIN and registration numbers. In Redis, the lookup happens via two secondary indexes, which are sorted sets. Here's an overview:
autobot_vehicles
is a hashmap where the key is a hash of the Vehicle struct, metadata excluded, and the value is a serialized representation of Vehicle. Concretely, serialization is performed by converting the struct to JSON and then stringifying it.autobot_vin_index
is a sorted set with keys following the pattern<vin>:<hash>
. It acts as a lexicographical index with support for direct or partial VIN number lookups.autobot_regnr_index
is a sorted set with keys following the pattern<regnr>:<hash>
. It acts as a lexicographical index with support for direct or partial registration number lookups. Registration numbers are stored in uppercase which also requires searches to be performed with uppercase letters.
While the data structures are set in stone, their names are configurable via the config file.
The following is a concrete explanation of how the Redis lookup mechanism works in Autobot.
Registration number lookups are performed against the sorted set autobot_regnr_index
. For the license plate "AB13513",
Autobot performs the equivalent of the following command:
ZRANGEBYLEX autobot_regnr_index "[AB13513" "[AB13513\xff"
and similar for VIN lookups:
ZRANGEBYLEX autobot_vin_index "[ZAR93200001204085" "[ZAR93200001204085\xff"
This will return the vehicle hash, which can then be used to retrieve the vehicle directly:
hget autobot_vehicles 16029023328557318062
That's all there is to it.
Figure out how to efficiently perform REGNO+VIN lookups in RedisDoneRemove values from indexes where the hash no longer refers to a vehicleDoneAdd a CLI command that generates an empty config file for the sake of convenienceDoneAdd a CLI command for retrieving vehicle data, also for the sake of convenienceDoneAdd usage information when called without argumentsDoneAdd support for disabling vehiclesDoneBuild a simple HTTP API with support for lookupsDone- Switch from Go's builtin http package to Gin and add request logging, central error handling etc.
Allow the user to disable and re-enable vehicles via the APIDone- Allow the user to create revisions of vehicles via the API
- Handle
*net.OpError
(network interruptions) during sync, if it makes sense - Implement a cleanup job that removes all vehicles from the store that are not present in an index
- Add a discrete progress indicator while running sync (CLI only)
Split up data providers and their configs so autobot will support multiple providersDone- Consider providing optional CSV output for both CLI and API
- Add a CLI command "test" that tests integration with each provider
Add support for direct vehicle lookups in case of cache misses?Done- Achieve some test coverage!
- Improve quality of imported vehicles: ignore old (recycled plates) and invalid vehicle data
- Convert provider implementations into country-based "plugins" with higher decoupling
- v1.0 (Dec. 18) Initial version, with synchronization from DMR using Redis/Google Memory Store and data hashing.
Why is it called Autobot?
Because I like Transformers, and since we're dealing with cars here, the name was evident. Also, the synchronization service qualifies as a bot :-)
Why does Autobot exist?
It exists to meet a concrete need at my workplace, OmniCar A/S. As a company that deals in service contracts on vehicles, there is a regular need for performing lookups based on license plate numbers and other car master data.
These lookups are rarely free - in fact, the services that provide them often charge a fee per lookup. To save money on lookups, it becomes prudent to not only cache the results, but also to create our own vehicle database.
Autobot is the answer to these needs.
Why did you write this in Golang?
Because Go is perfect for cloud applications such as this one. Also, I'm learning the language and was looking for a real-world project to apply my knowledge to. So it's a learning project too.
Why is this open source?
Because you might benefit from this code too :-)