11import json
22import os
3+ import threading
34import time
45from enum import Enum
56from io import StringIO
7+ from time import sleep
68from typing import List , Union
79
810from mcdreforged .api .all import *
@@ -44,7 +46,13 @@ class TaskType(Enum):
4446 python_code = 'python_code'
4547
4648
47- class Task (Serializable ):
49+ class Task :
50+ def __init__ (self , name , task_type , created_by , command ):
51+ self .name = name
52+ self .task_type = task_type
53+ self .created_by = created_by
54+ self .command = command
55+
4856 name : str = 'undefined'
4957
5058 task_type : TaskType = TaskType .undefined
@@ -113,12 +121,55 @@ def execute_task(self, server: PluginServerInterface, hook: str, var_dict: dict
113121 if obj_dict is not None :
114122 exec (self .command , obj_dict , {})
115123 else :
116- exec (self .command , var_dict , locals ())
117-
124+ if var_dict is not None :
125+ exec (self .command , var_dict , locals ())
126+ else :
127+ exec (self .command , globals (), locals ())
128+
118129 server .logger .debug (f'Task finished, name: { self .name } , task_type: { self .task_type } , command: { self .command } , '
119130 f'costs { time .time () - start_time } seconds.' )
120131
121132
133+ def stop_all_schedule_daemon_threads ():
134+ if len (temp_config .schedule_daemon_threads ) == 0 :
135+ return
136+
137+ for thr in temp_config .schedule_daemon_threads :
138+ thr .break_thread ()
139+ temp_config .schedule_daemon_threads .remove (thr )
140+
141+
142+ class AThread (threading .Thread ):
143+ def init_thread (self ):
144+ super ().__init__ (daemon = True )
145+
146+
147+ class ScheduleTask (Task , AThread ):
148+ def __init__ (self , name , task_type , created_by , command , server_inst , exec_interval ):
149+ super ().__init__ (name , task_type , created_by , command )
150+ self .server_inst = server_inst
151+ self .exec_interval = exec_interval
152+ self .stop_event = threading .Event ()
153+ super ().init_thread ()
154+ temp_config .schedule_daemon_threads .append (self )
155+
156+ def break_thread (self ):
157+ self .stop_event .set ()
158+
159+ def run (self ):
160+ if self .exec_interval <= 0 :
161+ self .server_inst .logger .warning (
162+ f'Schedule task { self .name } has illegal exec_interval: { self .exec_interval } ' )
163+ return
164+
165+ while True :
166+ for _ in range (self .exec_interval ):
167+ if self .stop_event .is_set ():
168+ return
169+ sleep (1.0 )
170+ self .execute_task (self .server_inst , 'schedule' )
171+
172+
122173class Configuration (Serializable ):
123174 def __init__ (self , ** kwargs ):
124175 super ().__init__ (** kwargs )
@@ -156,6 +207,8 @@ def __init__(self):
156207 task : dict [str , Task ]
157208
158209 scripts_list : dict [str , str ]
210+
211+ schedule_daemon_threads : list = list ()
159212
160213
161214temp_config : TempConfig
@@ -249,7 +302,7 @@ def unmount_task(hook: str, task: str, src: CommandSource, server: PluginServerI
249302
250303
251304def create_task (task_type : str , command : str , name : str , src : CommandSource , server : PluginServerInterface ,
252- created_by = None ):
305+ is_schedule = False , exec_interval = 0 , created_by = None ):
253306 if name in temp_config .task :
254307 src .reply (RTextMCDRTranslation ('hooks.create.already_exist' ))
255308 return
@@ -266,7 +319,14 @@ def create_task(task_type: str, command: str, name: str, src: CommandSource, ser
266319 if created_by is None :
267320 created_by = str (src )
268321
269- temp_config .task [name ] = Task (name = name , task_type = tsk_type , command = command , created_by = created_by )
322+ if not is_schedule :
323+ temp_config .task [name ] = Task (name = name , task_type = tsk_type , command = command , created_by = created_by )
324+ else :
325+ var1 = ScheduleTask (name = name , task_type = tsk_type , command = command , created_by = created_by ,
326+ server_inst = server , exec_interval = exec_interval )
327+ temp_config .task [name ] = var1
328+ var1 .start ()
329+ var1 .name = f'hooks - schedule_task_daemon({ name } )'
270330
271331 server .logger .info (f'Successfully created task { name } ' )
272332 src .reply (RTextMCDRTranslation ('hooks.create.success' , name ))
@@ -282,6 +342,11 @@ def delete_task(name: str, src: CommandSource, server: PluginServerInterface):
282342 if tasks_in_hook == name :
283343 unmount_task (hook , name , src , server )
284344
345+ var1 = temp_config .task .get (name )
346+ if isinstance (var1 , ScheduleTask ):
347+ var1 .break_thread ()
348+ temp_config .schedule_daemon_threads .remove (var1 )
349+
285350 temp_config .task .pop (name )
286351
287352 server .logger .info (f'Successfully deleted task { name } ' )
@@ -314,7 +379,7 @@ def list_mount(src: CommandSource):
314379 list_hooks .append (str (temp_config .hooks .get (str (hk ))))
315380
316381 src .reply (RTextMCDRTranslation ('hooks.list.mount' , * list_hooks ))
317-
382+
318383
319384@new_thread ('hooks - list' )
320385def list_scripts (src : CommandSource ):
@@ -332,6 +397,8 @@ def list_scripts(src: CommandSource):
332397def reload_config (src : CommandSource , server : PluginServerInterface ):
333398 global config , temp_config
334399
400+ stop_all_schedule_daemon_threads ()
401+
335402 temp_config = TempConfig ()
336403 config = server .load_config_simple (target_class = Configuration )
337404
@@ -394,7 +461,7 @@ def parse_and_apply_scripts(script: str, server: PluginServerInterface):
394461 create_task (task .get ('task_type' ), task .get ('command' ), task .get ('name' ),
395462 server .get_plugin_command_source (),
396463 server , created_by = script )
397-
464+
398465 for hook in task .get ('hooks' ):
399466 # 挂载
400467 mount_task (hook , task .get ('name' ), server .get_plugin_command_source (), server )
@@ -464,6 +531,25 @@ def on_load(server: PluginServerInterface, old_module):
464531 )
465532 )
466533 )
534+ .then (
535+ Literal ('schedule' )
536+ .then (
537+ Text ('name' )
538+ .then (
539+ Integer ('exec_interval' )
540+ .then (
541+ Text ('task_type' )
542+ .then (
543+ GreedyText ('command' )
544+ .requires (lambda src : src .has_permission (3 ))
545+ .runs (lambda src , ctx : create_task (ctx ['task_type' ], ctx ['command' ], ctx ['name' ], src ,
546+ server , is_schedule = True ,
547+ exec_interval = ctx ['exec_interval' ]))
548+ )
549+ )
550+ )
551+ )
552+ )
467553 .then (
468554 Literal ('mount' )
469555 .then (
@@ -535,6 +621,9 @@ def on_load(server: PluginServerInterface, old_module):
535621
536622def on_unload (server : PluginServerInterface ):
537623 global temp_config
624+
625+ stop_all_schedule_daemon_threads ()
626+
538627 trigger_hooks (Hooks .on_plugin_unloaded , server , {'server' : process_arg_server (server )})
539628
540629 server .save_config_simple (config )
0 commit comments