committed by
GitHub
31 changed files with 599 additions and 179 deletions
@ -0,0 +1,26 @@ |
|||
# DON'T UPDATE TO alpine3.13, 1.14, see #41. |
|||
FROM node:14-alpine3.12 AS release |
|||
WORKDIR /app |
|||
|
|||
# split the sqlite install here, so that it can caches the arm prebuilt |
|||
RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev git && \ |
|||
ln -s /usr/bin/python3 /usr/bin/python && \ |
|||
npm install mapbox/node-sqlite3#593c9d && \ |
|||
apk del .build-deps && \ |
|||
rm -f /usr/bin/python |
|||
|
|||
# Install apprise |
|||
RUN apk add --no-cache python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib |
|||
RUN pip3 --no-cache-dir install apprise && \ |
|||
rm -rf /root/.cache |
|||
|
|||
COPY . . |
|||
RUN npm install --legacy-peer-deps && npm run build && npm prune |
|||
|
|||
EXPOSE 3001 |
|||
VOLUME ["/app/data"] |
|||
HEALTHCHECK --interval=600s --timeout=130s --start-period=300s CMD node extra/healthcheck.js |
|||
CMD ["node", "server/server.js"] |
|||
|
|||
FROM release AS nightly |
|||
RUN npm run mark-as-nightly |
@ -1,28 +0,0 @@ |
|||
# DON'T UPDATE TO alpine3.13, 1.14, see #41. |
|||
FROM node:14-bullseye AS release |
|||
WORKDIR /app |
|||
|
|||
RUN apt update |
|||
RUN apt --yes install python3 python3-pip python3-dev git g++ make |
|||
RUN ln -s /usr/bin/python3 /usr/bin/python |
|||
|
|||
# split the sqlite install here, so that it can caches the arm prebuilt |
|||
RUN npm install mapbox/node-sqlite3#593c9d |
|||
|
|||
# Install apprise |
|||
RUN apt --yes install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib |
|||
RUN pip3 --no-cache-dir install apprise && \ |
|||
rm -rf /root/.cache |
|||
|
|||
RUN apt --yes install iputils-ping |
|||
|
|||
COPY . . |
|||
RUN npm install --legacy-peer-deps && npm run build && npm prune |
|||
|
|||
EXPOSE 3001 |
|||
VOLUME ["/app/data"] |
|||
HEALTHCHECK --interval=60s --timeout=30s --start-period=300s CMD node extra/healthcheck.js |
|||
CMD ["node", "server/server.js"] |
|||
|
|||
FROM release AS nightly |
|||
RUN npm run mark-as-nightly |
@ -1,19 +1,31 @@ |
|||
let http = require("http"); |
|||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; |
|||
|
|||
let client; |
|||
|
|||
if (process.env.SSL_KEY && process.env.SSL_CERT) { |
|||
client = require("https"); |
|||
} else { |
|||
client = require("http"); |
|||
} |
|||
|
|||
let options = { |
|||
host: "localhost", |
|||
port: "3001", |
|||
timeout: 2000, |
|||
host: process.env.HOST || "127.0.0.1", |
|||
port: parseInt(process.env.PORT) || 3001, |
|||
timeout: 120 * 1000, |
|||
}; |
|||
let request = http.request(options, (res) => { |
|||
console.log(`STATUS: ${res.statusCode}`); |
|||
if (res.statusCode == 200) { |
|||
|
|||
let request = client.request(options, (res) => { |
|||
console.log(`Health Check OK [Res Code: ${res.statusCode}]`); |
|||
if (res.statusCode === 200) { |
|||
process.exit(0); |
|||
} else { |
|||
process.exit(1); |
|||
} |
|||
}); |
|||
|
|||
request.on("error", function (err) { |
|||
console.log("ERROR"); |
|||
console.error("Health Check ERROR"); |
|||
process.exit(1); |
|||
}); |
|||
|
|||
request.end(); |
|||
|
@ -0,0 +1,91 @@ |
|||
/* |
|||
* For Client Socket |
|||
*/ |
|||
const { TimeLogger } = require("../src/util"); |
|||
const { R } = require("redbean-node"); |
|||
const { io } = require("./server"); |
|||
|
|||
async function sendNotificationList(socket) { |
|||
const timeLogger = new TimeLogger(); |
|||
|
|||
let result = []; |
|||
let list = await R.find("notification", " user_id = ? ", [ |
|||
socket.userID, |
|||
]); |
|||
|
|||
for (let bean of list) { |
|||
result.push(bean.export()) |
|||
} |
|||
|
|||
io.to(socket.userID).emit("notificationList", result) |
|||
|
|||
timeLogger.print("Send Notification List"); |
|||
|
|||
return list; |
|||
} |
|||
|
|||
/** |
|||
* Send Heartbeat History list to socket |
|||
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only |
|||
* @param overwrite Overwrite client-side's heartbeat list |
|||
*/ |
|||
async function sendHeartbeatList(socket, monitorID, toUser = false, overwrite = false) { |
|||
const timeLogger = new TimeLogger(); |
|||
|
|||
let list = await R.find("heartbeat", ` |
|||
monitor_id = ? |
|||
ORDER BY time DESC |
|||
LIMIT 100 |
|||
`, [
|
|||
monitorID, |
|||
]) |
|||
|
|||
let result = []; |
|||
|
|||
for (let bean of list) { |
|||
result.unshift(bean.toJSON()); |
|||
} |
|||
|
|||
if (toUser) { |
|||
io.to(socket.userID).emit("heartbeatList", monitorID, result, overwrite); |
|||
} else { |
|||
socket.emit("heartbeatList", monitorID, result, overwrite); |
|||
} |
|||
|
|||
timeLogger.print(`[Monitor: ${monitorID}] sendHeartbeatList`); |
|||
} |
|||
|
|||
/** |
|||
* Important Heart beat list (aka event list) |
|||
* @param socket |
|||
* @param monitorID |
|||
* @param toUser True = send to all browsers with the same user id, False = send to the current browser only |
|||
* @param overwrite Overwrite client-side's heartbeat list |
|||
*/ |
|||
async function sendImportantHeartbeatList(socket, monitorID, toUser = false, overwrite = false) { |
|||
const timeLogger = new TimeLogger(); |
|||
|
|||
let list = await R.find("heartbeat", ` |
|||
monitor_id = ? |
|||
AND important = 1 |
|||
ORDER BY time DESC |
|||
LIMIT 500 |
|||
`, [
|
|||
monitorID, |
|||
]) |
|||
|
|||
timeLogger.print(`[Monitor: ${monitorID}] sendImportantHeartbeatList`); |
|||
|
|||
if (toUser) { |
|||
io.to(socket.userID).emit("importantHeartbeatList", monitorID, list, overwrite); |
|||
} else { |
|||
socket.emit("importantHeartbeatList", monitorID, list, overwrite); |
|||
} |
|||
|
|||
} |
|||
|
|||
module.exports = { |
|||
sendNotificationList, |
|||
sendImportantHeartbeatList, |
|||
sendHeartbeatList, |
|||
} |
@ -0,0 +1,102 @@ |
|||
<template> |
|||
<div class="input-group mb-3"> |
|||
<!-- |
|||
Hack - Disable Chrome save password |
|||
readonly + onfocus |
|||
https://stackoverflow.com/questions/41217019/how-to-prevent-a-browser-from-storing-passwords |
|||
--> |
|||
<input |
|||
v-model="model" |
|||
:type="visibility" |
|||
class="form-control" |
|||
:placeholder="placeholder" |
|||
:maxlength="maxlength" |
|||
:autocomplete="autocomplete" |
|||
:required="required" |
|||
:readonly="isReadOnly" |
|||
@focus="removeReadOnly" |
|||
> |
|||
|
|||
<a v-if="visibility == 'password'" class="btn btn-outline-primary" @click="showInput()"> |
|||
<font-awesome-icon icon="eye" /> |
|||
</a> |
|||
<a v-if="visibility == 'text'" class="btn btn-outline-primary" @click="hideInput()"> |
|||
<font-awesome-icon icon="eye-slash" /> |
|||
</a> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
modelValue: { |
|||
type: String, |
|||
default: "" |
|||
}, |
|||
placeholder: { |
|||
type: String, |
|||
default: "" |
|||
}, |
|||
maxlength: { |
|||
type: Number, |
|||
default: 255 |
|||
}, |
|||
autocomplete: { |
|||
type: Boolean, |
|||
}, |
|||
required: { |
|||
type: Boolean |
|||
}, |
|||
readonly: { |
|||
type: Boolean, |
|||
default: false, |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
visibility: "password", |
|||
readOnlyValue: false, |
|||
} |
|||
}, |
|||
computed: { |
|||
model: { |
|||
get() { |
|||
return this.modelValue |
|||
}, |
|||
set(value) { |
|||
this.$emit("update:modelValue", value) |
|||
} |
|||
}, |
|||
isReadOnly() { |
|||
// Actually readonly from prop |
|||
if (this.readonly) { |
|||
return true; |
|||
} |
|||
|
|||
// Hack - Disable Chrome save password |
|||
return this.readOnlyValue; |
|||
} |
|||
}, |
|||
created() { |
|||
// Hack - Disable Chrome save password |
|||
if (this.autocomplete) { |
|||
this.readOnlyValue = "readonly"; |
|||
} |
|||
}, |
|||
methods: { |
|||
showInput() { |
|||
this.visibility = "text"; |
|||
}, |
|||
hideInput() { |
|||
this.visibility = "password"; |
|||
}, |
|||
|
|||
// Hack - Disable Chrome save password |
|||
removeReadOnly() { |
|||
if (this.autocomplete) { |
|||
this.readOnlyValue = false; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
@ -1,10 +1,10 @@ |
|||
import { library } from "@fortawesome/fontawesome-svg-core" |
|||
import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp } from "@fortawesome/free-solid-svg-icons" |
|||
import { faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons" |
|||
//import { fa } from '@fortawesome/free-regular-svg-icons'
|
|||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome" |
|||
|
|||
// Add Free Font Awesome Icons here
|
|||
// https://fontawesome.com/v5.15/icons?d=gallery&p=2&s=solid&m=free
|
|||
library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp); |
|||
library.add(faCog, faEdit, faPlus, faPause, faPlay, faTachometerAlt, faTrash, faList, faArrowAltCircleUp, faEye, faEyeSlash); |
|||
|
|||
export { FontAwesomeIcon } |
|||
|
Loading…
Reference in new issue