Wox/wox.core/plugin/system/sys.go

293 lines
8.4 KiB
Go

package system
import (
"context"
"encoding/json"
"fmt"
"os"
"path"
"runtime/pprof"
"time"
"wox/common"
"wox/i18n"
"wox/plugin"
"wox/ui"
"wox/util"
"wox/util/shell"
)
var sysIcon = plugin.PluginSysIcon
func init() {
plugin.AllSystemPlugin = append(plugin.AllSystemPlugin, &SysPlugin{})
}
type SysPlugin struct {
api plugin.API
commands []SysCommand
}
type SysCommand struct {
Title string
SubTitle string
Icon common.WoxImage
PreventHideAfterAction bool
Action func(ctx context.Context, actionContext plugin.ActionContext)
}
type sysContextData struct {
CommandTitle string `json:"commandTitle"`
}
func (r *SysPlugin) GetMetadata() plugin.Metadata {
return plugin.Metadata{
Id: "227f7d64-df08-4e35-ad05-98a26d540d06",
Name: "System Commands",
Author: "Wox Launcher",
Website: "https://github.com/Wox-launcher/Wox",
Version: "1.0.0",
MinWoxVersion: "2.0.0",
Runtime: "Go",
Description: "Provide System related commands. e.g. shutdown,lock,setting etc.",
Icon: sysIcon.String(),
Entry: "",
TriggerKeywords: []string{
"*",
},
Commands: []plugin.MetadataCommand{},
SupportedOS: []string{
"Windows",
"Macos",
"Linux",
},
Features: []plugin.MetadataFeature{
{
Name: plugin.MetadataFeatureMRU,
},
},
}
}
func (r *SysPlugin) Init(ctx context.Context, initParams plugin.InitParams) {
r.api = initParams.API
r.commands = []SysCommand{
{
Title: "i18n:plugin_sys_lock_computer",
Icon: plugin.LockIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
if util.IsMacOS() {
shell.Run("osascript", "-e", "tell application \"System Events\" to keystroke \"q\" using {control down, command down}")
}
if util.IsWindows() {
shell.Run("rundll32.exe", "user32.dll,LockWorkStation")
}
},
},
{
Title: "i18n:plugin_sys_empty_trash",
Icon: plugin.TrashIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
if util.IsMacOS() {
shell.Run("osascript", "-e", "tell application \"Finder\" to empty trash")
}
if util.IsWindows() {
shell.Run("powershell.exe", "-Command", "Clear-RecycleBin -Force")
}
},
},
{
Title: "i18n:plugin_sys_quit_wox",
Icon: plugin.ExitIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
ui.GetUIManager().ExitApp(ctx)
},
},
{
Title: "i18n:plugin_sys_open_wox_settings",
PreventHideAfterAction: true,
Icon: plugin.WoxIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
plugin.GetPluginManager().GetUI().OpenSettingWindow(ctx, common.DefaultSettingWindowContext)
},
},
{
Title: "i18n:plugin_sys_open_system_settings",
Icon: plugin.SettingIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
if util.IsMacOS() {
shell.Run("open", "-a", "System Preferences")
}
if util.IsWindows() {
shell.Run("control.exe", "desk.cpl")
}
},
},
}
if util.IsDev() {
r.commands = append(r.commands, SysCommand{
Title: "i18n:plugin_sys_performance_cpu_profiling",
Icon: plugin.CPUProfileIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
cpuProfPath := path.Join(util.GetLocation().GetWoxDataDirectory(), "cpu.prof")
f, err := os.Create(cpuProfPath)
if err != nil {
util.GetLogger().Info(ctx, "failed to create cpu profile file: "+err.Error())
return
}
util.GetLogger().Info(ctx, "start cpu profile")
profileErr := pprof.StartCPUProfile(f)
if profileErr != nil {
util.GetLogger().Info(ctx, "failed to start cpu profile: "+profileErr.Error())
return
}
time.AfterFunc(30*time.Second, func() {
pprof.StopCPUProfile()
util.GetLogger().Info(ctx, "cpu profile saved to "+cpuProfPath)
})
},
})
r.commands = append(r.commands, SysCommand{
Title: "i18n:plugin_sys_performance_memory_profiling",
Icon: plugin.CPUProfileIcon,
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
memoryProfPath := path.Join(util.GetLocation().GetWoxDataDirectory(), "memory.prof")
f, err := os.Create(memoryProfPath)
if err != nil {
util.GetLogger().Info(ctx, "failed to create memory profile file: "+err.Error())
return
}
util.GetLogger().Info(ctx, "start memory profile")
profileErr := pprof.WriteHeapProfile(f)
if profileErr != nil {
util.GetLogger().Info(ctx, "failed to start memory profile: "+profileErr.Error())
return
}
util.GetLogger().Info(ctx, "memory profile saved to "+memoryProfPath)
},
})
r.commands = append(r.commands, SysCommand{
Title: "i18n:plugin_sys_delete_image_cache",
Icon: common.NewWoxImageEmoji("🗑️"),
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
location := util.GetLocation()
imageCacheDirectory := location.GetImageCacheDirectory()
if _, err := os.Stat(imageCacheDirectory); err == nil {
os.RemoveAll(imageCacheDirectory)
}
},
})
}
}
func (r *SysPlugin) Query(ctx context.Context, query plugin.Query) (results []plugin.QueryResult) {
for _, command := range r.commands {
translatedTitle := i18n.GetI18nManager().TranslateWox(ctx, command.Title)
isTitleMatch, titleScore := IsStringMatchScore(ctx, translatedTitle, query.Search)
if !isTitleMatch {
translatedTitleEnUs := i18n.GetI18nManager().TranslateWoxEnUs(ctx, command.Title)
isTitleMatch, titleScore = IsStringMatchScore(ctx, translatedTitleEnUs, query.Search)
}
if isTitleMatch {
contextData := sysContextData{
CommandTitle: command.Title,
}
contextDataJson, _ := json.Marshal(contextData)
results = append(results, plugin.QueryResult{
Title: command.Title,
SubTitle: command.SubTitle,
Score: titleScore,
Icon: command.Icon,
ContextData: string(contextDataJson),
Actions: []plugin.QueryResultAction{
{
Name: "i18n:plugin_sys_execute",
Action: command.Action,
PreventHideAfterAction: command.PreventHideAfterAction,
},
},
})
}
r.api.OnMRURestore(ctx, r.handleMRURestore)
}
for _, instance := range plugin.GetPluginManager().GetPluginInstances() {
//check if plugin has setting
if len(instance.Metadata.SettingDefinitions) > 0 {
if match, score := IsStringMatchScore(ctx, instance.Metadata.Name, query.Search); match {
// load icon
pluginIcon := plugin.SettingIcon
iconImg, parseErr := common.ParseWoxImage(instance.Metadata.Icon)
if parseErr == nil {
pluginIcon = common.ConvertRelativePathToAbsolutePath(ctx, iconImg, instance.PluginDirectory)
}
results = append(results, plugin.QueryResult{
Title: fmt.Sprintf(i18n.GetI18nManager().TranslateWox(ctx, "plugin_sys_open_plugin_settings"), instance.Metadata.Name),
Score: score,
Icon: pluginIcon,
Actions: []plugin.QueryResultAction{
{
Name: "i18n:plugin_sys_execute",
Action: func(ctx context.Context, actionContext plugin.ActionContext) {
plugin.GetPluginManager().GetUI().OpenSettingWindow(ctx, common.SettingWindowContext{
Path: "/plugin/setting",
Param: instance.Metadata.Name,
})
},
PreventHideAfterAction: true,
},
},
})
}
}
}
return
}
func (r *SysPlugin) handleMRURestore(mruData plugin.MRUData) (*plugin.QueryResult, error) {
var contextData sysContextData
if err := json.Unmarshal([]byte(mruData.ContextData), &contextData); err != nil {
return nil, fmt.Errorf("failed to parse context data: %w", err)
}
// Find the command by title
var foundCommand *SysCommand
for _, command := range r.commands {
if command.Title == contextData.CommandTitle {
foundCommand = &command
break
}
}
if foundCommand == nil {
return nil, fmt.Errorf("system command no longer exists: %s", contextData.CommandTitle)
}
result := &plugin.QueryResult{
Title: foundCommand.Title,
SubTitle: foundCommand.SubTitle,
Icon: mruData.Icon,
ContextData: mruData.ContextData,
Actions: []plugin.QueryResultAction{
{
Name: "i18n:plugin_sys_execute",
Action: foundCommand.Action,
PreventHideAfterAction: foundCommand.PreventHideAfterAction,
},
},
}
return result, nil
}