SASGIS - SAS.Планета
View Issue Details
0003756SAS.Планета[All Projects] Хотелкаpublic02-04-2021 11:2609-04-2021 14:42
VadimK 
zed 
normalminoralways
resolvedfixed 
201212 
211230211230 
0003756: PascalScript: Добавить итерфейс для работы с тайлохранилищем (чтение, запись, инф. о тайле)
Если скрипт скачивает тайл и сохраняет его в кэш на диск, то этот тайл не отображается на карте. Чтобы он отобразился, необходимо при просмотре карты изменить зум в ту или иную сторону и вернуть обратно. Тогда тайл отобразится (кстати, даже в случае, если переключалка "Кэш-Интернет" стоит в режиме "Интернет" (Alt-I))

Уже упоминал об этом на форуме (подробности
http://www.sasgis.org/forum/viewtopic.php?p=49956#p49956)
Собственно, просьба:
ЕСЛИ
в params.txt установлено IsUseDownloaderInScript=1
И
скрипт возвращает ResultURL=''
ТО
проверять наличие тайла на диске,
и если он присутствует -- отображать тайл на карте
Конечно, из этой ситуации можно выйти другими способами.
Но у них есть недостатки.
Например, повторная перекачка тайла посредством указания ссылки в ResultURL увеличивает нагрузку на сервер. А указание в ResultURL локального пути до сохранённого тайла приводит к лишней файловой операции копирования.
No tags attached.
zip GarminQD_.zmp.zip (4,467) 02-04-2021 11:26
http://www.sasgis.org/mantis/file_download.php?file_id=2512&type=bug
png AccessViolation.png (274,344) 09-04-2021 09:38
http://www.sasgis.org/mantis/file_download.php?file_id=2514&type=bug
png AssertionFailure.png (127,663) 09-04-2021 12:52
http://www.sasgis.org/mantis/file_download.php?file_id=2515&type=bug
png

png статистика_не_обновляется.png (45,816) 09-04-2021 14:34
http://www.sasgis.org/mantis/file_download.php?file_id=2516&type=bug
png
Issue History
02-04-2021 11:26VadimKNew Issue
02-04-2021 11:26VadimKFile Added: GarminQD_.zmp.zip
02-04-2021 12:36zedNote Added: 0020083
02-04-2021 12:36zedAssigned To => zed
02-04-2021 12:36zedStatusnew => feedback
02-04-2021 13:15VadimKNote Added: 0020084
02-04-2021 13:15VadimKStatusfeedback => assigned
02-04-2021 13:33vdemidovNote Added: 0020085
02-04-2021 14:08VadimKNote Added: 0020086
02-04-2021 14:25VadimKNote Edited: 0020086bug_revision_view_page.php?bugnote_id=20086#r7738
02-04-2021 14:58zedAssigned Tozed =>
02-04-2021 14:58zedStatusassigned => new
02-04-2021 14:58zedSummaryсразу не отображаются тайлы, скачанные и сохранённые скриптом => PascalScript: Добавить итерфейс для работы с тайлохранилищем (чтение, запись, инф. о тайле)
02-04-2021 15:04zedNote Added: 0020087
02-04-2021 15:09zedNote Added: 0020088
02-04-2021 15:45vdemidovNote Added: 0020089
02-04-2021 16:19zedNote Added: 0020090
02-04-2021 16:25vdemidovNote Added: 0020091
05-04-2021 08:33zedStatusnew => confirmed
05-04-2021 08:33zedTarget Version => 211230
06-04-2021 16:42zedNote Added: 0020097
06-04-2021 16:42zedNote Edited: 0020097bug_revision_view_page.php?bugnote_id=20097#r7740
06-04-2021 17:25vdemidovNote Added: 0020098
06-04-2021 18:46zedNote Added: 0020099
07-04-2021 12:09vdemidovNote Added: 0020100
07-04-2021 12:39zedNote Added: 0020101
08-04-2021 07:26zedNote Added: 0020102
08-04-2021 07:26zedAssigned To => zed
08-04-2021 07:26zedStatusconfirmed => feedback
08-04-2021 07:26zedNote Edited: 0020102bug_revision_view_page.php?bugnote_id=20102#r7742
09-04-2021 09:38VadimKFile Added: AccessViolation.png
09-04-2021 09:47VadimKNote Added: 0020104
09-04-2021 09:47VadimKStatusfeedback => assigned
09-04-2021 09:48VadimKNote Edited: 0020104bug_revision_view_page.php?bugnote_id=20104#r7744
09-04-2021 10:35VadimKNote Added: 0020106
09-04-2021 10:36VadimKNote Edited: 0020106bug_revision_view_page.php?bugnote_id=20106#r7746
09-04-2021 11:08VadimKNote Edited: 0020106bug_revision_view_page.php?bugnote_id=20106#r7749
09-04-2021 12:02zedNote Added: 0020109
09-04-2021 12:06zedNote Added: 0020110
09-04-2021 12:07zedStatusassigned => feedback
09-04-2021 12:52VadimKFile Added: AssertionFailure.png
09-04-2021 12:58VadimKNote Added: 0020111
09-04-2021 12:58VadimKStatusfeedback => assigned
09-04-2021 13:00VadimKNote Edited: 0020111bug_revision_view_page.php?bugnote_id=20111#r7751
09-04-2021 13:04VadimKNote Edited: 0020111bug_revision_view_page.php?bugnote_id=20111#r7754
09-04-2021 13:32zedNote Added: 0020112
09-04-2021 13:32zedStatusassigned => feedback
09-04-2021 14:34VadimKFile Added: статистика_не_обновляется.png
09-04-2021 14:38VadimKNote Added: 0020113
09-04-2021 14:38VadimKStatusfeedback => assigned
09-04-2021 14:39VadimKNote Edited: 0020113bug_revision_view_page.php?bugnote_id=20113#r7756
09-04-2021 14:42zedStatusassigned => resolved
09-04-2021 14:42zedFixed in Version => 211230
09-04-2021 14:42zedResolutionopen => fixed

Notes
(0020083)
zed   
02-04-2021 12:36   
Вы как-то очень странно решили использовать скрипт, формирующий ссылку для загрузки тайла. Зачем вы качаете руками, то что SAS и так прекрасно может скачать?

Кроме того, из скрипта вы ведь в SQLite/Беркли тайлы сохранить не сможете, так что это очень сомнительная хотелка.

Возможно, вашу задачу можно решить другим способом, добавив, например, в скрипты вызовы OnBeforeDownload и OnAfterDownload. Или ещё как-то? Т.е. не вкорячивать абы что абы куда, а сделать по человечески?
(0020084)
VadimK   
02-04-2021 13:15   
Тайлы предварительно закачиваются руками, чтобы узнать их размер и при необходимости пополнить список/БД пустых тайлов. А раз уж тайл скачан, зачем его перекачивать повторно? Учитывая, что тайлов сотни тысяч а операция скачивания из интернета самая длительная, то получится неплохая экономия времени и снижение нагрузки на сервер, если повторного скачивания удастся избежать.

Касательно других типов кэша, в которых тайлы не хранятся пофайлово. Да, я думал об этом и мне это тоже не нравится. Но я до сих пор использую только второй тип.

Если задачу удастся решить другими способами, я буду только рад. :)
Надеюсь, там будет присутствовать функция добавления тайла в кэш _любого_ типа (это должна была быть моя следующая хотелка). А уж использование такой функции в скрипте было бы неплохим поводом для программы отобразить сохраняемый тайл на карте.
(0020085)
vdemidov   
02-04-2021 13:33   
Я бы вообще запретил из скрипта любые операции с файловой системой. Пока только малая распространенность САС.Планеты спасает нас от ситуации: "Ой, я скачал с какого-то сайта zmp, попробовал посмотреть в САС, а все мои документы удалились"

