1
0
mirror of https://github.com/donaldzou/WGDashboard.git synced 2024-11-22 15:20:09 +01:00

Schedule system is finally running, still need to more testing :)

This commit is contained in:
Donald Zou 2024-07-01 00:58:02 +08:00
parent 2d838b69fd
commit 48dc8033f5
4 changed files with 169 additions and 22 deletions

View File

@ -171,10 +171,82 @@ class PeerJobs:
''', (Job.Field, Job.Operator, Job.Value, Job.Action, Job.JobID))
self.jobdb.commit()
self.__getJobs()
return True, list(filter(lambda x: x.Configuration == Job.Configuration and x.Peer == Job.Peer and x.JobID == Job.JobID, self.Jobs))
return True, list(
filter(lambda x: x.Configuration == Job.Configuration and x.Peer == Job.Peer and x.JobID == Job.JobID,
self.Jobs))
except Exception as e:
return False, str(e)
def deleteJob(self, Job: PeerJob) -> tuple[bool, list] | tuple[bool, str]:
try:
if (len(str(Job.CreationDate))) == 0:
return False, "Job does not exist"
self.jobdbCursor.execute('''
DELETE FROM PeerJobs WHERE JobID = ?
''', (Job.JobID,))
self.jobdb.commit()
self.__getJobs()
return True, list(
filter(lambda x: x.Configuration == Job.Configuration and x.Peer == Job.Peer and x.JobID == Job.JobID,
self.Jobs))
except Exception as e:
return False, str(e)
def finishJob(self, Job: PeerJob) -> tuple[bool, list] | tuple[bool, str]:
try:
if (len(str(Job.CreationDate))) == 0:
return False, "Job does not exist"
self.jobdbCursor.execute('''
UPDATE PeerJobs SET ExpireDate = strftime('%Y-%m-%d %H:%M:%S','now') WHERE JobId = ?
''', (Job.JobID,))
self.jobdb.commit()
self.__getJobs()
return True, list(
filter(lambda x: x.Configuration == Job.Configuration and x.Peer == Job.Peer and x.JobID == Job.JobID,
self.Jobs))
except Exception as e:
return False, str(e)
def runJob(self):
print("======")
needToDelete = []
for job in self.Jobs:
print(job.toJson())
c = WireguardConfigurations.get(job.Configuration)
if c is not None:
f, fp = c.searchPeer(job.Peer)
if f:
if job.Field in ["total_receive", "total_sent", "total_data"]:
s = job.Field.split("_")[1]
x: float = getattr(fp, f"total_{s}") + getattr(fp, f"cumu_{s}")
y: float = float(job.Value)
else:
x: datetime = datetime.now()
y: datetime = datetime.fromtimestamp(float(job.Value))
runAction: bool = self.__runJob_Compare(x, y, job.Operator)
print("Running Job:" + str(runAction) + "\n")
if runAction:
if job.Action == "restrict":
print(str(c.restrictPeers([fp.id]).get_json()))
elif job.Action == "delete":
print(str(c.deletePeers([fp.id]).get_json()))
needToDelete.append(job)
for j in needToDelete:
self.deleteJob(j)
def __runJob_Compare(self, x: float | datetime, y: float | datetime, operator: str):
print(x, y, operator)
if operator == "eq":
return x == y
if operator == "neq":
return x != y
if operator == "lgt":
return x > y
if operator == "lst":
return x < y
class WireguardConfiguration:
class InvalidConfigurationFileException(Exception):
@ -1406,6 +1478,27 @@ def API_savePeerScheduleJob():
return ResponseObject(s, message=p)
@app.route('/api/deletePeerScheduleJob/', methods=['POST'])
def API_deletePeerScheduleJob():
data = request.json
if "Job" not in data.keys() not in WireguardConfigurations.keys():
return ResponseObject(False, "Please specify job")
job: dict = data['Job']
if "Peer" not in job.keys() or "Configuration" not in job.keys():
return ResponseObject(False, "Please specify peer and configuration")
configuration = WireguardConfigurations.get(job['Configuration'])
f, fp = configuration.searchPeer(job['Peer'])
if not f:
return ResponseObject(False, "Peer does not exist in this configuration")
s, p = AllPeerJobs.deleteJob(PeerJob(
job['JobID'], job['Configuration'], job['Peer'], job['Field'], job['Operator'], job['Value'],
job['CreationDate'], job['ExpireDate'], job['Action']))
if s:
return ResponseObject(s, data=p)
return ResponseObject(s, message=p)
'''
Tools
'''
@ -1583,6 +1676,14 @@ def backGroundThread():
time.sleep(10)
def peerJobScheduleBackgroundThread():
with app.app_context():
print("-- Peer Schedule: Waiting 5 sec")
while True:
AllPeerJobs.runJob()
time.sleep(10)
def gunicornConfig():
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port")
@ -1600,5 +1701,9 @@ bgThread = threading.Thread(target=backGroundThread)
bgThread.daemon = True
bgThread.start()
bg2Thread = threading.Thread(target=peerJobScheduleBackgroundThread)
bg2Thread.daemon = True
bg2Thread.start()
if __name__ == "__main__":
app.run(host=app_ip, debug=True, port=app_port)
app.run(host=app_ip, debug=False, port=app_port)

View File

@ -71,16 +71,11 @@ export default {
}
},
methods:{
deleteJob(j, index){
if (j.CreationDate){
}else{
this.selectedPeer.jobs = this.selectedPeer.jobs.filter(x => x.JobID !== j.JobID)
}
deleteJob(j){
this.selectedPeer.jobs = this.selectedPeer.jobs.filter(x => x.JobID !== j.JobID)
},
addJob(){
this.selectedPeer.jobs.push(JSON.parse(JSON.stringify({
this.selectedPeer.jobs.unshift(JSON.parse(JSON.stringify({
JobID: crypto.randomUUID(),
Configuration: this.selectedPeer.configuration.Name,
Peer: this.selectedPeer.id,
@ -100,7 +95,7 @@ export default {
<template>
<div class="peerSettingContainer w-100 h-100 position-absolute top-0 start-0 overflow-y-scroll">
<div class="container d-flex h-100 w-100">
<div class="m-auto modal-dialog-centered dashboardModal">
<div class="m-auto modal-dialog-centered dashboardModal mt-0">
<div class="card rounded-3 shadow" style="width: 700px">
<div class="card-header bg-transparent d-flex align-items-center gap-2 border-0 p-4 pb-2">
<h4 class="mb-0 fw-normal">Schedule Jobs
@ -108,23 +103,29 @@ export default {
</h4>
<button type="button" class="btn-close ms-auto" @click="this.$emit('close')"></button>
</div>
<div class="card-body px-4 pb-4 pt-2">
<div class="card-body px-4 pb-4 pt-2 position-relative">
<div class="d-flex align-items-center mb-3">
<input class="form-control form-control-sm w-auto rounded-3" placeholder="Search Job...">
<button class="btn btn-sm btn-primary rounded-3 ms-auto" @click="this.addJob()">
<button class="btn btn-sm btn-primary rounded-3" @click="this.addJob()">
<i class="bi bi-plus-lg me-2"></i> Job
</button>
</div>
<TransitionGroup name="fade">
<TransitionGroup name="schedulePeerJobTransition" tag="div" class="position-relative">
<SchedulePeerJob
@refresh="this.$emit('refresh')"
@refresh="(j) => job = j"
@delete="this.deleteJob(job)"
:dropdowns="this.dropdowns"
:key="job.JobID"
:pjob="job" v-for="(job) in this.selectedPeer.jobs">
</SchedulePeerJob>
<div class="card" key="none" v-if="this.selectedPeer.jobs.length === 0">
<div class="card-body text-muted text-center">
<h1><i class="bi bi-emoji-frown-fill"></i></h1>
<h6 class="mb-0">This peer does not have any job yet.</h6>
</div>
</div>
</TransitionGroup>
</div>
</div>
@ -134,5 +135,22 @@ export default {
</template>
<style scoped>
.schedulePeerJobTransition-move, /* apply transition to moving elements */
.schedulePeerJobTransition-enter-active,
.schedulePeerJobTransition-leave-active {
transition: all 0.4s cubic-bezier(0.82, 0.58, 0.17, 0.9);
}
.schedulePeerJobTransition-enter-from,
.schedulePeerJobTransition-leave-to {
opacity: 0;
transform: scale(0.9);
}
/* ensure leaving items are taken out of layout flow so that moving
animations can be calculated correctly. */
.schedulePeerJobTransition-leave-active {
position: absolute;
width: 100%;
}
</style>

View File

@ -24,11 +24,11 @@ export default {
<template>
<div class="dropdown scheduleDropdown">
<button class="btn btn-sm btn-outline-primary rounded-3"
:class="{'disabled': !edit}" type="button" data-bs-toggle="dropdown" aria-expanded="false">
:class="{'disabled border-transparent': !edit}" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<samp>{{this.currentSelection.display}}</samp>
</button>
<ul class="dropdown-menu rounded-3 shadow" style="font-size: 0.875rem; width: 200px">
<li v-for="x in this.options">
<li v-for="x in this.options" v-if="edit">
<a class="dropdown-item d-flex align-items-center" role="button" @click="$emit('update', x.value)">
<samp>{{x.display}}</samp>
<i class="bi bi-check ms-auto" v-if="x.value === this.currentSelection.value"></i>
@ -42,8 +42,7 @@ export default {
.btn.disabled{
opacity: 1;
background-color: rgba(13, 110, 253, 0.09);
border-color: transparent;
}
.btn{
//padding: 0.1rem 0.4rem;
}
</style>

View File

@ -31,7 +31,9 @@ export default {
watch:{
pjob: {
deep: true,
immediate: true,
handler(newValue){
console.log(newValue)
this.job = JSON.parse(JSON.stringify(newValue))
}
}
@ -45,7 +47,8 @@ export default {
if (res.status){
this.edit = false;
this.store.newMessage("Server", "Job Saved!", "success")
this.$emit("refresh")
this.$emit("refresh", this.data)
this.newJob = false;
}else{
this.store.newMessage("Server", res.message, "danger")
}
@ -72,6 +75,22 @@ export default {
}else{
this.$emit('delete')
}
},
delete(){
if(this.job.CreationDate){
fetchPost(`/api/deletePeerScheduleJob/`, {
Job: this.job
}, (res) => {
if (!res.status){
this.store.newMessage("Server", res.message, "danger")
this.$emit('delete')
}else{
this.store.newMessage("Server", "Job Deleted!", "success")
}
})
}
this.$emit('delete')
}
},
}
@ -137,6 +156,7 @@ export default {
class="ms-auto text-decoration-none"
@click="this.edit = true">[E] Edit</a>
<a role="button"
@click="this.delete()"
class=" text-danger text-decoration-none">[D] Delete</a>
</div>
<div class="ms-auto d-flex gap-3" v-else>
@ -160,4 +180,9 @@ export default {
input{
padding: 0.1rem 0.4rem;
}
input:disabled{
border-color: transparent;
background-color: rgba(13, 110, 253, 0.09);
color: #0d6efd;
}
</style>