Files
rikkei_simple_care/client/internal/blocker/blocker.go
2026-07-01 09:49:27 +07:00

120 lines
2.5 KiB
Go

package blocker
import (
"log"
"strings"
"sync"
"time"
)
type Blocker struct {
mu sync.Mutex
allowedKeywords []string
running bool
stopChan chan struct{}
OnBlocked func(procName string, title string)
OnKill func(procName string, title string)
}
var Instance = &Blocker{
allowedKeywords: []string{"chrome", "idea64", "vscode", "wails", "simple_care", "client"},
stopChan: make(chan struct{}),
}
func parseKeywordList(keywords string) []string {
keywords = strings.ReplaceAll(keywords, "\r\n", "\n")
parts := strings.FieldsFunc(keywords, func(r rune) bool {
return r == ',' || r == '\n' || r == ';' || r == '|'
})
seen := map[string]bool{}
var list []string
for _, p := range parts {
trimmed := strings.TrimSpace(strings.ToLower(p))
trimmed = strings.TrimSuffix(trimmed, ".exe")
if trimmed == "" || seen[trimmed] {
continue
}
seen[trimmed] = true
list = append(list, trimmed)
}
return list
}
var keywordAliases = map[string][]string{
"lark": {"lark", "feishu", "larkshell", "larkhelper"},
"feishu": {"lark", "feishu", "larkshell", "larkhelper"},
"teams": {"teams", "ms-teams", "msteams"},
"zalo": {"zalo", "zalopcb"},
}
func expandKeyword(kw string) []string {
base := []string{kw}
if aliases, ok := keywordAliases[kw]; ok {
base = append(base, aliases...)
}
seen := map[string]bool{}
var out []string
for _, a := range base {
a = strings.TrimSpace(strings.ToLower(a))
if a != "" && !seen[a] {
seen[a] = true
out = append(out, a)
}
}
return out
}
func matchesAllowedKeyword(kw, pNameLower, wTitleLower string) bool {
for _, variant := range expandKeyword(kw) {
if strings.Contains(pNameLower, variant) || strings.Contains(wTitleLower, variant) {
return true
}
}
return false
}
func (b *Blocker) SetKeywords(keywords string) {
b.mu.Lock()
b.allowedKeywords = parseKeywordList(keywords)
b.mu.Unlock()
log.Printf("[BLOCKER] Keywords updated: %v", b.allowedKeywords)
}
func (b *Blocker) Start() {
b.mu.Lock()
if b.running {
b.mu.Unlock()
return
}
b.running = true
b.stopChan = make(chan struct{})
b.mu.Unlock()
go func() {
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
b.checkAndKill()
case <-b.stopChan:
return
}
}
}()
log.Println("[BLOCKER] Application Blocker Daemon Started.")
}
func (b *Blocker) Stop() {
b.mu.Lock()
defer b.mu.Unlock()
if !b.running {
return
}
b.running = false
close(b.stopChan)
log.Println("[BLOCKER] Application Blocker Daemon Stopped.")
}