Реализация ожидания потока в импортированном скрипте

Jonathan Rosewood

Известный
Автор темы
20
0
updater.lua:
script_name('Updater')
script_version_number(1)

function downloadUrlToFileSync(url, path)
    local dlstatus = require 'moonloader'.download_status
    download_id = downloadUrlToFile(url, path, function(id, status, p1, p2)
        if status ~= dlstatus.STATUSEX_ENDDOWNLOAD then return end
        download_id = nil
    end)
    while download_id do wait(100) end
end

function EXPORTS.autoupdate(url, version, force)
    -- Download version file
    local version_url = url .. '/version.json'
    local version_path = os.getenv('TEMP') .. '\\' .. 'version.json'
    if doesFileExist(version_path) then os.remove(version_path) end
    downloadUrlToFileSync(version_url, version_path)

    -- Open version file
    local version_file = io.open(version_path, 'r')
    if not file then return false end

    -- Read version data
    local version_data = decodeJson(file:read('*a'))
    file:close()
    os.remove(version_path)
    if not version_data then return false end

    -- Check update available
    if not force and version_data.version <= version then return false end
    print('Script update found, downloading...')

    -- Download update files
    for index, file in pairs(version_data.files) do
        local file_url = base_url .. '/files/' .. file
        local file_path = getWorkingDirectory() .. '\\' .. file
        downloadUrlToFileSync(file_url, file_path)
    end

    -- Reload script
    print('Download complete, reloading script...')
    return true
end

function main()
    wait(-1)
end

script.lua:
script_name('Some updatable script')
script_version_number(1)

local updater = import('updater.lua')

function main()
    local script = thisScript()
    local url = 'https://some-direct-url-to-script-update-server.directory/'
    if updater.autoupdate(url, script.version) then script:reload() end
    wait(-1)
end

Попытка выполнения данного кода, вызывает ошибку (номера строк могут не соответствовать действительности)
console:
(error)    Updater: D:\Games\GTA San Andreas\moonloader\updater.lua:10: attempt to yield across C-call boundary
stack traceback:
    [C]: in function 'wait'
    D:\Games\GTA San Andreas\moonloader\updater.lua:10: in function 'downloadUrlToFileSync'
    D:\Games\GTA San Andreas\moonloader\updater.lua:26: in function <D:\Games\GTA San Andreas\moonloader\updater.lua:31>
stack traceback:
    [C]: in function 'autoupdate'
    D:\Games\GTA San Andreas\moonloader\script.lua:91: in function <D:\Games\GTA San Andreas\moonloader\script.lua:84>
(error)    Script: Script died due to an error. (1F50E674)
 

meowprd

Тот самый Котовский
Проверенный
1,278
720
единственное что пришло на ум в первую секунду:
function downloadUrlToFileSync(url, path) сделать в потоке
Lua:
function downloadUrlToFileSync(url, path)
    lua_thread.create(function()
        local dlstatus = require 'moonloader'.download_status
        download_id = downloadUrlToFile(url, path, function(id, status, p1, p2)
            if status ~= dlstatus.STATUSEX_ENDDOWNLOAD then return end
            download_id = nil
        end)
        while download_id do wait(100) end
    end)
end
 

Jonathan Rosewood

Известный
Автор темы
20
0
единственное что пришло на ум в первую секунду:
function downloadUrlToFileSync(url, path) сделать в потоке
Lua:
function downloadUrlToFileSync(url, path)
    lua_thread.create(function()
        local dlstatus = require 'moonloader'.download_status
        download_id = downloadUrlToFile(url, path, function(id, status, p1, p2)
            if status ~= dlstatus.STATUSEX_ENDDOWNLOAD then return end
            download_id = nil
        end)
        while download_id do wait(100) end
    end)
end
Да, но это ломает суть функции.
Мне необходимо дождаться её выполнения, ибо загрузка должна быть синхронная и блокировать поток :)
 
Последнее редактирование:

Jonathan Rosewood