Так что думайте как решить свои проблемы без прямого доступа к файлам и соответственно формулируйте хотелки. Эта хотелка, в том виде как она сейчас есть,с вероятностью 99% будет закрыта.
(0020086)
VadimK   
02-04-2021 14:08   
(edited on: 02-04-2021 14:25)
Благодаря вашим замечаниям хотелка приобретает следующий вид.

Добавить для использования в скриптах функцию:

Function SaveTileToCache(X,Y,Z:integer; Tile:ansistring):boolean;

Она сохранит тайл именно в кэш того типа, который указан в params.txt
Эта функция безопасна для остальных пользовательских файлов на диске.

В режиме просмотра карты: если в скрипте задействуется эта функция (SaveTileToCache), то основная программа оповещается, что (не смотря на ResultURL='') тайл сохранён и его можно отобразить.

ЗЫ:
Почему Tile:AnsiString ? Потому что сюда пойдёт VResponseData, которая объявлена именно как AnsiString.

(0020087)
zed   
02-04-2021 15:04   
Одной функции тут будет мало, тут уже речь про целый интерфейс - вам же наверняка ещё захочется проверить наличие тайла или .tne в кэше. И для записи в кэш ещё нужно указывать версию, content-type и т.д.

> Я бы вообще запретил из скрипта любые операции с файловой системой
Для этого придётся запретить вызывать dll в скриптах.
(0020088)
zed   
02-04-2021 15:09   
> В режиме просмотра карты: если в скрипте задействуется эта функция (SaveTileToCache), то основная программа оповещается, что (не смотря на ResultURL='') тайл сохранён и его можно отобразить.

