Как реализовать загрузчик модулей контейнера Lua (виртуальной файловой системы) в C # - PullRequest
5 голосов
/ 06 апреля 2011

Звучит немного страшно, не так ли?

Немного справочной информации, я хочу загрузить tar-архив, содержащий несколько модулей lua, в мое приложение C # с использованием LuaInterface.Самый простой способ - извлечь эти файлы во временную папку, изменить путь поиска модуля lua и, как обычно, прочитать их с помощью require.Но я не хочу помещать эти сценарии где-нибудь в файловую систему.

Поэтому я подумал, что можно загрузить tar-архив с помощью # ziplib Я знаю, что их многореализаций lua для tar и тому подобного.Но #zlib уже является частью проекта.

После успешной загрузки файла в виде строк (потоков) из архива я смогу передать их в lua.DoString (...) в C # черезLuaInterface.

Но простая загрузка модулей с помощью dostring или dofile не работает, если у модулей есть строка, подобная этой: "module (..., package.seeall)" Есть сообщение об ошибке, например, передача аргумента 1 в ноль,но ожидаемая строка.

Другая проблема в том, что модуль может зависеть от других модулей, которые также находятся в архиве tar.

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

Моя идея состоит в том, чтобы реализовать такой загрузчик в C # с помощью #ziplib и отобразить этот загрузчикв стек lua ​​моего приложения на C #.

Кто-нибудь из вас сталкивался с подобной задачей?Есть ли готовые к использованию решения, которые уже решают подобные проблемы?

Файл tar не обязательно должен иметь формат пакета.

Является ли эта идея осуществимой или полностью неосуществимой?

Я написал пример класса для извлечения файлов lua из архива.Этот метод работает как загрузчик и возвращает функцию lua.

namespace LuaInterfaceTest
{
 class LuaTarModuleLoader
 {
    private LuaTarModuleLoader() { }
    ~LuaTarModuleLoader()
    {
        in_stream_.Close();
    }
    public LuaTarModuleLoader(Stream in_stream,Lua lua )
    {
        in_stream_ = in_stream;
        lua_ = lua;
    }

    public LuaFunction load(string modulename, out string error_message)
    {
        string lua_chunk = "test=hello";
        string filename = modulename + ".lua";
        error_message = "Unable to locate the file";
        in_stream_.Position = 0; // rewind
        Stream gzipStream = new BZip2InputStream(in_stream_);
        TarInputStream tar = new TarInputStream(gzipStream);
        TarEntry tarEntry;
        LuaFunction func = null;
        while ((tarEntry = tar.GetNextEntry()) != null)
        {
            if (tarEntry.IsDirectory)
            {
                continue;
            }
            if (filename == tarEntry.Name)
            {
                MemoryStream out_stream = new MemoryStream();
                tar.CopyEntryContents(out_stream);
                out_stream.Position = 0; // rewind
                StreamReader stream_reader = new StreamReader(out_stream);
                lua_chunk = stream_reader.ReadToEnd();
                func = lua_.LoadString(lua_chunk, filename);
                string dum = func.ToString();
                error_message = "No Error!";
                break;
            }
        }
        return func;
    }
    private Stream in_stream_;
    private Lua lua_;
}

}

Я пытаюсь зарегистрировать метод загрузки следующим образом в LuaInterface

        Lua lua = new Lua();
        GC.Collect();
        Stream inStream = File.OpenRead("c:\\tmp\\lua_scripts.tar.bz2");
        LuaTarModuleLoader tar_loader = new LuaTarModuleLoader(inStream, lua);
        lua.DoString("require 'CLRPackage'");
        lua.DoString("import \"ICSharpCode.SharpZipLib.dll\"");
        lua.DoString("import \"System\"");
        lua["container_module_loader"] = tar_loader;
        lua.DoString("table.insert(package.loaders, 2, container_module_loader.load)");
        lua.DoString("require 'def_sensor'");

Если япопробуйте так, я получу исключение, в то время как вызов требует:

"экземпляр метода 'load' требует ненулевого целевого объекта"

Я пыталсявызовите метод загрузки напрямую, здесь я должен использовать нотацию ":".

lua.DoString("container_module_loader:load('def_sensor')");

Если я вызываю метод таким образом, я попадаю на точку останова в отладчике, который находится поверх метода, так что все работает как положено.

Но если я пытаюсь зарегистрироватьметод с нотацией ":" Я получаю исключение при регистрации метода:

lua.DoString("table.insert(package.loaders, 2, container_module_loader:load)");

"[string" chunk "]: 1: аргументы функции ожидаются рядом с ')'"

Ответы [ 2 ]

3 голосов
/ 07 апреля 2011

Я наконец-то получил трюк; -)

Одна проблема, которую я сейчас не совсем понимаю, заключается в том, что мой загрузчик не должен возвращать ни одной строки. Вот мое решение:

Сам класс погрузчика:

namespace LuaInterfaceTest
{
class LuaTarModuleLoader
{
    private LuaTarModuleLoader() { }
    ~LuaTarModuleLoader()
    {
        in_stream_.Close();
    }
    public LuaTarModuleLoader(Stream in_stream,Lua lua )
    {
        in_stream_ = in_stream;
        lua_ = lua;
    }

    public LuaFunction load(string modulename)
    {
        string lua_chunk = "";
        string filename = modulename + ".lua";
        in_stream_.Position = 0; // rewind
        Stream gzipStream = new BZip2InputStream(in_stream_);
        TarInputStream tar = new TarInputStream(gzipStream);
        TarEntry tarEntry;
        LuaFunction func = null;
        while ((tarEntry = tar.GetNextEntry()) != null)
        {
            if (tarEntry.IsDirectory)
            {
                continue;
            }
            if (filename == tarEntry.Name)
            {
                MemoryStream out_stream = new MemoryStream();
                tar.CopyEntryContents(out_stream);
                out_stream.Position = 0; // rewind
                StreamReader stream_reader = new StreamReader(out_stream);
                lua_chunk = stream_reader.ReadToEnd();
                func = lua_.LoadString(lua_chunk, modulename);
                string dum = func.ToString();
                break;
            }
        }
        return func;
    }
    private Stream in_stream_;
    private Lua lua_;
}

}

А как использовать загрузчик, я не уверен, действительно ли нужен весь пакет. Но мне пришлось заключить вызов в нотацию ":" и спрятать его за моей функцией load_wrapper.

        string load_wrapper = "local function load_wrapper(modname)\n return container_module_loader:load(modname)\n end";
        Lua lua = new Lua();
        GC.Collect();
        Stream inStream = File.OpenRead("c:\\tmp\\lua_scripts.tar.bz2");
        LuaTarModuleLoader tar_loader = new LuaTarModuleLoader(inStream, lua);
        lua.DoString("require 'CLRPackage'");
        lua.DoString("import \"System\"");
        lua["container_module_loader"] = tar_loader;
        lua.DoString(load_wrapper);

        string loader_package = "module('my_loader', package.seeall) \n";
        loader_package += load_wrapper + "\n";
        loader_package += "table.insert(package.loaders, 2, load_wrapper)";
        lua.DoString(loader_package);
        lua.DoFile("./load_modules.lua");

Надеюсь, это может помочь и другим

3 голосов
/ 07 апреля 2011

В LÖVE у них это работает. Все файлы Lua находятся внутри одного zip-файла, и они работают, даже если используется .... Используемая ими библиотека: PhysicsFS .

Посмотрите на источник . Возможно, / modules / filesystem поможет вам начать.

...