fix: Lua factory init failure under concurrent display editing
This commit is contained in:
@@ -20,23 +20,24 @@ let LuaEditDisplayIds = new Set<string>()
|
|||||||
let LuaLowLevelIds = new Set<string>()
|
let LuaLowLevelIds = new Set<string>()
|
||||||
|
|
||||||
interface LuaEngineState {
|
interface LuaEngineState {
|
||||||
code: string;
|
code?: string;
|
||||||
engine: LuaEngine;
|
engine?: LuaEngine;
|
||||||
mutex: Mutex;
|
mutex: Mutex;
|
||||||
chat: Chat;
|
wasEmpty?: boolean;
|
||||||
setVar: (key:string, value:string) => void,
|
chat?: Chat;
|
||||||
getVar: (key:string) => string,
|
setVar?: (key:string, value:string) => void,
|
||||||
getGlobalVar: (key:string) => any,
|
getVar?: (key:string) => string,
|
||||||
}
|
}
|
||||||
|
|
||||||
let LuaEngines = new Map<string, LuaEngineState>()
|
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:{
|
export async function runLua(code:string, arg:{
|
||||||
char?:character|groupChat|simpleCharacterArgument,
|
char?:character|groupChat|simpleCharacterArgument,
|
||||||
chat?:Chat
|
chat?:Chat
|
||||||
setVar?: (key:string, value:string) => void,
|
setVar?: (key:string, value:string) => void,
|
||||||
getVar?: (key:string) => string,
|
getVar?: (key:string) => string,
|
||||||
getGlobalVar?: (key:string) => any,
|
|
||||||
lowLevelAccess?: boolean,
|
lowLevelAccess?: boolean,
|
||||||
mode?: string,
|
mode?: string,
|
||||||
data?: any
|
data?: any
|
||||||
@@ -44,40 +45,25 @@ export async function runLua(code:string, arg:{
|
|||||||
const char = arg.char ?? getCurrentCharacter()
|
const char = arg.char ?? getCurrentCharacter()
|
||||||
const setVar = arg.setVar ?? setChatVar
|
const setVar = arg.setVar ?? setChatVar
|
||||||
const getVar = arg.getVar ?? getChatVar
|
const getVar = arg.getVar ?? getChatVar
|
||||||
const getGlobalVar = arg.getGlobalVar ?? getGlobalChatVar
|
|
||||||
const mode = arg.mode ?? 'manual'
|
const mode = arg.mode ?? 'manual'
|
||||||
const data = arg.data ?? {}
|
const data = arg.data ?? {}
|
||||||
let chat = arg.chat ?? getCurrentChat()
|
let chat = arg.chat ?? getCurrentChat()
|
||||||
let stopSending = false
|
let stopSending = false
|
||||||
let lowLevelAccess = arg.lowLevelAccess ?? false
|
let lowLevelAccess = arg.lowLevelAccess ?? false
|
||||||
|
|
||||||
if(!luaFactory){
|
await ensureLuaFactory()
|
||||||
await makeLuaFactory()
|
let luaEngineState = await getOrCreateEngineState(mode);
|
||||||
}
|
|
||||||
let luaEngineState = LuaEngines.get(mode)
|
return await luaEngineState.mutex.runExclusive(async () => {
|
||||||
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 {
|
|
||||||
luaEngineState.chat = chat
|
luaEngineState.chat = chat
|
||||||
luaEngineState.setVar = setVar
|
luaEngineState.setVar = setVar
|
||||||
luaEngineState.getVar = getVar
|
luaEngineState.getVar = getVar
|
||||||
luaEngineState.getGlobalVar = getGlobalVar
|
if (code !== luaEngineState.code) {
|
||||||
}
|
if (!luaEngineState.wasEmpty){
|
||||||
return await luaEngineState.mutex.runExclusive(async () => {
|
|
||||||
if (wasEmpty || code !== luaEngineState.code) {
|
|
||||||
if (!wasEmpty)
|
|
||||||
luaEngineState.engine.global.close()
|
luaEngineState.engine.global.close()
|
||||||
|
}
|
||||||
|
luaEngineState.code = code
|
||||||
|
luaEngineState.wasEmpty = false
|
||||||
luaEngineState.engine = await luaFactory.createEngine({injectObjects: true})
|
luaEngineState.engine = await luaFactory.createEngine({injectObjects: true})
|
||||||
const luaEngine = luaEngineState.engine
|
const luaEngine = luaEngineState.engine
|
||||||
luaEngine.global.set('setChatVar', (id:string,key:string, value:string) => {
|
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)){
|
if(!LuaSafeIds.has(id) && !LuaEditDisplayIds.has(id)){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return luaEngineState.getGlobalVar(key)
|
return getGlobalChatVar(key)
|
||||||
})
|
})
|
||||||
luaEngine.global.set('stopChat', (id:string) => {
|
luaEngine.global.set('stopChat', (id:string) => {
|
||||||
if(!LuaSafeIds.has(id)){
|
if(!LuaSafeIds.has(id)){
|
||||||
@@ -564,7 +550,7 @@ export async function runLua(code:string, arg:{
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function makeLuaFactory(){
|
async function makeLuaFactory(){
|
||||||
luaFactory = new LuaFactory()
|
const _luaFactory = new LuaFactory()
|
||||||
async function mountFile(name:string){
|
async function mountFile(name:string){
|
||||||
let code = ''
|
let code = ''
|
||||||
for(let i = 0; i < 3; i++){
|
for(let i = 0; i < 3; i++){
|
||||||
@@ -576,10 +562,61 @@ async function makeLuaFactory(){
|
|||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
await luaFactory.mountFile(name,code)
|
await _luaFactory.mountFile(name,code)
|
||||||
}
|
}
|
||||||
|
|
||||||
await mountFile('json.lua')
|
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){
|
function luaCodeWarper(code:string){
|
||||||
@@ -687,7 +724,6 @@ callListenMain = async(function(type, id, value)
|
|||||||
if type == 'editDisplay' then
|
if type == 'editDisplay' then
|
||||||
for _, func in ipairs(editDisplayFuncs) do
|
for _, func in ipairs(editDisplayFuncs) do
|
||||||
realValue = func(id, realValue)
|
realValue = func(id, realValue)
|
||||||
print(realValue)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user