С этим как раз проблем нет - если запись в кэш происходит через интерфейс, то там есть оповещение об изменениях и гуй перерисовывается автоматически.
(0020089)
vdemidov   
02-04-2021 15:45   
>Для этого придётся запретить вызывать dll в скриптах.
Ну, это еще большая дыра в безопасности. Спасает только то, что очень уж мало людей пользуется САС.Планетой - соответственно атака через эти дырки невыгодна. Но это не значит, что не стоит думать как прикрыть совсем уж вопиющие дырки или хотя бы не плодить новых.
(0020090)
zed   
02-04-2021 16:19   
Считаешь ли ты интерфейс для взаимодействия с тайлохранилищем дырой?
(0020091)
vdemidov   
02-04-2021 16:25   
> Считаешь ли ты интерфейс для взаимодействия с тайлохранилищем дырой?
Конечно нет. Другое дело, что ИМХО было бы полезней развить скриптовый движек другими типами скриптов (получение акутальной версии, предзапрос, пост обработка скачанного и тд.), вместо того что бы костылить все это внутри скрипта получения урла.
Но я, увы, понимаю насколько сложнее это сделать качественно, удобно, безопасно, логично и без ухудшения хотя бы обратной совместимости. Поэтому я, в принципе, за такой интерфейс.
(0020097)
zed   
06-04-2021 16:42   
Появился вопрос: а что делать если скрипт запускается из IDE? Может, от греха подальше, создавать хранилище в памяти и подставлять его?

(0020098)
vdemidov   
06-04-2021 17:25   
> Появился вопрос: а что делать если скрипт запускается из IDE?
Да, думаю это правильно будет. Другое дело, что для отладки было бы хорошо видеть что там вышло в результате работы скрипта. А как это сделать удобно я не знаю.
(0020099)
zed   
06-04-2021 18:46   
Да, сделаю наверное RAM кэш + сохранение дампа (в виде архива) на диск.
(0020100)
vdemidov   
07-04-2021 12:09   
> Да, сделаю наверное RAM кэш + сохранение дампа (в виде архива) на диск.
ИМХО оптимальное решение. Я что-то про экспорт в виде архива не додумался.
(0020101)
zed   
07-04-2021 12:39   
Можно тестировать использование интерфейса и из IDE. Единственное, что не доделано так это сохранение на диск, но в DebugOutput выводится вся информация о содержимом TileCache по окончании работы скрипта.


  TTileInfo = packed record
    IsExists : Boolean;
    IsExistsTne : Boolean;
    LoadDate : Int64; // unix timestamp
    Size : Cardinal;
    Version : string;
    ContentType : AnsiString;
    Data : AnsiString;
  end;

  IPascalScriptTileCache = interface
    function Read(
      const X: Integer;
      const Y: Integer;
      const AZoom: Byte;
      const AVersion: string;
      const AWithData: Boolean
    ): TTileInfo;

    function Write(
      const X: Integer;
      const Y: Integer;
      const AZoom: Byte;
      const AVersion: string;
      const AContentType: AnsiString;
      const AData: AnsiString;
      const AIsOverwrite: Boolean
    ): Boolean;

    function WriteTne(
      const X: Integer;
      const Y: Integer;
      const AZoom: Byte;
      const AVersion: string
    ): Boolean;

    function Delete(
      const X: Integer;
      const Y: Integer;
      const AZoom: Byte;
      const AVersion: string
    ): Boolean;
  end;


Пример использования:

procedure PrintInfo(var AInfo: TTileInfo);
begin
  Logger.WriteFmt(
    'IsExists: %d, IsExistsTne: %d, Size: %d, Content-Type: %s, Date: %d',
    [AInfo.IsExists, AInfo.IsExistsTne, AInfo.Size, AInfo.ContentType, AInfo.LoadDate]
  );
end;

var
  VInfo: TTileInfo;
  VResult: Boolean;
begin
  VResult := TileCache.Write(0, 0, 0, '', 'image/png', '123', False);
  writeln(IntToStr(Integer(VResult)));
  
  VInfo := TileCache.Read(0, 0, 0, '', True);
  PrintInfo(VInfo);
  
  VResult := TileCache.WriteTne(0, 0, 0, '');
  writeln(IntToStr(Integer(VResult)));
  
  VInfo := TileCache.Read(0, 0, 0, '', True);
  PrintInfo(VInfo);
end.
(0020102)
zed   
08-04-2021 07:26   
Доделал, тестируйте. Дамп из IDE будет сохраняться в файл TileCacheDump.zip в корне с программой.

Пара советов по поводу вашего скрипта:
- не используйте ScriptBuffer для хранения информации об отсутствующих/пустых тайлах, а вместо этого записывайте tne в кэш (TileCache.WriteTne(...))
- надо задавать MaxConnectToServerCount=1 если вы не хотите, чтобы с сервера качалось несколько раз одно и то же разными экземплярами скрипта. Либо, весь свой код поместите в блокировку:

