scheduler.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. package main
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "imuslab.com/arozos/mod/agi"
  6. module "imuslab.com/arozos/mod/modules"
  7. prout "imuslab.com/arozos/mod/prouter"
  8. "imuslab.com/arozos/mod/time/nightly"
  9. "imuslab.com/arozos/mod/time/scheduler"
  10. "imuslab.com/arozos/mod/utils"
  11. )
  12. /*
  13. Nightly.go
  14. author: tobychui
  15. This is a handle for putting everything that is required to run everynight.
  16. Default: Run once every day 3am in the morning.
  17. */
  18. var (
  19. nightlyManager *nightly.TaskManager
  20. systemScheduler *scheduler.Scheduler
  21. )
  22. func NightlyTasksInit() {
  23. /*
  24. Nighty Task Manager
  25. The tasks that should be done once per night. Internal function only.
  26. */
  27. nightlyManager = nightly.NewNightlyTaskManager(*nightlyTaskRunTime)
  28. }
  29. func SchedulerInit() {
  30. /*
  31. System Scheudler
  32. The internal scheudler for arozos
  33. */
  34. //Create an user router and its module
  35. router := prout.NewModuleRouter(prout.RouterOption{
  36. ModuleName: "Tasks Scheduler",
  37. AdminOnly: false,
  38. UserHandler: userHandler,
  39. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  40. utils.SendErrorResponse(w, "Permission Denied")
  41. },
  42. })
  43. adminRouter := prout.NewModuleRouter(prout.RouterOption{
  44. ModuleName: "Tasks Scheduler",
  45. AdminOnly: true,
  46. UserHandler: userHandler,
  47. DeniedHandler: func(w http.ResponseWriter, r *http.Request) {
  48. utils.SendErrorResponse(w, "Permission Denied")
  49. },
  50. })
  51. //Register the module
  52. moduleHandler.RegisterModule(module.ModuleInfo{
  53. Name: "Tasks Scheduler",
  54. Group: "System Tools",
  55. IconPath: "SystemAO/arsm/img/scheduler.png",
  56. Version: "1.2",
  57. StartDir: "SystemAO/arsm/scheduler.html",
  58. SupportFW: true,
  59. InitFWSize: []int{1080, 580},
  60. LaunchFWDir: "SystemAO/arsm/scheduler.html",
  61. SupportEmb: false,
  62. })
  63. //Startup the ArOZ Emulated Crontab Service
  64. newScheduler, err := scheduler.NewScheduler(&scheduler.ScheudlerOption{
  65. UserHandler: userHandler,
  66. Gateway: AGIGateway,
  67. Logger: systemWideLogger,
  68. CronFile: "system/cron.json",
  69. })
  70. if err != nil {
  71. systemWideLogger.PrintAndLog("Cron", "ArOZ Emulated Cron Startup Failed. Stopping all scheduled tasks.", err)
  72. }
  73. systemScheduler = newScheduler
  74. // Register the module uninstall hook to auto-clean cron jobs when a webapp is removed.
  75. moduleHandler.OnModuleUninstall = func(moduleName string) {
  76. systemWideLogger.PrintAndLog("Scheduler", "Module '"+moduleName+"' uninstalled – removing associated cron jobs", nil)
  77. newScheduler.RemoveJobsByApp(moduleName)
  78. }
  79. // Register the AGI scheduler library now that we have a scheduler instance.
  80. // We pass callback functions to avoid a circular import between agi and scheduler packages.
  81. AGIGateway.RegisterSchedulerLib(&agi.SchedulerCallbacks{
  82. RegisterJob: func(creator, appName, taskName, scriptVpath, fshID, description string, interval, baseTime int64) error {
  83. return newScheduler.RegisterJobFromAGI(creator, appName, taskName, scriptVpath, description, interval, baseTime)
  84. },
  85. UnregisterJob: func(creator, taskName string) error {
  86. return newScheduler.UnregisterJobFromAGI(creator, taskName)
  87. },
  88. AppJobExists: func(appName, creator, taskName string) bool {
  89. return newScheduler.AppJobExists(appName, creator, taskName)
  90. },
  91. CanCreate: func(username string) bool {
  92. u, err := userHandler.GetUserInfoFromUsername(username)
  93. if err != nil {
  94. return false
  95. }
  96. return u.CanCreateCronJob()
  97. },
  98. })
  99. //Register Endpoints
  100. http.HandleFunc("/system/arsm/aecron/list", func(w http.ResponseWriter, r *http.Request) {
  101. if authAgent.CheckAuth(r) {
  102. //User logged in
  103. newScheduler.HandleListJobs(w, r)
  104. } else {
  105. //User not logged in
  106. errorHandlePermissionDenied(w, r)
  107. }
  108. })
  109. // Check whether the current user has cron creation permission
  110. http.HandleFunc("/system/arsm/aecron/permission", func(w http.ResponseWriter, r *http.Request) {
  111. if authAgent.CheckAuth(r) {
  112. newScheduler.HandleCheckPermission(w, r)
  113. } else {
  114. errorHandlePermissionDenied(w, r)
  115. }
  116. })
  117. router.HandleFunc("/system/arsm/aecron/add", systemScheduler.HandleAddJob)
  118. router.HandleFunc("/system/arsm/aecron/remove", systemScheduler.HandleJobRemoval)
  119. // App-based scheduler registration endpoints (for webapp integration)
  120. router.HandleFunc("/system/arsm/aecron/app/register", systemScheduler.HandleAppRegisterJob)
  121. router.HandleFunc("/system/arsm/aecron/app/unregister", systemScheduler.HandleAppUnregisterJob)
  122. http.HandleFunc("/system/arsm/aecron/app/check", func(w http.ResponseWriter, r *http.Request) {
  123. if authAgent.CheckAuth(r) {
  124. newScheduler.HandleAppCheckJob(w, r)
  125. } else {
  126. errorHandlePermissionDenied(w, r)
  127. }
  128. })
  129. // Admin endpoints for managing group cron permissions
  130. adminRouter.HandleFunc("/system/arsm/aecron/groupperm/list", handleListGroupCronPermissions)
  131. adminRouter.HandleFunc("/system/arsm/aecron/groupperm/set", handleSetGroupCronPermission)
  132. //Register settings
  133. registerSetting(settingModule{
  134. Name: "Tasks Scheduler",
  135. Desc: "System Tasks and Execution Scheduler",
  136. IconPath: "SystemAO/arsm/img/small_icon.png",
  137. Group: "Cluster",
  138. StartDir: "SystemAO/arsm/aecron.html",
  139. RequireAdmin: false,
  140. })
  141. }
  142. // handleListGroupCronPermissions returns all permission groups and their cron creation setting
  143. func handleListGroupCronPermissions(w http.ResponseWriter, r *http.Request) {
  144. ph := permissionHandler
  145. permMap := ph.GetGroupCronJobPermissionList()
  146. type groupPermEntry struct {
  147. GroupName string
  148. IsAdmin bool
  149. CanCreateCronJob bool
  150. }
  151. results := []groupPermEntry{}
  152. for _, pg := range ph.PermissionGroups {
  153. results = append(results, groupPermEntry{
  154. GroupName: pg.Name,
  155. IsAdmin: pg.IsAdmin,
  156. CanCreateCronJob: permMap[pg.Name],
  157. })
  158. }
  159. js, _ := json.Marshal(results)
  160. utils.SendJSONResponse(w, string(js))
  161. }
  162. // handleSetGroupCronPermission sets the cron creation permission for a given group (admin only)
  163. func handleSetGroupCronPermission(w http.ResponseWriter, r *http.Request) {
  164. groupName, err := utils.PostPara(r, "group")
  165. if err != nil {
  166. utils.SendErrorResponse(w, "Invalid group name")
  167. return
  168. }
  169. allowStr, err := utils.PostPara(r, "allow")
  170. if err != nil {
  171. utils.SendErrorResponse(w, "Missing allow parameter")
  172. return
  173. }
  174. allow := (allowStr == "true")
  175. if err := permissionHandler.SetGroupCronJobPermission(groupName, allow); err != nil {
  176. utils.SendErrorResponse(w, err.Error())
  177. return
  178. }
  179. utils.SendOK(w)
  180. }