mirror of
https://github.com/whyour/qinglong.git
synced 2025-11-08 15:06:08 +08:00
Merge 5e7e39753c into 73f8f3c5fa
This commit is contained in:
commit
fefad28fd8
|
|
@ -11,12 +11,11 @@ export default (app: Router) => {
|
|||
route.get(
|
||||
'/',
|
||||
celebrate({
|
||||
query:
|
||||
Joi.object({
|
||||
searchValue: Joi.string().optional().allow(''),
|
||||
type: Joi.string().optional().allow(''),
|
||||
status: Joi.string().optional().allow(''),
|
||||
}),
|
||||
query: Joi.object({
|
||||
searchValue: Joi.string().optional().allow(''),
|
||||
type: Joi.string().optional().allow(''),
|
||||
status: Joi.string().optional().allow(''),
|
||||
}),
|
||||
}),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
const logger: Logger = Container.get('logger');
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ export default (app: Router) => {
|
|||
logger.error('🔥 error: %o', e);
|
||||
return next(e);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
route.get(
|
||||
'/detail',
|
||||
|
|
@ -85,7 +86,7 @@ export default (app: Router) => {
|
|||
try {
|
||||
const scriptService = Container.get(ScriptService);
|
||||
const content = await scriptService.getFile(
|
||||
req.query?.path as string || '',
|
||||
(req.query?.path as string) || '',
|
||||
req.query.file as string,
|
||||
);
|
||||
res.send({ code: 200, data: content });
|
||||
|
|
@ -109,7 +110,7 @@ export default (app: Router) => {
|
|||
try {
|
||||
const scriptService = Container.get(ScriptService);
|
||||
const content = await scriptService.getFile(
|
||||
req.query?.path as string || '',
|
||||
(req.query?.path as string) || '',
|
||||
req.params.file,
|
||||
);
|
||||
res.send({ code: 200, data: content });
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import path from 'path';
|
|||
import { v4 as uuidV4 } from 'uuid';
|
||||
import rateLimit from 'express-rate-limit';
|
||||
import config from '../config';
|
||||
import { isDemoEnv } from '../config/util';
|
||||
import { isDemoEnv, getToken } from '../config/util';
|
||||
const route = Router();
|
||||
|
||||
const storage = multer.diskStorage({
|
||||
|
|
@ -56,7 +56,8 @@ export default (app: Router) => {
|
|||
const logger: Logger = Container.get('logger');
|
||||
try {
|
||||
const userService = Container.get(UserService);
|
||||
await userService.logout(req.platform);
|
||||
const token = getToken(req);
|
||||
await userService.logout(req.platform, token);
|
||||
res.send({ code: 200 });
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
|
|
|
|||
29
back/app.ts
29
back/app.ts
|
|
@ -28,12 +28,18 @@ class Application {
|
|||
constructor() {
|
||||
this.app = express();
|
||||
// 创建一个全局中间件,删除查询参数中的t
|
||||
this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
if (req.query.t) {
|
||||
delete req.query.t;
|
||||
}
|
||||
next();
|
||||
});
|
||||
this.app.use(
|
||||
(
|
||||
req: express.Request,
|
||||
res: express.Response,
|
||||
next: express.NextFunction,
|
||||
) => {
|
||||
if (req.query.t) {
|
||||
delete req.query.t;
|
||||
}
|
||||
next();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async start() {
|
||||
|
|
@ -61,7 +67,8 @@ class Application {
|
|||
if (metadata) {
|
||||
if (!this.isShuttingDown) {
|
||||
Logger.error(
|
||||
`${metadata.serviceType} worker ${worker.process.pid} died (${signal || code
|
||||
`${metadata.serviceType} worker ${worker.process.pid} died (${
|
||||
signal || code
|
||||
}). Restarting...`,
|
||||
);
|
||||
const newWorker = this.forkWorker(metadata.serviceType);
|
||||
|
|
@ -96,9 +103,11 @@ class Application {
|
|||
}
|
||||
|
||||
private setupMiddlewares() {
|
||||
this.app.use(helmet({
|
||||
contentSecurityPolicy: false,
|
||||
}));
|
||||
this.app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: false,
|
||||
}),
|
||||
);
|
||||
this.app.use(cors(config.cors));
|
||||
this.app.use(compression());
|
||||
this.app.use(monitoringMiddleware);
|
||||
|
|
|
|||
|
|
@ -176,4 +176,5 @@ export default {
|
|||
sshdPath,
|
||||
systemLogPath,
|
||||
dependenceCachePath,
|
||||
maxTokensPerPlatform: 10, // Maximum number of concurrent sessions per platform
|
||||
};
|
||||
|
|
|
|||
|
|
@ -81,4 +81,4 @@ export function createRandomString(min: number, max: number): string {
|
|||
}
|
||||
|
||||
return newArr.join('');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ export enum CrontabStatus {
|
|||
'disabled',
|
||||
}
|
||||
|
||||
export interface CronInstance extends Model<Crontab, Crontab>, Crontab { }
|
||||
export interface CronInstance extends Model<Crontab, Crontab>, Crontab {}
|
||||
export const CrontabModel = sequelize.define<CronInstance>('Crontab', {
|
||||
name: {
|
||||
unique: 'compositeIndex',
|
||||
|
|
|
|||
|
|
@ -24,7 +24,13 @@ export interface AppToken {
|
|||
expiration: number;
|
||||
}
|
||||
|
||||
export type AppScope = 'envs' | 'crons' | 'configs' | 'scripts' | 'logs' | 'system';
|
||||
export type AppScope =
|
||||
| 'envs'
|
||||
| 'crons'
|
||||
| 'configs'
|
||||
| 'scripts'
|
||||
| 'logs'
|
||||
| 'system';
|
||||
|
||||
export interface AppInstance extends Model<App, App>, App {}
|
||||
export const AppModel = sequelize.define<AppInstance>('App', {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,19 @@ export interface LoginLogInfo {
|
|||
status?: LoginStatus;
|
||||
}
|
||||
|
||||
export interface TokenInfo {
|
||||
value: string;
|
||||
timestamp: number;
|
||||
ip: string;
|
||||
address: string;
|
||||
platform: string;
|
||||
/**
|
||||
* Token expiration time in seconds since Unix epoch.
|
||||
* If undefined, the token uses JWT's built-in expiration.
|
||||
*/
|
||||
expiration?: number;
|
||||
}
|
||||
|
||||
export interface AuthInfo {
|
||||
username: string;
|
||||
password: string;
|
||||
|
|
@ -58,7 +71,7 @@ export interface AuthInfo {
|
|||
platform: string;
|
||||
isTwoFactorChecking: boolean;
|
||||
token: string;
|
||||
tokens: Record<string, string>;
|
||||
tokens: Record<string, string | TokenInfo[]>;
|
||||
twoFactorActivated: boolean;
|
||||
twoFactorSecret: string;
|
||||
avatar: string;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ async function linkToNodeModule(src: string, dst?: string) {
|
|||
if (!stats) {
|
||||
await fs.symlink(source, target, 'dir');
|
||||
}
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
}
|
||||
|
||||
async function linkCommand() {
|
||||
|
|
@ -41,7 +41,7 @@ async function linkCommand() {
|
|||
if (stats) {
|
||||
await fs.unlink(tmpTarget);
|
||||
}
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
await fs.symlink(source, tmpTarget);
|
||||
await fs.rename(tmpTarget, target);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import rewrite from 'express-urlrewrite';
|
|||
import { errors } from 'celebrate';
|
||||
import { serveEnv } from '../config/serverEnv';
|
||||
import { IKeyvStore, shareStore } from '../shared/store';
|
||||
import { isValidToken } from '../shared/auth';
|
||||
import path from 'path';
|
||||
|
||||
export default ({ app }: { app: Application }) => {
|
||||
|
|
@ -77,11 +78,8 @@ export default ({ app }: { app: Application }) => {
|
|||
}
|
||||
|
||||
const authInfo = await shareStore.getAuthInfo();
|
||||
if (authInfo && headerToken) {
|
||||
const { token = '', tokens = {} } = authInfo;
|
||||
if (headerToken === token || tokens[req.platform] === headerToken) {
|
||||
return next();
|
||||
}
|
||||
if (isValidToken(authInfo, headerToken, req.platform)) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const errorCode = headerToken ? 'invalid_token' : 'credentials_required';
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Container } from 'typedi';
|
|||
import SockService from '../services/sock';
|
||||
import { getPlatform } from '../config/util';
|
||||
import { shareStore } from '../shared/store';
|
||||
import { isValidToken } from '../shared/auth';
|
||||
|
||||
export default async ({ server }: { server: Server }) => {
|
||||
const echo = sockJs.createServer({ prefix: '/api/ws', log: () => {} });
|
||||
|
|
@ -17,21 +18,19 @@ export default async ({ server }: { server: Server }) => {
|
|||
const authInfo = await shareStore.getAuthInfo();
|
||||
const platform = getPlatform(conn.headers['user-agent'] || '') || 'desktop';
|
||||
const headerToken = conn.url.replace(`${conn.pathname}?token=`, '');
|
||||
if (authInfo) {
|
||||
const { token = '', tokens = {} } = authInfo;
|
||||
if (headerToken === token || tokens[platform] === headerToken) {
|
||||
sockService.addClient(conn);
|
||||
|
||||
conn.on('data', (message) => {
|
||||
conn.write(message);
|
||||
});
|
||||
if (isValidToken(authInfo, headerToken, platform)) {
|
||||
sockService.addClient(conn);
|
||||
|
||||
conn.on('close', function () {
|
||||
sockService.removeClient(conn);
|
||||
});
|
||||
conn.on('data', (message) => {
|
||||
conn.write(message);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
conn.on('close', function () {
|
||||
sockService.removeClient(conn);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
conn.close('404');
|
||||
|
|
|
|||
1220
back/protos/api.ts
1220
back/protos/api.ts
File diff suppressed because it is too large
Load Diff
|
|
@ -5,7 +5,7 @@
|
|||
// source: back/protos/cron.proto
|
||||
|
||||
/* eslint-disable */
|
||||
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
||||
import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire';
|
||||
import {
|
||||
type CallOptions,
|
||||
ChannelCredentials,
|
||||
|
|
@ -17,9 +17,9 @@ import {
|
|||
Metadata,
|
||||
type ServiceError,
|
||||
type UntypedServiceImplementation,
|
||||
} from "@grpc/grpc-js";
|
||||
} from '@grpc/grpc-js';
|
||||
|
||||
export const protobufPackage = "com.ql.cron";
|
||||
export const protobufPackage = 'com.ql.cron';
|
||||
|
||||
export interface ISchedule {
|
||||
schedule: string;
|
||||
|
|
@ -37,30 +37,32 @@ export interface AddCronRequest {
|
|||
crons: ICron[];
|
||||
}
|
||||
|
||||
export interface AddCronResponse {
|
||||
}
|
||||
export interface AddCronResponse {}
|
||||
|
||||
export interface DeleteCronRequest {
|
||||
ids: string[];
|
||||
}
|
||||
|
||||
export interface DeleteCronResponse {
|
||||
}
|
||||
export interface DeleteCronResponse {}
|
||||
|
||||
function createBaseISchedule(): ISchedule {
|
||||
return { schedule: "" };
|
||||
return { schedule: '' };
|
||||
}
|
||||
|
||||
export const ISchedule: MessageFns<ISchedule> = {
|
||||
encode(message: ISchedule, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.schedule !== "") {
|
||||
encode(
|
||||
message: ISchedule,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
if (message.schedule !== '') {
|
||||
writer.uint32(10).string(message.schedule);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ISchedule {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseISchedule();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -84,12 +86,16 @@ export const ISchedule: MessageFns<ISchedule> = {
|
|||
},
|
||||
|
||||
fromJSON(object: any): ISchedule {
|
||||
return { schedule: isSet(object.schedule) ? globalThis.String(object.schedule) : "" };
|
||||
return {
|
||||
schedule: isSet(object.schedule)
|
||||
? globalThis.String(object.schedule)
|
||||
: '',
|
||||
};
|
||||
},
|
||||
|
||||
toJSON(message: ISchedule): unknown {
|
||||
const obj: any = {};
|
||||
if (message.schedule !== "") {
|
||||
if (message.schedule !== '') {
|
||||
obj.schedule = message.schedule;
|
||||
}
|
||||
return obj;
|
||||
|
|
@ -98,39 +104,45 @@ export const ISchedule: MessageFns<ISchedule> = {
|
|||
create<I extends Exact<DeepPartial<ISchedule>, I>>(base?: I): ISchedule {
|
||||
return ISchedule.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ISchedule>, I>>(object: I): ISchedule {
|
||||
fromPartial<I extends Exact<DeepPartial<ISchedule>, I>>(
|
||||
object: I,
|
||||
): ISchedule {
|
||||
const message = createBaseISchedule();
|
||||
message.schedule = object.schedule ?? "";
|
||||
message.schedule = object.schedule ?? '';
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
function createBaseICron(): ICron {
|
||||
return { id: "", schedule: "", command: "", extra_schedules: [], name: "" };
|
||||
return { id: '', schedule: '', command: '', extra_schedules: [], name: '' };
|
||||
}
|
||||
|
||||
export const ICron: MessageFns<ICron> = {
|
||||
encode(message: ICron, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.id !== "") {
|
||||
encode(
|
||||
message: ICron,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
if (message.id !== '') {
|
||||
writer.uint32(10).string(message.id);
|
||||
}
|
||||
if (message.schedule !== "") {
|
||||
if (message.schedule !== '') {
|
||||
writer.uint32(18).string(message.schedule);
|
||||
}
|
||||
if (message.command !== "") {
|
||||
if (message.command !== '') {
|
||||
writer.uint32(26).string(message.command);
|
||||
}
|
||||
for (const v of message.extra_schedules) {
|
||||
ISchedule.encode(v!, writer.uint32(34).fork()).join();
|
||||
}
|
||||
if (message.name !== "") {
|
||||
if (message.name !== '') {
|
||||
writer.uint32(42).string(message.name);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): ICron {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseICron();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -165,7 +177,9 @@ export const ICron: MessageFns<ICron> = {
|
|||
break;
|
||||
}
|
||||
|
||||
message.extra_schedules.push(ISchedule.decode(reader, reader.uint32()));
|
||||
message.extra_schedules.push(
|
||||
ISchedule.decode(reader, reader.uint32()),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
case 5: {
|
||||
|
|
@ -187,31 +201,35 @@ export const ICron: MessageFns<ICron> = {
|
|||
|
||||
fromJSON(object: any): ICron {
|
||||
return {
|
||||
id: isSet(object.id) ? globalThis.String(object.id) : "",
|
||||
schedule: isSet(object.schedule) ? globalThis.String(object.schedule) : "",
|
||||
command: isSet(object.command) ? globalThis.String(object.command) : "",
|
||||
id: isSet(object.id) ? globalThis.String(object.id) : '',
|
||||
schedule: isSet(object.schedule)
|
||||
? globalThis.String(object.schedule)
|
||||
: '',
|
||||
command: isSet(object.command) ? globalThis.String(object.command) : '',
|
||||
extra_schedules: globalThis.Array.isArray(object?.extra_schedules)
|
||||
? object.extra_schedules.map((e: any) => ISchedule.fromJSON(e))
|
||||
: [],
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : "",
|
||||
name: isSet(object.name) ? globalThis.String(object.name) : '',
|
||||
};
|
||||
},
|
||||
|
||||
toJSON(message: ICron): unknown {
|
||||
const obj: any = {};
|
||||
if (message.id !== "") {
|
||||
if (message.id !== '') {
|
||||
obj.id = message.id;
|
||||
}
|
||||
if (message.schedule !== "") {
|
||||
if (message.schedule !== '') {
|
||||
obj.schedule = message.schedule;
|
||||
}
|
||||
if (message.command !== "") {
|
||||
if (message.command !== '') {
|
||||
obj.command = message.command;
|
||||
}
|
||||
if (message.extra_schedules?.length) {
|
||||
obj.extra_schedules = message.extra_schedules.map((e) => ISchedule.toJSON(e));
|
||||
obj.extra_schedules = message.extra_schedules.map((e) =>
|
||||
ISchedule.toJSON(e),
|
||||
);
|
||||
}
|
||||
if (message.name !== "") {
|
||||
if (message.name !== '') {
|
||||
obj.name = message.name;
|
||||
}
|
||||
return obj;
|
||||
|
|
@ -222,11 +240,12 @@ export const ICron: MessageFns<ICron> = {
|
|||
},
|
||||
fromPartial<I extends Exact<DeepPartial<ICron>, I>>(object: I): ICron {
|
||||
const message = createBaseICron();
|
||||
message.id = object.id ?? "";
|
||||
message.schedule = object.schedule ?? "";
|
||||
message.command = object.command ?? "";
|
||||
message.extra_schedules = object.extra_schedules?.map((e) => ISchedule.fromPartial(e)) || [];
|
||||
message.name = object.name ?? "";
|
||||
message.id = object.id ?? '';
|
||||
message.schedule = object.schedule ?? '';
|
||||
message.command = object.command ?? '';
|
||||
message.extra_schedules =
|
||||
object.extra_schedules?.map((e) => ISchedule.fromPartial(e)) || [];
|
||||
message.name = object.name ?? '';
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
|
@ -236,7 +255,10 @@ function createBaseAddCronRequest(): AddCronRequest {
|
|||
}
|
||||
|
||||
export const AddCronRequest: MessageFns<AddCronRequest> = {
|
||||
encode(message: AddCronRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
encode(
|
||||
message: AddCronRequest,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
for (const v of message.crons) {
|
||||
ICron.encode(v!, writer.uint32(10).fork()).join();
|
||||
}
|
||||
|
|
@ -244,7 +266,8 @@ export const AddCronRequest: MessageFns<AddCronRequest> = {
|
|||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): AddCronRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseAddCronRequest();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -268,7 +291,11 @@ export const AddCronRequest: MessageFns<AddCronRequest> = {
|
|||
},
|
||||
|
||||
fromJSON(object: any): AddCronRequest {
|
||||
return { crons: globalThis.Array.isArray(object?.crons) ? object.crons.map((e: any) => ICron.fromJSON(e)) : [] };
|
||||
return {
|
||||
crons: globalThis.Array.isArray(object?.crons)
|
||||
? object.crons.map((e: any) => ICron.fromJSON(e))
|
||||
: [],
|
||||
};
|
||||
},
|
||||
|
||||
toJSON(message: AddCronRequest): unknown {
|
||||
|
|
@ -279,10 +306,14 @@ export const AddCronRequest: MessageFns<AddCronRequest> = {
|
|||
return obj;
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<AddCronRequest>, I>>(base?: I): AddCronRequest {
|
||||
create<I extends Exact<DeepPartial<AddCronRequest>, I>>(
|
||||
base?: I,
|
||||
): AddCronRequest {
|
||||
return AddCronRequest.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<AddCronRequest>, I>>(object: I): AddCronRequest {
|
||||
fromPartial<I extends Exact<DeepPartial<AddCronRequest>, I>>(
|
||||
object: I,
|
||||
): AddCronRequest {
|
||||
const message = createBaseAddCronRequest();
|
||||
message.crons = object.crons?.map((e) => ICron.fromPartial(e)) || [];
|
||||
return message;
|
||||
|
|
@ -294,12 +325,16 @@ function createBaseAddCronResponse(): AddCronResponse {
|
|||
}
|
||||
|
||||
export const AddCronResponse: MessageFns<AddCronResponse> = {
|
||||
encode(_: AddCronResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
encode(
|
||||
_: AddCronResponse,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): AddCronResponse {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseAddCronResponse();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -323,10 +358,14 @@ export const AddCronResponse: MessageFns<AddCronResponse> = {
|
|||
return obj;
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<AddCronResponse>, I>>(base?: I): AddCronResponse {
|
||||
create<I extends Exact<DeepPartial<AddCronResponse>, I>>(
|
||||
base?: I,
|
||||
): AddCronResponse {
|
||||
return AddCronResponse.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<AddCronResponse>, I>>(_: I): AddCronResponse {
|
||||
fromPartial<I extends Exact<DeepPartial<AddCronResponse>, I>>(
|
||||
_: I,
|
||||
): AddCronResponse {
|
||||
const message = createBaseAddCronResponse();
|
||||
return message;
|
||||
},
|
||||
|
|
@ -337,7 +376,10 @@ function createBaseDeleteCronRequest(): DeleteCronRequest {
|
|||
}
|
||||
|
||||
export const DeleteCronRequest: MessageFns<DeleteCronRequest> = {
|
||||
encode(message: DeleteCronRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
encode(
|
||||
message: DeleteCronRequest,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
for (const v of message.ids) {
|
||||
writer.uint32(10).string(v!);
|
||||
}
|
||||
|
|
@ -345,7 +387,8 @@ export const DeleteCronRequest: MessageFns<DeleteCronRequest> = {
|
|||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): DeleteCronRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseDeleteCronRequest();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -369,7 +412,11 @@ export const DeleteCronRequest: MessageFns<DeleteCronRequest> = {
|
|||
},
|
||||
|
||||
fromJSON(object: any): DeleteCronRequest {
|
||||
return { ids: globalThis.Array.isArray(object?.ids) ? object.ids.map((e: any) => globalThis.String(e)) : [] };
|
||||
return {
|
||||
ids: globalThis.Array.isArray(object?.ids)
|
||||
? object.ids.map((e: any) => globalThis.String(e))
|
||||
: [],
|
||||
};
|
||||
},
|
||||
|
||||
toJSON(message: DeleteCronRequest): unknown {
|
||||
|
|
@ -380,10 +427,14 @@ export const DeleteCronRequest: MessageFns<DeleteCronRequest> = {
|
|||
return obj;
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<DeleteCronRequest>, I>>(base?: I): DeleteCronRequest {
|
||||
create<I extends Exact<DeepPartial<DeleteCronRequest>, I>>(
|
||||
base?: I,
|
||||
): DeleteCronRequest {
|
||||
return DeleteCronRequest.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<DeleteCronRequest>, I>>(object: I): DeleteCronRequest {
|
||||
fromPartial<I extends Exact<DeepPartial<DeleteCronRequest>, I>>(
|
||||
object: I,
|
||||
): DeleteCronRequest {
|
||||
const message = createBaseDeleteCronRequest();
|
||||
message.ids = object.ids?.map((e) => e) || [];
|
||||
return message;
|
||||
|
|
@ -395,12 +446,19 @@ function createBaseDeleteCronResponse(): DeleteCronResponse {
|
|||
}
|
||||
|
||||
export const DeleteCronResponse: MessageFns<DeleteCronResponse> = {
|
||||
encode(_: DeleteCronResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
encode(
|
||||
_: DeleteCronResponse,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): DeleteCronResponse {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
decode(
|
||||
input: BinaryReader | Uint8Array,
|
||||
length?: number,
|
||||
): DeleteCronResponse {
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseDeleteCronResponse();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -424,10 +482,14 @@ export const DeleteCronResponse: MessageFns<DeleteCronResponse> = {
|
|||
return obj;
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<DeleteCronResponse>, I>>(base?: I): DeleteCronResponse {
|
||||
create<I extends Exact<DeepPartial<DeleteCronResponse>, I>>(
|
||||
base?: I,
|
||||
): DeleteCronResponse {
|
||||
return DeleteCronResponse.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<DeleteCronResponse>, I>>(_: I): DeleteCronResponse {
|
||||
fromPartial<I extends Exact<DeepPartial<DeleteCronResponse>, I>>(
|
||||
_: I,
|
||||
): DeleteCronResponse {
|
||||
const message = createBaseDeleteCronResponse();
|
||||
return message;
|
||||
},
|
||||
|
|
@ -436,21 +498,25 @@ export const DeleteCronResponse: MessageFns<DeleteCronResponse> = {
|
|||
export type CronService = typeof CronService;
|
||||
export const CronService = {
|
||||
addCron: {
|
||||
path: "/com.ql.cron.Cron/addCron",
|
||||
path: '/com.ql.cron.Cron/addCron',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestSerialize: (value: AddCronRequest) => Buffer.from(AddCronRequest.encode(value).finish()),
|
||||
requestSerialize: (value: AddCronRequest) =>
|
||||
Buffer.from(AddCronRequest.encode(value).finish()),
|
||||
requestDeserialize: (value: Buffer) => AddCronRequest.decode(value),
|
||||
responseSerialize: (value: AddCronResponse) => Buffer.from(AddCronResponse.encode(value).finish()),
|
||||
responseSerialize: (value: AddCronResponse) =>
|
||||
Buffer.from(AddCronResponse.encode(value).finish()),
|
||||
responseDeserialize: (value: Buffer) => AddCronResponse.decode(value),
|
||||
},
|
||||
delCron: {
|
||||
path: "/com.ql.cron.Cron/delCron",
|
||||
path: '/com.ql.cron.Cron/delCron',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestSerialize: (value: DeleteCronRequest) => Buffer.from(DeleteCronRequest.encode(value).finish()),
|
||||
requestSerialize: (value: DeleteCronRequest) =>
|
||||
Buffer.from(DeleteCronRequest.encode(value).finish()),
|
||||
requestDeserialize: (value: Buffer) => DeleteCronRequest.decode(value),
|
||||
responseSerialize: (value: DeleteCronResponse) => Buffer.from(DeleteCronResponse.encode(value).finish()),
|
||||
responseSerialize: (value: DeleteCronResponse) =>
|
||||
Buffer.from(DeleteCronResponse.encode(value).finish()),
|
||||
responseDeserialize: (value: Buffer) => DeleteCronResponse.decode(value),
|
||||
},
|
||||
} as const;
|
||||
|
|
@ -478,38 +544,68 @@ export interface CronClient extends Client {
|
|||
): ClientUnaryCall;
|
||||
delCron(
|
||||
request: DeleteCronRequest,
|
||||
callback: (error: ServiceError | null, response: DeleteCronResponse) => void,
|
||||
callback: (
|
||||
error: ServiceError | null,
|
||||
response: DeleteCronResponse,
|
||||
) => void,
|
||||
): ClientUnaryCall;
|
||||
delCron(
|
||||
request: DeleteCronRequest,
|
||||
metadata: Metadata,
|
||||
callback: (error: ServiceError | null, response: DeleteCronResponse) => void,
|
||||
callback: (
|
||||
error: ServiceError | null,
|
||||
response: DeleteCronResponse,
|
||||
) => void,
|
||||
): ClientUnaryCall;
|
||||
delCron(
|
||||
request: DeleteCronRequest,
|
||||
metadata: Metadata,
|
||||
options: Partial<CallOptions>,
|
||||
callback: (error: ServiceError | null, response: DeleteCronResponse) => void,
|
||||
callback: (
|
||||
error: ServiceError | null,
|
||||
response: DeleteCronResponse,
|
||||
) => void,
|
||||
): ClientUnaryCall;
|
||||
}
|
||||
|
||||
export const CronClient = makeGenericClientConstructor(CronService, "com.ql.cron.Cron") as unknown as {
|
||||
new (address: string, credentials: ChannelCredentials, options?: Partial<ClientOptions>): CronClient;
|
||||
export const CronClient = makeGenericClientConstructor(
|
||||
CronService,
|
||||
'com.ql.cron.Cron',
|
||||
) as unknown as {
|
||||
new (
|
||||
address: string,
|
||||
credentials: ChannelCredentials,
|
||||
options?: Partial<ClientOptions>,
|
||||
): CronClient;
|
||||
service: typeof CronService;
|
||||
serviceName: string;
|
||||
};
|
||||
|
||||
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
||||
type Builtin =
|
||||
| Date
|
||||
| Function
|
||||
| Uint8Array
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| undefined;
|
||||
|
||||
export type DeepPartial<T> = T extends Builtin ? T
|
||||
: T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
export type DeepPartial<T> = T extends Builtin
|
||||
? T
|
||||
: T extends globalThis.Array<infer U>
|
||||
? globalThis.Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U>
|
||||
? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {}
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: Partial<T>;
|
||||
|
||||
type KeysOfUnion<T> = T extends T ? keyof T : never;
|
||||
export type Exact<P, I extends P> = P extends Builtin ? P
|
||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
|
||||
export type Exact<P, I extends P> = P extends Builtin
|
||||
? P
|
||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & {
|
||||
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
|
||||
};
|
||||
|
||||
function isSet(value: any): boolean {
|
||||
return value !== null && value !== undefined;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
// source: back/protos/health.proto
|
||||
|
||||
/* eslint-disable */
|
||||
import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire";
|
||||
import { BinaryReader, BinaryWriter } from '@bufbuild/protobuf/wire';
|
||||
import {
|
||||
type CallOptions,
|
||||
ChannelCredentials,
|
||||
|
|
@ -19,9 +19,9 @@ import {
|
|||
Metadata,
|
||||
type ServiceError,
|
||||
type UntypedServiceImplementation,
|
||||
} from "@grpc/grpc-js";
|
||||
} from '@grpc/grpc-js';
|
||||
|
||||
export const protobufPackage = "com.ql.health";
|
||||
export const protobufPackage = 'com.ql.health';
|
||||
|
||||
export interface HealthCheckRequest {
|
||||
service: string;
|
||||
|
|
@ -39,57 +39,68 @@ export enum HealthCheckResponse_ServingStatus {
|
|||
UNRECOGNIZED = -1,
|
||||
}
|
||||
|
||||
export function healthCheckResponse_ServingStatusFromJSON(object: any): HealthCheckResponse_ServingStatus {
|
||||
export function healthCheckResponse_ServingStatusFromJSON(
|
||||
object: any,
|
||||
): HealthCheckResponse_ServingStatus {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case "UNKNOWN":
|
||||
case 'UNKNOWN':
|
||||
return HealthCheckResponse_ServingStatus.UNKNOWN;
|
||||
case 1:
|
||||
case "SERVING":
|
||||
case 'SERVING':
|
||||
return HealthCheckResponse_ServingStatus.SERVING;
|
||||
case 2:
|
||||
case "NOT_SERVING":
|
||||
case 'NOT_SERVING':
|
||||
return HealthCheckResponse_ServingStatus.NOT_SERVING;
|
||||
case 3:
|
||||
case "SERVICE_UNKNOWN":
|
||||
case 'SERVICE_UNKNOWN':
|
||||
return HealthCheckResponse_ServingStatus.SERVICE_UNKNOWN;
|
||||
case -1:
|
||||
case "UNRECOGNIZED":
|
||||
case 'UNRECOGNIZED':
|
||||
default:
|
||||
return HealthCheckResponse_ServingStatus.UNRECOGNIZED;
|
||||
}
|
||||
}
|
||||
|
||||
export function healthCheckResponse_ServingStatusToJSON(object: HealthCheckResponse_ServingStatus): string {
|
||||
export function healthCheckResponse_ServingStatusToJSON(
|
||||
object: HealthCheckResponse_ServingStatus,
|
||||
): string {
|
||||
switch (object) {
|
||||
case HealthCheckResponse_ServingStatus.UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
return 'UNKNOWN';
|
||||
case HealthCheckResponse_ServingStatus.SERVING:
|
||||
return "SERVING";
|
||||
return 'SERVING';
|
||||
case HealthCheckResponse_ServingStatus.NOT_SERVING:
|
||||
return "NOT_SERVING";
|
||||
return 'NOT_SERVING';
|
||||
case HealthCheckResponse_ServingStatus.SERVICE_UNKNOWN:
|
||||
return "SERVICE_UNKNOWN";
|
||||
return 'SERVICE_UNKNOWN';
|
||||
case HealthCheckResponse_ServingStatus.UNRECOGNIZED:
|
||||
default:
|
||||
return "UNRECOGNIZED";
|
||||
return 'UNRECOGNIZED';
|
||||
}
|
||||
}
|
||||
|
||||
function createBaseHealthCheckRequest(): HealthCheckRequest {
|
||||
return { service: "" };
|
||||
return { service: '' };
|
||||
}
|
||||
|
||||
export const HealthCheckRequest: MessageFns<HealthCheckRequest> = {
|
||||
encode(message: HealthCheckRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
if (message.service !== "") {
|
||||
encode(
|
||||
message: HealthCheckRequest,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
if (message.service !== '') {
|
||||
writer.uint32(10).string(message.service);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): HealthCheckRequest {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
decode(
|
||||
input: BinaryReader | Uint8Array,
|
||||
length?: number,
|
||||
): HealthCheckRequest {
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseHealthCheckRequest();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -113,23 +124,29 @@ export const HealthCheckRequest: MessageFns<HealthCheckRequest> = {
|
|||
},
|
||||
|
||||
fromJSON(object: any): HealthCheckRequest {
|
||||
return { service: isSet(object.service) ? globalThis.String(object.service) : "" };
|
||||
return {
|
||||
service: isSet(object.service) ? globalThis.String(object.service) : '',
|
||||
};
|
||||
},
|
||||
|
||||
toJSON(message: HealthCheckRequest): unknown {
|
||||
const obj: any = {};
|
||||
if (message.service !== "") {
|
||||
if (message.service !== '') {
|
||||
obj.service = message.service;
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<HealthCheckRequest>, I>>(base?: I): HealthCheckRequest {
|
||||
create<I extends Exact<DeepPartial<HealthCheckRequest>, I>>(
|
||||
base?: I,
|
||||
): HealthCheckRequest {
|
||||
return HealthCheckRequest.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<HealthCheckRequest>, I>>(object: I): HealthCheckRequest {
|
||||
fromPartial<I extends Exact<DeepPartial<HealthCheckRequest>, I>>(
|
||||
object: I,
|
||||
): HealthCheckRequest {
|
||||
const message = createBaseHealthCheckRequest();
|
||||
message.service = object.service ?? "";
|
||||
message.service = object.service ?? '';
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
|
@ -139,15 +156,22 @@ function createBaseHealthCheckResponse(): HealthCheckResponse {
|
|||
}
|
||||
|
||||
export const HealthCheckResponse: MessageFns<HealthCheckResponse> = {
|
||||
encode(message: HealthCheckResponse, writer: BinaryWriter = new BinaryWriter()): BinaryWriter {
|
||||
encode(
|
||||
message: HealthCheckResponse,
|
||||
writer: BinaryWriter = new BinaryWriter(),
|
||||
): BinaryWriter {
|
||||
if (message.status !== 0) {
|
||||
writer.uint32(8).int32(message.status);
|
||||
}
|
||||
return writer;
|
||||
},
|
||||
|
||||
decode(input: BinaryReader | Uint8Array, length?: number): HealthCheckResponse {
|
||||
const reader = input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
decode(
|
||||
input: BinaryReader | Uint8Array,
|
||||
length?: number,
|
||||
): HealthCheckResponse {
|
||||
const reader =
|
||||
input instanceof BinaryReader ? input : new BinaryReader(input);
|
||||
let end = length === undefined ? reader.len : reader.pos + length;
|
||||
const message = createBaseHealthCheckResponse();
|
||||
while (reader.pos < end) {
|
||||
|
|
@ -171,7 +195,11 @@ export const HealthCheckResponse: MessageFns<HealthCheckResponse> = {
|
|||
},
|
||||
|
||||
fromJSON(object: any): HealthCheckResponse {
|
||||
return { status: isSet(object.status) ? healthCheckResponse_ServingStatusFromJSON(object.status) : 0 };
|
||||
return {
|
||||
status: isSet(object.status)
|
||||
? healthCheckResponse_ServingStatusFromJSON(object.status)
|
||||
: 0,
|
||||
};
|
||||
},
|
||||
|
||||
toJSON(message: HealthCheckResponse): unknown {
|
||||
|
|
@ -182,10 +210,14 @@ export const HealthCheckResponse: MessageFns<HealthCheckResponse> = {
|
|||
return obj;
|
||||
},
|
||||
|
||||
create<I extends Exact<DeepPartial<HealthCheckResponse>, I>>(base?: I): HealthCheckResponse {
|
||||
create<I extends Exact<DeepPartial<HealthCheckResponse>, I>>(
|
||||
base?: I,
|
||||
): HealthCheckResponse {
|
||||
return HealthCheckResponse.fromPartial(base ?? ({} as any));
|
||||
},
|
||||
fromPartial<I extends Exact<DeepPartial<HealthCheckResponse>, I>>(object: I): HealthCheckResponse {
|
||||
fromPartial<I extends Exact<DeepPartial<HealthCheckResponse>, I>>(
|
||||
object: I,
|
||||
): HealthCheckResponse {
|
||||
const message = createBaseHealthCheckResponse();
|
||||
message.status = object.status ?? 0;
|
||||
return message;
|
||||
|
|
@ -195,21 +227,25 @@ export const HealthCheckResponse: MessageFns<HealthCheckResponse> = {
|
|||
export type HealthService = typeof HealthService;
|
||||
export const HealthService = {
|
||||
check: {
|
||||
path: "/com.ql.health.Health/Check",
|
||||
path: '/com.ql.health.Health/Check',
|
||||
requestStream: false,
|
||||
responseStream: false,
|
||||
requestSerialize: (value: HealthCheckRequest) => Buffer.from(HealthCheckRequest.encode(value).finish()),
|
||||
requestSerialize: (value: HealthCheckRequest) =>
|
||||
Buffer.from(HealthCheckRequest.encode(value).finish()),
|
||||
requestDeserialize: (value: Buffer) => HealthCheckRequest.decode(value),
|
||||
responseSerialize: (value: HealthCheckResponse) => Buffer.from(HealthCheckResponse.encode(value).finish()),
|
||||
responseSerialize: (value: HealthCheckResponse) =>
|
||||
Buffer.from(HealthCheckResponse.encode(value).finish()),
|
||||
responseDeserialize: (value: Buffer) => HealthCheckResponse.decode(value),
|
||||
},
|
||||
watch: {
|
||||
path: "/com.ql.health.Health/Watch",
|
||||
path: '/com.ql.health.Health/Watch',
|
||||
requestStream: false,
|
||||
responseStream: true,
|
||||
requestSerialize: (value: HealthCheckRequest) => Buffer.from(HealthCheckRequest.encode(value).finish()),
|
||||
requestSerialize: (value: HealthCheckRequest) =>
|
||||
Buffer.from(HealthCheckRequest.encode(value).finish()),
|
||||
requestDeserialize: (value: Buffer) => HealthCheckRequest.decode(value),
|
||||
responseSerialize: (value: HealthCheckResponse) => Buffer.from(HealthCheckResponse.encode(value).finish()),
|
||||
responseSerialize: (value: HealthCheckResponse) =>
|
||||
Buffer.from(HealthCheckResponse.encode(value).finish()),
|
||||
responseDeserialize: (value: Buffer) => HealthCheckResponse.decode(value),
|
||||
},
|
||||
} as const;
|
||||
|
|
@ -222,20 +258,32 @@ export interface HealthServer extends UntypedServiceImplementation {
|
|||
export interface HealthClient extends Client {
|
||||
check(
|
||||
request: HealthCheckRequest,
|
||||
callback: (error: ServiceError | null, response: HealthCheckResponse) => void,
|
||||
callback: (
|
||||
error: ServiceError | null,
|
||||
response: HealthCheckResponse,
|
||||
) => void,
|
||||
): ClientUnaryCall;
|
||||
check(
|
||||
request: HealthCheckRequest,
|
||||
metadata: Metadata,
|
||||
callback: (error: ServiceError | null, response: HealthCheckResponse) => void,
|
||||
callback: (
|
||||
error: ServiceError | null,
|
||||
response: HealthCheckResponse,
|
||||
) => void,
|
||||
): ClientUnaryCall;
|
||||
check(
|
||||
request: HealthCheckRequest,
|
||||
metadata: Metadata,
|
||||
options: Partial<CallOptions>,
|
||||
callback: (error: ServiceError | null, response: HealthCheckResponse) => void,
|
||||
callback: (
|
||||
error: ServiceError | null,
|
||||
response: HealthCheckResponse,
|
||||
) => void,
|
||||
): ClientUnaryCall;
|
||||
watch(request: HealthCheckRequest, options?: Partial<CallOptions>): ClientReadableStream<HealthCheckResponse>;
|
||||
watch(
|
||||
request: HealthCheckRequest,
|
||||
options?: Partial<CallOptions>,
|
||||
): ClientReadableStream<HealthCheckResponse>;
|
||||
watch(
|
||||
request: HealthCheckRequest,
|
||||
metadata?: Metadata,
|
||||
|
|
@ -243,23 +291,44 @@ export interface HealthClient extends Client {
|
|||
): ClientReadableStream<HealthCheckResponse>;
|
||||
}
|
||||
|
||||
export const HealthClient = makeGenericClientConstructor(HealthService, "com.ql.health.Health") as unknown as {
|
||||
new (address: string, credentials: ChannelCredentials, options?: Partial<ClientOptions>): HealthClient;
|
||||
export const HealthClient = makeGenericClientConstructor(
|
||||
HealthService,
|
||||
'com.ql.health.Health',
|
||||
) as unknown as {
|
||||
new (
|
||||
address: string,
|
||||
credentials: ChannelCredentials,
|
||||
options?: Partial<ClientOptions>,
|
||||
): HealthClient;
|
||||
service: typeof HealthService;
|
||||
serviceName: string;
|
||||
};
|
||||
|
||||
type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
|
||||
type Builtin =
|
||||
| Date
|
||||
| Function
|
||||
| Uint8Array
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| undefined;
|
||||
|
||||
export type DeepPartial<T> = T extends Builtin ? T
|
||||
: T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
export type DeepPartial<T> = T extends Builtin
|
||||
? T
|
||||
: T extends globalThis.Array<infer U>
|
||||
? globalThis.Array<DeepPartial<U>>
|
||||
: T extends ReadonlyArray<infer U>
|
||||
? ReadonlyArray<DeepPartial<U>>
|
||||
: T extends {}
|
||||
? { [K in keyof T]?: DeepPartial<T[K]> }
|
||||
: Partial<T>;
|
||||
|
||||
type KeysOfUnion<T> = T extends T ? keyof T : never;
|
||||
export type Exact<P, I extends P> = P extends Builtin ? P
|
||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & { [K in Exclude<keyof I, KeysOfUnion<P>>]: never };
|
||||
export type Exact<P, I extends P> = P extends Builtin
|
||||
? P
|
||||
: P & { [K in keyof P]: Exact<P[K], I[K]> } & {
|
||||
[K in Exclude<keyof I, KeysOfUnion<P>>]: never;
|
||||
};
|
||||
|
||||
function isSet(value: any): boolean {
|
||||
return value !== null && value !== undefined;
|
||||
|
|
|
|||
|
|
@ -231,7 +231,8 @@ export const systemNotify = async (
|
|||
const data = await systemService.notify({
|
||||
title: call.request.title,
|
||||
content: call.request.content,
|
||||
notificationInfo: call.request.notificationInfo as unknown as NotificationInfo,
|
||||
notificationInfo: call.request
|
||||
.notificationInfo as unknown as NotificationInfo,
|
||||
});
|
||||
callback(null, data);
|
||||
} catch (e: any) {
|
||||
|
|
|
|||
|
|
@ -9,11 +9,8 @@ const delCron = (
|
|||
) => {
|
||||
for (const id of call.request.ids) {
|
||||
if (scheduleStacks.has(id)) {
|
||||
Logger.info(
|
||||
'[schedule][取消定时任务] 任务ID: %s',
|
||||
id,
|
||||
);
|
||||
scheduleStacks.get(id)?.forEach(x => x.cancel());
|
||||
Logger.info('[schedule][取消定时任务] 任务ID: %s', id);
|
||||
scheduleStacks.get(id)?.forEach((x) => x.cancel());
|
||||
scheduleStacks.delete(id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ const check = async (
|
|||
`tail -n 300 ~/.pm2/logs/schedule-error.log`,
|
||||
);
|
||||
return callback(
|
||||
new Error(`${scheduleErrLog || ''}\n${panelErrLog || ''}\n${res}`.trim()),
|
||||
new Error(
|
||||
`${scheduleErrLog || ''}\n${panelErrLog || ''}\n${res}`.trim(),
|
||||
),
|
||||
);
|
||||
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default class DependenceService {
|
|||
constructor(
|
||||
@Inject('logger') private logger: winston.Logger,
|
||||
private sockService: SockService,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
public async create(payloads: Dependence[]): Promise<Dependence[]> {
|
||||
const tabs = payloads.map((x) => {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class MetricsService {
|
|||
// 定期清理旧数据
|
||||
setInterval(() => {
|
||||
const oneHourAgo = Date.now() - 3600000;
|
||||
this.metrics = this.metrics.filter(m => m.timestamp > oneHourAgo);
|
||||
this.metrics = this.metrics.filter((m) => m.timestamp > oneHourAgo);
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +46,11 @@ class MetricsService {
|
|||
}
|
||||
}
|
||||
|
||||
async measureAsync(name: string, fn: () => Promise<void>, tags?: Record<string, string>) {
|
||||
async measureAsync(
|
||||
name: string,
|
||||
fn: () => Promise<void>,
|
||||
tags?: Record<string, string>,
|
||||
) {
|
||||
const start = performance.now();
|
||||
try {
|
||||
await fn();
|
||||
|
|
@ -58,23 +62,26 @@ class MetricsService {
|
|||
|
||||
getMetrics(name?: string, tags?: Record<string, string>) {
|
||||
let filtered = this.metrics;
|
||||
|
||||
|
||||
if (name) {
|
||||
filtered = filtered.filter(m => m.name === name);
|
||||
filtered = filtered.filter((m) => m.name === name);
|
||||
}
|
||||
|
||||
|
||||
if (tags) {
|
||||
filtered = filtered.filter(m => {
|
||||
filtered = filtered.filter((m) => {
|
||||
if (!m.tags) return false;
|
||||
return Object.entries(tags).every(([key, value]) => m.tags![key] === value);
|
||||
return Object.entries(tags).every(
|
||||
([key, value]) => m.tags![key] === value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
count: filtered.length,
|
||||
average: filtered.reduce((acc, curr) => acc + curr.value, 0) / filtered.length,
|
||||
min: Math.min(...filtered.map(m => m.value)),
|
||||
max: Math.max(...filtered.map(m => m.value)),
|
||||
average:
|
||||
filtered.reduce((acc, curr) => acc + curr.value, 0) / filtered.length,
|
||||
min: Math.min(...filtered.map((m) => m.value)),
|
||||
max: Math.max(...filtered.map((m) => m.value)),
|
||||
metrics: filtered,
|
||||
};
|
||||
}
|
||||
|
|
@ -89,4 +96,4 @@ class MetricsService {
|
|||
}
|
||||
}
|
||||
|
||||
export const metricsService = MetricsService.getInstance();
|
||||
export const metricsService = MetricsService.getInstance();
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { SockMessage } from '../data/sock';
|
|||
export default class SockService {
|
||||
private clients: Connection[] = [];
|
||||
|
||||
constructor(@Inject('logger') private logger: winston.Logger) { }
|
||||
constructor(@Inject('logger') private logger: winston.Logger) {}
|
||||
|
||||
public getClients() {
|
||||
return this.clients;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export default class SystemService {
|
|||
@Inject('logger') private logger: winston.Logger,
|
||||
private scheduleService: ScheduleService,
|
||||
private sockService: SockService,
|
||||
) { }
|
||||
) {}
|
||||
|
||||
public async getSystemConfig() {
|
||||
const doc = await this.getDb({ type: AuthDataType.systemConfig });
|
||||
|
|
@ -287,7 +287,7 @@ export default class SystemService {
|
|||
);
|
||||
const text = await body.text();
|
||||
lastVersionContent = parseContentVersion(text);
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
|
||||
if (!lastVersionContent) {
|
||||
lastVersionContent = currentVersionContent;
|
||||
|
|
@ -401,16 +401,23 @@ export default class SystemService {
|
|||
}
|
||||
}
|
||||
|
||||
public async run({ command, logPath }: { command: string; logPath?: string }, callback: TaskCallbacks) {
|
||||
public async run(
|
||||
{ command, logPath }: { command: string; logPath?: string },
|
||||
callback: TaskCallbacks,
|
||||
) {
|
||||
if (!command.startsWith(TASK_COMMAND)) {
|
||||
command = `${TASK_COMMAND} ${command}`;
|
||||
}
|
||||
const logPathPrefix = logPath ? `real_log_path=${logPath}` : ''
|
||||
this.scheduleService.runTask(`${logPathPrefix} real_time=true ${command}`, callback, {
|
||||
command,
|
||||
id: command.replace(/ /g, '-'),
|
||||
runOrigin: 'system',
|
||||
});
|
||||
const logPathPrefix = logPath ? `real_log_path=${logPath}` : '';
|
||||
this.scheduleService.runTask(
|
||||
`${logPathPrefix} real_time=true ${command}`,
|
||||
callback,
|
||||
{
|
||||
command,
|
||||
id: command.replace(/ /g, '-'),
|
||||
runOrigin: 'system',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public async stop({ command, pid }: { command: string; pid: number }) {
|
||||
|
|
@ -443,7 +450,8 @@ export default class SystemService {
|
|||
}
|
||||
const dataPaths = dataDirs.map((dir) => `data/${dir}`);
|
||||
await promiseExec(
|
||||
`cd ${config.dataPath} && cd ../ && tar -zcvf ${config.dataTgzFile
|
||||
`cd ${config.dataPath} && cd ../ && tar -zcvf ${
|
||||
config.dataTgzFile
|
||||
} ${dataPaths.join(' ')}`,
|
||||
);
|
||||
res.download(config.dataTgzFile);
|
||||
|
|
@ -537,7 +545,7 @@ export default class SystemService {
|
|||
try {
|
||||
const finalPath = path.join(config.dependenceCachePath, type);
|
||||
await fs.promises.rm(finalPath, { recursive: true });
|
||||
} catch (error) { }
|
||||
} catch (error) {}
|
||||
return { code: 200 };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
SystemModelInfo,
|
||||
LoginStatus,
|
||||
AuthInfo,
|
||||
TokenInfo,
|
||||
} from '../data/system';
|
||||
import { NotificationInfo } from '../data/notify';
|
||||
import NotificationService from './notify';
|
||||
|
|
@ -101,12 +102,23 @@ export default class UserService {
|
|||
algorithm: 'HS384',
|
||||
});
|
||||
|
||||
const tokenInfo: TokenInfo = {
|
||||
value: token,
|
||||
timestamp,
|
||||
ip,
|
||||
address,
|
||||
platform: req.platform,
|
||||
};
|
||||
|
||||
const updatedTokens = this.addTokenToList(
|
||||
tokens,
|
||||
req.platform,
|
||||
tokenInfo,
|
||||
);
|
||||
|
||||
await this.updateAuthInfo(content, {
|
||||
token,
|
||||
tokens: {
|
||||
...tokens,
|
||||
[req.platform]: token,
|
||||
},
|
||||
tokens: updatedTokens,
|
||||
lastlogon: timestamp,
|
||||
retries: 0,
|
||||
lastip: ip,
|
||||
|
|
@ -180,11 +192,37 @@ export default class UserService {
|
|||
}
|
||||
}
|
||||
|
||||
public async logout(platform: string): Promise<any> {
|
||||
public async logout(platform: string, tokenValue: string): Promise<any> {
|
||||
if (!platform || !tokenValue) {
|
||||
this.logger.warn('Invalid logout parameters - empty platform or token');
|
||||
return;
|
||||
}
|
||||
|
||||
const authInfo = await this.getAuthInfo();
|
||||
|
||||
// Verify the token exists before attempting to remove it
|
||||
const tokenExists = this.findTokenInList(
|
||||
authInfo.tokens,
|
||||
platform,
|
||||
tokenValue,
|
||||
);
|
||||
if (!tokenExists && authInfo.token !== tokenValue) {
|
||||
// Token not found, but don't throw error - user may have already logged out
|
||||
this.logger.info(
|
||||
`Logout attempted for non-existent token on platform: ${platform}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedTokens = this.removeTokenFromList(
|
||||
authInfo.tokens,
|
||||
platform,
|
||||
tokenValue,
|
||||
);
|
||||
|
||||
await this.updateAuthInfo(authInfo, {
|
||||
token: '',
|
||||
tokens: { ...authInfo.tokens, [platform]: '' },
|
||||
token: authInfo.token === tokenValue ? '' : authInfo.token,
|
||||
tokens: updatedTokens,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -364,6 +402,100 @@ export default class UserService {
|
|||
}
|
||||
}
|
||||
|
||||
private normalizeTokens(
|
||||
tokens: Record<string, string | TokenInfo[]>,
|
||||
): Record<string, TokenInfo[]> {
|
||||
const normalized: Record<string, TokenInfo[]> = {};
|
||||
|
||||
for (const [platform, value] of Object.entries(tokens)) {
|
||||
if (typeof value === 'string') {
|
||||
// Legacy format: convert string token to TokenInfo array
|
||||
if (value) {
|
||||
normalized[platform] = [
|
||||
{
|
||||
value,
|
||||
timestamp: Date.now(),
|
||||
ip: '',
|
||||
address: '',
|
||||
platform,
|
||||
},
|
||||
];
|
||||
} else {
|
||||
normalized[platform] = [];
|
||||
}
|
||||
} else {
|
||||
// Already in new format
|
||||
normalized[platform] = value || [];
|
||||
}
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private addTokenToList(
|
||||
tokens: Record<string, string | TokenInfo[]>,
|
||||
platform: string,
|
||||
tokenInfo: TokenInfo,
|
||||
maxTokensPerPlatform: number = config.maxTokensPerPlatform,
|
||||
): Record<string, TokenInfo[]> {
|
||||
// Validate maxTokensPerPlatform parameter
|
||||
if (!Number.isInteger(maxTokensPerPlatform) || maxTokensPerPlatform < 1) {
|
||||
this.logger.warn(
|
||||
`Invalid maxTokensPerPlatform value: ${maxTokensPerPlatform}, using default`,
|
||||
);
|
||||
maxTokensPerPlatform = config.maxTokensPerPlatform;
|
||||
}
|
||||
|
||||
const normalized = this.normalizeTokens(tokens);
|
||||
|
||||
if (!normalized[platform]) {
|
||||
normalized[platform] = [];
|
||||
}
|
||||
|
||||
// Add new token
|
||||
normalized[platform].unshift(tokenInfo);
|
||||
|
||||
// Limit the number of active tokens per platform
|
||||
if (normalized[platform].length > maxTokensPerPlatform) {
|
||||
normalized[platform] = normalized[platform].slice(
|
||||
0,
|
||||
maxTokensPerPlatform,
|
||||
);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private removeTokenFromList(
|
||||
tokens: Record<string, string | TokenInfo[]>,
|
||||
platform: string,
|
||||
tokenValue: string,
|
||||
): Record<string, TokenInfo[]> {
|
||||
const normalized = this.normalizeTokens(tokens);
|
||||
|
||||
if (normalized[platform]) {
|
||||
normalized[platform] = normalized[platform].filter(
|
||||
(t) => t.value !== tokenValue,
|
||||
);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private findTokenInList(
|
||||
tokens: Record<string, string | TokenInfo[]>,
|
||||
platform: string,
|
||||
tokenValue: string,
|
||||
): TokenInfo | undefined {
|
||||
const normalized = this.normalizeTokens(tokens);
|
||||
|
||||
if (normalized[platform]) {
|
||||
return normalized[platform].find((t) => t.value === tokenValue);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async resetAuthInfo(info: Partial<AuthInfo>) {
|
||||
const { retries, twoFactorActivated, password, username } = info;
|
||||
const authInfo = await this.getAuthInfo();
|
||||
|
|
|
|||
46
back/shared/auth.ts
Normal file
46
back/shared/auth.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { AuthInfo, TokenInfo } from '../data/system';
|
||||
|
||||
/**
|
||||
* Validates if a token exists in the authentication info.
|
||||
* Supports both legacy string tokens and new TokenInfo array format.
|
||||
*
|
||||
* @param authInfo - The authentication information
|
||||
* @param headerToken - The token to validate
|
||||
* @param platform - The platform (desktop, mobile)
|
||||
* @returns true if the token is valid, false otherwise
|
||||
*/
|
||||
export function isValidToken(
|
||||
authInfo: AuthInfo | null | undefined,
|
||||
headerToken: string,
|
||||
platform: string,
|
||||
): boolean {
|
||||
if (!authInfo || !headerToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { token = '', tokens = {} } = authInfo;
|
||||
|
||||
// Check legacy token field
|
||||
if (headerToken === token) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check platform-specific tokens (support both legacy string and new TokenInfo[] format)
|
||||
const platformTokens = tokens[platform];
|
||||
|
||||
// Handle null/undefined platformTokens
|
||||
if (platformTokens === null || platformTokens === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof platformTokens === 'string') {
|
||||
// Legacy format: single string token
|
||||
return headerToken === platformTokens;
|
||||
} else if (Array.isArray(platformTokens)) {
|
||||
// New format: array of TokenInfo objects
|
||||
return platformTokens.some((t: TokenInfo) => t && t.value === headerToken);
|
||||
}
|
||||
|
||||
// Unexpected type - log warning and reject
|
||||
return false;
|
||||
}
|
||||
2
back/types/express.d.ts
vendored
2
back/types/express.d.ts
vendored
|
|
@ -8,4 +8,4 @@ declare global {
|
|||
platform: 'desktop' | 'mobile';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
{
|
||||
"watch": [
|
||||
"back",
|
||||
".env"
|
||||
],
|
||||
"watch": ["back", ".env"],
|
||||
"ext": "js,ts,json",
|
||||
"env": {
|
||||
"NODE_ENV": "development",
|
||||
|
|
@ -12,4 +9,4 @@
|
|||
"execMap": {
|
||||
"ts": "node --require ts-node/register"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1262,7 +1262,15 @@ function ntfyNotify(text, desp) {
|
|||
}
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const { NTFY_URL, NTFY_TOPIC, NTFY_PRIORITY, NTFY_TOKEN, NTFY_USERNAME, NTFY_PASSWORD, NTFY_ACTIONS } = push_config;
|
||||
const {
|
||||
NTFY_URL,
|
||||
NTFY_TOPIC,
|
||||
NTFY_PRIORITY,
|
||||
NTFY_TOKEN,
|
||||
NTFY_USERNAME,
|
||||
NTFY_PASSWORD,
|
||||
NTFY_ACTIONS,
|
||||
} = push_config;
|
||||
if (NTFY_TOPIC) {
|
||||
const options = {
|
||||
url: `${NTFY_URL || 'https://ntfy.sh'}/${NTFY_TOPIC}`,
|
||||
|
|
@ -1277,7 +1285,9 @@ function ntfyNotify(text, desp) {
|
|||
if (NTFY_TOKEN) {
|
||||
options.headers['Authorization'] = `Bearer ${NTFY_TOKEN}`;
|
||||
} else if (NTFY_USERNAME && NTFY_PASSWORD) {
|
||||
options.headers['Authorization'] = `Basic ${Buffer.from(`${NTFY_USERNAME}:${NTFY_PASSWORD}`).toString('base64')}`;
|
||||
options.headers['Authorization'] = `Basic ${Buffer.from(
|
||||
`${NTFY_USERNAME}:${NTFY_PASSWORD}`,
|
||||
).toString('base64')}`;
|
||||
}
|
||||
if (NTFY_ACTIONS) {
|
||||
options.headers['Actions'] = encodeRFC2047(NTFY_ACTIONS);
|
||||
|
|
|
|||
16
src/app.ts
16
src/app.ts
|
|
@ -4,14 +4,16 @@ import intl from 'react-intl-universal';
|
|||
|
||||
export function rootContainer(container: any) {
|
||||
const locales = {
|
||||
'en': require('./locales/en-US.json'),
|
||||
'zh': require('./locales/zh-CN.json'),
|
||||
en: require('./locales/en-US.json'),
|
||||
zh: require('./locales/zh-CN.json'),
|
||||
};
|
||||
let currentLocale = intl.determineLocale({
|
||||
urlLocaleKey: 'lang',
|
||||
cookieLocaleKey: 'lang',
|
||||
localStorageLocaleKey: 'lang',
|
||||
}).slice(0, 2);
|
||||
let currentLocale = intl
|
||||
.determineLocale({
|
||||
urlLocaleKey: 'lang',
|
||||
cookieLocaleKey: 'lang',
|
||||
localStorageLocaleKey: 'lang',
|
||||
})
|
||||
.slice(0, 2);
|
||||
|
||||
if (!currentLocale || !Object.keys(locales).includes(currentLocale)) {
|
||||
currentLocale = 'zh';
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ const Config = () => {
|
|||
lineNumbersMinChars: 3,
|
||||
folding: false,
|
||||
glyphMargin: false,
|
||||
accessibilitySupport: 'off'
|
||||
accessibilitySupport: 'off',
|
||||
}}
|
||||
onMount={(editor) => {
|
||||
editorRef.current = editor;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import intl from "react-intl-universal";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import intl from 'react-intl-universal';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Modal,
|
||||
message,
|
||||
|
|
@ -8,17 +8,17 @@ import {
|
|||
Statistic,
|
||||
Button,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { request } from "@/utils/http";
|
||||
import config from "@/utils/config";
|
||||
} from 'antd';
|
||||
import { request } from '@/utils/http';
|
||||
import config from '@/utils/config';
|
||||
import {
|
||||
Loading3QuartersOutlined,
|
||||
CheckCircleOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { PageLoading } from "@ant-design/pro-layout";
|
||||
import { logEnded } from "@/utils";
|
||||
import { CrontabStatus } from "./type";
|
||||
import Ansi from "ansi-to-react";
|
||||
} from '@ant-design/icons';
|
||||
import { PageLoading } from '@ant-design/pro-layout';
|
||||
import { logEnded } from '@/utils';
|
||||
import { CrontabStatus } from './type';
|
||||
import Ansi from 'ansi-to-react';
|
||||
|
||||
const { Countdown } = Statistic;
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ const CronLogModal = ({
|
|||
data?: string;
|
||||
logUrl?: string;
|
||||
}) => {
|
||||
const [value, setValue] = useState<string>(intl.get("启动中..."));
|
||||
const [value, setValue] = useState<string>(intl.get('启动中...'));
|
||||
const [loading, setLoading] = useState<any>(true);
|
||||
const [executing, setExecuting] = useState<any>(true);
|
||||
const [isPhone, setIsPhone] = useState(false);
|
||||
|
|
@ -49,15 +49,15 @@ const CronLogModal = ({
|
|||
.then(({ code, data }) => {
|
||||
if (
|
||||
code === 200 &&
|
||||
localStorage.getItem("logCron") === uniqPath &&
|
||||
localStorage.getItem('logCron') === uniqPath &&
|
||||
data !== value
|
||||
) {
|
||||
const log = data as string;
|
||||
setValue(log || intl.get("暂无日志"));
|
||||
setValue(log || intl.get('暂无日志'));
|
||||
const hasNext = Boolean(
|
||||
log && !logEnded(log) && !log.includes("日志不存在"),
|
||||
log && !logEnded(log) && !log.includes('日志不存在'),
|
||||
);
|
||||
if (!hasNext && !logEnded(value) && value !== intl.get("启动中...")) {
|
||||
if (!hasNext && !logEnded(value) && value !== intl.get('启动中...')) {
|
||||
setTimeout(() => {
|
||||
autoScroll();
|
||||
});
|
||||
|
|
@ -85,13 +85,13 @@ const CronLogModal = ({
|
|||
|
||||
setTimeout(() => {
|
||||
document
|
||||
.querySelector("#log-flag")
|
||||
?.scrollIntoView({ behavior: "smooth" });
|
||||
.querySelector('#log-flag')
|
||||
?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, 600);
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
localStorage.removeItem("logCron");
|
||||
localStorage.removeItem('logCron');
|
||||
handleCancel();
|
||||
};
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ const CronLogModal = ({
|
|||
|
||||
const titleElement = () => {
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
{(executing || loading) && <Loading3QuartersOutlined spin />}
|
||||
{!executing && !loading && <CheckCircleOutlined />}
|
||||
<Typography.Text ellipsis={true} style={{ marginLeft: 5 }}>
|
||||
|
|
@ -144,7 +144,7 @@ const CronLogModal = ({
|
|||
onCancel={() => cancel()}
|
||||
footer={[
|
||||
<Button type="primary" onClick={() => cancel()}>
|
||||
{intl.get("知道了")}
|
||||
{intl.get('知道了')}
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
|
|
@ -156,9 +156,9 @@ const CronLogModal = ({
|
|||
style={
|
||||
isPhone
|
||||
? {
|
||||
fontFamily: "Source Code Pro",
|
||||
zoom: 0.83,
|
||||
}
|
||||
fontFamily: 'Source Code Pro',
|
||||
zoom: 0.83,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -312,4 +312,3 @@ const CronLabelModal = ({
|
|||
};
|
||||
|
||||
export { CronLabelModal, CronModal as default };
|
||||
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@ export enum Status {
|
|||
'删除失败',
|
||||
'队列中',
|
||||
'已取消',
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ const Diff = () => {
|
|||
|
||||
const getConfig = () => {
|
||||
request
|
||||
.get(`${config.apiPrefix}configs/detail?path=${encodeURIComponent(current)}`)
|
||||
.get(
|
||||
`${config.apiPrefix}configs/detail?path=${encodeURIComponent(current)}`,
|
||||
)
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200) {
|
||||
setCurrentValue(data);
|
||||
|
|
@ -36,7 +38,9 @@ const Diff = () => {
|
|||
|
||||
const getSample = () => {
|
||||
request
|
||||
.get(`${config.apiPrefix}configs/detail?path=${encodeURIComponent(origin)}`)
|
||||
.get(
|
||||
`${config.apiPrefix}configs/detail?path=${encodeURIComponent(origin)}`,
|
||||
)
|
||||
.then(({ code, data }) => {
|
||||
if (code === 200) {
|
||||
setOriginValue(data);
|
||||
|
|
|
|||
6
src/pages/env/editNameModal.tsx
vendored
6
src/pages/env/editNameModal.tsx
vendored
|
|
@ -1,4 +1,4 @@
|
|||
import intl from 'react-intl-universal'
|
||||
import intl from 'react-intl-universal';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Modal, message, Input, Form } from 'antd';
|
||||
import { request } from '@/utils/http';
|
||||
|
|
@ -55,7 +55,9 @@ const EditNameModal = ({
|
|||
<Form form={form} layout="vertical" name="edit_name_modal">
|
||||
<Form.Item
|
||||
name="name"
|
||||
rules={[{ required: true, message: intl.get('请输入新的环境变量名称') }]}
|
||||
rules={[
|
||||
{ required: true, message: intl.get('请输入新的环境变量名称') },
|
||||
]}
|
||||
>
|
||||
<Input placeholder={intl.get('请输入新的环境变量名称')} />
|
||||
</Form.Item>
|
||||
|
|
|
|||
|
|
@ -64,4 +64,4 @@
|
|||
.warningIcon {
|
||||
font-size: 14px;
|
||||
color: #faad14;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,10 @@ const UnsupportedFilePreview: React.FC<UnsupportedFilePreviewProps> = ({
|
|||
<div className={styles.iconWrapper}>
|
||||
<FileUnknownOutlined className={styles.icon} />
|
||||
</div>
|
||||
<div className={styles.message}>
|
||||
{intl.get('当前文件不支持预览')}
|
||||
</div>
|
||||
<div className={styles.message}>{intl.get('当前文件不支持预览')}</div>
|
||||
<Space direction="vertical" size={8} className={styles.actionArea}>
|
||||
<Button
|
||||
type="primary"
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={onForceOpen}
|
||||
className={styles.button}
|
||||
>
|
||||
|
|
@ -38,4 +36,4 @@ const UnsupportedFilePreview: React.FC<UnsupportedFilePreviewProps> = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default UnsupportedFilePreview;
|
||||
export default UnsupportedFilePreview;
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
import { disableBody } from "@/utils";
|
||||
import config from "@/utils/config";
|
||||
import { request } from "@/utils/http";
|
||||
import WebSocketManager from "@/utils/websocket";
|
||||
import Ansi from "ansi-to-react";
|
||||
import { Button, Modal, Statistic, message } from "antd";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import intl from "react-intl-universal";
|
||||
import { disableBody } from '@/utils';
|
||||
import config from '@/utils/config';
|
||||
import { request } from '@/utils/http';
|
||||
import WebSocketManager from '@/utils/websocket';
|
||||
import Ansi from 'ansi-to-react';
|
||||
import { Button, Modal, Statistic, message } from 'antd';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import intl from 'react-intl-universal';
|
||||
|
||||
const { Countdown } = Statistic;
|
||||
|
||||
const CheckUpdate = ({ systemInfo }: any) => {
|
||||
const [updateLoading, setUpdateLoading] = useState(false);
|
||||
const [value, setValue] = useState("");
|
||||
const [value, setValue] = useState('');
|
||||
const modalRef = useRef<any>();
|
||||
|
||||
const checkUpgrade = () => {
|
||||
if (updateLoading) return;
|
||||
setUpdateLoading(true);
|
||||
message.loading(intl.get("检查更新中..."), 0);
|
||||
message.loading(intl.get('检查更新中...'), 0);
|
||||
request
|
||||
.put(`${config.apiPrefix}system/update-check`)
|
||||
.then(({ code, data }) => {
|
||||
|
|
@ -42,22 +42,22 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
const showForceUpdateModal = (data: any) => {
|
||||
Modal.confirm({
|
||||
width: 500,
|
||||
title: intl.get("更新"),
|
||||
title: intl.get('更新'),
|
||||
content: (
|
||||
<>
|
||||
<div>{intl.get("已经是最新版了!")}</div>
|
||||
<div>{intl.get('已经是最新版了!')}</div>
|
||||
<div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}>
|
||||
{intl.get("青龙")} {data.lastVersion}{" "}
|
||||
{intl.get("是目前检测到的最新可用版本了。")}
|
||||
{intl.get('青龙')} {data.lastVersion}{' '}
|
||||
{intl.get('是目前检测到的最新可用版本了。')}
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
okText: intl.get("重新下载"),
|
||||
okText: intl.get('重新下载'),
|
||||
onOk() {
|
||||
showUpdatingModal();
|
||||
request
|
||||
.put(`${config.apiPrefix}system/update`)
|
||||
.then((_data: any) => { })
|
||||
.then((_data: any) => {})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
|
@ -71,10 +71,10 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
width: 500,
|
||||
title: (
|
||||
<>
|
||||
<div>{intl.get("更新可用")}</div>
|
||||
<div>{intl.get('更新可用')}</div>
|
||||
<div style={{ fontSize: 12, fontWeight: 400, marginTop: 5 }}>
|
||||
{intl.get("新版本")} {lastVersion}{" "}
|
||||
{intl.get("可用,你使用的版本为")} {systemInfo.version}。
|
||||
{intl.get('新版本')} {lastVersion}{' '}
|
||||
{intl.get('可用,你使用的版本为')} {systemInfo.version}。
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
|
|
@ -83,13 +83,13 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
<Ansi>{lastLog}</Ansi>
|
||||
</pre>
|
||||
),
|
||||
okText: intl.get("下载更新"),
|
||||
cancelText: intl.get("以后再说"),
|
||||
okText: intl.get('下载更新'),
|
||||
cancelText: intl.get('以后再说'),
|
||||
onOk() {
|
||||
showUpdatingModal();
|
||||
request
|
||||
.put(`${config.apiPrefix}system/update`)
|
||||
.then((_data: any) => { })
|
||||
.then((_data: any) => {})
|
||||
.catch((error: any) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
|
@ -98,14 +98,14 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
};
|
||||
|
||||
const showUpdatingModal = () => {
|
||||
setValue("");
|
||||
setValue('');
|
||||
modalRef.current = Modal.info({
|
||||
width: 600,
|
||||
maskClosable: false,
|
||||
closable: false,
|
||||
keyboard: false,
|
||||
okButtonProps: { disabled: true },
|
||||
title: intl.get("下载更新中..."),
|
||||
title: intl.get('下载更新中...'),
|
||||
centered: true,
|
||||
content: (
|
||||
<pre>
|
||||
|
|
@ -122,13 +122,13 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
message.success({
|
||||
content: (
|
||||
<span>
|
||||
{intl.get("系统将在")}
|
||||
{intl.get('系统将在')}
|
||||
<Countdown
|
||||
className="inline-countdown"
|
||||
format="ss"
|
||||
value={Date.now() + 1000 * 30}
|
||||
/>
|
||||
{intl.get("秒后自动刷新")}
|
||||
{intl.get('秒后自动刷新')}
|
||||
</span>
|
||||
),
|
||||
duration: 30,
|
||||
|
|
@ -147,12 +147,12 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
Modal.confirm({
|
||||
width: 600,
|
||||
maskClosable: false,
|
||||
title: intl.get("确认重启"),
|
||||
title: intl.get('确认重启'),
|
||||
centered: true,
|
||||
content: intl.get("系统安装包下载成功,确认重启"),
|
||||
okText: intl.get("重启"),
|
||||
content: intl.get('系统安装包下载成功,确认重启'),
|
||||
okText: intl.get('重启'),
|
||||
onOk() {
|
||||
reloadSystem("system");
|
||||
reloadSystem('system');
|
||||
},
|
||||
onCancel() {
|
||||
modalRef.current.update({
|
||||
|
|
@ -166,7 +166,7 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
|
||||
useEffect(() => {
|
||||
if (!value) return;
|
||||
const updateFailed = value.includes("失败,请检查");
|
||||
const updateFailed = value.includes('失败,请检查');
|
||||
|
||||
modalRef.current.update({
|
||||
maskClosable: updateFailed,
|
||||
|
|
@ -185,19 +185,19 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
|
||||
const handleMessage = useCallback((payload: any) => {
|
||||
let { message: _message } = payload;
|
||||
const updateFailed = _message.includes("失败,请检查");
|
||||
const updateFailed = _message.includes('失败,请检查');
|
||||
|
||||
if (updateFailed) {
|
||||
message.error(intl.get("更新失败,请检查网络及日志或稍后再试"));
|
||||
message.error(intl.get('更新失败,请检查网络及日志或稍后再试'));
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
document
|
||||
.querySelector("#log-identifier")
|
||||
?.scrollIntoView({ behavior: "smooth" });
|
||||
.querySelector('#log-identifier')
|
||||
?.scrollIntoView({ behavior: 'smooth' });
|
||||
}, 600);
|
||||
|
||||
if (_message.includes("更新包下载成功")) {
|
||||
if (_message.includes('更新包下载成功')) {
|
||||
setTimeout(() => {
|
||||
showReloadModal();
|
||||
}, 1000);
|
||||
|
|
@ -208,24 +208,24 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
|||
|
||||
useEffect(() => {
|
||||
const ws = WebSocketManager.getInstance();
|
||||
ws.subscribe("updateSystemVersion", handleMessage);
|
||||
ws.subscribe('updateSystemVersion', handleMessage);
|
||||
|
||||
return () => {
|
||||
ws.unsubscribe("updateSystemVersion", handleMessage);
|
||||
ws.unsubscribe('updateSystemVersion', handleMessage);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" onClick={checkUpgrade}>
|
||||
{intl.get("检查更新")}
|
||||
{intl.get('检查更新')}
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => reloadSystem("reload")}
|
||||
onClick={() => reloadSystem('reload')}
|
||||
style={{ marginLeft: 8 }}
|
||||
>
|
||||
{intl.get("重新启动")}
|
||||
{intl.get('重新启动')}
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ const NotificationSetting = ({ data }: any) => {
|
|||
>
|
||||
{x.items ? (
|
||||
<Select
|
||||
placeholder={x.placeholder || `${intl.get('请选择')} ${x.label}`}
|
||||
placeholder={
|
||||
x.placeholder || `${intl.get('请选择')} ${x.label}`
|
||||
}
|
||||
disabled={loading}
|
||||
>
|
||||
{x.items.map((y) => (
|
||||
|
|
@ -89,7 +91,9 @@ const NotificationSetting = ({ data }: any) => {
|
|||
<Input.TextArea
|
||||
disabled={loading}
|
||||
autoSize={{ minRows: 1, maxRows: 5 }}
|
||||
placeholder={x.placeholder || `${intl.get('请输入')} ${x.label}`}
|
||||
placeholder={
|
||||
x.placeholder || `${intl.get('请输入')} ${x.label}`
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
|
|
|
|||
|
|
@ -97,9 +97,7 @@ const SecuritySettings = ({ user, userChange }: any) => {
|
|||
|
||||
const onChange = (e) => {
|
||||
if (e.file && e.file.response) {
|
||||
setAvatar(
|
||||
`${config.apiPrefix}static/${e.file.response.data}`,
|
||||
);
|
||||
setAvatar(`${config.apiPrefix}static/${e.file.response.data}`);
|
||||
userChange();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import * as monaco from 'monaco-editor';
|
||||
|
||||
interface FileTypeConfig {
|
||||
extensions?: string[]; // 文件扩展名
|
||||
filenames?: string[]; // 完整文件名
|
||||
patterns?: RegExp[]; // 文件名正则匹配
|
||||
startsWith?: string[]; // 文件名前缀匹配
|
||||
endsWith?: string[]; // 文件名后缀匹配
|
||||
extensions?: string[]; // 文件扩展名
|
||||
filenames?: string[]; // 完整文件名
|
||||
patterns?: RegExp[]; // 文件名正则匹配
|
||||
startsWith?: string[]; // 文件名前缀匹配
|
||||
endsWith?: string[]; // 文件名后缀匹配
|
||||
}
|
||||
|
||||
// 文件类型分类配置(只包含特殊文件类型)
|
||||
|
|
@ -13,13 +13,13 @@ const fileTypeConfigs: Record<string, FileTypeConfig> = {
|
|||
// 前端特殊文件
|
||||
frontend: {
|
||||
extensions: [
|
||||
'.json5', // JSON5
|
||||
'.vue', // Vue
|
||||
'.svelte', // Svelte
|
||||
'.astro', // Astro
|
||||
'.wxss', // 微信小程序样式
|
||||
'.pcss', // PostCSS
|
||||
'.acss', // 支付宝小程序样式
|
||||
'.json5', // JSON5
|
||||
'.vue', // Vue
|
||||
'.svelte', // Svelte
|
||||
'.astro', // Astro
|
||||
'.wxss', // 微信小程序样式
|
||||
'.pcss', // PostCSS
|
||||
'.acss', // 支付宝小程序样式
|
||||
],
|
||||
patterns: [
|
||||
/\.env\.(local|development|production|test)$/,
|
||||
|
|
@ -32,28 +32,28 @@ const fileTypeConfigs: Record<string, FileTypeConfig> = {
|
|||
// 小程序相关
|
||||
miniprogram: {
|
||||
extensions: [
|
||||
'.wxml', // 微信小程序
|
||||
'.wxs', // 微信小程序
|
||||
'.axml', // 支付宝小程序
|
||||
'.sjs', // 支付宝小程序
|
||||
'.swan', // 百度小程序
|
||||
'.ttml', // 字节跳动小程序
|
||||
'.ttss', // 字节跳动小程序
|
||||
'.wxl', // 微信小程序语言包
|
||||
'.qml', // QQ小程序
|
||||
'.qss', // QQ小程序
|
||||
'.ksml', // 快手小程序
|
||||
'.kss', // 快手小程序
|
||||
'.wxml', // 微信小程序
|
||||
'.wxs', // 微信小程序
|
||||
'.axml', // 支付宝小程序
|
||||
'.sjs', // 支付宝小程序
|
||||
'.swan', // 百度小程序
|
||||
'.ttml', // 字节跳动小程序
|
||||
'.ttss', // 字节跳动小程序
|
||||
'.wxl', // 微信小程序语言包
|
||||
'.qml', // QQ小程序
|
||||
'.qss', // QQ小程序
|
||||
'.ksml', // 快手小程序
|
||||
'.kss', // 快手小程序
|
||||
],
|
||||
},
|
||||
|
||||
// 开发工具相关
|
||||
devtools: {
|
||||
extensions: [
|
||||
'.prisma', // Prisma
|
||||
'.mdx', // MDX
|
||||
'.swagger', // Swagger
|
||||
'.openapi', // OpenAPI
|
||||
'.prisma', // Prisma
|
||||
'.mdx', // MDX
|
||||
'.swagger', // Swagger
|
||||
'.openapi', // OpenAPI
|
||||
],
|
||||
},
|
||||
|
||||
|
|
@ -84,9 +84,7 @@ const fileTypeConfigs: Record<string, FileTypeConfig> = {
|
|||
'.gcloudignore',
|
||||
'.htaccess',
|
||||
],
|
||||
patterns: [
|
||||
/^\.env\./,
|
||||
],
|
||||
patterns: [/^\.env\./],
|
||||
},
|
||||
|
||||
// CI/CD 配置
|
||||
|
|
@ -106,28 +104,33 @@ const fileTypeConfigs: Record<string, FileTypeConfig> = {
|
|||
*/
|
||||
export function canPreviewInMonaco(fileName: string): boolean {
|
||||
if (!fileName) return false;
|
||||
|
||||
|
||||
// 获取 Monaco 支持的语言
|
||||
const supportedLanguages = monaco.languages.getLanguages();
|
||||
const ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase();
|
||||
const lowercaseFileName = fileName.toLowerCase();
|
||||
|
||||
// 检查 Monaco 原生支持
|
||||
if (supportedLanguages.some((lang) =>
|
||||
lang.extensions?.includes(ext) ||
|
||||
(lang.filenames?.includes(lowercaseFileName))
|
||||
)) {
|
||||
if (
|
||||
supportedLanguages.some(
|
||||
(lang) =>
|
||||
lang.extensions?.includes(ext) ||
|
||||
lang.filenames?.includes(lowercaseFileName),
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查额外支持的文件类型
|
||||
return Object.values(fileTypeConfigs).some(config => {
|
||||
return Object.values(fileTypeConfigs).some((config) => {
|
||||
return (
|
||||
(config.extensions?.includes(ext)) ||
|
||||
(config.filenames?.includes(lowercaseFileName)) ||
|
||||
(config.patterns?.some(pattern => pattern.test(lowercaseFileName))) ||
|
||||
(config.startsWith?.some(prefix => lowercaseFileName.startsWith(prefix))) ||
|
||||
(config.endsWith?.some(suffix => lowercaseFileName.endsWith(suffix)))
|
||||
config.extensions?.includes(ext) ||
|
||||
config.filenames?.includes(lowercaseFileName) ||
|
||||
config.patterns?.some((pattern) => pattern.test(lowercaseFileName)) ||
|
||||
config.startsWith?.some((prefix) =>
|
||||
lowercaseFileName.startsWith(prefix),
|
||||
) ||
|
||||
config.endsWith?.some((suffix) => lowercaseFileName.endsWith(suffix))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
@ -139,17 +142,19 @@ export function canPreviewInMonaco(fileName: string): boolean {
|
|||
*/
|
||||
export function getFileCategory(fileName: string): string {
|
||||
if (!fileName) return 'unknown';
|
||||
|
||||
|
||||
const lowercaseFileName = fileName.toLowerCase();
|
||||
const ext = fileName.slice(fileName.lastIndexOf('.')).toLowerCase();
|
||||
|
||||
for (const [category, config] of Object.entries(fileTypeConfigs)) {
|
||||
if (
|
||||
(config.extensions?.includes(ext)) ||
|
||||
(config.filenames?.includes(lowercaseFileName)) ||
|
||||
(config.patterns?.some(pattern => pattern.test(lowercaseFileName))) ||
|
||||
(config.startsWith?.some(prefix => lowercaseFileName.startsWith(prefix))) ||
|
||||
(config.endsWith?.some(suffix => lowercaseFileName.endsWith(suffix)))
|
||||
config.extensions?.includes(ext) ||
|
||||
config.filenames?.includes(lowercaseFileName) ||
|
||||
config.patterns?.some((pattern) => pattern.test(lowercaseFileName)) ||
|
||||
config.startsWith?.some((prefix) =>
|
||||
lowercaseFileName.startsWith(prefix),
|
||||
) ||
|
||||
config.endsWith?.some((suffix) => lowercaseFileName.endsWith(suffix))
|
||||
) {
|
||||
return category;
|
||||
}
|
||||
|
|
@ -157,10 +162,13 @@ export function getFileCategory(fileName: string): string {
|
|||
|
||||
// 检查 Monaco 原生支持
|
||||
const supportedLanguages = monaco.languages.getLanguages();
|
||||
if (supportedLanguages.some((lang) =>
|
||||
lang.extensions?.includes(ext) ||
|
||||
(lang.filenames?.includes(lowercaseFileName))
|
||||
)) {
|
||||
if (
|
||||
supportedLanguages.some(
|
||||
(lang) =>
|
||||
lang.extensions?.includes(ext) ||
|
||||
lang.filenames?.includes(lowercaseFileName),
|
||||
)
|
||||
) {
|
||||
return 'monaco-native';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ class WebSocketManager {
|
|||
private static instance: WebSocketManager | null = null;
|
||||
private url: string;
|
||||
private socket: WebSocket | null = null;
|
||||
private subscriptions: Map<SockMessageType, Set<(p: any) => void>> = new Map();
|
||||
private subscriptions: Map<SockMessageType, Set<(p: any) => void>> =
|
||||
new Map();
|
||||
private options: {
|
||||
maxReconnectAttempts: number;
|
||||
reconnectInterval: number;
|
||||
|
|
@ -15,7 +16,10 @@ class WebSocketManager {
|
|||
private heartbeatTimeout: NodeJS.Timeout | null = null;
|
||||
private state: 'closed' | 'connecting' | 'open' = 'closed';
|
||||
|
||||
constructor(url: string, options: Partial<typeof WebSocketManager.prototype.options> = {}) {
|
||||
constructor(
|
||||
url: string,
|
||||
options: Partial<typeof WebSocketManager.prototype.options> = {},
|
||||
) {
|
||||
this.url = url;
|
||||
this.options = {
|
||||
maxReconnectAttempts: options.maxReconnectAttempts || 5,
|
||||
|
|
@ -26,7 +30,10 @@ class WebSocketManager {
|
|||
this.init();
|
||||
}
|
||||
|
||||
public static getInstance(url: string = '', options?: Partial<typeof WebSocketManager.prototype.options>): WebSocketManager {
|
||||
public static getInstance(
|
||||
url: string = '',
|
||||
options?: Partial<typeof WebSocketManager.prototype.options>,
|
||||
): WebSocketManager {
|
||||
if (!WebSocketManager.instance) {
|
||||
WebSocketManager.instance = new WebSocketManager(url, options);
|
||||
}
|
||||
|
|
@ -47,7 +54,9 @@ class WebSocketManager {
|
|||
this.socket = null;
|
||||
this.reconnectAttempts++;
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, this.options.reconnectInterval));
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, this.options.reconnectInterval),
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
this.handleError(error);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user