In English

GaladrielCache License: CC BY-NC-SA 4.0

Простой кеш/прокси сервер для тайловых карт с сохранением тайлов на диск. Предназначен в первую очередь для применения на очень слабых компьютерах типа RaspberryPi или различных NAS. Автор использует его на своей яхте Galadriel на wi-fi маршрутизаторе под управлением OpenWRT, который является сервером в бортовой сети.
GaladrielCache может быть источником тайлов для любого приложения, умеющего показывать растровые или векторные карты из интернета. Например, это может быть OruxMaps на телефоне или планшете, или GaladrielMap на том же сервере для использования с ноутбука или вообще любого устройства с браузером.
Тайлы хранятся в принятой для OSM файловой структуре z/x/y Такая иерархия понимается очень многими (всеми?) программами показа карт, поэтому в случае проблем с сервером флешку с картами можно вставить в планшет и пользоваться растровыми картами напрямую.
Кроме того, возможна организация хранения тайлов в базе данных или zip архиве.

Код программы написан без использования ИИ, "лучших практик", ООП и ИСР.

v. 3.1

Содержание:

Возможности:

  1. Конфигурируемые пользователем источники карт
  2. Надёжное скачивание тайлов в условиях плохой связи и блокировок
  3. Опережающее скачивание тайлов крупных масштабов
  4. Фоновое обновление кеша
  5. Надёжный многопоточный загрузчик тайлов
  6. Настраиваемое локальное хранение тайлов в файловой системе или базе данных формата MBTiles
  7. Составные и многослойные карты для клиентских приложений, умеющих API

Но никакой трансформации карт в смысле изменения проекции и/или разграфки нет. Проекции и прочее -- это проблема клиентского приложения.

Требования

Linux, PHP < 8. Кретинские решения, принятые в PHP 8 не позволяют GaladrielCache работать под PHP 8 без переделок, а я не хочу следовать этим решениям. На сервере должен быть установлен PHP7 со следующими модулями:

  • cli
  • php-fpm - если предполагается использовать не Apache2
  • curl
  • exif
  • fileinfo
  • gd
  • iconv
  • json
  • mbstring
  • openssl
  • pcntl
  • session
  • shmop
  • simplexml
  • sockets
  • sqlite3
  • tokenizer
  • zip

Все эти модули обычно входят в состав PHP по умолчанию в "полноценных" вариантах Linux, но в OpenWRT и сборках для Raspberry Pi многие из них надо ставить отдельно.

Установка и конфигурирование:

