diff --git a/main.go b/main.go index 482b56f..c0798b2 100644 --- a/main.go +++ b/main.go @@ -34,10 +34,9 @@ func init() { go func() { // 完成model的迁移之后,需要加载异步任务 migrate.Setup() - // 1. 加载日志清除服务(第一次实例化会初始化日志的定时设置,所以要在迁移以后) - cron_service.StartLogsCronRun() - // 2. 加载用户自己设定的定时消息任务 - cron_msg_service.StartUpMsgCronTask() + cron_service.StartTasksRunOnStartup() + // 加载用户自己设定的定时消息任务 + cron_msg_service.StartUpUserSetupMsgCronTask() }() } diff --git a/migrate/migrate.go b/migrate/migrate.go index 0dc1e78..5215ed6 100644 --- a/migrate/migrate.go +++ b/migrate/migrate.go @@ -90,6 +90,7 @@ func Setup() { entry.Infof("Init Cron data...") ss.InitLogConfig() + ss.InitHostedMsgConfig() entry.Infof("All table data init done.") } diff --git a/models/hosted_mesages.go b/models/hosted_mesages.go index 50c658e..7c35aef 100644 --- a/models/hosted_mesages.go +++ b/models/hosted_mesages.go @@ -79,3 +79,32 @@ func GetHostMessagesTotal(text string, maps map[string]interface{}) (int64, erro query.Count(&total) return total, nil } + +// DeleteOutDateHostedMessages 删除过期的托管消息,保留最新的 keepNum 条 +func DeleteOutDateHostedMessages(keepNum int) (int, error) { + var affectedRows int + + // 优化方案:使用GORM的Offset和Limit找到临界ID,兼容多种数据库 + // 1. 获取第 keepNum 条记录的ID作为临界值 + var threshold HostedMessage + result := db.Model(&HostedMessage{}). + Select("id"). + Order("created_on DESC"). + Offset(keepNum - 1). + Limit(1). + First(&threshold) + + // 如果记录总数不足keepNum条,则不需要删除 + if result.Error != nil { + return 0, nil + } + + // 2. 删除ID小于临界值的记录 + deleteResult := db.Where("id < ?", threshold.ID).Delete(&HostedMessage{}) + if deleteResult.Error != nil { + return affectedRows, deleteResult.Error + } + + affectedRows = int(deleteResult.RowsAffected) + return affectedRows, nil +} diff --git a/models/send_tasks_logs.go b/models/send_tasks_logs.go index 01d65c6..f60b72a 100644 --- a/models/send_tasks_logs.go +++ b/models/send_tasks_logs.go @@ -156,22 +156,29 @@ func GetSendLogsTotal(name string, taskId string, maps map[string]interface{}) ( // GetSendLogsTotal 获取所有日志总数 func DeleteOutDateLogs(keepNum int) (int, error) { var affectedRows int - logt := GetSchema(SendTasksLogs{}) - sql := fmt.Sprintf(`DELETE FROM %s - WHERE id NOT IN ( - SELECT id FROM ( - SELECT id - FROM %s - ORDER BY created_on DESC - LIMIT %d - ) tmp - );`, logt, logt, keepNum) - - result := db.Exec(sql) + + // 优化方案:使用GORM的Offset和Limit找到临界ID,兼容多种数据库 + // 1. 获取第 keepNum 条记录的ID作为临界值 + var threshold SendTasksLogs + result := db.Model(&SendTasksLogs{}). + Select("id"). + Order("created_on DESC"). + Offset(keepNum - 1). + Limit(1). + First(&threshold) + + // 如果记录总数不足keepNum条,则不需要删除 if result.Error != nil { - return affectedRows, result.Error + return 0, nil } - affectedRows = int(result.RowsAffected) + + // 2. 删除ID小于临界值的记录 + deleteResult := db.Where("id < ?", threshold.ID).Delete(&SendTasksLogs{}) + if deleteResult.Error != nil { + return affectedRows, deleteResult.Error + } + + affectedRows = int(deleteResult.RowsAffected) return affectedRows, nil } diff --git a/pkg/constant/constant.go b/pkg/constant/constant.go index f1d5f25..5500f4f 100644 --- a/pkg/constant/constant.go +++ b/pkg/constant/constant.go @@ -3,6 +3,7 @@ package constant import "github.com/robfig/cron/v3" const CleanLogsTaskId = "T-IM1GBswSRY" +const CleanHostedMsgTaskId = "T-HM2KCxwTZQ" const SiteSettingSectionName = "site_config" //const SiteSettingTitleKeyName = "title" @@ -22,11 +23,26 @@ var SiteSiteDefaultValueMap = map[string]string{ const LogsCleanSectionName = "log_config" const LogsCleanCronKeyName = "cron" const LogsCleanKeepKeyName = "keep_num" +const LogsCleanEnabledKeyName = "enabled" // 日志清理默认值 var LogsCleanDefaultValueMap = map[string]string{ "cron": "1 0 * * *", "keep_num": "1000", + "enabled": "true", +} + +// 托管消息清理自定义 +const HostedMsgCleanSectionName = "hosted_msg_config" +const HostedMsgCleanCronKeyName = "cron" +const HostedMsgCleanKeepKeyName = "keep_num" +const HostedMsgCleanEnabledKeyName = "enabled" + +// 托管消息清理默认值 +var HostedMsgCleanDefaultValueMap = map[string]string{ + "cron": "30 0 * * *", + "keep_num": "50000", + "enabled": "false", } const AboutSectionName = "about" diff --git a/service/cron_msg_service/startup_cron_msg.go b/service/cron_msg_service/startup_cron_msg.go index fc88a4f..f64921d 100644 --- a/service/cron_msg_service/startup_cron_msg.go +++ b/service/cron_msg_service/startup_cron_msg.go @@ -2,12 +2,13 @@ package cron_msg_service import ( "fmt" - "strings" - "github.com/sirupsen/logrus" "message-nest/models" "message-nest/pkg/constant" "message-nest/service/cron_service" "message-nest/service/send_message_service" + "strings" + + "github.com/sirupsen/logrus" ) type MsgCronTask struct { @@ -62,6 +63,7 @@ func CronMsgSendF(msg models.CronMessages) { } sender := send_message_service.SendMessageService{ TaskID: task.ID, + SendMode: "task", Title: msg.Title, Text: msg.Content, URL: msg.Url, @@ -104,7 +106,7 @@ func RemoveCronMsgToCronServer(msg models.CronMessages) { } // StartUpMsgCronTask 启动注册定时任务 -func StartUpMsgCronTask() { +func StartUpUserSetupMsgCronTask() { MsgCronTask{}.Register() } diff --git a/service/cron_service/cron_service.go b/service/cron_service/cron_service.go deleted file mode 100644 index 08c8465..0000000 --- a/service/cron_service/cron_service.go +++ /dev/null @@ -1,86 +0,0 @@ -package cron_service - -import ( - "fmt" - "github.com/robfig/cron/v3" - "github.com/sirupsen/logrus" - "github.com/unknwon/com" - "message-nest/models" - "message-nest/pkg/constant" - "message-nest/service/send_message_service" -) - -var ClearLogsTaskId cron.EntryID - -// ClearLogs 清除日志的定时任务 -func ClearLogs() { - var errStr string - sm := send_message_service.SendMessageService{ - TaskID: constant.CleanLogsTaskId, - DefaultLogger: logrus.WithFields(logrus.Fields{ - "prefix": "[Cron Clear Logs]", - }), - } - sm.Status = send_message_service.SendSuccess - - sm.LogsAndStatusMark("开始清除日志", sm.Status) - - setting, err := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanKeepKeyName) - if err != nil { - errStr = fmt.Sprintf("获取日志的保留数失败,原因:%s", err) - sm.LogsAndStatusMark(errStr, send_message_service.SendFail) - } - - keepNum := com.StrTo(setting.Value).MustInt() - affectedRows, err := models.DeleteOutDateLogs(keepNum) - if err != nil { - errStr = fmt.Sprintf("删除日志失败,原因:%s", err) - sm.LogsAndStatusMark(errStr, send_message_service.SendFail) - } else { - errStr = fmt.Sprintf("删除日志成功,删除条数:%d,保留数目:%d", affectedRows, keepNum) - sm.LogsAndStatusMark(errStr, sm.Status) - } - - sm.RecordSendLog() -} - -type CronService struct { -} - -// StartLogsCronRun 启动注册清除任务定时任务 -func (cs *CronService) StartLogsCronRun() { - // 注册任务 - setting, err := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanCronKeyName) - if err != nil { - logrus.Error(fmt.Sprintf("获取日志的cron失败,原因:%s", err)) - } - ClearLogsTaskId = AddTask(ScheduledTask{ - Schedule: setting.Value, - Job: ClearLogs, - }) - - // 添加任务 - err = models.AddSendTaskWithID("日志定时清除", constant.CleanLogsTaskId, "admin") - if err != nil { - logrus.Error(fmt.Sprintf("添加日志定时清除任务失败,原因:%s", err)) - } -} - -// UpdateLogsCronRun 更新清除任务定时任务 -func (cs *CronService) UpdateLogsCronRun(cron string) { - RemoveTask(ClearLogsTaskId) - ClearLogsTaskId = AddTask(ScheduledTask{ - Schedule: cron, - Job: ClearLogs, - }) - logrus.Error(fmt.Sprintf("更新日志的cron成功,%s", cron)) - logrus.Error(fmt.Sprintf("所有的定时任务: %s", TaskList)) - -} - -// StartLogsCronRun 启动的时候开启定时任务 -func StartLogsCronRun() { - logrus.Infof("开始注册定时清除日志任务...") - cs := CronService{} - cs.StartLogsCronRun() -} diff --git a/service/cron_service/startup_tasks.go b/service/cron_service/startup_tasks.go new file mode 100644 index 0000000..b07c6fd --- /dev/null +++ b/service/cron_service/startup_tasks.go @@ -0,0 +1,207 @@ +package cron_service + +import ( + "fmt" + "message-nest/models" + "message-nest/pkg/constant" + "message-nest/service/send_message_service" + + "github.com/robfig/cron/v3" + "github.com/sirupsen/logrus" + "github.com/unknwon/com" +) + +var ClearLogsTaskId cron.EntryID +var ClearHostedMsgTaskId cron.EntryID + +// CleanConfig 清理任务配置 +type CleanConfig struct { + TaskID string + TaskName string + LogPrefix string + SectionName string + EnabledKey string + KeepNumKey string + DeleteFunc func(int) (int, error) + ResourceName string // 资源名称,如"日志"、"托管消息" +} + +// executeCleanTask 执行清理任务的通用逻辑 +func executeCleanTask(config CleanConfig) { + var errStr string + sm := send_message_service.SendMessageService{ + TaskID: config.TaskID, + Name: config.TaskName, + DefaultLogger: logrus.WithFields(logrus.Fields{ + "prefix": config.LogPrefix, + }), + } + sm.Status = send_message_service.SendSuccess + + // 检查是否启用 + enabledSetting, err := models.GetSettingByKey(config.SectionName, config.EnabledKey) + if err != nil { + errStr = fmt.Sprintf("获取%s清理开关失败,原因:%s", config.ResourceName, err) + sm.LogsAndStatusMark(errStr, send_message_service.SendFail) + sm.RecordSendLog() + return + } + + if enabledSetting.Value != "true" { + sm.LogsAndStatusMark(fmt.Sprintf("%s清理功能未启用,跳过执行", config.ResourceName), sm.Status) + sm.RecordSendLog() + return + } + + sm.LogsAndStatusMark(fmt.Sprintf("开始清除%s", config.ResourceName), sm.Status) + + setting, err := models.GetSettingByKey(config.SectionName, config.KeepNumKey) + if err != nil { + errStr = fmt.Sprintf("获取%s的保留数失败,原因:%s", config.ResourceName, err) + sm.LogsAndStatusMark(errStr, send_message_service.SendFail) + } + + keepNum := com.StrTo(setting.Value).MustInt() + affectedRows, err := config.DeleteFunc(keepNum) + if err != nil { + errStr = fmt.Sprintf("删除%s失败,原因:%s", config.ResourceName, err) + sm.LogsAndStatusMark(errStr, send_message_service.SendFail) + } else { + errStr = fmt.Sprintf("删除%s成功,删除条数:%d,保留数目:%d", config.ResourceName, affectedRows, keepNum) + sm.LogsAndStatusMark(errStr, sm.Status) + } + + sm.RecordSendLog() +} + +// ClearLogs 清除日志的定时任务 +func ClearLogs() { + executeCleanTask(CleanConfig{ + TaskID: constant.CleanLogsTaskId, + TaskName: "日志定时清除", + LogPrefix: "[Cron Clear Logs]", + SectionName: constant.LogsCleanSectionName, + EnabledKey: constant.LogsCleanEnabledKeyName, + KeepNumKey: constant.LogsCleanKeepKeyName, + DeleteFunc: models.DeleteOutDateLogs, + ResourceName: "日志", + }) +} + +type CronService struct { +} + +// startCleanCronTask 启动清理任务的通用逻辑 +func startCleanCronTask(sectionName, enabledKey, cronKey, resourceName string, job func(), taskId *cron.EntryID) { + // 检查是否启用 + enabledSetting, err := models.GetSettingByKey(sectionName, enabledKey) + if err != nil { + logrus.Error(fmt.Sprintf("获取[%s]清理开关失败,原因:%s", resourceName, err)) + return + } + + if enabledSetting.Value != "true" { + logrus.Info(fmt.Sprintf("[%s]清理功能未启用", resourceName)) + return + } + + // 注册任务 + setting, err := models.GetSettingByKey(sectionName, cronKey) + if err != nil { + logrus.Error(fmt.Sprintf("获取[%s]的cron失败,原因:%s", resourceName, err)) + return + } + *taskId = AddTask(ScheduledTask{ + Schedule: setting.Value, + Job: job, + }) + logrus.Info(fmt.Sprintf("[%s]清理任务已启动", resourceName)) +} + +// updateCleanCronTask 更新清理任务的通用逻辑 +func updateCleanCronTask(cron string, enabled bool, resourceName string, job func(), taskId *cron.EntryID) { + // 先移除旧任务 + if *taskId > 0 { + RemoveTask(*taskId) + *taskId = 0 + } + + // 如果启用,则添加新任务 + if enabled { + *taskId = AddTask(ScheduledTask{ + Schedule: cron, + Job: job, + }) + logrus.Info(fmt.Sprintf("更新%s的cron成功,%s", resourceName, cron)) + } else { + logrus.Info(fmt.Sprintf("%s清理任务已停止", resourceName)) + } + logrus.Info(fmt.Sprintf("所有的定时任务总数: %d", len(TaskList))) +} + +// StartLogsCronRun 启动注册清除任务定时任务 +func (cs *CronService) StartLogsCronRun() { + startCleanCronTask( + constant.LogsCleanSectionName, + constant.LogsCleanEnabledKeyName, + constant.LogsCleanCronKeyName, + "日志", + ClearLogs, + &ClearLogsTaskId, + ) +} + +// UpdateLogsCronRun 更新清除任务定时任务 +func (cs *CronService) UpdateLogsCronRun(cron string, enabled bool) { + updateCleanCronTask(cron, enabled, "日志", ClearLogs, &ClearLogsTaskId) +} + +// ClearHostedMessages 清除托管消息的定时任务 +func ClearHostedMessages() { + executeCleanTask(CleanConfig{ + TaskID: constant.CleanHostedMsgTaskId, + TaskName: "托管消息定时清除", + LogPrefix: "[Cron Clear Hosted Messages]", + SectionName: constant.HostedMsgCleanSectionName, + EnabledKey: constant.HostedMsgCleanEnabledKeyName, + KeepNumKey: constant.HostedMsgCleanKeepKeyName, + DeleteFunc: models.DeleteOutDateHostedMessages, + ResourceName: "托管消息", + }) +} + +// StartHostedMsgCronRun 启动注册托管消息清除任务定时任务 +func (cs *CronService) StartHostedMsgCronRun() { + startCleanCronTask( + constant.HostedMsgCleanSectionName, + constant.HostedMsgCleanEnabledKeyName, + constant.HostedMsgCleanCronKeyName, + "托管消息", + ClearHostedMessages, + &ClearHostedMsgTaskId, + ) +} + +// UpdateHostedMsgCronRun 更新托管消息清除任务定时任务 +func (cs *CronService) UpdateHostedMsgCronRun(cron string, enabled bool) { + updateCleanCronTask(cron, enabled, "托管消息", ClearHostedMessages, &ClearHostedMsgTaskId) +} + +// StartLogsCronRunOnStartup 启动的时候开启定时任务 +func StartLogsCronRunOnStartup() { + logrus.Infof("开始注册定时清除日志任务...") + cs := CronService{} + cs.StartLogsCronRun() +} + +// StartHostedMsgCronRunOnStartup 启动的时候开启托管消息清理定时任务 +func StartHostedMsgCronRunOnStartup() { + logrus.Infof("开始注册定时清除托管消息任务...") + cs := CronService{} + cs.StartHostedMsgCronRun() +} + +func StartTasksRunOnStartup() { + StartLogsCronRunOnStartup() + StartHostedMsgCronRunOnStartup() +} diff --git a/service/settings_service/init_site.go b/service/settings_service/init_site.go index d940c0a..85d7947 100644 --- a/service/settings_service/init_site.go +++ b/service/settings_service/init_site.go @@ -41,3 +41,11 @@ func (es *InitSettingService) InitLogConfig() { es.CommonAddSetting(section, key, value) } } + +// InitHostedMsgConfig 初始化托管消息清理设置 +func (es *InitSettingService) InitHostedMsgConfig() { + section := constant.HostedMsgCleanSectionName + for key, value := range constant.HostedMsgCleanDefaultValueMap { + es.CommonAddSetting(section, key, value) + } +} diff --git a/service/settings_service/settings.go b/service/settings_service/settings.go index fcf1a6c..ae93cef 100644 --- a/service/settings_service/settings.go +++ b/service/settings_service/settings.go @@ -93,9 +93,25 @@ func (us *UserSettings) EditSettings(section string, key string, value string, c data["value"] = value data["modified_by"] = currentUser err := models.EditSetting(setting.ID, data) - if key == constant.LogsCleanCronKeyName { - cronService := cron_service.CronService{} - cronService.UpdateLogsCronRun(value) + // 更新日志清理配置 + if section == constant.LogsCleanSectionName { + if key == constant.LogsCleanCronKeyName || key == constant.LogsCleanEnabledKeyName { + cronService := cron_service.CronService{} + // 获取最新的cron和enabled值 + cronSetting, _ := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanCronKeyName) + enabledSetting, _ := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanEnabledKeyName) + cronService.UpdateLogsCronRun(cronSetting.Value, enabledSetting.Value == "true") + } + } + // 更新托管消息清理配置 + if section == constant.HostedMsgCleanSectionName { + if key == constant.HostedMsgCleanCronKeyName || key == constant.HostedMsgCleanEnabledKeyName { + cronService := cron_service.CronService{} + // 获取最新的cron和enabled值 + cronSetting, _ := models.GetSettingByKey(constant.HostedMsgCleanSectionName, constant.HostedMsgCleanCronKeyName) + enabledSetting, _ := models.GetSettingByKey(constant.HostedMsgCleanSectionName, constant.HostedMsgCleanEnabledKeyName) + cronService.UpdateHostedMsgCronRun(cronSetting.Value, enabledSetting.Value == "true") + } } // 如果是site_config,清除缓存 if section == constant.SiteSettingSectionName { @@ -116,6 +132,13 @@ type SiteConfig struct { type LogConfig struct { Cron string `json:"cron" validate:"required,cron" label:"日志定时表达式"` KeepNum string `json:"keep_num" validate:"required,min=1,max=50" label:"日志保留数"` + Enabled string `json:"enabled" validate:"required,oneof=true false" label:"是否启用"` +} + +type HostedMsgConfig struct { + Cron string `json:"cron" validate:"required,cron" label:"托管消息定时表达式"` + KeepNum string `json:"keep_num" validate:"required,min=1,max=50" label:"托管消息保留数"` + Enabled string `json:"enabled" validate:"required,oneof=true false" label:"是否启用"` } // GetCookieExpDays 获取 cookie 过期天数,若无配置则返回默认值 1 @@ -157,6 +180,19 @@ func (us *UserSettings) ValidateDiffSetting(section string, data map[string]stri var config LogConfig config.Cron = data["cron"] config.KeepNum = data["keep_num"] + config.Enabled = data["enabled"] + _, err := cron.ParseStandard(config.Cron) + if err != nil { + return fmt.Sprintf("%s 不是合法的corn表达式", config.Cron) + } + _, errStr := app.CommonPlaygroundValid(config) + return errStr + } + if section == constant.HostedMsgCleanSectionName { + var config HostedMsgConfig + config.Cron = data["cron"] + config.KeepNum = data["keep_num"] + config.Enabled = data["enabled"] _, err := cron.ParseStandard(config.Cron) if err != nil { return fmt.Sprintf("%s 不是合法的corn表达式", config.Cron) diff --git a/web/src/components/pages/settings/CleanSettings.vue b/web/src/components/pages/settings/CleanSettings.vue new file mode 100644 index 0000000..fc0ebf2 --- /dev/null +++ b/web/src/components/pages/settings/CleanSettings.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/web/src/components/pages/settings/LogsSettings.vue b/web/src/components/pages/settings/LogsSettings.vue deleted file mode 100644 index 0104cd0..0000000 --- a/web/src/components/pages/settings/LogsSettings.vue +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - diff --git a/web/src/components/pages/settings/Settings.vue b/web/src/components/pages/settings/Settings.vue index 00690d2..8ede9f4 100644 --- a/web/src/components/pages/settings/Settings.vue +++ b/web/src/components/pages/settings/Settings.vue @@ -2,7 +2,7 @@ import { ref } from 'vue' import SettingsSidebar from './SettingsSidebar.vue' import PasswordSettings from './PasswordSettings.vue' -import LogsSettings from './LogsSettings.vue' +import CleanSettings from './CleanSettings.vue' import SiteSettings from './SiteSettings.vue' import AboutSettings from './AboutSettings.vue' import LoginLogs from './LoginLogs.vue' @@ -25,8 +25,8 @@ const activeTab = ref('password') - - + + diff --git a/web/src/components/pages/settings/SettingsSidebar.vue b/web/src/components/pages/settings/SettingsSidebar.vue index 1a8704c..ef30044 100644 --- a/web/src/components/pages/settings/SettingsSidebar.vue +++ b/web/src/components/pages/settings/SettingsSidebar.vue @@ -18,7 +18,7 @@ defineEmits() // 设置菜单项 const settingsMenu = [ { id: 'password', name: '重置密码', icon: KeyIcon }, - { id: 'logs', name: '日志清理', icon: TrashIcon }, + { id: 'clean', name: '数据清理', icon: TrashIcon }, { id: 'loginlogs', name: '登录日志', icon: HistoryIcon }, { id: 'site', name: '站点设置', icon: SettingsIcon }, { id: 'about', name: '站点关于', icon: InfoIcon } diff --git a/web/src/components/ui/separator/Separator.vue b/web/src/components/ui/separator/Separator.vue new file mode 100644 index 0000000..78d60ec --- /dev/null +++ b/web/src/components/ui/separator/Separator.vue @@ -0,0 +1,29 @@ + + + diff --git a/web/src/components/ui/separator/index.ts b/web/src/components/ui/separator/index.ts new file mode 100644 index 0000000..4407287 --- /dev/null +++ b/web/src/components/ui/separator/index.ts @@ -0,0 +1 @@ +export { default as Separator } from "./Separator.vue" diff --git a/web/src/constant.d.ts b/web/src/constant.d.ts index 018f26f..b2dc16f 100644 --- a/web/src/constant.d.ts +++ b/web/src/constant.d.ts @@ -4,6 +4,7 @@ export interface ConstantType { TOTAL: number; DEFALUT_SITE_CONFIG: string; LOG_TASK_ID: string; + HOSTED_MSG_TASK_ID: string; STORE_TOKEN_NAME: string; STORE_CUSTOM_NAME: string; NO_AUTH_URL: string[]; diff --git a/web/src/constant.js b/web/src/constant.js index ad938de..7952669 100644 --- a/web/src/constant.js +++ b/web/src/constant.js @@ -10,6 +10,7 @@ const CONSTANT = { TOTAL: 0, DEFALUT_SITE_CONFIG: JSON.stringify({ "logo": "", "pagesize": "8", "slogan": "A Message Way Hosted Site", "title": "Message Nest" }), LOG_TASK_ID: "T-IM1GBswSRY", + HOSTED_MSG_TASK_ID: "T-HM2KCxwTZQ", STORE_TOKEN_NAME: '__message_nest_token__', STORE_CUSTOM_NAME: '__message_nest_custom_site__', NO_AUTH_URL: [