diff --git a/lastore/agent.go b/lastore/agent.go new file mode 100644 index 000000000..8f3d5db97 --- /dev/null +++ b/lastore/agent.go @@ -0,0 +1,88 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package lastore + +import ( + "sync" + + "github.com/godbus/dbus" + lastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +// lastore agent的interface name +const ( + sessionAgentInterface = "com.deepin.lastore.Agent" +) + +// 对应com.deepin.daemon.Network.GetProxy方法的key值 +const ( + proxyTypeHttp = "http" + proxyTypeHttps = "https" + proxyTypeFtp = "ftp" + proxyTypeSocks = "socks" +) + +// 对应系统代理环境变量 +const ( + envHttpProxy = "http_proxy" + envHttpsProxy = "https_proxy" + envFtpProxy = "ftp_proxy" + envAllProxy = "all_proxy" +) + +// Agent 需要实现GetManualProxy和SendNotify两个接口 +type Agent struct { + sysService *dbusutil.Service + lastoreObj *Lastore + sysLastore lastore.Lastore + mu sync.Mutex +} + +func newAgent(l *Lastore) (*Agent, error) { + sysBus, err := dbusutil.NewSystemService() + if err != nil { + logger.Warning(err) + return nil, err + } + a := &Agent{ + sysService: sysBus, + } + a.lastoreObj = l + a.sysLastore = lastore.NewLastore(a.sysService.Conn()) + return a, nil +} + +func (a *Agent) init() { + err := a.sysService.Export("/com/deepin/lastore/agent", a) + if err != nil { + logger.Warning(err) + return + } + err = a.sysLastore.Manager().RegisterAgent(0, "/com/deepin/lastore/agent") + if err != nil { + logger.Warning(err) + } +} + +func (a *Agent) destroy() { + err := a.sysLastore.Manager().UnRegisterAgent(0, "/com/deepin/lastore/agent") + if err != nil { + logger.Warning(err) + } +} + +func (a *Agent) checkCallerAuth(sender dbus.Sender) bool { + const rootUid = 0 + uid, err := a.sysService.GetConnUID(string(sender)) + if err != nil { + return false + } + if uid != rootUid { + logger.Warningf("not allow %v call this method", sender) + return false + } + return true +} diff --git a/lastore/agent_ifc.go b/lastore/agent_ifc.go new file mode 100644 index 000000000..c6d803148 --- /dev/null +++ b/lastore/agent_ifc.go @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +package lastore + +import ( + "errors" + "fmt" + "github.com/godbus/dbus" + "github.com/linuxdeepin/go-lib/dbusutil" +) + +func (*Agent) GetInterfaceName() string { + return sessionAgentInterface +} + +func (a *Agent) GetManualProxy(sender dbus.Sender) (map[string]string, *dbus.Error) { + // TODO 获取代理认证信息 + if !a.checkCallerAuth(sender) { + return nil, dbusutil.ToError(fmt.Errorf("not allow %v call this method", sender)) + } + method, err := a.lastoreObj.network.GetProxyMethod(0) + if err != nil { + logger.Warning(err) + return nil, dbusutil.ToError(err) + } + if method != "manual" { + return nil, dbusutil.ToError(errors.New("only support manual proxy")) + } + proxyTypeList := []string{ + proxyTypeHttp, proxyTypeHttps, proxyTypeFtp, + } + proxyEnvMap := make(map[string]string) + for _, typ := range proxyTypeList { + host, port, err := a.lastoreObj.network.GetProxy(0, typ) + if err != nil { + logger.Warning(err) + continue + } + proxyEnvMap[fmt.Sprintf("%s_proxy", typ)] = fmt.Sprintf("%s://%s:%s", proxyTypeHttp, host, port) + } + host, port, err := a.lastoreObj.network.GetProxy(0, proxyTypeSocks) + if err != nil { + logger.Warning(err) + return proxyEnvMap, dbusutil.ToError(err) + } + proxyEnvMap[envAllProxy] = fmt.Sprintf("%s://%s:%s", proxyTypeSocks, host, port) + return proxyEnvMap, nil +} + +func (a *Agent) SendNotify(sender dbus.Sender, appName string, replacesId uint32, appIcon string, summary string, body string, actions []string, hints map[string]dbus.Variant, expireTimeout int32) (uint32, *dbus.Error) { + if !a.checkCallerAuth(sender) { + return 0, dbusutil.ToError(fmt.Errorf("not allow %v call this method", sender)) + } + logger.Info("receive notify from lastore daemon") + id, err := a.lastoreObj.notifications.Notify(0, appName, replacesId, appIcon, summary, body, actions, hints, expireTimeout) + return id, dbusutil.ToError(err) +} + +func (a *Agent) CloseNotification(sender dbus.Sender, id uint32) *dbus.Error { + if !a.checkCallerAuth(sender) { + return dbusutil.ToError(fmt.Errorf("not allow %v call this method", sender)) + } + logger.Info("receive close notify from lastore daemon") + return dbusutil.ToError(a.lastoreObj.notifications.CloseNotification(0, id)) +} diff --git a/lastore/daemon.go b/lastore/daemon.go index 6b5220a95..09d680b5a 100644 --- a/lastore/daemon.go +++ b/lastore/daemon.go @@ -5,8 +5,8 @@ package lastore import ( - "github.com/linuxdeepin/go-lib/log" "github.com/linuxdeepin/dde-daemon/loader" + "github.com/linuxdeepin/go-lib/log" ) const ( @@ -22,6 +22,7 @@ func init() { type Daemon struct { lastore *Lastore + agent *Agent *loader.ModuleBase } @@ -38,13 +39,12 @@ func (*Daemon) GetDependencies() []string { func (d *Daemon) Start() error { service := loader.GetService() - lastore, err := newLastore(service) + lastoreObj, err := newLastore(service) if err != nil { return err } - d.lastore = lastore - - err = service.Export(dbusPath, lastore, lastore.syncConfig) + d.lastore = lastoreObj + err = service.Export(dbusPath, lastoreObj, lastoreObj.syncConfig) if err != nil { return err } @@ -53,32 +53,44 @@ func (d *Daemon) Start() error { if err != nil { return err } - - err = lastore.syncConfig.Register() + err = lastoreObj.syncConfig.Register() if err != nil { logger.Warning("Failed to register sync service:", err) } + agent, err := newAgent(lastoreObj) + if err != nil { + logger.Warning(err) + return err + } + d.agent = agent + agent.init() return nil } func (d *Daemon) Stop() error { - if d.lastore == nil { - return nil + if d.lastore != nil { + service := loader.GetService() + err := service.ReleaseName(dbusServiceName) + if err != nil { + logger.Warning(err) + } + d.lastore.destroy() + err = service.StopExport(d.lastore) + if err != nil { + logger.Warning(err) + } + + d.lastore = nil } - service := loader.GetService() - err := service.ReleaseName(dbusServiceName) - if err != nil { - logger.Warning(err) - } - - d.lastore.destroy() - - err = service.StopExport(d.lastore) - if err != nil { - logger.Warning(err) + if d.agent != nil { + service := loader.GetService() + d.agent.destroy() + err := service.StopExport(d.agent) + if err != nil { + logger.Warning(err) + } + d.agent = nil } - - d.lastore = nil return nil } diff --git a/lastore/exported_methods_auto.go b/lastore/exported_methods_auto.go index d3337afd4..a81ab95b7 100644 --- a/lastore/exported_methods_auto.go +++ b/lastore/exported_methods_auto.go @@ -1,4 +1,4 @@ -// Code generated by "dbusutil-gen em -type Lastore"; DO NOT EDIT. +// Code generated by "dbusutil-gen em -type Lastore,Agent"; DO NOT EDIT. package lastore @@ -6,6 +6,26 @@ import ( "github.com/linuxdeepin/go-lib/dbusutil" ) +func (v *Agent) GetExportedMethods() dbusutil.ExportedMethods { + return dbusutil.ExportedMethods{ + { + Name: "CloseNotification", + Fn: v.CloseNotification, + InArgs: []string{"id"}, + }, + { + Name: "GetManualProxy", + Fn: v.GetManualProxy, + OutArgs: []string{"outArg0"}, + }, + { + Name: "SendNotify", + Fn: v.SendNotify, + InArgs: []string{"appName", "replacesId", "appIcon", "summary", "body", "actions", "hints", "expireTimeout"}, + OutArgs: []string{"outArg0"}, + }, + } +} func (v *Lastore) GetExportedMethods() dbusutil.ExportedMethods { return dbusutil.ExportedMethods{ { diff --git a/lastore/lastore.go b/lastore/lastore.go index c981ee463..4cdedfe1c 100644 --- a/lastore/lastore.go +++ b/lastore/lastore.go @@ -5,26 +5,13 @@ package lastore import ( - "os/exec" - "strings" - "sync" - "time" - "github.com/godbus/dbus" - abrecovery "github.com/linuxdeepin/go-dbus-factory/com.deepin.abrecovery" + "github.com/linuxdeepin/dde-daemon/common/dsync" + network "github.com/linuxdeepin/go-dbus-factory/com.deepin.daemon.network" lastore "github.com/linuxdeepin/go-dbus-factory/com.deepin.lastore" - sessionmanager "github.com/linuxdeepin/go-dbus-factory/com.deepin.sessionmanager" - power "github.com/linuxdeepin/go-dbus-factory/com.deepin.system.power" - ofdbus "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.dbus" notifications "github.com/linuxdeepin/go-dbus-factory/org.freedesktop.notifications" - gio "github.com/linuxdeepin/go-gir/gio-2.0" "github.com/linuxdeepin/go-lib/dbusutil" - "github.com/linuxdeepin/go-lib/dbusutil/proxy" - "github.com/linuxdeepin/go-lib/gettext" - "github.com/linuxdeepin/go-lib/gsettings" - "github.com/linuxdeepin/go-lib/strv" - "github.com/linuxdeepin/dde-api/powersupply/battery" - "github.com/linuxdeepin/dde-daemon/common/dsync" + "sync" ) //go:generate dbusutil-gen em -type Lastore @@ -33,67 +20,22 @@ type Lastore struct { service *dbusutil.Service sysSigLoop *dbusutil.SignalLoop sessionSigLoop *dbusutil.SignalLoop - jobStatus map[dbus.ObjectPath]CacheJobInfo - lang string - inhibitFd dbus.UnixFD - power power.Power - core lastore.Lastore - sysDBusDaemon ofdbus.DBus - notifications notifications.Notifications - sessionManager sessionmanager.SessionManager + core lastore.Lastore + notifications notifications.Notifications - syncConfig *dsync.Config - settings *gio.Settings - rebootTimer *time.Timer - updatingLowPowerPercent float64 - updateNotifyId uint32 - isBackuping bool - isUpdating bool - // 默认间隔时间2小时,但当设置了稍后提醒时间后,需要修改默认时间,单位分钟 - intervalTime uint16 - needShowUpgradeFinishedNotify bool - - notifiedBattery bool - notifyIdHidMap map[uint32]dbusutil.SignalHandlerId - lastoreRule dbusutil.MatchRule - jobsPropsChangedHId dbusutil.SignalHandlerId + syncConfig *dsync.Config + network network.Network // prop: - PropsMu sync.RWMutex - SourceCheckEnabled bool -} - -type CacheJobInfo struct { - Id string - Status Status - Name string - Progress float64 - Type string + PropsMu sync.RWMutex } -const ( - gsSchemaPower = "com.deepin.dde.power" - gsKeyUpdatingLowPowerPercent = "low-power-percent-in-updating-notify" - intervalTime10Min = 10 - intervalTime30Min = 30 - intervalTime120Min = 120 - intervalTime360Min = 360 -) - func newLastore(service *dbusutil.Service) (*Lastore, error) { l := &Lastore{ - service: service, - jobStatus: make(map[dbus.ObjectPath]CacheJobInfo), - inhibitFd: -1, - lang: QueryLang(), - updateNotifyId: 0, - isUpdating: false, - intervalTime: intervalTime120Min, - needShowUpgradeFinishedNotify: false, + service: service, } - - logger.Debugf("CurrentLang: %q", l.lang) + l.network = network.NewNetwork(service.Conn()) systemBus, err := dbus.SystemBus() if err != nil { return nil, err @@ -109,457 +51,30 @@ func newLastore(service *dbusutil.Service) (*Lastore, error) { l.sessionSigLoop = dbusutil.NewSignalLoop(sessionBus, 10) l.sessionSigLoop.Start() - l.sessionManager = sessionmanager.NewSessionManager(sessionBus) - - l.settings = gio.NewSettings(gsSchemaPower) - l.updatingLowPowerPercent = l.settings.GetDouble(gsKeyUpdatingLowPowerPercent) - l.notifyGSettingsChanged() l.initCore(systemBus) l.initNotify(sessionBus) - l.initSysDBusDaemon(systemBus) - l.initPower(systemBus) - l.initABRecovery(systemBus) - l.listenBattery() - l.syncConfig = dsync.NewConfig("updater", &syncConfig{l: l}, - l.sessionSigLoop, dbusPath, logger) + l.syncConfig = dsync.NewConfig("updater", &syncConfig{l: l}, l.sessionSigLoop, dbusPath, logger) return l, nil } -func (l *Lastore) initPower(systemBus *dbus.Conn) { - l.power = power.NewPower(systemBus) - l.power.InitSignalExt(l.sysSigLoop, true) - err := l.power.HasBattery().ConnectChanged(func(hasValue bool, hasBattery bool) { - if !hasBattery { - l.notifiedBattery = false - } - }) - if err != nil { - logger.Warning(err) - } - - err = l.power.OnBattery().ConnectChanged(func(hasValue bool, onBattery bool) { - // 充电状态时,清除低电量横幅提示 - if hasValue && !onBattery { - l.removeLowBatteryInUpdatingNotify() - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (l *Lastore) initABRecovery(systemBus *dbus.Conn) { - abRecovery := abrecovery.NewABRecovery(systemBus) - abRecovery.InitSignalExt(l.sysSigLoop, true) - - err := abRecovery.BackingUp().ConnectChanged(func(hasValue bool, hasBackup bool) { - if hasValue { - if hasBackup { - l.isBackuping = true - if l.needLowBatteryNotify() { - l.lowBatteryInUpdatingNotify() - } - } else { - l.isBackuping = false - } - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (l *Lastore) listenBattery() { - err := l.power.BatteryPercentage().ConnectChanged(func(hasValue bool, value float64) { - if hasValue { - if value > l.updatingLowPowerPercent { - return - } - - if l.needLowBatteryNotify() { - l.lowBatteryInUpdatingNotify() - } - } - }) - if err != nil { - logger.Warning(err) - } -} - func (l *Lastore) initNotify(sessionBus *dbus.Conn) { l.notifications = notifications.NewNotifications(sessionBus) - l.notifications.InitSignalExt(l.sessionSigLoop, true) - - l.notifyIdHidMap = make(map[uint32]dbusutil.SignalHandlerId) - _, err := l.notifications.ConnectNotificationClosed(func(id uint32, reason uint32) { - logger.Debug("notification closed id", id) - hid, ok := l.notifyIdHidMap[id] - if ok { - logger.Debugf("remove id: %d, hid: %d", id, hid) - delete(l.notifyIdHidMap, id) - - // delay call removeHandler - time.AfterFunc(100*time.Millisecond, func() { - l.notifications.RemoveHandler(hid) - }) - } - }) - if err != nil { - logger.Warning(err) - } -} - -func (l *Lastore) initSysDBusDaemon(systemBus *dbus.Conn) { - l.sysDBusDaemon = ofdbus.NewDBus(systemBus) - l.sysDBusDaemon.InitSignalExt(l.sysSigLoop, true) - _, err := l.sysDBusDaemon.ConnectNameOwnerChanged( - func(name string, oldOwner string, newOwner string) { - if name == l.core.ServiceName_() { - if newOwner == "" { - l.offline() - } else { - l.online() - } - } - }) - if err != nil { - logger.Warning(err) - } -} - -var allowPathList = []string{ - "/com/deepin/lastore/Jobprepare_system_upgrade", - "/com/deepin/lastore/Jobprepare_appstore_upgrade", - "/com/deepin/lastore/Jobprepare_security_upgrade", - "/com/deepin/lastore/Jobprepare_unknown_upgrade", - "/com/deepin/lastore/Jobsystem_upgrade", - "/com/deepin/lastore/Jobappstore_upgrade", - "/com/deepin/lastore/Jobsecurity_upgrade", - "/com/deepin/lastore/Jobunknown_upgrade", - "/com/deepin/lastore/Jobdist_upgrade", - "/com/deepin/lastore/Jobprepare_dist_upgrade", -} - -func (l *Lastore) isUpgradeJobType(path dbus.ObjectPath) bool { - job, ok := l.jobStatus[path] - if !ok { - return false - } - if !strv.Strv(allowPathList).Contains(string(path)) { - return false - } - if strings.Contains(string(path), "prepare") && strings.Contains(job.Name, "OnlyDownload") { - return false - } - return true -} - -func (l *Lastore) checkUpdateNotify(path dbus.ObjectPath) { - if !l.isUpgradeJobType(path) { - return - } - - l.isUpdating = true - // 当前job处于 end 状态时,不处理 - if l.jobStatus[path].Status == EndStatus { - l.isUpdating = false - return - } - - if l.needLowBatteryNotify() { - l.lowBatteryInUpdatingNotify() - } - if l.jobStatus[path].Id == SystemUpgradeJobType { - l.needShowUpgradeFinishedNotify = true - } - if !l.needShowUpgradeFinishedNotify { - return - } - - jobList, err := l.core.Manager().JobList().Get(0) - if err != nil { - logger.Warning(err) - } - - if l.jobStatus[path].Status == SucceedStatus { - for _, jobPath := range jobList { - if job, ok := l.jobStatus[jobPath]; ok { - if l.isUpgradeJobType(jobPath) { - if job.Status != SucceedStatus && job.Status != EndStatus && job.Status != FailedStatus { - return - } - if strings.Contains(string(jobPath), "prepare") { - return - } - } - } - } - - l.removeLowBatteryInUpdatingNotify() - l.updateSucceedNotify(l.createUpdateSucceedActions()) - l.isUpdating = false - l.needShowUpgradeFinishedNotify = false - } -} - -func (l *Lastore) needLowBatteryNotify() bool { - if l.updateNotifyId != 0 { - return false - } - - // 横幅未弹出,且处于ABRecovery或update状态时才弹出横幅 - if l.isUpdating || l.isBackuping { - batteryStatus, _ := l.power.BatteryStatus().Get(0) - hasBattery, _ := l.power.HasBattery().Get(0) - onBattery, _ := l.power.OnBattery().Get(0) - percent, _ := l.power.BatteryPercentage().Get(0) - if hasBattery && onBattery && percent < l.updatingLowPowerPercent && - batteryStatus != uint32(battery.StatusCharging) { - return true - } - } - - return false } func (l *Lastore) initCore(systemBus *dbus.Conn) { l.core = lastore.NewLastore(systemBus) - l.lastoreRule = dbusutil.NewMatchRuleBuilder(). - Sender(l.core.ServiceName_()). - Type("signal"). - Interface("org.freedesktop.DBus.Properties"). - Member("PropertiesChanged"). - Build() - err := l.lastoreRule.AddTo(systemBus) - if err != nil { - logger.Warning(err) - } - - l.core.InitSignalExt(l.sysSigLoop, false) - err = l.core.Manager().JobList().ConnectChanged(func(hasValue bool, value []dbus.ObjectPath) { - if !hasValue { - return - } - l.updateJobList(value) - }) - if err != nil { - logger.Warning(err) - } - - l.jobsPropsChangedHId = l.sysSigLoop.AddHandler(&dbusutil.SignalRule{ - Name: "org.freedesktop.DBus.Properties.PropertiesChanged", - }, func(sig *dbus.Signal) { - if len(sig.Body) != 3 { - return - } - props, _ := sig.Body[1].(map[string]dbus.Variant) - ifc, _ := sig.Body[0].(string) - if ifc == "com.deepin.lastore.Job" { - l.updateCacheJobInfo(sig.Path, props) - } - }) - - jobList, err := l.core.Manager().JobList().Get(0) - if err != nil { - logger.Warning(err) - } - - l.updateJobList(jobList) } func (l *Lastore) destroy() { - l.sessionSigLoop.Stop() l.sysSigLoop.Stop() l.syncConfig.Destroy() - - systemBus := l.sysSigLoop.Conn() - err := l.lastoreRule.RemoveFrom(systemBus) - if err != nil { - logger.Warning(err) - } - - l.sysSigLoop.RemoveHandler(l.jobsPropsChangedHId) - l.power.RemoveHandler(proxy.RemoveAllHandlers) - l.core.RemoveHandler(proxy.RemoveAllHandlers) - l.notifications.RemoveHandler(proxy.RemoveAllHandlers) } func (l *Lastore) GetInterfaceName() string { return "com.deepin.LastoreSessionHelper" } -// updateJobList clean invalid cached Job status -// The list is the newest JobList. -func (l *Lastore) updateJobList(list []dbus.ObjectPath) { - var invalids []dbus.ObjectPath - for jobPath := range l.jobStatus { - safe := false - for _, p := range list { - if p == jobPath { - safe = true - break - } - } - if !safe { - invalids = append(invalids, jobPath) - } - } - for _, jobPath := range invalids { - delete(l.jobStatus, jobPath) - } - logger.Debugf("UpdateJobList: %v - %v", list, invalids) -} - -func (l *Lastore) offline() { - logger.Info("Lastore.Daemon Offline") - l.jobStatus = make(map[dbus.ObjectPath]CacheJobInfo) -} - -func (l *Lastore) online() { - logger.Info("Lastore.Daemon Online") -} - -func (l *Lastore) createJobFailedActions(jobId string) []NotifyAction { - ac := []NotifyAction{ - { - Id: "retry", - Name: gettext.Tr("Retry"), - Callback: func() { - err := l.core.Manager().StartJob(dbus.FlagNoAutoStart, jobId) - logger.Infof("StartJob %q : %v", jobId, err) - }, - }, - { - Id: "cancel", - Name: gettext.Tr("Cancel"), - Callback: func() { - err := l.core.Manager().CleanJob(dbus.FlagNoAutoStart, jobId) - logger.Infof("CleanJob %q : %v", jobId, err) - }, - }, - } - return ac -} - -func (l *Lastore) createUpdateActions() []NotifyAction { - ac := []NotifyAction{ - { - Id: "update", - Name: gettext.Tr("Update Now"), - Callback: func() { - go func() { - err := exec.Command("dde-control-center", "-m", "update", "-p", "Checking").Run() - if err != nil { - logger.Warningf("createUpdateActions: %v", err) - } - }() - }, - }, - } - - return ac -} - -func (l *Lastore) resetUpdateSucceedNotifyTimer(intervalTimeMinute uint16) { - l.intervalTime = intervalTimeMinute - if l.rebootTimer == nil { - l.rebootTimer = time.AfterFunc(time.Minute*time.Duration(intervalTimeMinute), func() { - l.updateSucceedNotify(l.createUpdateSucceedActions()) - }) - } else { - l.rebootTimer.Reset(time.Minute * time.Duration(intervalTimeMinute)) - } -} - -func (l *Lastore) createUpdateSucceedActions() []NotifyAction { - ac := []NotifyAction{ - { - Id: notifyActKeyRebootNow, - Name: gettext.Tr("Reboot Now"), - }, - { - Id: notifyActKeyRebootLater, - Name: gettext.Tr("Remind Me Later"), - Callback: func() { - l.resetUpdateSucceedNotifyTimer(intervalTime120Min) - }, - }, - { - Id: notifyActKeyReboot10Minutes, - Name: gettext.Tr("10 mins later"), - Callback: func() { - l.resetUpdateSucceedNotifyTimer(intervalTime10Min) - }, - }, - { - Id: notifyActKeyReboot30Minutes, - Name: gettext.Tr("30 mins later"), - Callback: func() { - l.resetUpdateSucceedNotifyTimer(intervalTime30Min) - }, - }, - { - Id: notifyActKeyReboot2Hours, - Name: gettext.Tr("2h later"), - Callback: func() { - l.resetUpdateSucceedNotifyTimer(intervalTime120Min) - }, - }, - { - Id: notifyActKeyReboot6Hours, - Name: gettext.Tr("6h later"), - Callback: func() { - l.resetUpdateSucceedNotifyTimer(intervalTime360Min) - }, - }, - } - - return ac -} - -func (l *Lastore) notifyJob(path dbus.ObjectPath) { - l.checkBattery() - - info := l.jobStatus[path] - status := info.Status - logger.Debugf("notifyJob: %q %q --> %v", path, status, info) - if info.Name == "uos-release-note" { - logger.Debug("do not notify when package name is uos-release-note") - return - } - switch guestJobTypeFromPath(path) { - case InstallJobType: - switch status { - case FailedStatus: - l.notifyInstall(info.Name, false, l.createJobFailedActions(info.Id)) - case SucceedStatus: - if info.Progress == 1 { - l.notifyInstall(info.Name, true, nil) - } - } - case RemoveJobType: - switch status { - case FailedStatus: - l.notifyRemove(info.Name, false, l.createJobFailedActions(info.Id)) - case SucceedStatus: - l.notifyRemove(info.Name, true, nil) - } - - case CleanJobType: - if status == SucceedStatus && - strings.Contains(info.Name, "+notify") { - l.notifyAutoClean() - } - case UpdateSourceJobType, CustomUpdateJobType: - val, _ := l.core.Updater().UpdatablePackages().Get(0) - if status == SucceedStatus && len(val) > 0 && - strings.Contains(info.Name, "+notify") { - l.notifyUpdateSource(l.createUpdateActions()) - } - } -} - func (*Lastore) IsDiskSpaceSufficient() (result bool, busErr *dbus.Error) { avail, err := queryVFSAvailable("/") if err != nil { @@ -567,123 +82,3 @@ func (*Lastore) IsDiskSpaceSufficient() (result bool, busErr *dbus.Error) { } return avail > 1024*1024*10 /* 10 MB */, nil } - -func (l *Lastore) updateCacheJobInfo(path dbus.ObjectPath, props map[string]dbus.Variant) { - info := l.jobStatus[path] - oldStatus := info.Status - - systemBus := l.sysSigLoop.Conn() - job, err := lastore.NewJob(systemBus, path) - if err != nil { - logger.Warning(err) - return - } - - if info.Id == "" { - if v, ok := props["Id"]; ok { - info.Id, _ = v.Value().(string) - } - if info.Id == "" { - id, _ := job.Id().Get(dbus.FlagNoAutoStart) - info.Id = id - } - } - - if info.Name == "" { - if v, ok := props["Name"]; ok { - info.Name, _ = v.Value().(string) - } - if info.Name == "" { - name, _ := job.Name().Get(dbus.FlagNoAutoStart) - - if name == "" { - pkgs, _ := job.Packages().Get(dbus.FlagNoAutoStart) - if len(pkgs) == 0 { - name = "unknown" - } else { - name = PackageName(pkgs[0], l.lang) - } - } - - info.Name = name - } - } - - if v, ok := props["Progress"]; ok { - info.Progress, _ = v.Value().(float64) - } - - if v, ok := props["Status"]; ok { - status := v.Value().(string) - info.Status = Status(status) - } - - if info.Type == "" { - if v, ok := props["Type"]; ok { - info.Type, _ = v.Value().(string) - } - if info.Type == "" { - info.Type, _ = job.Type().Get(dbus.FlagNoAutoStart) - } - } else { - if v, ok := props["Type"]; ok { - info.Type, _ = v.Value().(string) - } - } - l.jobStatus[path] = info - logger.Debugf("updateCacheJobInfo: %#v", info) - - if oldStatus != info.Status { - l.notifyJob(path) - l.checkUpdateNotify(path) - } -} - -// guestJobTypeFromPath guest the JobType from object path -// We can't get the JobType when the DBusObject destroyed. -func guestJobTypeFromPath(path dbus.ObjectPath) string { - _path := string(path) - for _, jobType := range []string{ - // job types: - InstallJobType, DownloadJobType, RemoveJobType, - UpdateSourceJobType, DistUpgradeJobType, CleanJobType, CustomUpdateJobType, - } { - if strings.Contains(_path, jobType) { - return jobType - } - } - return "" -} - -var MinBatteryPercent = 30.0 - -func (l *Lastore) checkBattery() { - if l.notifiedBattery { - return - } - hasBattery, _ := l.power.HasBattery().Get(0) - onBattery, _ := l.power.OnBattery().Get(0) - percent, _ := l.power.BatteryPercentage().Get(0) - if hasBattery && onBattery && percent <= MinBatteryPercent { - l.notifiedBattery = true - l.notifyLowPower() - } -} - -func (l *Lastore) notifyGSettingsChanged() { - if l.settings == nil { - l.updatingLowPowerPercent = 50 - logger.Warning("failed to get gsetting") - return - } - - gsettings.ConnectChanged(gsSchemaPower, "*", func(key string) { - switch key { - case gsKeyUpdatingLowPowerPercent: - l.updatingLowPowerPercent = l.settings.GetDouble(key) - return - default: - return - } - }) -} diff --git a/lastore/notify.go b/lastore/notify.go deleted file mode 100644 index aa30a839c..000000000 --- a/lastore/notify.go +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-FileCopyrightText: 2018 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package lastore - -import ( - "fmt" - "os" - - "github.com/godbus/dbus" - "github.com/linuxdeepin/go-lib/gettext" -) - -type NotifyAction struct { - Id string - Name string - Callback func() -} - -func getAppStoreAppName() string { - _, err := os.Stat("/usr/share/applications/deepin-app-store.desktop") - if err == nil { - return "deepin-app-store" - } - return "deepin-appstore" -} - -const ( - notifyExpireTimeoutDefault = -1 - notifyExpireTimeoutReboot = 30 * 1000 - systemUpdatedIcon = "system-updated" - notifyActKeyRebootNow = "RebootNow" - notifyActKeyRebootLater = "Later" - notifyActKeyReboot10Minutes = "10Min" - notifyActKeyReboot30Minutes = "30Min" - notifyActKeyReboot2Hours = "2Hr" - notifyActKeyReboot6Hours = "6Hr" -) - -func (l *Lastore) sendNotify(icon string, summary string, msg string, actions []NotifyAction, - hints map[string]dbus.Variant, expireTimeout int32, appName string) { - logger.Infof("sendNotify icon: %s, msg: %q, actions: %v, timeout: %d", - icon, msg, actions, expireTimeout) - n := l.notifications - var as []string - for _, action := range actions { - as = append(as, action.Id, action.Name) - } - - if icon == "" { - icon = "deepin-appstore" - } - id, err := n.Notify(0, appName, 0, icon, summary, - msg, as, hints, expireTimeout) - if err != nil { - logger.Warningf("Notify failed: %q: %v\n", msg, err) - return - } - - if len(actions) == 0 { - return - } - - hid, err := l.notifications.ConnectActionInvoked( - func(id0 uint32, actionId string) { - logger.Debugf("notification action invoked id: %d, actionId: %q", - id0, actionId) - if id != id0 { - return - } - - for _, action := range actions { - if action.Id == actionId && action.Callback != nil { - action.Callback() - return - } - } - logger.Warningf("not found action id %q in %v", actionId, actions) - }) - if err != nil { - logger.Warning(err) - return - } - logger.Debugf("notifyIdHidMap[%d]=%d", id, hid) - l.notifyIdHidMap[id] = hid -} - -// NotifyInstall send desktop notify for install job -func (l *Lastore) notifyInstall(pkgId string, succeed bool, ac []NotifyAction) { - var msg string - if succeed { - msg = fmt.Sprintf(gettext.Tr("%q installed successfully."), pkgId) - l.sendNotify("package_install_succeed", "", msg, ac, nil, notifyExpireTimeoutDefault, getAppStoreAppName()) - } else { - msg = fmt.Sprintf(gettext.Tr("%q failed to install."), pkgId) - l.sendNotify("package_install_failed", "", msg, ac, nil, notifyExpireTimeoutDefault, getAppStoreAppName()) - } -} - -func (l *Lastore) notifyRemove(pkgId string, succeed bool, ac []NotifyAction) { - var msg string - if succeed { - msg = gettext.Tr("Removed successfully") - } else { - msg = gettext.Tr("Failed to remove the app") - } - l.sendNotify("deepin-appstore", "", msg, ac, nil, notifyExpireTimeoutDefault, getAppStoreAppName()) -} - -//NotifyLowPower send notify for low power -func (l *Lastore) notifyLowPower() { - msg := gettext.Tr("In order to prevent automatic shutdown, please plug in for normal update.") - l.sendNotify("notification-battery_low", "", msg, nil, nil, notifyExpireTimeoutDefault, getAppStoreAppName()) -} - -func (l *Lastore) notifyAutoClean() { - msg := gettext.Tr("Package cache wiped") - l.sendNotify("deepin-appstore", "", msg, nil, nil, notifyExpireTimeoutDefault, "dde-control-center") -} - -func (l *Lastore) notifyUpdateSource(actions []NotifyAction) { - msg := gettext.Tr("Updates Available") - l.sendNotify("preferences-system", "", msg, actions, nil, notifyExpireTimeoutDefault, "dde-control-center") -} - -func (l *Lastore) updateSucceedNotify(actions []NotifyAction) { - summary := gettext.Tr("Reboot after Updates") - msg := gettext.Tr("Restart the computer to use the system and applications properly") - hints := map[string]dbus.Variant{"x-deepin-action-RebootNow": dbus.MakeVariant("busctl,--user,call,com.deepin.SessionManager," + - "/com/deepin/SessionManager,com.deepin.SessionManager,RequestReboot")} - l.sendNotify(systemUpdatedIcon, summary, msg, actions, hints, notifyExpireTimeoutReboot, "dde-control-center") - - // 默认弹出横幅时间为每2小时 - l.resetUpdateSucceedNotifyTimer(l.intervalTime) -} - -func (l *Lastore) lowBatteryInUpdatingNotify() { - msg := gettext.Tr("Your system is being updated, but the capacity is lower than 50%, please plug in to avoid power outage") - actions := []string{"ok", gettext.Tr("OK")} - notifyID, err := l.notifications.Notify(0, - "dde-control-center", - 0, - systemUpdatedIcon, - "", - msg, - actions, - nil, - 0, - ) - - if err != nil { - logger.Warning("failed to send notify:", err) - return - } - l.updateNotifyId = notifyID -} - -func (l *Lastore) removeLowBatteryInUpdatingNotify() { - err := l.notifications.CloseNotification(0, l.updateNotifyId) - if err != nil { - logger.Warningf("close low battery in updating notification failed,err:%v", err) - } - l.updateNotifyId = 0 -} diff --git a/lastore/system.go b/lastore/system.go deleted file mode 100644 index 8d1f498fc..000000000 --- a/lastore/system.go +++ /dev/null @@ -1,51 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -package lastore - -import ( - "encoding/json" - "os" -) - -const ( - DownloadJobType = "download" - InstallJobType = "install" - RemoveJobType = "remove" - UpdateJobType = "update" - DistUpgradeJobType = "dist_upgrade" - PrepareDistUpgradeJobType = "prepare_dist_upgrade" - UpdateSourceJobType = "update_source" - CustomUpdateJobType = "custom_update" - CleanJobType = "clean" - SystemUpgradeJobType = "system_upgrade" -) - -type Status string - -const ( - ReadyStatus Status = "ready" - RunningStatus Status = "running" - FailedStatus Status = "failed" - SucceedStatus Status = "succeed" - PausedStatus Status = "paused" - - EndStatus = "end" -) -const varLibDir = "/var/lib/lastore" - -func decodeJson(fpath string, d interface{}) error { - f, err := os.Open(fpath) - if err != nil { - return err - } - defer func() { - err := f.Close() - if err != nil { - logger.Warning(err) - } - }() - - return json.NewDecoder(f).Decode(&d) -} diff --git a/lastore/tools.go b/lastore/tools.go index dbc807f41..42847922b 100644 --- a/lastore/tools.go +++ b/lastore/tools.go @@ -11,84 +11,10 @@ package lastore import "C" import ( - "os" - "path" "sort" - "strings" "unsafe" ) -// QueryLang return user lang. -// the rule is document at man gettext(3) -func QueryLang() string { - return QueryLangs()[0] -} - -// QueryLangs return array of user lang, split by ":". -// the rule is document at man gettext(3) -func QueryLangs() []string { - LC_ALL := os.Getenv("LC_ALL") - LC_MESSAGE := os.Getenv("LC_MESSAGE") - LANGUAGE := os.Getenv("LANGUAGE") - LANG := os.Getenv("LANG") - - cutoff := func(s string) string { - for i, c := range s { - if c == '.' { - return s[:i] - } - } - return s - } - - if LC_ALL != "C" && LANGUAGE != "" { - var r []string - for _, lang := range strings.Split(LANGUAGE, ":") { - r = append(r, cutoff(lang)) - } - return r - } - - if LC_ALL != "" { - return []string{cutoff(LC_ALL)} - } - if LC_MESSAGE != "" { - return []string{cutoff(LC_MESSAGE)} - } - if LANG != "" { - return []string{cutoff(LANG)} - } - return []string{""} -} - -func PackageName(pkg string, lang string) string { - names := make(map[string]struct { - Id string `json:"id"` - Name string `json:"name"` - LocaleName map[string]string `json:"locale_name"` - }) - - err := decodeJson(path.Join(varLibDir, "applications.json"), &names) - if err != nil { - logger.Warning(err) - } - - info, ok := names[pkg] - if !ok { - return pkg - } - - name := info.LocaleName[lang] - if name == "" { - if info.Name != "" { - name = info.Name - } else { - name = pkg - } - } - return name -} - func strSliceSetEqual(a, b []string) bool { if len(a) != len(b) { return false