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

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

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

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

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

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

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

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

Файл 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')");

Если я вызываю такой метод, я попадаю в точку останова в отладчике, который находится поверх метода, поэтому все работает, как ожидалось. xmlns: android = "http://schemas.android.com/apk/res/android">

Я добавляю скрипты с Lua в наше приложение, и мне нужно реализовать привязки для GUI-инструментария. Набор инструментов, который мы используем, - это wxWidgets.

Я использую Lua 5.1 и luabind 0.9.1, и до сих пор он работал очень хорошо. Однако я не уверен, как лучше всего обрабатывать события. Например, если вы хотите создать кнопку и печатать строку при ее нажатии, вы напишете что-то подобное на C ++

class MyClass : public wxFrame
{
    MyClass (...)
    {
        b = new wxButton (this, -1, "Click me");
        b->Bind (wxEVT_COMMAND_BUTTON_CLICKED, &MyClass::HandleButtonClick, this);
    }

    void HandleButtonClick (wxCommandEvent& ev)
    {
        wxMessageBox ("You clicked me");
    }
}

API моей мечты для выполнения того же самого в Lua будет выглядеть примерно так:

b = wx.Button (frm, -1, "Click me")
b.on_click = function (ev)
    print ("Button clicked")
end

Или , позволяя использовать несколько обработчиков событий:

b.on_click:add (function (ev)
    print ("Button clicked again ...")
end)

Если это невозможно, то что-то вроде этого, что больше похоже на C ++ API:

b.bind (wx.EVT_COMMAND_BUTTON_CLICKED, function (ev)
    print ("Yet again")
end)

Однако я не уверен, как реализовать это с помощью Luabind без написания класса-оболочки для каждого класса в wxWidgets -библиотека, которую я хочу использовать.

Есть предложения?

Может быть, Luabind может каким-то образом автоматически создавать вспомогательные классы (скажем, «wxLuaEventPropagator»)? Таким образом, класс wxButton имеет вложенный класс wxLuaEventPropagator для каждого события («on_click» и т. Д.). Еще раз, я не хочу создавать классы-оболочки для каждого класса в wxWidgets, который я использую, поскольку их очень много.

(Да, я знаю о wxLua)

27
задан Jonatan 6 April 2011 в 19:58
поделиться