Global.Lock;
try
  // тут весь код формирования ResultURL
finally
  Global.Unlock;
end;


(0020104)
VadimK   
09-04-2021 09:47   
(edited on: 09-04-2021 09:48)
Спасибо большое за быстрое добавление новой фичи в программу!
Только сегодня смог протестировать.
Но к сожалению вышеприведённый пример не заработал. :( Добавил скриншот в инцидент:

Если уменьшить скрипт до:
var
  VInfo: TTileInfo;
  VResult: Boolean;
begin
// VResult := TileCache.Write(0, 0, 0, '', 'image/png', '123', False);
  writeln(IntToStr(Integer(VResult)));
// VInfo := TileCache.Read(0, 0, 0, '', True);
end.

То работает.
Если раскомментировать первую строку, то тоже продолжает работать.
Но если расскоментировать последнюю строку, то снова ошибка, пока не закомментишь _обе_ строки обратно.

(0020106)
VadimK   
09-04-2021 10:35   
(edited on: 09-04-2021 11:08)
"zed" wrote

Пара советов по поводу вашего скрипта:
- не используйте ScriptBuffer для хранения информации об отсутствующих/пустых тайлах, а вместо этого записывайте tne в кэш (TileCache.WriteTne(...))

ScriptBuffer содержит координаты в гарминовском формате, более удобном для сравнения, чем XYZ. В гарминовском формате, чтобы узнать координаты (точнее, координатУ) вышележащего тайла, достаточно удалить одну цифру в координате текущего тайла. При работе же с кэшем (XYZ), как мне кажется, всё сильно усложнится и замедлится.

"zed" wrote

надо задавать MaxConnectToServerCount=1 если вы не хотите, чтобы с сервера качалось несколько раз одно и то же разными экземплярами скрипта. Либо, весь свой код поместите в блокировку:
Сразу после публикации скрипта на форуме (месяц назад) в личке мне подробно рассказали про Global.Lock|Unlock (с ссылками на примеры). И я собираюсь применить это в своём скрипте. Жаль, что в описании скриптов на сайте про эту полезную возможность не упоминается. :(

(0020109)
zed   
09-04-2021 12:02   
> Добавил скриншот в инцидент:
Скриншот это хорошо, но ещё лучше - запустить SASPlanet.Debug.exe и приложить лог с ошибкой (появится файл с расширением .elf в корне с программой).

> ScriptBuffer содержит координаты
Этот буфер не переживёт перезапуска программы, а tne переживут. Чтобы определить координаты вышележащего тайла, достаточно сделать целочисленное деление координат текущего тайла на 2: X := GetX div 2; Y := GetY div 2;
(0020110)
zed   
09-04-2021 12:06   
У меня ошибка не воспроизводится. Приложите, в дополнение к логу, ещё и params.txt из IDE.
(0020111)
VadimK   
09-04-2021 12:58   
(edited on: 09-04-2021 13:04)
Запустил SASPlanet.Debug.exe
После закрытия окошка с ошибкой программа продолжает работать.
Файл .elf ни после возникновения ошибки, ни после закрытия программы не появился. Возможно потому, что ошибка возникла в PascalScript IDE.

В дебажной версии текст ошибки, кстати, изменился
Было Access Violation, стало Assertion Failure:



PARAMS.TXT:
---
[PARAMS]
GUID={CBA03063-23D9-F11F-C22C-9182B98644B1}
asLayer=1
name_ru=Test
CacheType=2
projection=1
sradiusa=6378137
sradiusb=6378137
NameInCache=Test
Ext=.png
ContentType=image/png
UseDwn=1
---

Заархивировал всю папку с программой как есть:
https://disk.yandex.ru/d/hjS0L21U6fqkpw (18Mb)

(0020112)
zed   
09-04-2021 13:32   
Вроде починил, тестируйте новую сборку.
(0020113)
VadimK   
09-04-2021 14:38   
(edited on: 09-04-2021 14:39)
Ошибка ушла.
Ваш скрипт нормально работает.
Попробовал его упростить и разнообразить одновременно:
---
var
  VResult: Boolean;
begin
  VResult := TileCache.Write(GetX, GetY, GetZ, '', 'image/png', inttostr(GetX)+'-'+inttostr(GetY)+'-'+inttostr(GetZ), False);
  writeln(IntToStr(Integer(VResult)));
end.
---
Отработал этот скрипт нормально.

В режиме скачивания области по окончании процесса в статистике скачанных файлов/байт стоит 0.



Похоже, статистика подсчитывает только файлы, полученные через ResultURL.

PS: Попозже попробую интегрировать новые фишки в свой скрипт. Ещё раз, спасибо вам огромное за быструю реакцию на мои "хотелки" !!!