Известный
Автор темы
20
0
Lua:
function downloadUrlToFileSync(url, path)
    local dlstatus = require 'moonloader'.download_status
    download_id = downloadUrlToFile(url, path, function(id, status, p1, p2)
        if status ~= dlstatus.STATUSEX_ENDDOWNLOAD then return end
        download_id = nil
    end)
    lua_thread.create(function()
        while download_id do wait(100) end
    end)
end
Аналогично ответу выше :)
 

meowprd

Тот самый Котовский
Проверенный
1,278
720
updater.lua:
script_name('Updater')
script_version_number(1)


function downloadUrlToFileSync(url, path)
    local dlstatus = require 'moonloader'.download_status
    download_id = downloadUrlToFile(url, path, function(id, status, p1, p2)
        if status ~= dlstatus.STATUSEX_ENDDOWNLOAD then return end
        download_id = nil
    end)
    return
end

function EXPORTS.autoupdate(url, version, force)
    -- Download version file
    local version_url = url .. '/version.json'
    local version_path = os.getenv('TEMP') .. '\\' .. 'version.json'
    if doesFileExist(version_path) then os.remove(version_path) end
    --downloadUrlToFileSync(version_url, version_path)
    update = lua_thread.create_suspended(downloadUrlToFileSync)
    update:run(version_url, version_path)
    while not update.dead do wait(100) end

    -- Open version file
    local version_file = io.open(version_path, 'r')
    if not file then return false end

    -- Read version data
    local version_data = decodeJson(file:read('*a'))
    file:close()
    os.remove(version_path)
    if not version_data then return false end

    -- Check update available
    if not force and version_data.version <= version then return false end
    print('Script update found, downloading...')

    -- Download update files
    for index, file in pairs(version_data.files) do
        local file_url = base_url .. '/files/' .. file
        local file_path = getWorkingDirectory() .. '\\' .. file
        downloadUrlToFileSync(file_url, file_path)
    end

    -- Reload script
    print('Download complete, reloading script...')
    return true
end

function main()
    wait(-1)
end

Проверил - запустилось, работоспособность проверять не стал, уверен что будет работать.
Вспомнил одну из таких реализаций в своем древнем скрипте


upd: стало интересно перечитать код, примерно понять как он работает. Заметил пару недочетов
Lua:
local version_file = io.open(version_path, 'r') -- 21 line
if not file then return false end -- 22 line

Надеюсь сам с ними разберешься или я что-то не так понимаю
 
Последнее редактирование:
  • Нравится
Реакции: Jonathan Rosewood

Jonathan Rosewood

Известный
Автор темы
20
0
updater.lua:
script_name('Updater')
script_version_number(1)


function downloadUrlToFileSync(url, path)
    local dlstatus = require 'moonloader'.download_status
    download_id = downloadUrlToFile(url, path, function(id, status, p1, p2)
        if status ~= dlstatus.STATUSEX_ENDDOWNLOAD then return end
        download_id = nil
    end)
    return
end

function EXPORTS.autoupdate(url, version, force)
    -- Download version file
    local version_url = url .. '/version.json'
    local version_path = os.getenv('TEMP') .. '\\' .. 'version.json'
    if doesFileExist(version_path) then os.remove(version_path) end
    --downloadUrlToFileSync(version_url, version_path)
    update = lua_thread.create_suspended(downloadUrlToFileSync)
    update:run(version_url, version_path)
    while not update.dead do wait(100) end

    -- Open version file
    local version_file = io.open(version_path, 'r')
    if not file then return false end

    -- Read version data
    local version_data = decodeJson(file:read('*a'))
    file:close()
    os.remove(version_path)
    if not version_data then return false end

    -- Check update available
    if not force and version_data.version <= version then return false end
    print('Script update found, downloading...')

    -- Download update files
    for index, file in pairs(version_data.files) do
        local file_url = base_url .. '/files/' .. file
        local file_path = getWorkingDirectory() .. '\\' .. file
        downloadUrlToFileSync(file_url, file_path)
    end

    -- Reload script
    print('Download complete, reloading script...')
    return true
end

function main()
    wait(-1)
end

