mirror of
				https://github.com/louislam/uptime-kuma.git
				synced 2025-11-04 21:56:12 +08:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master'
This commit is contained in:
		
							
								
								
									
										25
									
								
								db/patch-grpc-monitor.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								db/patch-grpc-monitor.sql
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
 | 
				
			||||||
 | 
					BEGIN TRANSACTION;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_url VARCHAR(255) default null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_protobuf TEXT default null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_body TEXT default null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_metadata TEXT default null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_method VARCHAR(255) default null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_service_name VARCHAR(255) default null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE monitor
 | 
				
			||||||
 | 
					    ADD grpc_enable_tls BOOLEAN default 0 not null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COMMIT;
 | 
				
			||||||
							
								
								
									
										4140
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4140
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -64,6 +64,7 @@
 | 
				
			|||||||
        "cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\""
 | 
					        "cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\""
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "dependencies": {
 | 
					    "dependencies": {
 | 
				
			||||||
 | 
					        "@grpc/grpc-js": "^1.7.0",
 | 
				
			||||||
        "@louislam/sqlite3": "15.1.2",
 | 
					        "@louislam/sqlite3": "15.1.2",
 | 
				
			||||||
        "args-parser": "~1.3.0",
 | 
					        "args-parser": "~1.3.0",
 | 
				
			||||||
        "axios": "~0.27.0",
 | 
					        "axios": "~0.27.0",
 | 
				
			||||||
@@ -103,6 +104,7 @@
 | 
				
			|||||||
        "pg-connection-string": "~2.5.0",
 | 
					        "pg-connection-string": "~2.5.0",
 | 
				
			||||||
        "prom-client": "~13.2.0",
 | 
					        "prom-client": "~13.2.0",
 | 
				
			||||||
        "prometheus-api-metrics": "~3.2.1",
 | 
					        "prometheus-api-metrics": "~3.2.1",
 | 
				
			||||||
 | 
					        "protobufjs": "~7.1.1",
 | 
				
			||||||
        "redbean-node": "0.1.4",
 | 
					        "redbean-node": "0.1.4",
 | 
				
			||||||
        "socket.io": "~4.5.3",
 | 
					        "socket.io": "~4.5.3",
 | 
				
			||||||
        "socket.io-client": "~4.5.3",
 | 
					        "socket.io-client": "~4.5.3",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,6 +62,7 @@ class Database {
 | 
				
			|||||||
        "patch-add-clickable-status-page-link.sql": true,
 | 
					        "patch-add-clickable-status-page-link.sql": true,
 | 
				
			||||||
        "patch-add-sqlserver-monitor.sql": true,
 | 
					        "patch-add-sqlserver-monitor.sql": true,
 | 
				
			||||||
        "patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
 | 
					        "patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
 | 
				
			||||||
 | 
					        "patch-grpc-monitor.sql": true,
 | 
				
			||||||
        "patch-add-radius-monitor.sql": true,
 | 
					        "patch-add-radius-monitor.sql": true,
 | 
				
			||||||
        "patch-monitor-add-resend-interval.sql": true,
 | 
					        "patch-monitor-add-resend-interval.sql": true,
 | 
				
			||||||
        "patch-maintenance-table2.sql": true,
 | 
					        "patch-maintenance-table2.sql": true,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ const dayjs = require("dayjs");
 | 
				
			|||||||
const axios = require("axios");
 | 
					const axios = require("axios");
 | 
				
			||||||
const { Prometheus } = require("../prometheus");
 | 
					const { Prometheus } = require("../prometheus");
 | 
				
			||||||
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util");
 | 
					const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util");
 | 
				
			||||||
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm, radius } = require("../util-server");
 | 
					const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery } = require("../util-server");
 | 
				
			||||||
const { R } = require("redbean-node");
 | 
					const { R } = require("redbean-node");
 | 
				
			||||||
const { BeanModel } = require("redbean-node/dist/bean-model");
 | 
					const { BeanModel } = require("redbean-node/dist/bean-model");
 | 
				
			||||||
const { Notification } = require("../notification");
 | 
					const { Notification } = require("../notification");
 | 
				
			||||||
@@ -105,6 +105,11 @@ class Monitor extends BeanModel {
 | 
				
			|||||||
            authMethod: this.authMethod,
 | 
					            authMethod: this.authMethod,
 | 
				
			||||||
            authWorkstation: this.authWorkstation,
 | 
					            authWorkstation: this.authWorkstation,
 | 
				
			||||||
            authDomain: this.authDomain,
 | 
					            authDomain: this.authDomain,
 | 
				
			||||||
 | 
					            grpcUrl: this.grpcUrl,
 | 
				
			||||||
 | 
					            grpcProtobuf: this.grpcProtobuf,
 | 
				
			||||||
 | 
					            grpcMethod: this.grpcMethod,
 | 
				
			||||||
 | 
					            grpcServiceName: this.grpcServiceName,
 | 
				
			||||||
 | 
					            grpcEnableTls: this.getGrpcEnableTls(),
 | 
				
			||||||
            radiusUsername: this.radiusUsername,
 | 
					            radiusUsername: this.radiusUsername,
 | 
				
			||||||
            radiusPassword: this.radiusPassword,
 | 
					            radiusPassword: this.radiusPassword,
 | 
				
			||||||
            radiusCalledStationId: this.radiusCalledStationId,
 | 
					            radiusCalledStationId: this.radiusCalledStationId,
 | 
				
			||||||
@@ -117,6 +122,8 @@ class Monitor extends BeanModel {
 | 
				
			|||||||
                ...data,
 | 
					                ...data,
 | 
				
			||||||
                headers: this.headers,
 | 
					                headers: this.headers,
 | 
				
			||||||
                body: this.body,
 | 
					                body: this.body,
 | 
				
			||||||
 | 
					                grpcBody: this.grpcBody,
 | 
				
			||||||
 | 
					                grpcMetadata: this.grpcMetadata,
 | 
				
			||||||
                basic_auth_user: this.basic_auth_user,
 | 
					                basic_auth_user: this.basic_auth_user,
 | 
				
			||||||
                basic_auth_pass: this.basic_auth_pass,
 | 
					                basic_auth_pass: this.basic_auth_pass,
 | 
				
			||||||
                pushToken: this.pushToken,
 | 
					                pushToken: this.pushToken,
 | 
				
			||||||
@@ -167,6 +174,14 @@ class Monitor extends BeanModel {
 | 
				
			|||||||
        return Boolean(this.upsideDown);
 | 
					        return Boolean(this.upsideDown);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Parse to boolean
 | 
				
			||||||
 | 
					     * @returns {boolean}
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    getGrpcEnableTls() {
 | 
				
			||||||
 | 
					        return Boolean(this.grpcEnableTls);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get accepted status codes
 | 
					     * Get accepted status codes
 | 
				
			||||||
     * @returns {Object}
 | 
					     * @returns {Object}
 | 
				
			||||||
@@ -527,6 +542,37 @@ class Monitor extends BeanModel {
 | 
				
			|||||||
                    bean.msg = "";
 | 
					                    bean.msg = "";
 | 
				
			||||||
                    bean.status = UP;
 | 
					                    bean.status = UP;
 | 
				
			||||||
                    bean.ping = dayjs().valueOf() - startTime;
 | 
					                    bean.ping = dayjs().valueOf() - startTime;
 | 
				
			||||||
 | 
					                } else if (this.type === "grpc-keyword") {
 | 
				
			||||||
 | 
					                    let startTime = dayjs().valueOf();
 | 
				
			||||||
 | 
					                    const options = {
 | 
				
			||||||
 | 
					                        grpcUrl: this.grpcUrl,
 | 
				
			||||||
 | 
					                        grpcProtobufData: this.grpcProtobuf,
 | 
				
			||||||
 | 
					                        grpcServiceName: this.grpcServiceName,
 | 
				
			||||||
 | 
					                        grpcEnableTls: this.grpcEnableTls,
 | 
				
			||||||
 | 
					                        grpcMethod: this.grpcMethod,
 | 
				
			||||||
 | 
					                        grpcBody: this.grpcBody,
 | 
				
			||||||
 | 
					                        keyword: this.keyword
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    const response = await grpcQuery(options);
 | 
				
			||||||
 | 
					                    bean.ping = dayjs().valueOf() - startTime;
 | 
				
			||||||
 | 
					                    log.debug("monitor:", `gRPC response: ${JSON.stringify(response)}`);
 | 
				
			||||||
 | 
					                    let responseData = response.data;
 | 
				
			||||||
 | 
					                    if (responseData.length > 50) {
 | 
				
			||||||
 | 
					                        responseData = response.substring(0, 47) + "...";
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    if (response.code !== 1) {
 | 
				
			||||||
 | 
					                        bean.status = DOWN;
 | 
				
			||||||
 | 
					                        bean.msg = `Error in send gRPC ${response.code} ${response.errorMessage}`;
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        if (response.data.toString().includes(this.keyword)) {
 | 
				
			||||||
 | 
					                            bean.status = UP;
 | 
				
			||||||
 | 
					                            bean.msg = `${responseData}, keyword [${this.keyword}] is found`;
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            log.debug("monitor:", `GRPC response [${response.data}] + ", but keyword [${this.keyword}] is not in [" + ${response.data} + "]"`);
 | 
				
			||||||
 | 
					                            bean.status = DOWN;
 | 
				
			||||||
 | 
					                            bean.msg = `, but keyword [${this.keyword}] is not in [" + ${responseData} + "]`;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                } else if (this.type === "postgres") {
 | 
					                } else if (this.type === "postgres") {
 | 
				
			||||||
                    let startTime = dayjs().valueOf();
 | 
					                    let startTime = dayjs().valueOf();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ class StatusPage extends BeanModel {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    static async renderHTML(indexHTML, statusPage) {
 | 
					    static async renderHTML(indexHTML, statusPage) {
 | 
				
			||||||
        const $ = cheerio.load(indexHTML);
 | 
					        const $ = cheerio.load(indexHTML);
 | 
				
			||||||
        const description155 = statusPage.description?.substring(0, 155);
 | 
					        const description155 = statusPage.description?.substring(0, 155) ?? "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $("title").text(statusPage.title);
 | 
					        $("title").text(statusPage.title);
 | 
				
			||||||
        $("meta[name=description]").attr("content", description155);
 | 
					        $("meta[name=description]").attr("content", description155);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -706,6 +706,12 @@ let needSetup = false;
 | 
				
			|||||||
                bean.authMethod = monitor.authMethod;
 | 
					                bean.authMethod = monitor.authMethod;
 | 
				
			||||||
                bean.authWorkstation = monitor.authWorkstation;
 | 
					                bean.authWorkstation = monitor.authWorkstation;
 | 
				
			||||||
                bean.authDomain = monitor.authDomain;
 | 
					                bean.authDomain = monitor.authDomain;
 | 
				
			||||||
 | 
					                bean.grpcUrl = monitor.grpcUrl;
 | 
				
			||||||
 | 
					                bean.grpcProtobuf = monitor.grpcProtobuf;
 | 
				
			||||||
 | 
					                bean.grpcMethod = monitor.grpcMethod;
 | 
				
			||||||
 | 
					                bean.grpcBody = monitor.grpcBody;
 | 
				
			||||||
 | 
					                bean.grpcMetadata = monitor.grpcMetadata;
 | 
				
			||||||
 | 
					                bean.grpcEnableTls = monitor.grpcEnableTls;
 | 
				
			||||||
                bean.radiusUsername = monitor.radiusUsername;
 | 
					                bean.radiusUsername = monitor.radiusUsername;
 | 
				
			||||||
                bean.radiusPassword = monitor.radiusPassword;
 | 
					                bean.radiusPassword = monitor.radiusPassword;
 | 
				
			||||||
                bean.radiusCalledStationId = monitor.radiusCalledStationId;
 | 
					                bean.radiusCalledStationId = monitor.radiusCalledStationId;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,8 @@ const { Client } = require("pg");
 | 
				
			|||||||
const postgresConParse = require("pg-connection-string").parse;
 | 
					const postgresConParse = require("pg-connection-string").parse;
 | 
				
			||||||
const { NtlmClient } = require("axios-ntlm");
 | 
					const { NtlmClient } = require("axios-ntlm");
 | 
				
			||||||
const { Settings } = require("./settings");
 | 
					const { Settings } = require("./settings");
 | 
				
			||||||
 | 
					const grpc = require("@grpc/grpc-js");
 | 
				
			||||||
 | 
					const protojs = require("protobufjs");
 | 
				
			||||||
const radiusClient = require("node-radius-client");
 | 
					const radiusClient = require("node-radius-client");
 | 
				
			||||||
const {
 | 
					const {
 | 
				
			||||||
    dictionaries: {
 | 
					    dictionaries: {
 | 
				
			||||||
@@ -720,3 +722,51 @@ module.exports.timeObjectToUTC = (obj, timezone = undefined) => {
 | 
				
			|||||||
module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
 | 
					module.exports.timeObjectToLocal = (obj, timezone = undefined) => {
 | 
				
			||||||
    return timeObjectConvertTimezone(obj, timezone, false);
 | 
					    return timeObjectConvertTimezone(obj, timezone, false);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Create gRPC client stib
 | 
				
			||||||
 | 
					 * @param {Object} options from gRPC client
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					module.exports.grpcQuery = async (options) => {
 | 
				
			||||||
 | 
					    const { grpcUrl, grpcProtobufData, grpcServiceName, grpcEnableTls, grpcMethod, grpcBody } = options;
 | 
				
			||||||
 | 
					    const protocObject = protojs.parse(grpcProtobufData);
 | 
				
			||||||
 | 
					    const protoServiceObject = protocObject.root.lookupService(grpcServiceName);
 | 
				
			||||||
 | 
					    const Client = grpc.makeGenericClientConstructor({});
 | 
				
			||||||
 | 
					    const credentials = grpcEnableTls ? grpc.credentials.createSsl() : grpc.credentials.createInsecure();
 | 
				
			||||||
 | 
					    const client = new Client(
 | 
				
			||||||
 | 
					        grpcUrl,
 | 
				
			||||||
 | 
					        credentials
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const grpcService = protoServiceObject.create(function (method, requestData, cb) {
 | 
				
			||||||
 | 
					        const fullServiceName = method.fullName;
 | 
				
			||||||
 | 
					        const serviceFQDN = fullServiceName.split(".");
 | 
				
			||||||
 | 
					        const serviceMethod = serviceFQDN.pop();
 | 
				
			||||||
 | 
					        const serviceMethodClientImpl = `/${serviceFQDN.slice(1).join(".")}/${serviceMethod}`;
 | 
				
			||||||
 | 
					        log.debug("monitor", `gRPC method ${serviceMethodClientImpl}`);
 | 
				
			||||||
 | 
					        client.makeUnaryRequest(
 | 
				
			||||||
 | 
					            serviceMethodClientImpl,
 | 
				
			||||||
 | 
					            arg => arg,
 | 
				
			||||||
 | 
					            arg => arg,
 | 
				
			||||||
 | 
					            requestData,
 | 
				
			||||||
 | 
					            cb);
 | 
				
			||||||
 | 
					    }, false, false);
 | 
				
			||||||
 | 
					    return new Promise((resolve, _) => {
 | 
				
			||||||
 | 
					        return grpcService[`${grpcMethod}`](JSON.parse(grpcBody), function (err, response) {
 | 
				
			||||||
 | 
					            const responseData = JSON.stringify(response);
 | 
				
			||||||
 | 
					            if (err) {
 | 
				
			||||||
 | 
					                return resolve({
 | 
				
			||||||
 | 
					                    code: err.code,
 | 
				
			||||||
 | 
					                    errorMessage: err.details,
 | 
				
			||||||
 | 
					                    data: ""
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                log.debug("monitor:", `gRPC response: ${response}`);
 | 
				
			||||||
 | 
					                return resolve({
 | 
				
			||||||
 | 
					                    code: 1,
 | 
				
			||||||
 | 
					                    errorMessage: "",
 | 
				
			||||||
 | 
					                    data: responseData
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,8 @@ export default {
 | 
				
			|||||||
    ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
 | 
					    ignoreTLSError: "Ignore TLS/SSL error for HTTPS websites",
 | 
				
			||||||
    upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
 | 
					    upsideDownModeDescription: "Flip the status upside down. If the service is reachable, it is DOWN.",
 | 
				
			||||||
    maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
 | 
					    maxRedirectDescription: "Maximum number of redirects to follow. Set to 0 to disable redirects.",
 | 
				
			||||||
 | 
					    enableGRPCTls: "Allow to send gRPC request with TLS connection",
 | 
				
			||||||
 | 
					    grpcMethodDescription: "Method name is convert to cammelCase format such as sayHello, check, etc.",
 | 
				
			||||||
    acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
 | 
					    acceptedStatusCodesDescription: "Select status codes which are considered as a successful response.",
 | 
				
			||||||
    Maintenance: "Maintenance",
 | 
					    Maintenance: "Maintenance",
 | 
				
			||||||
    statusMaintenance: "Maintenance",
 | 
					    statusMaintenance: "Maintenance",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ export default {
 | 
				
			|||||||
    languageName: "简体中文",
 | 
					    languageName: "简体中文",
 | 
				
			||||||
    checkEverySecond: "检测频率 {0} 秒",
 | 
					    checkEverySecond: "检测频率 {0} 秒",
 | 
				
			||||||
    retryCheckEverySecond: "重试间隔 {0} 秒",
 | 
					    retryCheckEverySecond: "重试间隔 {0} 秒",
 | 
				
			||||||
    retriesDescription: "服务被标记为故障并发送通知之前得最大重试次数",
 | 
					    retriesDescription: "服务被标记为故障并发送通知之前的最大重试次数",
 | 
				
			||||||
    ignoreTLSError: "忽略 HTTPS 站点的 TLS/SSL 错误",
 | 
					    ignoreTLSError: "忽略 HTTPS 站点的 TLS/SSL 错误",
 | 
				
			||||||
    upsideDownModeDescription: "反转状态监控,如果服务可访问,则认为是故障。",
 | 
					    upsideDownModeDescription: "反转状态监控,如果服务可访问,则认为是故障。",
 | 
				
			||||||
    maxRedirectDescription: "允许的最大重定向次数。设置为 0 禁用重定向。",
 | 
					    maxRedirectDescription: "允许的最大重定向次数。设置为 0 禁用重定向。",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,9 @@
 | 
				
			|||||||
                                        <option value="keyword">
 | 
					                                        <option value="keyword">
 | 
				
			||||||
                                            HTTP(s) - {{ $t("Keyword") }}
 | 
					                                            HTTP(s) - {{ $t("Keyword") }}
 | 
				
			||||||
                                        </option>
 | 
					                                        </option>
 | 
				
			||||||
 | 
					                                        <option value="grpc-keyword">
 | 
				
			||||||
 | 
					                                            gRPC(s) - {{ $t("Keyword") }}
 | 
				
			||||||
 | 
					                                        </option>
 | 
				
			||||||
                                        <option value="dns">
 | 
					                                        <option value="dns">
 | 
				
			||||||
                                            DNS
 | 
					                                            DNS
 | 
				
			||||||
                                        </option>
 | 
					                                        </option>
 | 
				
			||||||
@@ -70,6 +73,12 @@
 | 
				
			|||||||
                                <input id="url" v-model="monitor.url" type="url" class="form-control" pattern="https?://.+" required>
 | 
					                                <input id="url" v-model="monitor.url" type="url" class="form-control" pattern="https?://.+" required>
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <!-- gRPC URL -->
 | 
				
			||||||
 | 
					                            <div v-if="monitor.type === 'grpc-keyword' " class="my-3">
 | 
				
			||||||
 | 
					                                <label for="grpc-url" class="form-label">{{ $t("URL") }}</label>
 | 
				
			||||||
 | 
					                                <input id="grpc-url" v-model="monitor.grpcUrl" type="url" class="form-control" pattern="[^\:]+:[0-9]{5}" required>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <!-- Push URL -->
 | 
					                            <!-- Push URL -->
 | 
				
			||||||
                            <div v-if="monitor.type === 'push' " class="my-3">
 | 
					                            <div v-if="monitor.type === 'push' " class="my-3">
 | 
				
			||||||
                                <label for="push-url" class="form-label">{{ $t("PushUrl") }}</label>
 | 
					                                <label for="push-url" class="form-label">{{ $t("PushUrl") }}</label>
 | 
				
			||||||
@@ -81,7 +90,7 @@
 | 
				
			|||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <!-- Keyword -->
 | 
					                            <!-- Keyword -->
 | 
				
			||||||
                            <div v-if="monitor.type === 'keyword' " class="my-3">
 | 
					                            <div v-if="monitor.type === 'keyword' || monitor.type === 'grpc-keyword' " class="my-3">
 | 
				
			||||||
                                <label for="keyword" class="form-label">{{ $t("Keyword") }}</label>
 | 
					                                <label for="keyword" class="form-label">{{ $t("Keyword") }}</label>
 | 
				
			||||||
                                <input id="keyword" v-model="monitor.keyword" type="text" class="form-control" required>
 | 
					                                <input id="keyword" v-model="monitor.keyword" type="text" class="form-control" required>
 | 
				
			||||||
                                <div class="form-text">
 | 
					                                <div class="form-text">
 | 
				
			||||||
@@ -313,7 +322,7 @@
 | 
				
			|||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            <!-- HTTP / Keyword only -->
 | 
					                            <!-- HTTP / Keyword only -->
 | 
				
			||||||
                            <template v-if="monitor.type === 'http' || monitor.type === 'keyword' ">
 | 
					                            <template v-if="monitor.type === 'http' || monitor.type === 'keyword' || monitor.type === 'grpc-keyword' ">
 | 
				
			||||||
                                <div class="my-3">
 | 
					                                <div class="my-3">
 | 
				
			||||||
                                    <label for="maxRedirects" class="form-label">{{ $t("Max. Redirects") }}</label>
 | 
					                                    <label for="maxRedirects" class="form-label">{{ $t("Max. Redirects") }}</label>
 | 
				
			||||||
                                    <input id="maxRedirects" v-model="monitor.maxredirects" type="number" class="form-control" required min="0" step="1">
 | 
					                                    <input id="maxRedirects" v-model="monitor.maxredirects" type="number" class="form-control" required min="0" step="1">
 | 
				
			||||||
@@ -491,6 +500,55 @@
 | 
				
			|||||||
                                    </template>
 | 
					                                    </template>
 | 
				
			||||||
                                </template>
 | 
					                                </template>
 | 
				
			||||||
                            </template>
 | 
					                            </template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            <!-- gRPC Options -->
 | 
				
			||||||
 | 
					                            <template v-if="monitor.type === 'grpc-keyword' ">
 | 
				
			||||||
 | 
					                                <!-- Proto service enable TLS -->
 | 
				
			||||||
 | 
					                                <h2 class="mt-5 mb-2">{{ $t("GRPC Options") }}</h2>
 | 
				
			||||||
 | 
					                                <div class="my-3 form-check">
 | 
				
			||||||
 | 
					                                    <input id="grpc-enable-tls" v-model="monitor.grpcEnableTls" class="form-check-input" type="checkbox" value="">
 | 
				
			||||||
 | 
					                                    <label class="form-check-label" for="grpc-enable-tls">
 | 
				
			||||||
 | 
					                                        {{ $t("Enable TLS") }}
 | 
				
			||||||
 | 
					                                    </label>
 | 
				
			||||||
 | 
					                                    <div class="form-text">
 | 
				
			||||||
 | 
					                                        {{ $t("enableGRPCTls") }}
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                                <!-- Proto service name data -->
 | 
				
			||||||
 | 
					                                <div class="my-3">
 | 
				
			||||||
 | 
					                                    <label for="protobuf" class="form-label">{{ $t("Proto Service Name") }}</label>
 | 
				
			||||||
 | 
					                                    <input id="name" v-model="monitor.grpcServiceName" type="text" class="form-control" :placeholder="protoServicePlaceholder" required>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                <!-- Proto method data -->
 | 
				
			||||||
 | 
					                                <div class="my-3">
 | 
				
			||||||
 | 
					                                    <label for="protobuf" class="form-label">{{ $t("Proto Method") }}</label>
 | 
				
			||||||
 | 
					                                    <input id="name" v-model="monitor.grpcMethod" type="text" class="form-control" :placeholder="protoMethodPlaceholder" required>
 | 
				
			||||||
 | 
					                                    <div class="form-text">
 | 
				
			||||||
 | 
					                                        {{ $t("grpcMethodDescription") }}
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                <!-- Proto data -->
 | 
				
			||||||
 | 
					                                <div class="my-3">
 | 
				
			||||||
 | 
					                                    <label for="protobuf" class="form-label">{{ $t("Proto Content") }}</label>
 | 
				
			||||||
 | 
					                                    <textarea id="protobuf" v-model="monitor.grpcProtobuf" class="form-control" :placeholder="protoBufDataPlaceholder"></textarea>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                <!-- Body -->
 | 
				
			||||||
 | 
					                                <div class="my-3">
 | 
				
			||||||
 | 
					                                    <label for="body" class="form-label">{{ $t("Body") }}</label>
 | 
				
			||||||
 | 
					                                    <textarea id="body" v-model="monitor.grpcBody" class="form-control" :placeholder="bodyPlaceholder"></textarea>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                                <!-- Metadata: temporary disable waiting for next PR allow to send gRPC with metadata -->
 | 
				
			||||||
 | 
					                                <template v-if="false">
 | 
				
			||||||
 | 
					                                    <div class="my-3">
 | 
				
			||||||
 | 
					                                        <label for="metadata" class="form-label">{{ $t("Metadata") }}</label>
 | 
				
			||||||
 | 
					                                        <textarea id="metadata" v-model="monitor.grpcMetadata" class="form-control" :placeholder="headersPlaceholder"></textarea>
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </template>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@@ -569,6 +627,40 @@ export default {
 | 
				
			|||||||
            return this.$root.baseURL + "/api/push/" + this.monitor.pushToken + "?status=up&msg=OK&ping=";
 | 
					            return this.$root.baseURL + "/api/push/" + this.monitor.pushToken + "?status=up&msg=OK&ping=";
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protoServicePlaceholder() {
 | 
				
			||||||
 | 
					            return this.$t("Example:", [ "Health" ]);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protoMethodPlaceholder() {
 | 
				
			||||||
 | 
					            return this.$t("Example:", [ "check" ]);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        protoBufDataPlaceholder() {
 | 
				
			||||||
 | 
					            return this.$t("Example:", [ `
 | 
				
			||||||
 | 
					syntax = "proto3";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package grpc.health.v1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					service Health {
 | 
				
			||||||
 | 
					  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
 | 
				
			||||||
 | 
					  rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message HealthCheckRequest {
 | 
				
			||||||
 | 
					  string service = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					message HealthCheckResponse {
 | 
				
			||||||
 | 
					  enum ServingStatus {
 | 
				
			||||||
 | 
					    UNKNOWN = 0;
 | 
				
			||||||
 | 
					    SERVING = 1;
 | 
				
			||||||
 | 
					    NOT_SERVING = 2;
 | 
				
			||||||
 | 
					    SERVICE_UNKNOWN = 3;  // Used only by the Watch method.
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  ServingStatus status = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					            ` ]);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        bodyPlaceholder() {
 | 
					        bodyPlaceholder() {
 | 
				
			||||||
            return this.$t("Example:", [ `
 | 
					            return this.$t("Example:", [ `
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user