Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

api.js 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. const apiCache = {};
  2. function Api(app, requireName) {
  3. this.app = app;
  4. this.requireName = requireName;
  5. }
  6. Api.prototype.initialize = function () {
  7. const self = this;
  8. return self.load().then(self.addApiCommands.bind(self));
  9. };
  10. Api.prototype.addApiCommands = function (api) {
  11. if (!this.nodeIntegration) return;
  12. this.addRenderProcessApis(api.electron);
  13. this.addMainProcessApis(api.electron.remote);
  14. this.addBrowserWindowApis(api.browserWindow);
  15. this.addWebContentsApis(api.webContents);
  16. this.addProcessApis(api.rendererProcess);
  17. this.api = {
  18. browserWindow: api.browserWindow,
  19. electron: api.electron,
  20. rendererProcess: api.rendererProcess,
  21. webContents: api.webContents
  22. };
  23. this.addClientProperties();
  24. };
  25. Api.prototype.load = function () {
  26. const self = this;
  27. return this.isNodeIntegrationEnabled().then(function (nodeIntegration) {
  28. self.nodeIntegration = nodeIntegration;
  29. if (!nodeIntegration) {
  30. return {
  31. electron: { remote: {} },
  32. browserWindow: {},
  33. webContents: {},
  34. rendererProcess: {}
  35. };
  36. }
  37. return self.getVersion().then(function (version) {
  38. const api = apiCache[version];
  39. if (api) return api;
  40. return self.loadApi().then(function (api) {
  41. if (version) apiCache[version] = api;
  42. return api;
  43. });
  44. });
  45. });
  46. };
  47. Api.prototype.isNodeIntegrationEnabled = function () {
  48. const self = this;
  49. return self.app.client.execute(function (requireName) {
  50. return typeof window[requireName] === 'function';
  51. }, self.requireName);
  52. };
  53. Api.prototype.getVersion = function () {
  54. return this.app.client.execute(function (requireName) {
  55. const process = window[requireName]('process');
  56. if (process != null && process.versions != null) {
  57. return process.versions.electron;
  58. }
  59. }, this.requireName);
  60. };
  61. Api.prototype.loadApi = function () {
  62. return this.app.client.execute(function (requireName) {
  63. if (typeof window[requireName] !== 'function') {
  64. throw new Error(
  65. 'Could not find global require method with name: ' + requireName
  66. );
  67. }
  68. const electron = window[requireName]('electron');
  69. const process = window[requireName]('process');
  70. const api = {
  71. browserWindow: {},
  72. electron: {},
  73. rendererProcess: {},
  74. webContents: {}
  75. };
  76. function ignoreModule(moduleName) {
  77. switch (moduleName) {
  78. case 'CallbacksRegistry':
  79. case 'deprecate':
  80. case 'deprecations':
  81. case 'hideInternalModules':
  82. case 'Tray':
  83. return true;
  84. case 'inAppPurchase':
  85. return process.platform !== 'darwin';
  86. }
  87. return false;
  88. }
  89. function isRemoteFunction(name) {
  90. switch (name) {
  91. case 'BrowserWindow':
  92. case 'Menu':
  93. case 'MenuItem':
  94. return false;
  95. }
  96. return typeof electron.remote[name] === 'function';
  97. }
  98. function ignoreApi(apiName) {
  99. switch (apiName) {
  100. case 'prototype':
  101. return true;
  102. default:
  103. return apiName[0] === '_';
  104. }
  105. }
  106. function addModule(parent, parentName, name, api) {
  107. api[name] = {};
  108. for (const key in parent[name]) {
  109. if (ignoreApi(key)) continue;
  110. api[name][key] = parentName + '.' + name + '.' + key;
  111. }
  112. }
  113. function addRenderProcessModules() {
  114. Object.getOwnPropertyNames(electron).forEach(function (key) {
  115. if (ignoreModule(key)) return;
  116. if (key === 'remote') return;
  117. addModule(electron, 'electron', key, api.electron);
  118. });
  119. }
  120. function addMainProcessModules() {
  121. api.electron.remote = {};
  122. Object.getOwnPropertyNames(electron.remote).forEach(function (key) {
  123. if (ignoreModule(key)) return;
  124. if (isRemoteFunction(key)) {
  125. api.electron.remote[key] = 'electron.remote.' + key;
  126. } else {
  127. addModule(
  128. electron.remote,
  129. 'electron.remote',
  130. key,
  131. api.electron.remote
  132. );
  133. }
  134. });
  135. addModule(
  136. electron.remote,
  137. 'electron.remote',
  138. 'process',
  139. api.electron.remote
  140. );
  141. }
  142. function addBrowserWindow() {
  143. const currentWindow = electron.remote.getCurrentWindow();
  144. for (const name in currentWindow) {
  145. if (ignoreApi(name)) continue;
  146. const value = currentWindow[name];
  147. if (typeof value === 'function') {
  148. api.browserWindow[name] = 'browserWindow.' + name;
  149. }
  150. }
  151. }
  152. function addWebContents() {
  153. const webContents = electron.remote.getCurrentWebContents();
  154. for (const name in webContents) {
  155. if (ignoreApi(name)) continue;
  156. const value = webContents[name];
  157. if (typeof value === 'function') {
  158. api.webContents[name] = 'webContents.' + name;
  159. }
  160. }
  161. }
  162. function addProcess() {
  163. if (typeof process !== 'object') return;
  164. for (const name in process) {
  165. if (ignoreApi(name)) continue;
  166. api.rendererProcess[name] = 'process.' + name;
  167. }
  168. }
  169. addRenderProcessModules();
  170. addMainProcessModules();
  171. addBrowserWindow();
  172. addWebContents();
  173. addProcess();
  174. return api;
  175. }, this.requireName);
  176. };
  177. Api.prototype.addClientProperty = function (name) {
  178. const self = this;
  179. const clientPrototype = Object.getPrototypeOf(self.app.client);
  180. Object.defineProperty(clientPrototype, name, {
  181. get: function () {
  182. const client = this;
  183. return transformObject(self.api[name], {}, function (value) {
  184. return client[value].bind(client);
  185. });
  186. }
  187. });
  188. };
  189. Api.prototype.addClientProperties = function () {
  190. this.addClientProperty('electron');
  191. this.addClientProperty('browserWindow');
  192. this.addClientProperty('webContents');
  193. this.addClientProperty('rendererProcess');
  194. Object.defineProperty(Object.getPrototypeOf(this.app.client), 'mainProcess', {
  195. get: function () {
  196. return this.electron.remote.process;
  197. }
  198. });
  199. };
  200. Api.prototype.addRenderProcessApis = function (api) {
  201. const app = this.app;
  202. const self = this;
  203. const electron = {};
  204. app.electron = electron;
  205. Object.keys(api).forEach(function (moduleName) {
  206. if (moduleName === 'remote') return;
  207. electron[moduleName] = {};
  208. const moduleApi = api[moduleName];
  209. Object.keys(moduleApi).forEach(function (key) {
  210. const commandName = moduleApi[key];
  211. app.client.addCommand(commandName, function () {
  212. const args = Array.prototype.slice.call(arguments);
  213. return this.execute(
  214. callRenderApi,
  215. moduleName,
  216. key,
  217. args,
  218. self.requireName
  219. );
  220. });
  221. electron[moduleName][key] = function () {
  222. return app.client[commandName].apply(app.client, arguments);
  223. };
  224. });
  225. });
  226. };
  227. Api.prototype.addMainProcessApis = function (api) {
  228. const app = this.app;
  229. const self = this;
  230. const remote = {};
  231. app.electron.remote = remote;
  232. Object.keys(api)
  233. .filter(function (propertyName) {
  234. return typeof api[propertyName] === 'string';
  235. })
  236. .forEach(function (name) {
  237. const commandName = api[name];
  238. app.client.addCommand(commandName, function () {
  239. const args = Array.prototype.slice.call(arguments);
  240. return this.execute(callMainApi, '', name, args, self.requireName);
  241. });
  242. remote[name] = function () {
  243. return app.client[commandName].apply(app.client, arguments);
  244. };
  245. });
  246. Object.keys(api)
  247. .filter(function (moduleName) {
  248. return typeof api[moduleName] === 'object';
  249. })
  250. .forEach(function (moduleName) {
  251. remote[moduleName] = {};
  252. const moduleApi = api[moduleName];
  253. Object.keys(moduleApi).forEach(function (key) {
  254. const commandName = moduleApi[key];
  255. app.client.addCommand(commandName, function () {
  256. const args = Array.prototype.slice.call(arguments);
  257. return this.execute(
  258. callMainApi,
  259. moduleName,
  260. key,
  261. args,
  262. self.requireName
  263. );
  264. });
  265. remote[moduleName][key] = function () {
  266. return app.client[commandName].apply(app.client, arguments);
  267. };
  268. });
  269. });
  270. };
  271. Api.prototype.addBrowserWindowApis = function (api) {
  272. const app = this.app;
  273. const self = this;
  274. app.browserWindow = {};
  275. const asyncApis = {
  276. 'browserWindow.capturePage': true
  277. };
  278. Object.keys(api)
  279. .filter(function (name) {
  280. return !Object.prototype.hasOwnProperty.call(asyncApis, api[name]);
  281. })
  282. .forEach(function (name) {
  283. const commandName = api[name];
  284. app.client.addCommand(commandName, function () {
  285. const args = Array.prototype.slice.call(arguments);
  286. return this.execute(callBrowserWindowApi, name, args, self.requireName);
  287. });
  288. app.browserWindow[name] = function () {
  289. return app.client[commandName].apply(app.client, arguments);
  290. };
  291. });
  292. this.addCapturePageSupport();
  293. };
  294. Api.prototype.addCapturePageSupport = function () {
  295. const app = this.app;
  296. const self = this;
  297. app.client.addCommand('browserWindow.capturePage', function (rect) {
  298. return this.executeAsync(
  299. async function (rect, requireName, done) {
  300. const args = [];
  301. if (rect != null) args.push(rect);
  302. const browserWindow = window[requireName](
  303. 'electron'
  304. ).remote.getCurrentWindow();
  305. const image = await browserWindow.capturePage.apply(
  306. browserWindow,
  307. args
  308. );
  309. if (image != null) {
  310. done(image.toPNG().toString('base64'));
  311. } else {
  312. done(image);
  313. }
  314. },
  315. rect,
  316. self.requireName
  317. ).then(function (image) {
  318. return Buffer.from(image, 'base64');
  319. });
  320. });
  321. app.browserWindow.capturePage = function () {
  322. return app.client['browserWindow.capturePage'].apply(app.client, arguments);
  323. };
  324. };
  325. Api.prototype.addWebContentsApis = function (api) {
  326. const app = this.app;
  327. const self = this;
  328. app.webContents = {};
  329. const asyncApis = {
  330. 'webContents.savePage': true,
  331. 'webContents.executeJavaScript': true
  332. };
  333. Object.keys(api)
  334. .filter(function (name) {
  335. return !Object.prototype.hasOwnProperty.call(asyncApis, api[name]);
  336. })
  337. .forEach(function (name) {
  338. const commandName = api[name];
  339. app.client.addCommand(commandName, function () {
  340. const args = Array.prototype.slice.call(arguments);
  341. return this.execute(callWebContentsApi, name, args, self.requireName);
  342. });
  343. app.webContents[name] = function () {
  344. return app.client[commandName].apply(app.client, arguments);
  345. };
  346. });
  347. this.addSavePageSupport();
  348. this.addExecuteJavaScriptSupport();
  349. };
  350. Api.prototype.addSavePageSupport = function () {
  351. const app = this.app;
  352. const self = this;
  353. app.client.addCommand('webContents.savePage', function (fullPath, saveType) {
  354. return this.executeAsync(
  355. async function (fullPath, saveType, requireName, done) {
  356. const webContents = window[requireName](
  357. 'electron'
  358. ).remote.getCurrentWebContents();
  359. await webContents.savePage(fullPath, saveType);
  360. done();
  361. },
  362. fullPath,
  363. saveType,
  364. self.requireName
  365. ).then(function (rawError) {
  366. if (rawError) {
  367. const error = new Error(rawError.message);
  368. if (rawError.name) error.name = rawError.name;
  369. throw error;
  370. }
  371. });
  372. });
  373. app.webContents.savePage = function () {
  374. return app.client['webContents.savePage'].apply(app.client, arguments);
  375. };
  376. };
  377. Api.prototype.addExecuteJavaScriptSupport = function () {
  378. const app = this.app;
  379. const self = this;
  380. app.client.addCommand(
  381. 'webContents.executeJavaScript',
  382. function (code, useGesture) {
  383. return this.executeAsync(
  384. async function (code, useGesture, requireName, done) {
  385. const webContents = window[requireName](
  386. 'electron'
  387. ).remote.getCurrentWebContents();
  388. const result = await webContents.executeJavaScript(code, useGesture);
  389. done(result);
  390. },
  391. code,
  392. useGesture,
  393. self.requireName
  394. );
  395. }
  396. );
  397. app.webContents.executeJavaScript = function () {
  398. return app.client['webContents.executeJavaScript'].apply(
  399. app.client,
  400. arguments
  401. );
  402. };
  403. };
  404. Api.prototype.addProcessApis = function (api) {
  405. const app = this.app;
  406. app.rendererProcess = {};
  407. Object.keys(api).forEach(function (name) {
  408. const commandName = api[name];
  409. app.client.addCommand(commandName, function () {
  410. const args = Array.prototype.slice.call(arguments);
  411. return this.execute(callProcessApi, name, args);
  412. });
  413. app.rendererProcess[name] = function () {
  414. return app.client[commandName].apply(app.client, arguments);
  415. };
  416. });
  417. app.mainProcess = app.electron.remote.process;
  418. };
  419. Api.prototype.transferPromiseness = function (target, promise) {
  420. if (!this.nodeIntegration) return;
  421. const addProperties = function (source, target, moduleName) {
  422. const sourceModule = source[moduleName];
  423. if (!sourceModule) return;
  424. target[moduleName] = transformObject(
  425. sourceModule,
  426. {},
  427. function (value, parent) {
  428. return value.bind(parent);
  429. }
  430. );
  431. };
  432. addProperties(promise, target, 'webContents');
  433. addProperties(promise, target, 'browserWindow');
  434. addProperties(promise, target, 'electron');
  435. addProperties(promise, target, 'mainProcess');
  436. addProperties(promise, target, 'rendererProcess');
  437. };
  438. Api.prototype.logApi = function () {
  439. const fs = require('fs');
  440. const path = require('path');
  441. const json = JSON.stringify(this.api, null, 2);
  442. fs.writeFileSync(path.join(__dirname, 'api.json'), json);
  443. };
  444. function transformObject(input, output, callback) {
  445. Object.keys(input).forEach(function (name) {
  446. const value = input[name];
  447. if (typeof value === 'object') {
  448. output[name] = {};
  449. transformObject(value, output[name], callback);
  450. } else {
  451. output[name] = callback(value, input);
  452. }
  453. });
  454. return output;
  455. }
  456. function callRenderApi(moduleName, api, args, requireName) {
  457. const module = window[requireName]('electron')[moduleName];
  458. if (typeof module[api] === 'function') {
  459. return module[api].apply(module, args);
  460. } else {
  461. return module[api];
  462. }
  463. }
  464. function callMainApi(moduleName, api, args, requireName) {
  465. let module = window[requireName]('electron').remote;
  466. if (moduleName) {
  467. module = module[moduleName];
  468. }
  469. if (typeof module[api] === 'function') {
  470. return module[api].apply(module, args);
  471. } else {
  472. return module[api];
  473. }
  474. }
  475. function callWebContentsApi(name, args, requireName) {
  476. const webContents = window[requireName](
  477. 'electron'
  478. ).remote.getCurrentWebContents();
  479. return webContents[name].apply(webContents, args);
  480. }
  481. function callBrowserWindowApi(name, args, requireName) {
  482. const browserWindow = window[requireName](
  483. 'electron'
  484. ).remote.getCurrentWindow();
  485. return browserWindow[name].apply(browserWindow, args);
  486. }
  487. function callProcessApi(name, args) {
  488. if (typeof process[name] === 'function') {
  489. return process[name].apply(process, args);
  490. } else {
  491. return process[name];
  492. }
  493. }
  494. module.exports = Api;