Проверил - запустилось, работоспособность проверять не стал, уверен что будет работать.
Вспомнил одну из таких реализаций в своем древнем скрипте


upd: стало интересно перечитать код, примерно понять как он работает. Заметил пару недочетов
Lua:
local version_file = io.open(version_path, 'r') -- 21 line
if not file then return false end -- 22 line

Надеюсь сам с ними разберешься или я что-то не так понимаю
Спасибо за ответ!
Но, возникает вопрос, как ожидается завершение загрузки выполнения функции downloadUrlToFile в теле downloadUrlToFileSync.
Получается, что мы ждём завершения функции downloadUrlToFileSync, которая вызывает "асинхронную" downloadUrlToFile и мы не дожидаемся завершения загрузки...
Я именно для этого использовал ожидание присвоения nil флагу download_id.

И спасибо за проявленный интерес к работе кода.
Всё это делается как единый модуль, отвечающий за обновление моих скриптов, дабы не дублировать код обновления в каждом из них.
21 и 22 строка - это издержки выпиливания кода для форума из боевого скрипта, где значительно больше функционала в этих функциях.
 
Последнее редактирование:

meowprd

Тот самый Котовский
Проверенный
1,278
720
Спасибо за ответ!
Но, возникает вопрос, как ожидается завершение загрузки выполнения функции downloadUrlToFile в теле downloadUrlToFileSync.
Получается, что мы ждём завершения функции downloadUrlToFileSync, которая вызывает "асинхронную" downloadUrlToFile и мы не дожидаемся завершения загрузки...
Я именно для этого использовал ожидание присвоения nil флагу download_id.

И спасибо за проявленный интерес к работе кода.
Всё это делается как единый модуль, отвечающий за обновление моих скриптов, дабы не дублировать код обновления в каждом из них.
21 и 22 строка - это издержки выпиливания кода для форума из боевого скрипта, где значительно больше функционала в этих функциях.
В принципе, по download_id можно сделать проверку, так как ты объявляешь ее не как локальную переменную внутри функции
Lua:
while download_id ~= nil do wait(100) end
вместо
Lua:
while not update.dead do wait(100) end
либо добавить данную проверку ниже.

Как буду дома - поэкспериментирую.
 

Jonathan Rosewood

Известный
Автор темы
20
0
В принципе, по download_id можно сделать проверку, так как ты объявляешь ее не как локальную переменную внутри функции
Lua:
while download_id ~= nil do wait(100) end
вместо
Lua:
while not update.dead do wait(100) end
либо добавить данную проверку ниже.

Как буду дома - поэкспериментирую.
В случае, если объявлять эту переменную как глобальную или вне экспортируемой функции, то будет невозможно использовать этот скрипт для обновления сразу нескольких скриптов.
 

meowprd

Тот самый Котовский
Проверенный
1,278
720
В случае, если объявлять эту переменную как глобальную или вне экспортируемой функции, то будет невозможно использовать этот скрипт для обновления сразу нескольких скриптов.
Lua:
script_name('Updater')
script_version_number(1)

local download_id = nil

-- code
 

Jonathan Rosewood

Известный
Автор темы
20
0
Lua:
script_name('Updater')
script_version_number(1)

local download_id = nil

-- code

Первое импортирование скрипта приводит к полному копированию (кроме функций) его экспортируемых данных в импортирующий скрипт, а повторное импортирование будет возвращать уже загруженные значения. Именно поэтому изменение значений экспортов становится бессмысленным после первого импортирования, и это может привести к несоответствиям между скриптами, если какой-то скрипт загрузит список импортов рано, а другой с задержкой. В связи с этим для правильной реализации доступа к изменяющимся данным нужно использовать функции.
(c) https://wiki.blast.hk/moonloader/exports

Похоже на правду, спасибо.
В свободное время попробую и отпишусь в данной теме.
 

meowprd

Тот самый Котовский
Проверенный
1,278
720
К сожалению, все попытки вызвать ожидание тщетны и вызывают ошибку attempt to yield across C-call boundary.
Можно сделать проверку по doesFileExist, как еще один вариант, но для autoupdate скрипта это не подойдет