Должен быть веб-сервер с поддержкой php. Просто скопируйте содержимое каталога GaladrielCache в нужное место.
Кофигурация путей и другие параметры описаны в params.php Настройте.
Файлы конфигурации источников карт находятся в mapsources/*
Описание файла источника карты см. ниже в разделе Конфигурируемые пользователем источники карт

Подготовка карты памяти SD card для хранения кеша

Если тайлы хранятся в файловой системе на SD-карте, то карта должна быть особым образом отформатирована:

# mkfs.ext4 -O 64bit,metadata_csum -b 4096 -i 4096 /dev/sdXX

Где
-b 4096 -i 4096 установить размер блока данных в 4096 bytes и установить количество i-nodes в максимально возможное.
-O 64bit,metadata_csum необязательный параметр, который может понадобиться для совместимости с некоторыми устройствами под управлением Android
/dev/sdXX -- путь к карте памяти SD card.

Однако, умолчальное форматирование SD карт в vfat позволяет хранить на карте достаточный для практических целей объём тайлов без необходимости переформатирования. Кроме того, флешка со стандартным форматированием не требует ручного монтирования в Android устройствах.

Использование

Для обычных клиентских приложений:

tiles.php?z=Zoom&x=X_tile_num&y=Y_tile_num&r=map_Name

Разработчикам следует использовать API

Конфигурирование клиентских приложений

Конфигурирование OruxMaps

Для использования GaladrielCache с OruxMaps нужно добавить в конфигурационный файл OruxMaps onlinemapsources.xml в соответствии с синтаксисом этого файла описания требуемых карт, например -- карты Yandex Sat:

<onlinemapsource uid="1055">
	<name>Yandex Sat через прокси (SAT)</name>
	<url><![CDATA[http://192.168.1.1/tileproxy/tiles.php?z={$z}&x={$x}&y={$y}&r=yasat.EPSG3395]]></url>
	<minzoom>5</minzoom>
	<maxzoom>19</maxzoom>
	<projection>MERCATORELIPSOIDAL</projection>
	<cacheable>1</cacheable>
	<downloadable>0</downloadable>
</onlinemapsource>

Где: 192.168.1.1 -- сервер с GaladrielCache
/tileproxy/tiles.php -- собственно GaladrielCache
yasat.EPSG3395 -- имя карты

То же самое -- для остальных карт.

ВНИМАНИЕ! Для использования конкретной проекции настраивать надо программу показа карт, а не GaladrielCache!
(В примере выше -- это строка <projection>MERCATORELIPSOIDAL</projection> )
GaladrielCache ничего не знает о проекциях. Он просто кеширует тайлы.

Конфигурирование GaladrielMap

GaladrielMap использует GaladrielCache по умолчанию. Детали см. в конфигурационном файле GaladrielMap params.php.

SignalK

Для применения GaladrielCache в SignlK настройте в плагине charts-plugin использование требуемых карт, указав в качестве источника GaladrielCache.
Например, для использования OpenTopoMap укажите в настройках карты в плагине URL http://you_server/tileproxy/tiles.php?z={z}&x={x}&y={y}&r=OpenTopoMap

Адреса тайлов OSM

Некоторые приложения (AvNav?) могут обращаться к тайлом только по адресу в формате OSM "slippy map" tilenames. Для использования GaladrielCache с такими приложениями можно сконфигурировать Apache2 следующим образом:

<IfModule rewrite_module>
	RewriteEngine On
	RewriteRule ^tiles/(.+)/([0-9]+)/([0-9]+)/([0-9.a-z]+)$ tiles.php?r=$1&z=$2&x=$3&y=$4
</IfModule>

После этого к GaladrielCache можно будет обратиться:

tiles/map_Name/Zoom/X_tile/Y_tile

с указанием в конце расширения файла изображения, или без указания, в зависимости от конфигурации карты.

MBTiles

Файл карты в формате mbtiles должен иметь расширение .mbtiles и находится в каталоге $tileCacheDir. Файл описания карты аналогичен другим файлам описания карты, но должен содержать функцию работы с mbtiles. Более подробно см. mapsourcesVariablesList.php

Сведения о кеше

По адресу cacheControl.php находится сервис (API) представляющий некоторую информацию о кеше и позволяющй активизировать загрузчик.
В ответ на запросы сервер возвращает JSON, в том числе и null в случае проблем.

Использование:

Список карт

http://you_address/cacheControl.php?getMapList

Возвращается:

{
	"map_Name": {
		"en": "Human-readable english map name or map_Name",
		["ru": ...]
	}
}

Сведения о карте

http://you_address/cacheControl.php?getMapInfo=map_Name

Возвращается:

{
    "ext": "...",
    "ContentType": "...",
    "epsg": "...",
    "minZoom": ?,
    "maxZoom": ?,
    "data": "...",
    "mapboxStyle": "..."
}

и другие параметры из файла из файла mapsources/map_Name.php

Запуск загрузки

http://you_address/cacheControl.php?loaderJob=map_Name.zoom&xys=csv_of_XY

Запускается загрузка списка тайлов csv_of_XY карты map_Name.zoom. Возвращается:

{
	"status": 0,
	"jobName": map_Name.zoom
}

Сведения о загрузках

`http://you_address/cacheControl.php?loaderStatus[&restartLoader]

Также можно потребовать (ре)старт загрузчика. Возвращается:

{
	"loaderRun": scheduler_PID,
	"jobsInfo": {
		"map_Name.zoom": %_of_complite
		[...]
	}
}

Загрузчик

GaladrielCache имеет в своём составе простой загрузчик тайлов. Для его использования нужно создать специальный файл задания - текстовый файл в формате csv. Имя файла должно совпадать с именем файла источника карты, а расширение - быть начальным масштабом в смысле z в координатах тайла. Файл задания должен содержать строки x,y координат требуемых тайлов, через запятую.

Поместите файл задания в каталог loaderjobs/ (настраивается в params.php) и запустите загрузчик как фоновый процесс:

tileproxy$ startLoaderDaemon

или как обычный процесс:

tileproxy$ php loaderSched.php

Указанные тайлы указанной карты начиная с указанного масштаба и вплоть до максимального масштаба, заданного в params.php, скачаются и будут сохранены в кеше.
Остановить загрузчик можно командой

tileproxy$ stopLoader

или удалив все файлы заданий в каталогах loaderjobs/ и loaderjobs/inWork/

Например, файл задания с именем OpenSeaMap.9, содержащий строки:

295,145
296,145
296,144
295,144
295,143
296,143

вызовет скачивание указанных шести тайлов карты OpenSeaMap масштаба 9, а также всех тайлов большего масштаба, которые укладываются в эти тайлы, вплоть до масштаба 16, который указан в params.php как максимальный для загрузчика.

Для управления загрузчиком и создания файлов заданий удобно использовать GaladrielMap, где есть все нужные инструменты. При этом созданные GaladrielMap файлы заданий дополнительно сохраняются в loaderjobs/oldjobs/ для возможного повторного использования.

Загрузка тайлов может осуществляться в несколько потоков, число которых указывается в params.php. Кроме того, загрузчик использует cron для надёжности, так что загрузка продолжится и после перезагрузки сервера. Для остановки процесса загрузки конкретной карты удалите соответствующий файл задания.

Использование загрузчика для особых целей

Если в первой строке файла задания поместить какую-нибудь команду, то вместо загрузки тайлов загрузчик будет выполнять эту команду. Такая первая строка должна обязательно начинаться с символа #.

Например, такой файл задания OpenSeaMap.9:

# mkdir -p /mnt/mySDcard/RegionTileCache/$r/$z/$x/ && cp -Hpu $tileCacheDir/$r/$z/$x/$y.png /mnt/mySDcard/RegionTileCache/$r/$z/$x/
295,145
296,145
296,144
295,144
295,143
296,143

вызовет копирование указанных тайлов, и всех тайлов большего масштаба, которые укладываются в эти тайлы, из каталога, указанного в переменной $tileCacheDir из конфигурационного файла params.php, в каталог /mnt/mySDcard/RegionTileCache с созданием всех подкаталогов.

Кроме однострочной команды можно написать развёрнутый код на PHP, который будет выполнен для каждой строки файла задания. В команде можно использовать переменные из конфигурационного файла params.php, и переменные из mapsourcesVariablesList.php.

Нельзя для одной карты одновременно запускать файлы задания со специальной командой и без неё. В конце-концов один из файлов задания перепишет другой, и останется какой-нибудь один.

Прямой доступ к файловому кешу

Если ваш сервер умер, но есть рутованное устройство (планшет или телефон) под управлением Android с навигационной программой, для доступа к файловому хранилищу тайлов можно сделать следующее:

Монтирование SD card в устройстве

  1. извлеките SD card с кешем из сервера
  2. вставьте SD card с кешкм в устройство под управлением Android
    на этом устройстве понадобится терминал (отдельная программа, или в составе чего-нибудь)
  3. Откройте терминал. Выполните:
# mount -o rw,remount /
# mkdir /data/mySDcard 
# chown 1000:1000 /data/mySDcard
# chmod 774 /data/mySDcard
# mount -o ro,remount /
# mount -rw -t ext4 /dev/block/mmcblk1p1 /data/mySDcard

Эти команды создают точку монтирования и монтируют туда SD card. Таким образом все карты оказываются на вашем Android-устройстве.
В этих командах:
/dev/block/mmcblk1p1 -- раздел на SD card, где находится кеш. Обычно путь именно такой, но на всякий случай следует уточнить:

$ ls /dev/block

Последнее устройство mmcblk -- обычно вставленная SD card, а p1 -- обычно единственный раздел на ней.
/data/mySDcard - точка монтирования
-t ext4 - файловая система. Если vfat - надо указать -t vatf. Можно опустить - тогда тип файловой системы определится автоматически. Может быть.
Ручное монтирование vfat может понадобится, если обычным образом вставленная влешка не видна прикладным программам.

В зависимости от способа рутования устройства (и организации конкретного варианта Android), команда mount может выглядеть иначе:

 # su --mount-master -c 'busybox mount -rw -t ext4 /dev/block/mmcblk1p1 /data/mySDcard'

Попробуйте такой вариант, если монтирование не получается.

Конфигурирование OruxMaps на устройстве

Чтобы OruxMaps работала с таким локальным файловым кешем, добавьте в конфигурационный файл OruxMaps onlinemapsources.xml в соответствии с синтаксисом этого файла такие описания требуемых карт:

<onlinemapsource uid="1052">
	<name>Navionics layer локально (NAV)</name>
	<url><![CDATA[file://data/mySDcard/tiles/navionics_layer/{$z}/{$x}/{$y}.png]]></url> 
	<minzoom>12</minzoom>
	<maxzoom>18</maxzoom>
	<projection>MERCATORESFERICA</projection>
	<cacheable>0</cacheable>
	<downloadable>0</downloadable>
</onlinemapsource>
<onlinemapsource uid="1054">
	<name>OpenTopoMap локально (TOPO)</name>
	<url><![CDATA[file://data/mySDcard/tiles/OpenTopoMap/{$z}/{$x}/{$y}.png]]></url> 
	<minzoom>5</minzoom>
	<maxzoom>18</maxzoom>
	<projection>MERCATORESFERICA</projection>
	<cacheable>0</cacheable>
	<downloadable>0</downloadable>
</onlinemapsource>

И всё остальное, что нужно, таким же способом
Здесь /data/mySDcard/tiles/ -- путь к кешу на примонтированной SD card от корня файловой системы.

Автоматизация процесса монтирования SD card на устройстве с помощью 3C toolbox

С помощью приложения 3C toolbox можно автоматически монтировать SD card при старте устройства. Для этого:

  1. Создайте файл с именем, например, 01_mountExtSDcard, и содержанием:
#!/system/bin/sh

EXT_SD_DIRECTORY=/data/mySDcard;

if [ ! -d $EXT_SD_DIRECTORY ];
then
mount -o rw,remount /
mkdir $EXT_SD_DIRECTORY;
chown 1000:1000 $EXT_SD_DIRECTORY;
chmod 774 $EXT_SD_DIRECTORY;
mount -o ro,remount /
fi
mount -rw -t ext4 /dev/block/mmcblk1p1 $EXT_SD_DIRECTORY
  1. Поместите этот файл в домашнюю директорию вашего устройства Android по следующему пути:
    Android/data/ccc71.at.free/scripts/ или
    Android/data/ccc71.at/scripts/
  2. Откройте 3C toolbox
  3. Перейдите Tools - Script editor
  4. Отметьте ваш файл 01_mountExtSDcard как запускаемый при старте.

Конфигурируемые пользователем источники карт

Файлы описания карт находятся в каталоге, указанном переменной $mapSourcesDir в файле params.php. По умолчанию это каталог mapsources/. Имена файлов имеют вид map_Name.php.
Собственно карты находятся в каталоге, указанном переменной $tileCacheDir. По умолчанию это каталог tiles/. В нём лежать каталоги с именем map_Name с файловым кешем или файлы с именем map_Name для других видов хранилища.

Файл описания карты содержит инструкции получения тайлов из Интернет, инструкции сохранения тайлов в локальном хранилище, извлечения из него и обработки тайла перед отдачей клиенскому приложению. Каждый их этих шагов может быть представлен пользовательской процедурой, однако имеется полный набор готовых процедур для обычных случаев применения.
Файл описания карты является кодом на PHP, поэтому соблюдение всего синтаксиса языка является обязательным.

Файл описания карьы может содержать сведения об одной карте, о составной карте или о многослойной карте.
Составная карта - это несколько отдельно описанных других карт, перечисленных в порядке, обратном предполагаемому порядку показа, т.е. последняя - показывается поверх.
Многослойная карта - это одна карта, однако, имеющая несколько слоёв. Например, карта погоды.

Клиентское приложение должно использовать составные и многослойные карты через API, однако описание каждого слоя многослойной карты может быть составлено так, чтобы допускать к нему отдельное обращение. А многие клиентские приложения - такие, как OruxMaps - позволяют создавать составные карты. Таким образом многослойная карта тоже может использоваться простым клиентским приложением, не умеющем API.

Переменные и функции, применяемые в файле описания карты, перечислены и более-менее описаны в файле mapsourcesVariablesList.php

Отладка

Для отладки файла описания карты можно использовать

php tilefromsource.php -z ZOOM -x X-num -y Y-num -r map_name --checkonly

или просто

php tilefromsource.php -r map_Name --checkonly

если переменная $trueTile имеется в mapsource/map_Name.php.

GaladrielCache возвращает http заголовок X-Debug с дополнительной информацией вместе с некоторыми 400 и 404 ответами. И конечно, следует нет забывать смотреть в журнал ошибок веб-сервера.

Вспомогательные приложения

Очистка кеша с помощью clearCache

Запустите

php clearCache.php map_Name [fresh]

для карты map_Name, или

php clearCache.php

для всех карт, чтобы удалить из кеша ненужные файлы.
Список ненужных файлов указывается в массиве $trash в описаноо каждой карты, и/или в массиве $globalTrash файла params.php для всех карт. Ненужными могут быть тайлы - заглушки, или, допустим, файлы .tne, если вы используете кеш от программы SAS.Planet.
Если у карты указаны границы - тайлы вне границ также удаляются.
Если указан параметр fresh, то также будут удалены устаревшие тайлы.

Проверка жизнеспособности источника карты

checkSources.php -- утилита командной строки, которая для каждого файла источника карты, в котором указан специальный тайл, пытается скачать этот тайл из Интернета и сравнивает полученное с сохранённым. Результат записывается в лог.
Собственно, утилита вызывает

php tilefromsource.php -r map_Name --checkonly

для каждого файла описания карты, где указан соответствующий параметр.
Таким образом можно проверить существует ли ещё указанный в конфигурации карты внешний источник. Рекомендуется запускать периодически cron'ом.

Карта покрытия

Запустите

php checkCovers.php map_Name.zoom max_zoom

для подсчёта отсутствующих тайлов в покрытии карты, описанном в файле задания для загрузчика map_Name.zoom. Отсутствующие тайлы будут записаны в виде файлов заданий для загрузчика в каталоге checkCoversData/notFound/

Для показа карты покрытия клинтское приложение должно запросить

tilesCOVER.php?z=Zoom&x=X_tile_num&y=Y_tile_num&r=map_Name

Оно получит прозрачный тайл масштаба Zoom, на катором серыми полупрозрачными пикселями будет показано наличие тайлов масштаба Zoom+8 карты map_Name.
Дополнительно тоном будет показан максимальный масштаб загрузчика согласно конфигурации, по достижении и превышении этого масштаба.

Интерфейс загрузчика GaladrielMap использует эту возможность.

Автоматическое подключение карт в формате MBTiles

Если у вас есть файл с картой формата MBTiles, файл описания карты можно создать автоматически на основе имеющейся в файле информации. Поместите файл в каталог $tileCacheDir и запустите

php collectMBTiles.php 

Этого достаточно для растровых карта, но не для векторных. Для векторных карт в любом случае придётся руками подготовить файл стиля. Но, если этот файл будет иметь имя карты с расширением .json и находится в каталоге $mapSourcesDir, он будет указан в файле описания источника карты.
GaladrielMap запускает collectMBTiles.php каждый старт, поэтому достаточно положить файл карты в указанный каталог - и картя появится в интерфейсе GaladrielMap.

Демо

Можно ознакомиться с функционированием GaladrielCache, запустив один из демонстрационных образов виртуальных машин.

Поддержка

Форум

Форум будет живее, если вы сделаете пожертвование на ЮМани.

Вы можете получить индивидуальную платную консультацию по вопросам установки и использования GaladrielCache.