83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
package browser
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"errors"
|
||
|
|
"fmt"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"chub/internal/domain"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
ProfileSourceMessageWindow = "browser_message_window"
|
||
|
|
ProfileSourceLock = "browser_lock"
|
||
|
|
ProfileSourceStaleLock = "stale_lock"
|
||
|
|
ProfileSourceStalePID = "stale_pid"
|
||
|
|
ProfileSourceUnknown = "unknown"
|
||
|
|
)
|
||
|
|
|
||
|
|
var ErrIdentityUnavailable = errors.New("browser process identity is unavailable")
|
||
|
|
|
||
|
|
type ProcessIdentity struct {
|
||
|
|
PID int
|
||
|
|
Executable string
|
||
|
|
CommandLine string
|
||
|
|
UserDataDir string
|
||
|
|
}
|
||
|
|
|
||
|
|
type ProcessInspector interface {
|
||
|
|
Inspect(context.Context, int) (ProcessIdentity, error)
|
||
|
|
Alive(context.Context, int) (bool, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
type ExternalProfileInspector interface {
|
||
|
|
InspectProfile(context.Context, domain.BrowserKind, string, int) (ProfileUse, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
type RuntimeInspector struct {
|
||
|
|
process ProcessInspector
|
||
|
|
profiles ExternalProfileInspector
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewRuntimeInspector(process ProcessInspector, profiles ExternalProfileInspector) *RuntimeInspector {
|
||
|
|
return &RuntimeInspector{process: process, profiles: profiles}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (i *RuntimeInspector) InspectProcess(ctx context.Context, pid int) (ProcessIdentity, error) {
|
||
|
|
if i == nil || i.process == nil {
|
||
|
|
return ProcessIdentity{}, ErrIdentityUnavailable
|
||
|
|
}
|
||
|
|
return i.process.Inspect(ctx, pid)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (i *RuntimeInspector) InspectProfile(ctx context.Context, kind domain.BrowserKind, userDataDir string, historicalPID int) (ProfileUse, error) {
|
||
|
|
if i == nil || i.profiles == nil {
|
||
|
|
return ProfileUse{}, ErrIdentityUnavailable
|
||
|
|
}
|
||
|
|
return i.profiles.InspectProfile(ctx, kind, userDataDir, historicalPID)
|
||
|
|
}
|
||
|
|
|
||
|
|
func expectedExecutableName(kind domain.BrowserKind) string {
|
||
|
|
if kind == domain.BrowserEdge {
|
||
|
|
return "msedge.exe"
|
||
|
|
}
|
||
|
|
return "chrome.exe"
|
||
|
|
}
|
||
|
|
|
||
|
|
func executableMatchesKind(path string, kind domain.BrowserKind) bool {
|
||
|
|
return strings.EqualFold(pathBase(path), expectedExecutableName(kind))
|
||
|
|
}
|
||
|
|
|
||
|
|
func pathBase(path string) string {
|
||
|
|
path = strings.TrimRight(path, `\\/`)
|
||
|
|
if index := strings.LastIndexAny(path, `\\/`); index >= 0 {
|
||
|
|
return path[index+1:]
|
||
|
|
}
|
||
|
|
return path
|
||
|
|
}
|
||
|
|
|
||
|
|
func unsupportedError() error {
|
||
|
|
return fmt.Errorf("%w: Windows process inspection is unavailable", ErrIdentityUnavailable)
|
||
|
|
}
|