fix: Lua factory init failure under concurrent display editing

This commit is contained in:
bangonicdd
2025-04-09 01:45:06 +09:00
parent d91dd1b825
commit dc753adf1f

View File

@@ -20,23 +20,24 @@ let LuaEditDisplayIds = new Set<string>()
let LuaLowLevelIds = new Set<string>()
interface LuaEngineState {
code: string;
engine: LuaEngine;
code?: string;
engine?: LuaEngine;
mutex: Mutex;
chat: Chat;
setVar: (key:string, value:string) => void,
getVar: (key:string) => string,
getGlobalVar: (key:string) => any,
wasEmpty?: boolean;
chat?: Chat;
setVar?: (key:string, value:string) => void,
getVar?: (key:string) => string,
}
let LuaEngines = new Map<string, LuaEngineState>()
let luaFactoryPromise: Promise<void> | null = null;
let pendingEngineCreations = new Map<string, Promise<LuaEngineState>>();
export async function runLua(code:string, arg:{
char?:character|groupChat|simpleCharacterArgument,
chat?:Chat
setVar?: (key:string, value:string) => void,
getVar?: (key:string) => string,
getGlobalVar?: (key:string) => any,
lowLevelAccess?: boolean,
mode?: string,
data?: any
@@ -44,40 +45,25 @@ export async function runLua(code:string, arg:{
const char = arg.char ?? getCurrentCharacter()
const setVar = arg.setVar ?? setChatVar
const getVar = arg.getVar ?? getChatVar
const getGlobalVar = arg.getGlobalVar ?? getGlobalChatVar
const mode = arg.mode ?? 'manual'
const data = arg.data ?? {}
let chat = arg.chat ?? getCurrentChat()
let stopSending = false
let lowLevelAccess = arg.lowLevelAccess ?? false
if(!luaFactory){
await makeLuaFactory()
}
let luaEngineState = LuaEngines.get(mode)
let wasEmpty = false
if (!luaEngineState) {
luaEngineState = {
code,
engine: await luaFactory.createEngine({injectObjects: true}),
mutex: new Mutex(),
chat,
setVar,
getVar,
getGlobalVar
}
LuaEngines.set(mode, luaEngineState)
wasEmpty = true
} else {
await ensureLuaFactory()
let luaEngineState = await getOrCreateEngineState(mode);
return await luaEngineState.mutex.runExclusive(async () => {
luaEngineState.chat = chat
luaEngineState.setVar = setVar
luaEngineState.getVar = getVar
luaEngineState.getGlobalVar = getGlobalVar
}
return await luaEngineState.mutex.runExclusive(async () => {
if (wasEmpty || code !== luaEngineState.code) {
if (!wasEmpty)
if (code !== luaEngineState.code) {
if (!luaEngineState.wasEmpty){
luaEngineState.engine.global.close()
}
luaEngineState.code = code
luaEngineState.wasEmpty = false
luaEngineState.engine = await luaFactory.createEngine({injectObjects: true})
const luaEngine = luaEngineState.engine
luaEngine.global.set('setChatVar', (id:string,key:string, value:string) => {
@@ -96,7 +82,7 @@ export async function runLua(code:string, arg:{
if(!LuaSafeIds.has(id) && !LuaEditDisplayIds.has(id)){
return
}
return luaEngineState.getGlobalVar(key)
return getGlobalChatVar(key)
})
luaEngine.global.set('stopChat', (id:string) => {
if(!LuaSafeIds.has(id)){
@@ -564,7 +550,7 @@ export async function runLua(code:string, arg:{
}
async function makeLuaFactory(){
luaFactory = new LuaFactory()
const _luaFactory = new LuaFactory()
async function mountFile(name:string){
let code = ''
for(let i = 0; i < 3; i++){
@@ -576,10 +562,61 @@ async function makeLuaFactory(){
}
} catch (error) {}
}
await luaFactory.mountFile(name,code)
await _luaFactory.mountFile(name,code)
}
await mountFile('json.lua')
luaFactory = _luaFactory
}
async function ensureLuaFactory() {
if (luaFactory) return;
if (luaFactoryPromise) {
try {
await luaFactoryPromise;
} catch (error) {
luaFactoryPromise = null;
}
return;
}
try {
luaFactoryPromise = makeLuaFactory();
await luaFactoryPromise;
} finally {
luaFactoryPromise = null;
}
}
async function getOrCreateEngineState(
mode: string,
): Promise<LuaEngineState> {
let engineState = LuaEngines.get(mode);
if (engineState) {
return engineState;
}
let pendingCreation = pendingEngineCreations.get(mode);
if (pendingCreation) {
return pendingCreation;
}
const creationPromise = (async () => {
const engineState: LuaEngineState = {
mutex: new Mutex(),
wasEmpty: true,
};
LuaEngines.set(mode, engineState);
pendingEngineCreations.delete(mode);
return engineState;
})();
pendingEngineCreations.set(mode, creationPromise);
return creationPromise;
}
function luaCodeWarper(code:string){
@@ -687,7 +724,6 @@ callListenMain = async(function(type, id, value)
if type == 'editDisplay' then
for _, func in ipairs(editDisplayFuncs) do
realValue = func(id, realValue)
print(realValue)
end
end