electron-main.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { join, basename, dirname } from 'path'
  2. import { lstatSync, readdirSync } from 'fs'
  3. import { app, BrowserWindow, shell } from 'electron'
  4. import ipc from 'electron-better-ipc'
  5. import { is } from 'electron-util'
  6. import Schild from 'schild'
  7. import CheapWatch from 'cheap-watch'
  8. import serializeError from 'serialize-error'
  9. import configFile from './configstore'
  10. import RollupBuild from './rollup'
  11. import { VERSION } from './version'
  12. import { mkDirByPathSync } from './mkdir'
  13. console.log(VERSION)
  14. if (process.argv.some(a => a === '-v')) app.exit()
  15. let configData = configFile.store
  16. configData['passAuth'] = process.argv.some(a => a === '--no-login') || is.development
  17. configData['debug'] = process.argv.some(a => a === '--debug') || is.development
  18. configData['version'] = VERSION
  19. console.log('Verzeichnisse anlegen oder verwenden …')
  20. mkDirByPathSync(configData.reports)
  21. if (process.env.PROD) {
  22. global.__statics = join(__dirname, 'statics').replace(/\\/g, '\\\\')
  23. }
  24. let mainWindow, win
  25. function createWindow () {
  26. mainWindow = new BrowserWindow({
  27. ...configData.windowBounds.main,
  28. show: false,
  29. useContentSize: true,
  30. nodeIntegration: is.development,
  31. title: `${app.getName()} ${VERSION['buildVersion']}`,
  32. icon: join(__dirname, '../icons/linux-256x256.png')
  33. })
  34. mainWindow.loadURL(process.env.APP_URL)
  35. if (is.development || process.argv.some(a => a === '--devtools')) mainWindow.openDevTools()
  36. mainWindow.on('close', e => {
  37. if (!configData.close) {
  38. e.preventDefault()
  39. configFile.set('windowBounds.main', mainWindow.getBounds())
  40. win && configFile.set('windowBounds.editor', win.getBounds())
  41. console.log('Konfigurationsdaten gespeichert.')
  42. configData.close = true
  43. mainWindow.close()
  44. win && win.close()
  45. }
  46. })
  47. mainWindow.webContents.on('will-navigate', (e, url) => {
  48. console.log(e, url)
  49. e.preventDefault()
  50. shell.openExternal(url)
  51. })
  52. mainWindow.on('closed', () => {
  53. mainWindow = null
  54. win = null
  55. })
  56. mainWindow.once('ready-to-show', async () => {
  57. mainWindow.show()
  58. scanSource()
  59. const fileWatcher = new CheapWatch({
  60. debounce: 50,
  61. dir: configData.reports,
  62. filter: ({ path, stats }) => stats.isDirectory() ? !path.includes('/') : path.endsWith('.html')
  63. })
  64. await fileWatcher.init()
  65. fileWatcher.on('+', ({ path, stats, isNew }) => { if (isNew) scanSource() })
  66. fileWatcher.on('-', ({ path, stats }) => { scanSource() })
  67. })
  68. }
  69. app.on('ready', createWindow)
  70. app.on('window-all-closed', () => {
  71. if (process.platform !== 'darwin') {
  72. app.quit()
  73. }
  74. })
  75. app.on('activate', () => {
  76. if (mainWindow === null) {
  77. createWindow()
  78. }
  79. })
  80. const scanSource = () => {
  81. const isDirectory = (source) => lstatSync(source).isDirectory()
  82. const getDirectories = (source) =>
  83. readdirSync(source).map(name => join(source, name)).filter(isDirectory)
  84. const obj = getDirectories(configData.reports)
  85. .reduce((o, element) => ({ ...o,
  86. [basename(element)]: readdirSync(element).filter(fn => fn.slice(-5) === '.html' && fn.charAt(0) !== '_')
  87. }), {})
  88. ipc.callRenderer(mainWindow, 'updateRepos', obj)
  89. }
  90. ipc.answerRenderer('repos', async () => scanSource())
  91. let webview
  92. ipc.on('webview', async (event) => { webview = event.sender })
  93. const rollup = new RollupBuild()
  94. rollup.on('message', error => ipc.callRenderer(mainWindow, 'messageRollup', serializeError(error)))
  95. let bundle
  96. rollup.on('bundle', b => {
  97. win && win.isVisible() && ipc.callRenderer(win, 'bundleRollup', b)
  98. bundle = b
  99. })
  100. let watcher = []
  101. rollup.on('moduleIDs', moduleIDs => {
  102. while (watcher.length) { watcher.pop().close() }
  103. Array.from(moduleIDs).forEach(async (moduleID) => {
  104. if (!moduleID.includes('node_modules')) {
  105. const emitter = new CheapWatch({
  106. dir: dirname(moduleID),
  107. debounce: 30,
  108. filter: ({ path, stats }) => moduleID.endsWith(path)
  109. })
  110. console.log('Beobachte: ' + moduleID)
  111. try {
  112. await emitter.init()
  113. emitter.on('+', async ({ path, stats, isNew }) => {
  114. if (!isNew) {
  115. console.log('Änderungen bei: ' + path)
  116. await runRollup()
  117. }
  118. })
  119. } catch (e) {
  120. console.log(e)
  121. }
  122. watcher.push(emitter)
  123. }
  124. })
  125. })
  126. const runRollup = async (args) => {
  127. const options = args && args.file ? {
  128. source: join(configData.reports, args.file),
  129. dest: join(configData.userData),
  130. debug: args.debug
  131. } : null
  132. try {
  133. await rollup.build(options)
  134. webview.send('loadSvelte')
  135. } catch (err) {
  136. console.log(err)
  137. }
  138. }
  139. ipc.on('runRollup', async (event, args) => {
  140. console.log('Rollup starten für', args.file, '…')
  141. runRollup(args)
  142. })
  143. const schild = new Schild()
  144. ipc.answerRenderer('schildConnect', async options => schild.connect(options))
  145. ipc.answerRenderer('schildTestConnection', async () => schild.testConnection())
  146. ipc.answerRenderer('schildSuche', async data => schild.suche(data))
  147. ipc.answerRenderer('schildGetKlasse', async id => schild.getKlasse(id))
  148. ipc.answerRenderer('schildGetSchule', async () => schild.getSchule())
  149. ipc.answerRenderer('schildGetSchueler', async id => schild.getSchueler(id))
  150. ipc.answerRenderer('schildGetSchuelerfoto', async id => schild.getSchuelerfoto(id))
  151. ipc.answerRenderer('schildGetNutzer', async id => schild.getNutzer(id))
  152. ipc.answerRenderer('getBundle', async () => bundle)
  153. ipc.answerRenderer('getConfigData', async () => configData)
  154. ipc.answerRenderer('setConfigData', async data => configData.set(data))
  155. ipc.answerRenderer('openEditor', async () => {
  156. if (win) {
  157. ipc.callRenderer(win, 'bundleRollup', bundle)
  158. win.show()
  159. } else {
  160. win = new BrowserWindow({ ...configData.windowBounds.editor, show: false })
  161. win.loadURL(process.env.APP_URL + '#/app/editor')
  162. win.once('ready-to-show', async () => {
  163. win.show()
  164. })
  165. win.on('closed', () => { win = null })
  166. win.on('close', async (e) => {
  167. if (!configData.close) {
  168. win.hide()
  169. e.preventDefault()
  170. }
  171. })
  172. }
  173. })