forked from cozy/cozy-stack
/
apps.go
193 lines (174 loc) · 5.48 KB
/
apps.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package app
import (
"fmt"
"io"
"net/url"
"path"
"time"
"github.com/cozy/cozy-stack/model/instance"
"github.com/cozy/cozy-stack/model/permission"
"github.com/cozy/cozy-stack/model/vfs"
"github.com/cozy/cozy-stack/model/vfs/vfsafero"
"github.com/cozy/cozy-stack/pkg/appfs"
"github.com/cozy/cozy-stack/pkg/config/config"
"github.com/cozy/cozy-stack/pkg/consts"
"github.com/cozy/cozy-stack/pkg/couchdb"
"github.com/cozy/cozy-stack/pkg/prefixer"
"github.com/spf13/afero"
)
const (
// ManifestMaxSize is the manifest maximum size
ManifestMaxSize = 2 << (2 * 10) // 2MB
// WebappManifestName is the name of the manifest at the root of the
// client-side application directory
WebappManifestName = "manifest.webapp"
// KonnectorManifestName is the name of the manifest at the root of the
// konnector application directory
KonnectorManifestName = "manifest.konnector"
)
// State is the state of the application
type State string
const (
// Installing state
Installing = "installing"
// Upgrading state
Upgrading = "upgrading"
// Installed state, can be used to state that an application has been
// installed but needs a user interaction to be activated and "ready".
Installed = "installed"
// Ready state
Ready = "ready"
// Errored state
Errored = "errored"
)
// KonnectorArchiveName is the name of the archive created to store the
// konnectors sources.
const KonnectorArchiveName = "app.tar"
// SubDomainer is an interface with a single method to build an URL from a slug
type SubDomainer interface {
SubDomain(s string) *url.URL
}
// Manifest interface is used by installer to encapsulate the manifest metadata
// that can represent either a webapp or konnector manifest
type Manifest interface {
couchdb.Doc
Fetch(field string) []string
ReadManifest(i io.Reader, slug, sourceURL string) (Manifest, error)
Create(db prefixer.Prefixer) error
Update(db prefixer.Prefixer, extraPerms permission.Set) error
Delete(db prefixer.Prefixer) error
AppType() consts.AppType
Permissions() permission.Set
Source() string
Version() string
AvailableVersion() string
Checksum() string
Slug() string
State() State
LastUpdate() time.Time
Terms() Terms
Name() string
Icon() string
Notifications() Notifications
SetError(err error)
Error() error
SetSlug(slug string)
SetSource(src *url.URL)
SetState(state State)
SetVersion(version string)
SetAvailableVersion(version string)
SetChecksum(shasum string)
}
// GetBySlug returns an app manifest identified by its slug
func GetBySlug(db prefixer.Prefixer, slug string, appType consts.AppType) (Manifest, error) {
var man Manifest
var err error
switch appType {
case consts.WebappType:
man, err = GetWebappBySlug(db, slug)
case consts.KonnectorType:
man, err = GetKonnectorBySlug(db, slug)
}
if err != nil {
return nil, err
}
return man, nil
}
func routeMatches(path, ctx []string) bool {
for i, part := range ctx {
if path[i] != part {
return false
}
}
return true
}
// UpgradeInstalledState is used to force the legacy "installed" state to
// "ready" for a webapp or a konnector manifest
func UpgradeInstalledState(inst *instance.Instance, man Manifest) error {
if man.State() == Installed {
man.SetState(Ready)
return man.Update(inst, nil)
}
return nil
}
// Copier returns the application copier associated with the specified
// application type
func Copier(appsType consts.AppType, inst *instance.Instance) appfs.Copier {
fsURL := config.FsURL()
switch fsURL.Scheme {
case config.SchemeFile:
var baseDirName string
switch appsType {
case consts.WebappType:
baseDirName = vfs.WebappsDirName
case consts.KonnectorType:
baseDirName = vfs.KonnectorsDirName
}
baseFS := afero.NewBasePathFs(afero.NewOsFs(),
path.Join(fsURL.Path, inst.DirName(), baseDirName))
return appfs.NewAferoCopier(baseFS)
case config.SchemeMem:
baseFS := vfsafero.GetMemFS("apps")
return appfs.NewAferoCopier(baseFS)
case config.SchemeSwift, config.SchemeSwiftSecure:
return appfs.NewSwiftCopier(config.GetSwiftConnection(), appsType)
default:
panic(fmt.Sprintf("instance: unknown storage provider %s", fsURL.Scheme))
}
}
// AppsFileServer returns the web-application file server associated to this
// instance.
func AppsFileServer(i *instance.Instance) appfs.FileServer {
fsURL := config.FsURL()
switch fsURL.Scheme {
case config.SchemeFile:
baseFS := afero.NewBasePathFs(afero.NewOsFs(),
path.Join(fsURL.Path, i.DirName(), vfs.WebappsDirName))
return appfs.NewAferoFileServer(baseFS, nil)
case config.SchemeMem:
baseFS := vfsafero.GetMemFS("apps")
return appfs.NewAferoFileServer(baseFS, nil)
case config.SchemeSwift, config.SchemeSwiftSecure:
return appfs.NewSwiftFileServer(config.GetSwiftConnection(), consts.WebappType)
default:
panic(fmt.Sprintf("instance: unknown storage provider %s", fsURL.Scheme))
}
}
// KonnectorsFileServer returns the web-application file server associated to this
// instance.
func KonnectorsFileServer(i *instance.Instance) appfs.FileServer {
fsURL := config.FsURL()
switch fsURL.Scheme {
case config.SchemeFile:
baseFS := afero.NewBasePathFs(afero.NewOsFs(),
path.Join(fsURL.Path, i.DirName(), vfs.KonnectorsDirName))
return appfs.NewAferoFileServer(baseFS, nil)
case config.SchemeMem:
baseFS := vfsafero.GetMemFS("apps")
return appfs.NewAferoFileServer(baseFS, nil)
case config.SchemeSwift, config.SchemeSwiftSecure:
return appfs.NewSwiftFileServer(config.GetSwiftConnection(), consts.KonnectorType)
default:
panic(fmt.Sprintf("instance: unknown storage provider %s", fsURL.Scheme))
}
}