mirror of
https://github.com/SikongJueluo/cc-utils.git
synced 2025-12-20 13:37:49 +08:00
fix: auto reload
reconstruct: semaphore and read write lock use undefined instead of null fix: accesscontrol auto reload config
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
import { CCLog } from "@/lib/ccLog";
|
import { CCLog } from "@/lib/ccLog";
|
||||||
import { AccessConfig, UserGroupConfig, saveConfig } from "./config";
|
import {
|
||||||
|
AccessConfig,
|
||||||
|
UserGroupConfig,
|
||||||
|
loadConfig,
|
||||||
|
saveConfig,
|
||||||
|
} from "./config";
|
||||||
import { ChatBoxEvent, pullEventAs } from "@/lib/event";
|
import { ChatBoxEvent, pullEventAs } from "@/lib/event";
|
||||||
import { parseBoolean } from "@/lib/common";
|
import { parseBoolean } from "@/lib/common";
|
||||||
|
|
||||||
@@ -16,19 +21,19 @@ interface CLIResult {
|
|||||||
success: boolean;
|
success: boolean;
|
||||||
message?: string;
|
message?: string;
|
||||||
shouldSaveConfig?: boolean;
|
shouldSaveConfig?: boolean;
|
||||||
|
config?: AccessConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CLI上下文
|
// CLI上下文
|
||||||
interface CLIContext {
|
interface CLIContext {
|
||||||
config: AccessConfig;
|
|
||||||
configFilepath: string;
|
configFilepath: string;
|
||||||
reloadConfig: () => void;
|
reloadConfig: () => void;
|
||||||
log: CCLog;
|
log: CCLog;
|
||||||
chatBox: ChatBoxPeripheral;
|
chatBox: ChatBoxPeripheral;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroupNames(context: CLIContext) {
|
function getGroupNames(config: AccessConfig) {
|
||||||
return context.config.usersGroups.flatMap((value) => value.groupName);
|
return config.usersGroups.flatMap((value) => value.groupName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 基础命令处理器
|
// 基础命令处理器
|
||||||
@@ -76,10 +81,6 @@ class CLICommandProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ret = command.execute(args, executor, this.context);
|
const ret = command.execute(args, executor, this.context);
|
||||||
if (ret.success) {
|
|
||||||
this.context.reloadConfig();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +102,8 @@ class CLICommandProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.shouldSaveConfig === true) {
|
if (result.shouldSaveConfig === true) {
|
||||||
saveConfig(this.context.config, this.context.configFilepath);
|
saveConfig(result.config!, this.context.configFilepath);
|
||||||
|
this.context.reloadConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,26 +123,30 @@ class AddCommand implements CLICommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [groupName, playerName] = args;
|
const [groupName, playerName] = args;
|
||||||
|
const config: AccessConfig = loadConfig(context.configFilepath)!;
|
||||||
|
|
||||||
if (groupName === "admin") {
|
if (groupName === "admin") {
|
||||||
context.config.adminGroupConfig.groupUsers.push(playerName);
|
config.adminGroupConfig.groupUsers.push(playerName);
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `Add player ${playerName} to admin`,
|
message: `Add player ${playerName} to admin`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupNames = getGroupNames(context);
|
const groupNames = getGroupNames(config);
|
||||||
|
|
||||||
if (!groupNames.includes(groupName)) {
|
if (!groupNames.includes(groupName)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `Invalid group: ${groupName}. Available groups: ${groupNames.join(", ")}`,
|
message: `Invalid group: ${groupName}. Available groups: ${groupNames.join(
|
||||||
|
", ",
|
||||||
|
)}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupConfig = context.config.usersGroups.find(
|
const groupConfig = config.usersGroups.find(
|
||||||
(value) => value.groupName === groupName,
|
(value) => value.groupName === groupName,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -161,6 +167,7 @@ class AddCommand implements CLICommand {
|
|||||||
success: true,
|
success: true,
|
||||||
message: `Add player ${playerName} to ${groupConfig.groupName}`,
|
message: `Add player ${playerName} to ${groupConfig.groupName}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,16 +195,19 @@ class DelCommand implements CLICommand {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupNames = getGroupNames(context);
|
const config: AccessConfig = loadConfig(context.configFilepath)!;
|
||||||
|
const groupNames = getGroupNames(config);
|
||||||
|
|
||||||
if (!groupNames.includes(groupName)) {
|
if (!groupNames.includes(groupName)) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: `Invalid group: ${groupName}. Available groups: ${groupNames.join(", ")}`,
|
message: `Invalid group: ${groupName}. Available groups: ${groupNames.join(
|
||||||
|
", ",
|
||||||
|
)}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const groupConfig = context.config.usersGroups.find(
|
const groupConfig = config.usersGroups.find(
|
||||||
(value) => value.groupName === groupName,
|
(value) => value.groupName === groupName,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -220,6 +230,7 @@ class DelCommand implements CLICommand {
|
|||||||
success: true,
|
success: true,
|
||||||
message: `Delete ${groupConfig.groupName} ${playerName}`,
|
message: `Delete ${groupConfig.groupName} ${playerName}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,9 +242,10 @@ class ListCommand implements CLICommand {
|
|||||||
usage = "list";
|
usage = "list";
|
||||||
|
|
||||||
execute(_args: string[], _executor: string, context: CLIContext): CLIResult {
|
execute(_args: string[], _executor: string, context: CLIContext): CLIResult {
|
||||||
let message = `Admins : [ ${context.config.adminGroupConfig.groupUsers.join(", ")} ]\n`;
|
const config = loadConfig(context.configFilepath)!;
|
||||||
|
let message = `Admins : [ ${config.adminGroupConfig.groupUsers.join(", ")} ]\n`;
|
||||||
|
|
||||||
for (const groupConfig of context.config.usersGroups) {
|
for (const groupConfig of config.usersGroups) {
|
||||||
const users = groupConfig.groupUsers ?? [];
|
const users = groupConfig.groupUsers ?? [];
|
||||||
message += `${groupConfig.groupName} : [ ${users.join(", ")} ]\n`;
|
message += `${groupConfig.groupName} : [ ${users.join(", ")} ]\n`;
|
||||||
}
|
}
|
||||||
@@ -269,29 +281,34 @@ class SetCommand implements CLICommand {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const config: AccessConfig = loadConfig(context.configFilepath)!;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case "warnInterval":
|
case "warnInterval":
|
||||||
context.config.watchInterval = value;
|
config.watchInterval = value;
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `Set warn interval to ${context.config.watchInterval}`,
|
message: `Set warn interval to ${config.watchInterval}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
|
|
||||||
case "detectInterval":
|
case "detectInterval":
|
||||||
context.config.detectInterval = value;
|
config.detectInterval = value;
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `Set detect interval to ${context.config.detectInterval}`,
|
message: `Set detect interval to ${config.detectInterval}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
|
|
||||||
case "detectRange":
|
case "detectRange":
|
||||||
context.config.detectRange = value;
|
config.detectRange = value;
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `Set detect range to ${context.config.detectRange}`,
|
message: `Set detect range to ${config.detectRange}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -310,7 +327,8 @@ class HelpCommand implements CLICommand {
|
|||||||
usage = "help";
|
usage = "help";
|
||||||
|
|
||||||
execute(_args: string[], _executor: string, context: CLIContext): CLIResult {
|
execute(_args: string[], _executor: string, context: CLIContext): CLIResult {
|
||||||
const groupNames = getGroupNames(context);
|
const config = loadConfig(context.configFilepath)!;
|
||||||
|
const groupNames = getGroupNames(config);
|
||||||
const helpMessage = `
|
const helpMessage = `
|
||||||
Command Usage: @AC /<Command> [args]
|
Command Usage: @AC /<Command> [args]
|
||||||
Commands:
|
Commands:
|
||||||
@@ -378,13 +396,14 @@ class EditCommand implements CLICommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const [groupName, property, valueStr] = args;
|
const [groupName, property, valueStr] = args;
|
||||||
|
const config: AccessConfig = loadConfig(context.configFilepath)!;
|
||||||
|
|
||||||
let groupConfig: UserGroupConfig | undefined;
|
let groupConfig: UserGroupConfig | undefined;
|
||||||
|
|
||||||
if (groupName === "admin") {
|
if (groupName === "admin") {
|
||||||
groupConfig = context.config.adminGroupConfig;
|
groupConfig = config.adminGroupConfig;
|
||||||
} else {
|
} else {
|
||||||
groupConfig = context.config.usersGroups.find(
|
groupConfig = config.usersGroups.find(
|
||||||
(group) => group.groupName === groupName,
|
(group) => group.groupName === groupName,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -405,6 +424,7 @@ class EditCommand implements CLICommand {
|
|||||||
success: true,
|
success: true,
|
||||||
message: `Set ${groupName}.isAllowed to ${groupConfig.isAllowed}`,
|
message: `Set ${groupName}.isAllowed to ${groupConfig.isAllowed}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@@ -423,6 +443,7 @@ class EditCommand implements CLICommand {
|
|||||||
success: true,
|
success: true,
|
||||||
message: `Set ${groupName}.isNotice to ${groupConfig.isNotice}`,
|
message: `Set ${groupName}.isNotice to ${groupConfig.isNotice}`,
|
||||||
shouldSaveConfig: true,
|
shouldSaveConfig: true,
|
||||||
|
config,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
@@ -450,15 +471,16 @@ class ShowConfigCommand implements CLICommand {
|
|||||||
|
|
||||||
execute(args: string[], _executor: string, context: CLIContext): CLIResult {
|
execute(args: string[], _executor: string, context: CLIContext): CLIResult {
|
||||||
const type = args[0] || "all";
|
const type = args[0] || "all";
|
||||||
|
const config = loadConfig(context.configFilepath)!;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "groups": {
|
case "groups": {
|
||||||
let groupsMessage = `Admin Group: ${context.config.adminGroupConfig.groupName}\n`;
|
let groupsMessage = `Admin Group: ${config.adminGroupConfig.groupName}\n`;
|
||||||
groupsMessage += ` Users: [${context.config.adminGroupConfig.groupUsers.join(", ")}]\n`;
|
groupsMessage += ` Users: [${config.adminGroupConfig.groupUsers.join(", ")}]\n`;
|
||||||
groupsMessage += ` Allowed: ${context.config.adminGroupConfig.isAllowed}\n`;
|
groupsMessage += ` Allowed: ${config.adminGroupConfig.isAllowed}\n`;
|
||||||
groupsMessage += ` notice: ${context.config.adminGroupConfig.isNotice}\n\n`;
|
groupsMessage += ` notice: ${config.adminGroupConfig.isNotice}\n\n`;
|
||||||
|
|
||||||
for (const group of context.config.usersGroups) {
|
for (const group of config.usersGroups) {
|
||||||
groupsMessage += `Group: ${group.groupName}\n`;
|
groupsMessage += `Group: ${group.groupName}\n`;
|
||||||
groupsMessage += ` Users: [${(group.groupUsers ?? []).join(", ")}]\n`;
|
groupsMessage += ` Users: [${(group.groupUsers ?? []).join(", ")}]\n`;
|
||||||
groupsMessage += ` Allowed: ${group.isAllowed}\n`;
|
groupsMessage += ` Allowed: ${group.isAllowed}\n`;
|
||||||
@@ -474,18 +496,18 @@ class ShowConfigCommand implements CLICommand {
|
|||||||
|
|
||||||
case "toast": {
|
case "toast": {
|
||||||
let toastMessage = "Default Toast Config:\n";
|
let toastMessage = "Default Toast Config:\n";
|
||||||
toastMessage += ` Title: ${context.config.welcomeToastConfig.title.text}\n`;
|
toastMessage += ` Title: ${config.welcomeToastConfig.title.text}\n`;
|
||||||
toastMessage += ` Message: ${context.config.welcomeToastConfig.msg.text}\n`;
|
toastMessage += ` Message: ${config.welcomeToastConfig.msg.text}\n`;
|
||||||
toastMessage += ` Prefix: ${context.config.welcomeToastConfig.prefix ?? "none"}\n`;
|
toastMessage += ` Prefix: ${config.welcomeToastConfig.prefix ?? "none"}\n`;
|
||||||
toastMessage += ` Brackets: ${context.config.welcomeToastConfig.brackets ?? "none"}\n`;
|
toastMessage += ` Brackets: ${config.welcomeToastConfig.brackets ?? "none"}\n`;
|
||||||
toastMessage += ` Bracket Color: ${context.config.welcomeToastConfig.bracketColor ?? "none"}\n\n`;
|
toastMessage += ` Bracket Color: ${config.welcomeToastConfig.bracketColor ?? "none"}\n\n`;
|
||||||
|
|
||||||
toastMessage += "Warn Toast Config:\n";
|
toastMessage += "Warn Toast Config:\n";
|
||||||
toastMessage += ` Title: ${context.config.warnToastConfig.title.text}\n`;
|
toastMessage += ` Title: ${config.warnToastConfig.title.text}\n`;
|
||||||
toastMessage += ` Message: ${context.config.warnToastConfig.msg.text}\n`;
|
toastMessage += ` Message: ${config.warnToastConfig.msg.text}\n`;
|
||||||
toastMessage += ` Prefix: ${context.config.warnToastConfig.prefix ?? "none"}\n`;
|
toastMessage += ` Prefix: ${config.warnToastConfig.prefix ?? "none"}\n`;
|
||||||
toastMessage += ` Brackets: ${context.config.warnToastConfig.brackets ?? "none"}\n`;
|
toastMessage += ` Brackets: ${config.warnToastConfig.brackets ?? "none"}\n`;
|
||||||
toastMessage += ` Bracket Color: ${context.config.warnToastConfig.bracketColor ?? "none"}`;
|
toastMessage += ` Bracket Color: ${config.warnToastConfig.bracketColor ?? "none"}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -494,9 +516,9 @@ class ShowConfigCommand implements CLICommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "all": {
|
case "all": {
|
||||||
let allMessage = `Detect Range: ${context.config.detectRange}\n`;
|
let allMessage = `Detect Range: ${config.detectRange}\n`;
|
||||||
allMessage += `Detect Interval: ${context.config.detectInterval}\n`;
|
allMessage += `Detect Interval: ${config.detectInterval}\n`;
|
||||||
allMessage += `Warn Interval: ${context.config.watchInterval}\n\n`;
|
allMessage += `Warn Interval: ${config.watchInterval}\n\n`;
|
||||||
allMessage +=
|
allMessage +=
|
||||||
"Use 'showconfig groups' or 'showconfig toast' for detailed view";
|
"Use 'showconfig groups' or 'showconfig toast' for detailed view";
|
||||||
|
|
||||||
@@ -530,10 +552,9 @@ export class AccessControlCLI {
|
|||||||
const ev = pullEventAs(ChatBoxEvent, "chat");
|
const ev = pullEventAs(ChatBoxEvent, "chat");
|
||||||
|
|
||||||
if (ev === undefined) continue;
|
if (ev === undefined) continue;
|
||||||
if (
|
|
||||||
!this.context.config.adminGroupConfig.groupUsers.includes(ev.username)
|
const config = loadConfig(this.context.configFilepath)!;
|
||||||
)
|
if (!config.adminGroupConfig.groupUsers.includes(ev.username)) continue;
|
||||||
continue;
|
|
||||||
if (!ev.message.startsWith("@AC")) continue;
|
if (!ev.message.startsWith("@AC")) continue;
|
||||||
|
|
||||||
this.context.log.info(
|
this.context.log.info(
|
||||||
@@ -542,7 +563,6 @@ export class AccessControlCLI {
|
|||||||
|
|
||||||
const result = this.processor.processCommand(ev.message, ev.username);
|
const result = this.processor.processCommand(ev.message, ev.username);
|
||||||
this.processor.sendResponse(result, ev.username);
|
this.processor.sendResponse(result, ev.username);
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
this.context.log.warn(`Command failed: ${result.message}`);
|
this.context.log.warn(`Command failed: ${result.message}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,9 +101,13 @@ const defaultConfig: AccessConfig = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadConfig(filepath: string): AccessConfig {
|
function loadConfig(
|
||||||
|
filepath: string,
|
||||||
|
useDefault = true,
|
||||||
|
): AccessConfig | undefined {
|
||||||
const [fp] = io.open(filepath, "r");
|
const [fp] = io.open(filepath, "r");
|
||||||
if (fp == undefined) {
|
if (fp == undefined) {
|
||||||
|
if (useDefault === false) return undefined;
|
||||||
print("Failed to open config file " + filepath);
|
print("Failed to open config file " + filepath);
|
||||||
print("Use default config");
|
print("Use default config");
|
||||||
saveConfig(defaultConfig, filepath);
|
saveConfig(defaultConfig, filepath);
|
||||||
@@ -112,6 +116,7 @@ function loadConfig(filepath: string): AccessConfig {
|
|||||||
|
|
||||||
const configJson = fp.read("*a");
|
const configJson = fp.read("*a");
|
||||||
if (configJson == undefined) {
|
if (configJson == undefined) {
|
||||||
|
if (useDefault === false) return undefined;
|
||||||
print("Failed to read config file");
|
print("Failed to read config file");
|
||||||
print("Use default config");
|
print("Use default config");
|
||||||
saveConfig(defaultConfig, filepath);
|
saveConfig(defaultConfig, filepath);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { createAccessControlCLI } from "./cli";
|
|||||||
import { launchAccessControlTUI } from "./tui";
|
import { launchAccessControlTUI } from "./tui";
|
||||||
import * as peripheralManager from "../lib/PeripheralManager";
|
import * as peripheralManager from "../lib/PeripheralManager";
|
||||||
import { deepCopy } from "@/lib/common";
|
import { deepCopy } from "@/lib/common";
|
||||||
|
import { ReadWriteLock } from "@/lib/ReadWriteLock";
|
||||||
|
|
||||||
const args = [...$vararg];
|
const args = [...$vararg];
|
||||||
|
|
||||||
@@ -16,7 +17,8 @@ const logger = new CCLog("accesscontrol.log", {
|
|||||||
|
|
||||||
// Load Config
|
// Load Config
|
||||||
const configFilepath = `${shell.dir()}/access.config.json`;
|
const configFilepath = `${shell.dir()}/access.config.json`;
|
||||||
let config = loadConfig(configFilepath);
|
let config = loadConfig(configFilepath)!;
|
||||||
|
const configLock = new ReadWriteLock();
|
||||||
logger.info("Load config successfully!");
|
logger.info("Load config successfully!");
|
||||||
logger.debug(textutils.serialise(config, { allow_repetitions: true }));
|
logger.debug(textutils.serialise(config, { allow_repetitions: true }));
|
||||||
|
|
||||||
@@ -25,7 +27,6 @@ const playerDetector = peripheralManager.findByNameRequired("playerDetector");
|
|||||||
const chatBox = peripheralManager.findByNameRequired("chatBox");
|
const chatBox = peripheralManager.findByNameRequired("chatBox");
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
let noticeTargetPlayers: string[];
|
|
||||||
let inRangePlayers: string[] = [];
|
let inRangePlayers: string[] = [];
|
||||||
let watchPlayersInfo: { name: string; hasNoticeTimes: number }[] = [];
|
let watchPlayersInfo: { name: string; hasNoticeTimes: number }[] = [];
|
||||||
|
|
||||||
@@ -36,9 +37,16 @@ interface ParseParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function reloadConfig() {
|
function reloadConfig() {
|
||||||
config = loadConfig(configFilepath);
|
let releaser = configLock.tryAcquireWrite();
|
||||||
|
while (releaser === undefined) {
|
||||||
|
sleep(1);
|
||||||
|
releaser = configLock.tryAcquireWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
config = loadConfig(configFilepath)!;
|
||||||
inRangePlayers = [];
|
inRangePlayers = [];
|
||||||
watchPlayersInfo = [];
|
watchPlayersInfo = [];
|
||||||
|
releaser.release();
|
||||||
logger.info("Reload config successfully!");
|
logger.info("Reload config successfully!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +88,13 @@ function sendToast(
|
|||||||
targetPlayer: string,
|
targetPlayer: string,
|
||||||
params: ParseParams,
|
params: ParseParams,
|
||||||
) {
|
) {
|
||||||
return chatBox.sendFormattedToastToPlayer(
|
let releaser = configLock.tryAcquireRead();
|
||||||
|
while (releaser === undefined) {
|
||||||
|
sleep(0.1);
|
||||||
|
releaser = configLock.tryAcquireRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
chatBox.sendFormattedToastToPlayer(
|
||||||
safeParseTextComponent(
|
safeParseTextComponent(
|
||||||
toastConfig.msg ?? config.welcomeToastConfig.msg,
|
toastConfig.msg ?? config.welcomeToastConfig.msg,
|
||||||
params,
|
params,
|
||||||
@@ -96,11 +110,18 @@ function sendToast(
|
|||||||
undefined,
|
undefined,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
releaser.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendNotice(player: string, playerInfo?: PlayerInfo) {
|
function sendNotice(player: string, playerInfo?: PlayerInfo) {
|
||||||
|
let releaser = configLock.tryAcquireRead();
|
||||||
|
while (releaser === undefined) {
|
||||||
|
sleep(0.1);
|
||||||
|
releaser = configLock.tryAcquireRead();
|
||||||
|
}
|
||||||
|
|
||||||
const onlinePlayers = playerDetector.getOnlinePlayers();
|
const onlinePlayers = playerDetector.getOnlinePlayers();
|
||||||
noticeTargetPlayers = config.adminGroupConfig.groupUsers.concat(
|
const noticeTargetPlayers = config.adminGroupConfig.groupUsers.concat(
|
||||||
config.usersGroups
|
config.usersGroups
|
||||||
.filter((value) => value.isNotice)
|
.filter((value) => value.isNotice)
|
||||||
.map((value) => value.groupUsers ?? [])
|
.map((value) => value.groupUsers ?? [])
|
||||||
@@ -114,12 +135,19 @@ function sendNotice(player: string, playerInfo?: PlayerInfo) {
|
|||||||
info: playerInfo,
|
info: playerInfo,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
releaser.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendWarn(player: string) {
|
function sendWarn(player: string) {
|
||||||
const warnMsg = `Not Allowed Player ${player} Break in Home `;
|
const warnMsg = `Not Allowed Player ${player} Break in Home `;
|
||||||
logger.warn(warnMsg);
|
logger.warn(warnMsg);
|
||||||
|
|
||||||
|
let releaser = configLock.tryAcquireRead();
|
||||||
|
while (releaser === undefined) {
|
||||||
|
sleep(0.1);
|
||||||
|
releaser = configLock.tryAcquireRead();
|
||||||
|
}
|
||||||
|
|
||||||
sendToast(config.warnToastConfig, player, { name: player });
|
sendToast(config.warnToastConfig, player, { name: player });
|
||||||
chatBox.sendFormattedMessageToPlayer(
|
chatBox.sendFormattedMessageToPlayer(
|
||||||
safeParseTextComponent(config.warnToastConfig.msg, { name: player }),
|
safeParseTextComponent(config.warnToastConfig.msg, { name: player }),
|
||||||
@@ -130,10 +158,17 @@ function sendWarn(player: string) {
|
|||||||
undefined,
|
undefined,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
releaser.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
function watchLoop() {
|
function watchLoop() {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
const releaser = configLock.tryAcquireRead();
|
||||||
|
if (releaser === undefined) {
|
||||||
|
os.sleep(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const watchPlayerNames = watchPlayersInfo.flatMap((value) => value.name);
|
const watchPlayerNames = watchPlayersInfo.flatMap((value) => value.name);
|
||||||
logger.debug(`Watch Players [ ${watchPlayerNames.join(", ")} ]`);
|
logger.debug(`Watch Players [ ${watchPlayerNames.join(", ")} ]`);
|
||||||
for (const player of watchPlayersInfo) {
|
for (const player of watchPlayersInfo) {
|
||||||
@@ -164,12 +199,19 @@ function watchLoop() {
|
|||||||
os.sleep(1);
|
os.sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
releaser.release();
|
||||||
os.sleep(config.watchInterval);
|
os.sleep(config.watchInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mainLoop() {
|
function mainLoop() {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
const releaser = configLock.tryAcquireRead();
|
||||||
|
if (releaser === undefined) {
|
||||||
|
os.sleep(0.1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const players = playerDetector.getPlayersInRange(config.detectRange);
|
const players = playerDetector.getPlayersInRange(config.detectRange);
|
||||||
const playersList = "[ " + players.join(",") + " ]";
|
const playersList = "[ " + players.join(",") + " ]";
|
||||||
logger.debug(`Detected ${players.length} players: ${playersList}`);
|
logger.debug(`Detected ${players.length} players: ${playersList}`);
|
||||||
@@ -214,6 +256,7 @@ function mainLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inRangePlayers = players;
|
inRangePlayers = players;
|
||||||
|
releaser.release();
|
||||||
os.sleep(config.detectInterval);
|
os.sleep(config.detectInterval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +275,6 @@ function keyboardLoop() {
|
|||||||
} finally {
|
} finally {
|
||||||
logger.setInTerminal(true);
|
logger.setInTerminal(true);
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
logger.info("Reload config successfully!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,7 +286,6 @@ function main(args: string[]) {
|
|||||||
if (args[0] == "start") {
|
if (args[0] == "start") {
|
||||||
// 创建CLI处理器
|
// 创建CLI处理器
|
||||||
const cli = createAccessControlCLI({
|
const cli = createAccessControlCLI({
|
||||||
config: config,
|
|
||||||
configFilepath: configFilepath,
|
configFilepath: configFilepath,
|
||||||
reloadConfig: () => reloadConfig(),
|
reloadConfig: () => reloadConfig(),
|
||||||
log: logger,
|
log: logger,
|
||||||
@@ -259,7 +300,7 @@ function main(args: string[]) {
|
|||||||
mainLoop();
|
mainLoop();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
void cli.startConfigLoop();
|
cli.startConfigLoop();
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
watchLoop();
|
watchLoop();
|
||||||
@@ -268,6 +309,7 @@ function main(args: string[]) {
|
|||||||
keyboardLoop();
|
keyboardLoop();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else if (args[0] == "config") {
|
} else if (args[0] == "config") {
|
||||||
logger.info("Launching Access Control TUI...");
|
logger.info("Launching Access Control TUI...");
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ interface ErrorState {
|
|||||||
const AccessControlTUI = () => {
|
const AccessControlTUI = () => {
|
||||||
// Load configuration on initialization
|
// Load configuration on initialization
|
||||||
const configFilepath = `${shell.dir()}/access.config.json`;
|
const configFilepath = `${shell.dir()}/access.config.json`;
|
||||||
const loadedConfig = loadConfig(configFilepath);
|
const loadedConfig = loadConfig(configFilepath)!;
|
||||||
// Configuration state
|
// Configuration state
|
||||||
const [config, setConfig] = createStore<AccessConfig>(loadedConfig);
|
const [config, setConfig] = createStore<AccessConfig>(loadedConfig);
|
||||||
|
|
||||||
|
|||||||
@@ -46,11 +46,11 @@ export class ReadWriteLock {
|
|||||||
/**
|
/**
|
||||||
* Tries to acquire a read lock immediately. Returns null if not available.
|
* Tries to acquire a read lock immediately. Returns null if not available.
|
||||||
*/
|
*/
|
||||||
tryAcquireRead(): ReadLockHandle | null {
|
tryAcquireRead(): ReadLockHandle | undefined {
|
||||||
const release = this._semaphore.tryAcquire(1);
|
const release = this._semaphore.tryAcquire(1);
|
||||||
|
|
||||||
if (release === null) {
|
if (release === undefined) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { release };
|
return { release };
|
||||||
@@ -72,11 +72,11 @@ export class ReadWriteLock {
|
|||||||
/**
|
/**
|
||||||
* Tries to acquire a write lock immediately. Returns null if not available.
|
* Tries to acquire a write lock immediately. Returns null if not available.
|
||||||
*/
|
*/
|
||||||
tryAcquireWrite(): WriteLockHandle | null {
|
tryAcquireWrite(): WriteLockHandle | undefined {
|
||||||
const release = this._semaphore.tryAcquire(this._writerWeight);
|
const release = this._semaphore.tryAcquire(this._writerWeight);
|
||||||
|
|
||||||
if (release === null) {
|
if (release === undefined) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { release };
|
return { release };
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ export class Semaphore {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tryAcquire(weight = 1): Releaser | null {
|
tryAcquire(weight = 1): Releaser | undefined {
|
||||||
if (weight <= 0) {
|
if (weight <= 0) {
|
||||||
throw new Error(`invalid weight ${weight}: must be positive`);
|
throw new Error(`invalid weight ${weight}: must be positive`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weight > this._value || this._queue.toArray().length > 0) {
|
if (weight > this._value || this._queue.toArray().length > 0) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._value -= weight;
|
this._value -= weight;
|
||||||
|
|||||||
Reference in New Issue
Block a user