1 | import R from "ramda";
|
2 | import Promise from "bluebird";
|
3 | import uuid from "uuid";
|
4 | import shell from "shelljs";
|
5 | import app from "./app";
|
6 | import gateway from "./gateway";
|
7 | import log from "./log";
|
8 | import start from "./main-start";
|
9 | import manifest from "./manifest";
|
10 | import { promises } from "./util";
|
11 | import pubSub from "./pub-sub";
|
12 | import {
|
13 | DEFAULT_APP_PORT,
|
14 | DEFAULT_TARGET_FOLDER,
|
15 | } from "./const";
|
16 |
|
17 |
|
18 |
|
19 |
|
20 | if (shell.exec("pm2 -v", { silent: true }).code !== 0) {
|
21 | log.warn("WARNING: The PM2 (Process Manager) must be install globally, run: `npm install -g pm2`.");
|
22 | }
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | export default (settings = {}) => {
|
44 | const userAgent = settings.userAgent || "app-syncer";
|
45 | const token = settings.token;
|
46 | let rabbitMQ = settings.rabbitMQ;
|
47 | let publishEvent;
|
48 |
|
49 | const api = {
|
50 | uid: uuid.v4().toString(),
|
51 | apps: [],
|
52 | userAgent,
|
53 | targetFolder: settings.targetFolder || DEFAULT_TARGET_FOLDER,
|
54 |
|
55 | |
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 | add(id, repo, route, options = {}) {
|
68 |
|
69 | if (R.find(item => item.id === id, this.apps)) {
|
70 | throw new Error(`An app with the ID '${ id }' has already been registered.`);
|
71 | }
|
72 | if (R.find(item => item.route.toString() === route, this.apps)) {
|
73 | throw new Error(`An app with the route '${ route }' has already been registered.`);
|
74 | }
|
75 |
|
76 |
|
77 | const port = DEFAULT_APP_PORT + (this.apps.length);
|
78 | const item = app({
|
79 | userAgent,
|
80 | token,
|
81 | targetFolder: this.targetFolder,
|
82 | id,
|
83 | repo,
|
84 | route,
|
85 | port,
|
86 | branch: options.branch,
|
87 | publishEvent
|
88 | });
|
89 | this.apps.push(item);
|
90 |
|
91 |
|
92 | return this;
|
93 | },
|
94 |
|
95 |
|
96 | |
97 |
|
98 |
|
99 |
|
100 |
|
101 | remove(id) {
|
102 | return new Promise((resolve, reject) => {
|
103 | Promise.coroutine(function*() {
|
104 | const removeApp = R.find(item => item.id === id, this.apps);
|
105 | if (!removeApp) {
|
106 | reject(new Error(`An app with the id '#{ id }' does not exist.`));
|
107 | } else {
|
108 | log.info(`Removing app '${ id }'`);
|
109 |
|
110 |
|
111 | yield removeApp.stop();
|
112 |
|
113 |
|
114 | const index = R.findIndex(item => item.id === id, this.apps);
|
115 | this.apps.splice(index, 1);
|
116 |
|
117 |
|
118 | resolve({});
|
119 | }
|
120 | }).call(this);
|
121 | });
|
122 | },
|
123 |
|
124 |
|
125 | |
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 | download(options = {}) {
|
133 | return new Promise((resolve, reject) => {
|
134 | promises(this.apps.map(item => item.download(options)))
|
135 | .then(result => resolve({ apps: result.results }))
|
136 | .catch(err => reject(err));
|
137 | });
|
138 | },
|
139 |
|
140 |
|
141 |
|
142 | |
143 |
|
144 |
|
145 |
|
146 |
|
147 | update(options = {}) {
|
148 | return new Promise((resolve, reject) => {
|
149 | const updatingApps = this.apps.map(item => item.downloading
|
150 | ? null
|
151 | : item.update(options));
|
152 | promises(updatingApps)
|
153 | .then(result => resolve({ apps: result.results }))
|
154 | .catch(err => reject(err));
|
155 | });
|
156 | },
|
157 |
|
158 |
|
159 |
|
160 | |
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | start(options = {}) {
|
167 | return start(
|
168 | this.apps,
|
169 | (args) => this.update(args),
|
170 | settings.apiRoute,
|
171 | this.manifest,
|
172 | options
|
173 | );
|
174 | },
|
175 |
|
176 |
|
177 |
|
178 | |
179 |
|
180 |
|
181 |
|
182 | stop() {
|
183 | log.info("Stopping...");
|
184 | return new Promise((resolve) => {
|
185 | gateway.stop();
|
186 | this.apps.forEach(item => item.stop());
|
187 | log.info("");
|
188 | log.info("Gateway and apps stopped.");
|
189 | resolve({});
|
190 | });
|
191 | }
|
192 | };
|
193 |
|
194 | return new Promise((resolve, reject) => {
|
195 | Promise.coroutine(function*() {
|
196 |
|
197 |
|
198 | if (settings.manifest) {
|
199 | api.manifest = manifest(userAgent, token, settings.manifest, api);
|
200 | log.info(`Reading manifest from: ${ api.manifest.repo.fullPath }`);
|
201 | yield api.manifest.get().catch(err => reject(err));
|
202 |
|
203 |
|
204 | const current = api.manifest.current;
|
205 | if (current) {
|
206 |
|
207 | if (current.targetFolder) {
|
208 | api.targetFolder = current.targetFolder;
|
209 | }
|
210 |
|
211 |
|
212 | if (!rabbitMQ && current.rabbitMQ) {
|
213 | rabbitMQ = current.rabbitMQ;
|
214 | }
|
215 | }
|
216 |
|
217 | if (rabbitMQ) {
|
218 | publishEvent = pubSub(api.uid, api.apps, rabbitMQ).publish;
|
219 | }
|
220 | }
|
221 |
|
222 |
|
223 | resolve(api);
|
224 |
|
225 | }).call(this);
|
226 | });
|
227 | };
|