-
Notifications
You must be signed in to change notification settings - Fork 3
/
software_updatable.go
154 lines (135 loc) · 5.65 KB
/
software_updatable.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright (c) 2021 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
package hawkbit
import (
"sync"
"github.com/eclipse/ditto-clients-golang"
"github.com/eclipse/ditto-clients-golang/model"
"github.com/eclipse/ditto-clients-golang/protocol"
"github.com/eclipse/ditto-clients-golang/protocol/things"
)
// SoftwareUpdatable is the HawkBit's library actual implementation.
// It provides SoftwareUpdatable capabilities to a specified Thing.
type SoftwareUpdatable struct {
dittoClient *ditto.Client
thingID *model.NamespacedID
featureID string
//handlers
downloadHandler DownloadHandler
installHandler InstallHandler
cancelHandler CancelHandler
removeHandler RemoveHandler
cancelRemoveHandler CancelRemoveHandler
statusLock sync.Mutex
status *softwareUpdatableStatus
active bool
}
// NewSoftwareUpdatable creates new SoftwareUpdatable instance, which will
// manage the SoftwareUdpate feature with the specified type to the provided
// Thing via Ditto client connection.
func NewSoftwareUpdatable(cfg *Configuration) (*SoftwareUpdatable, error) {
// Check for missing mandatory configuration values.
if err := validateConfiguration(cfg); err != nil {
return nil, err
}
return &SoftwareUpdatable{
dittoClient: cfg.dittoClient,
thingID: cfg.thingID,
featureID: cfg.featureID,
downloadHandler: cfg.downloadHandler,
installHandler: cfg.installHandler,
cancelHandler: cfg.cancelHandler,
removeHandler: cfg.removeHandler,
cancelRemoveHandler: cfg.cancelRemoveHandler,
status: &softwareUpdatableStatus{
SoftwareModuleType: cfg.softwareType,
InstalledDependencies: map[string]*DependencyDescription{},
},
active: false,
}, nil
}
// Activate subscribes for incoming Ditto messages and send SoftwareUpdatable
// feature initial information. If any error occurs during the feature
// initiation - it's returned here.
func (su *SoftwareUpdatable) Activate() error {
// Do not allow multiple goroutes to access SU status!
su.statusLock.Lock()
defer su.statusLock.Unlock()
// Do not activate already activated feature.
if su.active {
return nil
}
// Create new SoftwareUpdatable feature event.
INFO.Printf("Create new SoftwareUpdatable[%s] feature in: %s", su.status.SoftwareModuleType, su.thingID)
feature := (&model.Feature{}).
WithDefinition(model.NewDefinitionID(suDefinitionNamespace, suDefinitionName, suDefinitionVersion)).
WithProperty(suPropertyStatus, su.status)
event := things.NewCommand(su.thingID).Feature(su.featureID).Modify(feature).Twin()
// Add the SoftwareUpdatable feature.
su.dittoClient.Subscribe(su.messagesHandler)
if err := su.dittoClient.Send(event.Envelope(protocol.WithResponseRequired(false))); err != nil {
su.dittoClient.Unsubscribe()
return err
}
su.active = true
return nil
}
// Deactivate unsubscribes from incoming Ditto messages.
func (su *SoftwareUpdatable) Deactivate() {
// Do not allow multiple goroutes to access SU status!
su.statusLock.Lock()
defer su.statusLock.Unlock()
su.dittoClient.Unsubscribe()
su.active = false
}
// SetInstalledDependencies set the entire set of installed dependencies of
// underlying SoftwareUpdatable feature.
// Note: Involking this function before the feature activation will change
// its initial installed dependencies value.
func (su *SoftwareUpdatable) SetInstalledDependencies(deps ...*DependencyDescription) error {
// Do not allow multiple goroutes to access SU status!
su.statusLock.Lock()
defer su.statusLock.Unlock()
DEBUG.Printf("Set installed dependencies: %v", deps)
su.status.InstalledDependencies = toDependencyDescriptionMap(deps...)
return su.setProperty(suPropertyInstalledDependencies, su.status.InstalledDependencies)
}
// SetContextDependencies set the entire set of context dependencies of
// underlying SoftwareUpdatable feature.
// Note: Involking this function before the feature activation will change
// its initial context dependencies value.
func (su *SoftwareUpdatable) SetContextDependencies(deps ...*DependencyDescription) error {
// Do not allow multiple goroutes to access SU status!
su.statusLock.Lock()
defer su.statusLock.Unlock()
su.status.ContextDependencies = toDependencyDescriptionMap(deps...)
return su.setProperty(suPropertyContextDependencies, su.status.ContextDependencies)
}
// SetLastOperation set the last operation and last failed operation (if needed) of
// underlying SoftwareUpdatable feature.
// Note: Involking this function before the feature activation will change
// its initial last operation and last failed operation values.
func (su *SoftwareUpdatable) SetLastOperation(os *OperationStatus) error {
// Do not allow multiple goroutes to access SU status!
su.statusLock.Lock()
defer su.statusLock.Unlock()
// Check if OperationStatus has failed status, if so, update the LastFailedOperation.
su.status.LastOperation = os
if os != nil && (os.Status == StatusFinishedError || os.Status == StatusFinishedRejected ||
os.Status == StatusCancelRejected) {
su.status.LastFailedOperation = su.status.LastOperation
if err := su.setProperty(suPropertyLastFailedOperation, su.status.LastFailedOperation); err != nil {
return err
}
}
return su.setProperty(suPropertyLastOperation, su.status.LastOperation)
}