The high performance cache and proxy service for Imaginary.
This project aims to serve frontend website assets (mainly images) at the lowest possible level of consumption of cellular data and lowest possible latency without sacrificing the quality of our assets providing by that best personalized quality of assets for each user on every device separately.
This project supports automatic file caching and cache invalidation through HTTP API. It just forwards all requests that call /imaginary
endpoint to the Imaginary service if given request is not cached yet.
It also supports cache invalidation for files that were changed during development. It is done by saving latest commit hash in database and then fetching the this hash during CI
build, finding last known commit in Git
history, listing all changed files that fit given regular expressions under given directory and sending all changed file names for invalidation.
API, invalidator and react libraries can be found in this repository.
This project supports only URL source of image, no local file source support. Every image that you want to process have to be accessible from public network.
Also, you may allow only known origins for incoming requests and allow processing for images only from known domains.
This service share following HTTP endpoints:
-
GET /imaginary/...
- call it like normal Imaginary service, but it will cache the response if it is not cached yet. All available endpoints and parameters are available here. -
GET /latestInvalidation
- returns latest invalidation info. It is used byCI
build to invalidate get info about latest invalidation to get know from which commit to look for file changes. This endpoint is secured by access token set byIMCAXY_INVALIDATE_SECURITY_TOKEN
environment variable sent to server usingAuthorization
HTTP header. You need to includeprojectName
query parameter with project name that the invalidation is done for. It returns following json:interface InvalidationModel { projectName: string; commitHash: string; invalidationDate: Date; requestedInvalidations: string[]; doneInvalidations: string[]; invalidatedImages: { rawRequest: string; requestSignature: string; processorType: string; processorEndpoint: string; mimeType: string; imageSize: number; sourceImageURL: string; processingParams: Record<string, string[]>; }[]; invalidationError: string | null; }
-
DELETE /invalidate
- invalidates given cached images. This endpoint is secured by access token set byIMCAXY_INVALIDATE_SECURITY_TOKEN
environment variable sent to server usingAuthorization
HTTP header. You need to include following query params:projectName
- project name that the invalidation is done forlatestCommitHash
- the latest commit hash that was available, used later for finding which images were changed during developmenturls
- the urls of images that should be invalidated, for example:http://your-domain.com/image.png
It returns same json as
GET /latestInvalidation
endpoint:interface InvalidationModel { projectName: string; commitHash: string; invalidationDate: Date; requestedInvalidations: string[]; doneInvalidations: string[]; invalidatedImages: { rawRequest: string; requestSignature: string; processorType: string; processorEndpoint: string; mimeType: string; imageSize: number; sourceImageURL: string; processingParams: Record<string, string[]>; }[]; invalidationError: string | null; }
To setup the project you should follow these steps:
- Make sure that Imaginary service is running and available from Imcaxy service.
- Make sure that MongoDB service is running and available from Imcaxy service.
- Make sure that Minio service is running and available from Imcaxy service.
- Set environment variables. You can find examples in
./config/env/examples
directory. All environment variables are described below. - Run
make build
script to build the executable. - Now your executable is available in
./bin
directory, just run it.
Environment variables:
IMCAXY_MONGO_CONNECTION_STRING
- MongoDB connection stringIMCAXY_MINIO_ENDPOINT
- Minio service endpoint, in pattern:DOMAIN:PORT
- withouthttp(s)://
prefixIMCAXY_MINIO_ACCESS_KEY
- Minio service access keyIMCAXY_MINIO_SECRET_KEY
- Minio service secret keyIMCAXY_MINIO_BUCKET
- Bucket name that will be used as Imcaxy service data bucketIMCAXY_MINIO_LOCATION
- optional, location of the bucketIMCAXY_MINIO_SSL
- optional, set it totrue
if you want to use SSLIMCAXY_IMAGINARY_SERVICE_URL
- Imaginary service endpoint, in pattern:DOMAIN:PORT
- withouthttp(s)://
prefixIMCAXY_INVALIDATE_SECURITY_TOKEN
- security token that is used to access invalidation endpoint, use long random string for thatIMCAXY_ALLOWED_DOMAINS
- optional, list of allowed domains, separated with comma, for example:example.com,example.net
, if not set, all domains are allowedIMCAXY_ALLOWED_ORIGINS
- optional, list of allowed origins, separated with comma, for example:example.com,example.net
, if not set, all origins are allowed
You wll need make
, docker
, docker compose
and go
with version at least 1.17
.
- Go to
./config/env/examples
directory and copy twice all files to./config/env
directory with nameDev.
andIntegrationTests.
prefixes. - Do not change files with
Dev.
prefixes, they are ready to run. - Go to all files with
IntegrationTests.
prefixes and replaceDev.
string withIntegrationTests.
string. - Your development environment is ready.
There are available few useful make
scripts:
make build
- builds the executable and puts it in./bin
directorymake dev
- starts development environment for manual testing of the service, it starts also all necessary services:MongoDB
,Minio
andImaginary
, attaches to server logsmake stop-dev
- stops development environment, but preserves volumesmake cleanup-dev
- stops development environment and removes all containers and volumesmake build-dev
- builds all containers of development environmentmake test
- runs unit testsmake integration-tests
- runs unit and integration testsmake build-integration-tests
- builds all containers of integration tests environmentmake cleanup-integration-tests
- stops integration testing environment and removes all containers and volumes
Project structure is defined as follows:
./cmd/server/
- contains imcaxy main executable./config/env/
- contains environment variables configuration and examples./pkg
- root packages directorytest
- contains test data, global mocks and test utils
Hub
package contains DataHub
structure. It is responsible for multiplexing incoming data from single source into multiple destination.
But the special feature of this package and what makes it different that simple multiplexer is that it caches all incoming data in memory, which allows to attach new data stream listeners even when data fetching is almost done.
It unloads the network and because of that, there is no way to double the processing work on same requests when proxy is already processing request with same signature.
Cache
package is responsible for data persistence layer. It allows to read cached images from Minio
block storage and write new ones to Minio
and MongoDB
services.
This package shares also a InvalidationService
which takes care about images invalidation by implementing simple invalidation API that is used directly by HTTP handlers.
Processor
package contains image processing service abstraction. Under this package placed are all available processing service packages.
Currently only imaginary
processing service is available. But you can create your own processor if you want to implement support for another processing service.
Proxy
package contains service that proxies all requests to our known processors and caches them. If given request is already cached, it returns it from cache.
This service also takes care about requests validation and checks if request origin is allowed as well as the domain of source image to process.
The cmd in ./cmd/server/
directory contains main package of the service. It uses Wire
package to initialize all services and its dependencies in correct order.
HTTP handlers are defined in in ./cmd/server/handlers.go
file.
This project uses unit and integration testing techniques.
To run unit tests, run make test
command.
If you want to run integration and unit tests, run make integration-tests
command. Integration tests are skipped when running make test
command, as it runs only unit tests.
You can remove containers and volumes of integration testing environment by running make cleanup-integration-tests
command.
This project is licensed under MIT license. Feel free to do with it whatever you want.